Skip to main content

API: getting started

The Ultrathink REST API lets your own code read, search, add, change and delete your entries. Use it to connect another tool, run a sync, or pull your entries into a script.

This page covers what you need before your first call: a key, the address, the limits and the errors. The API reference lists every endpoint and field. To use your entries from Claude Code or another AI tool without writing code, connect the MCP server instead.

What you need

  • A Pro plan. The API is part of Pro, and a key on a Free account gets a 402 error.
  • A device key with API access. Device keys are what the browser extension and the desktop app use too. See Connect an app with a device key for the basics.

Turning on API access

  1. Open Settings, then Device keys (under Config).
  2. Type a Device name, for example “Sync script”, and click Create key.
  3. Copy the key straight away. The app shows it once and never again.
  4. In Your keys, find the new key and click API settings (the button next to Revoke key).
  5. Switch on API access.
  6. Choose Permissions:
PermissionWhat the key can do
Read onlyList, read and search entries, related entries, topics and people
Read and writeEverything above, plus create, update and delete entries and upload files

You can also add a Description, such as “ChatGPT custom GPT”, so you remember what uses the key. Keys with API access show an “API read only” or “API read and write” label in the list.

A read only key cannot save anything, from the API or from any app. Do not switch the key your browser extension uses to read only, or the extension stops saving.

Sending the key

Send the key as a Bearer token in the Authorization header of every request:

curl -H "Authorization: Bearer YOUR_DEVICE_KEY" \
  "https://us-central1-ultrathink-50f7f.cloudfunctions.net/api/v1/entries?limit=5"

Base URL

Every endpoint sits under:

https://us-central1-ultrathink-50f7f.cloudfunctions.net/api/v1

Requests and replies are JSON, apart from file uploads, which can also be multipart/form-data.

Replies

A successful reply looks like this:

{
  "success": true,
  "data": { },
  "meta": {
    "requestId": "a1b2c3d4e5f60718",
    "timestamp": "2026-10-14T12:00:00.000Z"
  }
}

data holds the entry, the list or the answer. Lists of entries carry items and a pagination object (see Paging below).

Rate limits

Limits are counted per account, per minute. Every key on the same account shares them.

EndpointLimit per minute
GET /entries60
GET /entries/{id}120
POST /entries30
PATCH /entries/{id}30
DELETE /entries/{id}60
GET /entries/{id}/related60
GET /topics30
GET /people30
POST /search15
POST /upload20

Every reply carries these headers:

HeaderWhat it says
X-RateLimit-LimitHow many requests the endpoint allows per minute
X-RateLimit-RemainingHow many are left in this minute
X-RateLimit-ResetWhen the minute resets, as an ISO 8601 time

Over the limit, you get a 429 reply. Its Retry-After header and error.details.retryAfter both give the number of seconds to wait.

Errors

An error reply has success: false and an error object:

{
  "success": false,
  "error": {
    "message": "Too many requests",
    "code": "RATE_LIMITED",
    "details": { "retryAfter": 45 }
  },
  "meta": {
    "requestId": "a1b2c3d4e5f60718",
    "timestamp": "2026-10-14T12:00:00.000Z"
  }
}
StatusCodeWhen
400BAD_REQUESTA field or filter is missing or not valid. details often lists what is wrong
401UNAUTHORIZEDNo key, a mistyped key, or a revoked key
402UPGRADE_REQUIREDThe account is not on Pro
403FORBIDDENThe key has no API access, or a read only key tried to write
404NOT_FOUNDNo such entry, or one you cannot see
405METHOD_NOT_ALLOWEDThe endpoint does not take that method. The Allow header lists the ones it does
413ENTRY_TOO_LARGEThe entry is too big to store
429RATE_LIMITEDToo many requests. Wait retryAfter seconds
500INTERNAL_ERRORSomething went wrong on our side. Try again

Messages you may see:

MessageWhat to do
“Missing API key”Send the Authorization: Bearer header, with a space before the key
“Invalid or revoked API key”Check you copied the whole key. If it was revoked, create a new one
“API access not enabled for this key”Switch on API access for the key in Settings, then Device keys
“Pro plan required for API access”Move the account to Pro in Settings, then Billing
“This API key only has read permission”Set the key’s Permissions to Read and write, or use another key

Paging

GET /entries returns a page at a time: 20 entries by default, up to 100 with limit. Each reply has a pagination object:

"pagination": {
  "page": 1,
  "limit": 100,
  "total": 1311,
  "totalPages": 14,
  "hasMore": true,
  "nextCursor": "Xk2c9QwLm3"
}

To get the next page, pass nextCursor back as cursor. Keep going until hasMore is false, when nextCursor is null.

page also works, but it can skip at most 2,000 entries. Past that, the API returns a 400 and asks you to use cursor.

Reading all your entries

There is no export button in the app. On Pro, the API is the way to read everything you have saved:

  1. Call GET /entries?limit=100.
  2. Save the items.
  3. Call again with cursor set to the last reply’s nextCursor.
  4. Stop when hasMore is false.
curl -H "Authorization: Bearer YOUR_DEVICE_KEY" \
  "https://us-central1-ultrathink-50f7f.cloudfunctions.net/api/v1/entries?limit=100&cursor=NEXT_CURSOR"

To keep a copy up to date afterwards, ask only for what changed with updatedSince, a date (2026-10-01) or an ISO 8601 time. At most 2,000 entries can match one call, so run it often enough, or use a later time.

curl -H "Authorization: Bearer YOUR_DEVICE_KEY" \
  "https://us-central1-ultrathink-50f7f.cloudfunctions.net/api/v1/entries?updatedSince=2026-10-01&limit=100"

Entries come back with their notes, AI summary, topics, people, task fields and, for audio, the transcript. Files such as screenshots and recordings are not included in the reply. To ask for a full copy of your data, email me@cmw.email.

Quick examples

Create a note:

curl -X POST \
  -H "Authorization: Bearer YOUR_DEVICE_KEY" \
  -H "Content-Type: application/json" \
  -d '{"title": "Call notes with Ana", "notes": "She wants the report by Friday.", "topics": ["reporting"]}' \
  "https://us-central1-ultrathink-50f7f.cloudfunctions.net/api/v1/entries"

Mark a task as done:

curl -X PATCH \
  -H "Authorization: Bearer YOUR_DEVICE_KEY" \
  -H "Content-Type: application/json" \
  -d '{"taskStatus": "@done"}' \
  "https://us-central1-ultrathink-50f7f.cloudfunctions.net/api/v1/entries/ENTRY_ID"

Ask a question:

curl -X POST \
  -H "Authorization: Bearer YOUR_DEVICE_KEY" \
  -H "Content-Type: application/json" \
  -d '{"query": "What did I decide about the pricing page?"}' \
  "https://us-central1-ultrathink-50f7f.cloudfunctions.net/api/v1/search"

Using the API from a ChatGPT custom GPT

A custom GPT can call the API through an action. The API is described in an OpenAPI file that the GPT builder can import:

https://tryultrathink.com/docs/api/openapi.yaml

Give the action your key as a Bearer token, so each call carries Authorization: Bearer YOUR_DEVICE_KEY. Use a key with Read only permission unless you want the GPT to save and change entries. Anyone who can use the GPT can then read your entries, so keep it private.

The same file works in Postman, Insomnia and other API tools.

Keeping your key safe

  • Treat the key like a password. Keep it out of shared files, chats and code you commit.
  • Give each tool its own key, so you can revoke one without breaking the others.
  • Use Read only unless the tool needs to write.
  • Revoke a key you no longer use with Revoke key in Settings, then Device keys. It stops working at once and cannot be turned back on.