Every API here is available over the APIs.io API and to AI agents over MCP.
MCP server
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
Tools for apis
7 MCP tools reach this
find_apisBrowse and filter every API in the catalog.
get_api_artifactsOne API's artifacts, grouped by type.
get_openapiThe primary OpenAPI for this API.
find_similar_apisAPIs that look like this one.
apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
resolveTurn a domain, URL or GitHub org into the provider it belongs to.
find_cohortsEvery scored population of providers in the catalog.
All 92 tools →
Call it yourself
curl for this page
This API
curl "https://apis.io/api/v1/apis/hjarni-com:hjarni-com-search-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"
Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.
Get an API key
Free tier, no form to fill in. Signing in shares your email address with us — we
store it to create your key and to recognise you if you sign in with another
provider. See our Privacy Policy and
Terms.
A second provider on the same verified email joins the account you already have.
openapi: 3.2.0
info:
title: Hjarni REST Search API
version: 1.0.0
description: Hjarni is a Markdown knowledge base that AI assistants and people share; this API reads and writes the same notes, folders (called containers) and tags that its MCP server exposes. Requests go to https://hjarni.com/api/v1 with a bearer token in the Authorization header, send and receive JSON, and list endpoints page with `page` and `per_page` and report totals in the `X-Total-Count`, `X-Page` and `X-Per-Page` headers. Requests are limited to 100 a minute per account across all of its tokens, and going over answers 429 with a `Retry-After` header.
termsOfService: https://hjarni.com/terms
contact:
name: Hjarni
email: evert@hjarni.com
url: https://hjarni.com/docs/api
servers:
- url: https://hjarni.com/api/v1
security:
- bearerAuth: []
tags:
- name: Search
description: Full-text search over notes.
paths:
/search:
get:
operationId: searchNotes
summary: Search notes
description: Full-text search over active notes (archived and trashed notes are left out), ranked by relevance when `q` is given. With a full-access token `search_scope` chooses personal notes, one team's notes, or both (`all`, the default); an agent token searches what its grants reach and is refused with 403 when it names a team it reaches nothing in. Paginated.
tags:
- Search
parameters:
- name: q
in: query
description: Search terms. Omitted, blank, or punctuation only, the scope is returned unfiltered and in no particular order.
schema:
type: string
- name: search_scope
in: query
description: '`personal` for personal notes only, `team:<id>` for one team''s notes, or `all` for personal notes plus every team the person belongs to. Any other value is treated as `all`. A `team:<id>` the person is not a member of answers 404.'
schema:
type: string
pattern: ^(personal|all|team:[0-9]+)$
default: all
example: personal
- $ref: '#/components/parameters/ExcludeBody'
- $ref: '#/components/parameters/Page'
- $ref: '#/components/parameters/PerPage'
responses:
'200':
description: One page of matching notes.
headers:
X-Total-Count:
$ref: '#/components/headers/X-Total-Count'
X-Page:
$ref: '#/components/headers/X-Page'
X-Per-Page:
$ref: '#/components/headers/X-Per-Page'
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/NoteSummary'
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'404':
$ref: '#/components/responses/NotFound'
'429':
$ref: '#/components/responses/TooManyRequests'
components:
schemas:
NoteAttachment:
type: object
description: A file attached to a note.
required:
- id
- description
- filename
- content_type
- byte_size
- url
- url_expires_at
properties:
id:
type: integer
description:
type:
- string
- 'null'
filename:
type: string
content_type:
type:
- string
- 'null'
byte_size:
type: integer
url:
type: string
format: uri
description: Signed download link that works without a token until `url_expires_at` (15 minutes). Treat it as a credential and do not store it; fetch the note again for a fresh one.
url_expires_at:
type: string
format: date-time
TeamRef:
type: object
required:
- id
- name
properties:
id:
type: integer
name:
type:
- string
- 'null'
ContainerRef:
type: object
required:
- id
- name
properties:
id:
type: integer
name:
type: string
Error:
type: object
description: 'Every error response carries `error`. The generic statuses also carry `code`, `message` and `docs_url`: 401, a 403 for an agent token outside its grants, and any status answered for a raised error or an unknown endpoint (400, 404, 5xx). Plan-limit 403s carry `upgrade_url` instead. Some endpoint-specific errors carry `error` alone.'
required:
- error
properties:
status:
type: integer
description: The HTTP status again. Present on errors raised inside the app and on unknown endpoints (400, 404, 5xx), not on 401 or the 403s.
error:
type: string
description: Human-readable message.
errors:
type: array
items:
type: string
description: 'Only on a validation failure raised inside the app (422): one message per problem.'
code:
type: string
description: 'Machine-readable code: `unauthorized` (401), `out_of_scope` (403, agent token), or for a raised error or unknown endpoint the snake_case name of the HTTP status, such as `bad_request`, `not_found`, `unprocessable_content` or `internal_server_error`.'
examples:
- unauthorized
- out_of_scope
- not_found
- internal_server_error
message:
type: string
description: What to do about it.
docs_url:
type: string
format: uri
description: The documentation page that explains this error.
upgrade_url:
type: string
format: uri-reference
description: Only on plan-limit 403s. A path on hjarni.com (relative, so prefix https://hjarni.com) to the checkout that lifts the limit.
team_url:
type: string
format: uri-reference
description: Only on the personal note-limit 403 from POST /notes. A relative path to creating a team, the other way past the personal limit.
NoteSummary:
type: object
description: A note as list endpoints return it. `body` is left out when the request sets `exclude_body=true`; `last_edited_by` and `last_edited_by_agent` appear only once someone has edited the note; `team` appears only on team notes.
required:
- id
- title
- summary
- summary_stale
- source_url
- archived
- favorited
- position
- lock_version
- created_at
- updated_at
- tag_list
- tags
- container
- files
properties:
id:
type: integer
title:
type: string
body:
type:
- string
- 'null'
description: Markdown. `[[id:Title]]` is a wiki-link to another note.
summary:
type:
- string
- 'null'
description: A short summary for scanning.
summary_stale:
type: boolean
description: True when the body changed after the summary was written.
source_url:
type:
- string
- 'null'
archived:
type: boolean
favorited:
type: boolean
position:
type:
- integer
- 'null'
description: Sort position among its siblings; null when unpositioned.
lock_version:
type: integer
description: Increases on every save. Send it back as expected_lock_version to guard a write.
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
last_edited_by:
type:
- string
- 'null'
description: Email address of whoever saved the note last.
last_edited_by_agent:
type:
- string
- 'null'
description: Name of the agent or token that saved last, if one did.
tag_list:
type: string
description: Tag names joined by a comma and a space, e.g. "planning, review".
tags:
type: array
items:
$ref: '#/components/schemas/TagRef'
container:
description: The folder the note is filed in; null for the inbox.
oneOf:
- $ref: '#/components/schemas/ContainerRef'
- type: 'null'
team:
$ref: '#/components/schemas/TeamRef'
files:
type: array
items:
$ref: '#/components/schemas/NoteAttachment'
TagRef:
type: object
required:
- id
- name
properties:
id:
type: integer
name:
type: string
responses:
TooManyRequests:
description: Over the rate limit of 100 requests a minute per account, counted across all of its tokens (counters are kept per server process, so the ceiling actually enforced can be somewhat higher). Wait the number of seconds in `Retry-After`. The body has `error` only.
headers:
Retry-After:
$ref: '#/components/headers/Retry-After'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error: Rate limit exceeded. Retry after 12 seconds.
NotFound:
description: No record with that id that this token can reach (including notes and folders in the Trash, except where an endpoint says otherwise), or no endpoint for this method and path. A revision that does not exist answers with `error` only.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
status: 404
error: Not Found
code: not_found
message: No endpoint matches this method and path, or the record is not one this token can reach. Every endpoint is listed in https://hjarni.com/openapi.json.
docs_url: https://hjarni.com/docs/api#errors
Forbidden:
description: 'Refused, for one of three reasons. (1) A plan limit: the Free plan''s note limit on create or restore, the Free file allowance on an attachment, or an account that is read-only because it holds more notes than its plan carries. The body has `error` and an `upgrade_url`, and the personal note-limit refusal also a `team_url`. (2) An agent token outside its grants: reading or writing where it was not given access, writing where it only reads, or calling an endpoint agent tokens cannot use. The body has `error` "Forbidden: outside token scope" with `code` `out_of_scope`, `message` and `docs_url`, and no `upgrade_url`. (3) A team folder where the person''s role is below editor: `error` only, "You don''t have permission to do that (editor required)."'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
examples:
outOfScope:
summary: Agent token outside its grants
value:
error: 'Forbidden: outside token scope'
code: out_of_scope
message: This token cannot do this. An agent token reaches only the folders it was given, at the level it was given, and never manages tags, personal instructions or folder order; those need a full-access token. A token's access is set in Settings > Connections.
docs_url: https://hjarni.com/docs/agent-tokens
noteLimit:
summary: Free plan note limit reached
value:
error: You've reached the 25 personal note limit on the Free plan. Upgrade to Pro for unlimited notes, or start a shared team knowledge base if this should live with your teammates.
upgrade_url: /checkout/new?reason=note_limit&ref=paywall_note_limit&t=CHECKOUT_TOKEN
team_url: /teams/new?ref=paywall_note_limit
editorRequired:
summary: Team role below editor
value:
error: You don't have permission to do that (editor required).
Unauthorized:
description: The bearer token is missing, unknown or expired.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error: Unauthorized
code: unauthorized
message: 'Missing or invalid token. Send it as Authorization: Bearer <token>; tokens are created in Settings > Connections.'
docs_url: https://hjarni.com/docs/api#auth
parameters:
Page:
name: page
in: query
description: Page number, starting at 1. Values below 1 are treated as 1.
schema:
type: integer
minimum: 1
default: 1
PerPage:
name: per_page
in: query
description: Items per page. Values outside 1-100 are clamped.
schema:
type: integer
minimum: 1
maximum: 100
default: 25
ExcludeBody:
name: exclude_body
in: query
description: '`true` leaves `body` out of every note, so a sync client can page through metadata cheaply and fetch bodies one at a time with GET /notes/{id}.'
schema:
type: boolean
default: false
headers:
X-Per-Page:
description: The page size used, after clamping.
schema:
type: integer
Retry-After:
description: Seconds until the current rate-limit window ends.
schema:
type: integer
X-Page:
description: The page returned.
schema:
type: integer
X-Total-Count:
description: Total number of records matching the query, across all pages.
schema:
type: integer
securitySchemes:
bearerAuth:
type: http
scheme: bearer
description: 'An API token in `Authorization: Bearer <token>`. Tokens are created in Settings > Connections, or issued to an assistant through the OAuth flow. A new token made in Settings reaches only the folders it is given, at Read or Write per folder, unless it is made with Everything I can reach (see https://hjarni.com/docs/agent-tokens); a token issued through OAuth acts with the person''s full access. A missing, unknown or expired token answers 401.'
externalDocs:
url: https://hjarni.com/docs/api