Skip to main content
The SDKs cover every operation an API key can call, and every endpoint in the API reference shows how to call it from each. They follow the API’s conventions, so what you read about the API holds for them too. This page covers what the three share. Each language’s page has its install, configuration and what is particular to it. Need an SDK in another language? Let us know which one. Meanwhile, anything can call the API over HTTP, or generate a client from /openapi.json.

Install and connect

Create a client with a project API key, made under API keys in the web app. Each reads NOHEAD_API_KEY from the environment when you don’t pass one; none reads the key that nohead login saves for the CLI, so give your app a key of its own. Writing content, drafts, uploads and webhooks needs a key with Published records only off and the write scopes (records:write, assets:write, …); new keys are published-only by default. API keys belong to a project, so you never pass a project ID, and you can name collections by slug.
API keys are secrets: use the SDKs on servers, never in a browser.

Read content

List methods give you a page, which you can also loop over: the SDK fetches the following pages as you go. Filters are the API’s: a value to equal, or operators such as { exists: true }.
In TypeScript, describe a collection’s fields and its records are typed: nohead.records.get<Post>(id) makes post.data.title a string. In Python, results are Pydantic models, and a record’s values are in its data dict. In Ruby, read fields as methods or with [] (post.data["title"]); timestamps are Times.

Write content

Every write is versioned and attributed to the key. Add a note to history with changeNote (TypeScript) or change_note (Python, Ruby).

Review changes before they go live

A draft holds changes to a record until they are merged into it, now or at a set time, while the record keeps its current content. A record has one draft at most, and a merge changes content only: a live record stays live. Agents can propose changes this way for a person to review and merge.

Retries and idempotency

Failed requests are retried twice by default:
  • connection errors and timeouts
  • 429 rate_limited, waiting for Retry-After when it is at most a minute (a longer wait raises RateLimitError at once)
  • 500, 502, 503 and 504
  • 409 with detail code in_progress: the same write, still running
Each attempt times out after 60 seconds. Set timeout and maxRetries (max_retries) on the client to change them. TypeScript also takes them for one call, and in Python with_options returns a client with other settings. Errors and retries covers what each error means. Every write carries an Idempotency-Key that stays the same across its retries, so a retry after a lost response never writes twice. To make a write safe across retries of your own (a job that may run twice), pass the key yourself:

Concurrent edits

Pass the record you read as ifMatch (if_match). If someone changed it since, the API refuses the write with 412 and nothing is written.

Errors

Each error type of the API is an error class: ValidationError (422), NotFoundError (404), RateLimitError (429) and so on, all subclasses of APIError. They carry the status, type, message, the request ID and the field-level details.

Upload files

Files go straight to storage, never through the API. assets.upload does the whole flow in one call: it creates the upload, sends the bytes to storage, completes the upload (which checks the file) and returns the ready asset. Reference the asset from an asset field.
Images covers image URLs and the loaders for Next.js, Astro and Nuxt. To search, see API search.

Verify webhooks

Webhook requests are signed. unwrap (unwrapWebhook in TypeScript) checks the signature and the timestamp and returns the event; it raises (or throws) when either is off. Pass the raw body, before any JSON parsing.
The same event can arrive twice: deduplicate by the webhook-id header. Webhooks covers the event types, the payload and rotating the secret.

Versions

The SDKs have their own version numbers, separate from the API’s /v1. Until 1.0, the SDKs, the CLI and the API may change in ways that break your code: pin a version, and read each release’s Breaking entries before upgrading. From 1.0, the API only adds within /v1, so an older SDK keeps working; anything an SDK depends on is deprecated at least 12 months before it is removed, and the SDKs warn when they call something deprecated. Each SDK’s releases on GitHub (linked from the table at the top) list what changed in each version.