Developers › Getting started

Quickstart

Send your first registered letter in three calls: upload a PDF, create the letter, follow its events. Every example on this page uses a test key, so nothing is printed or charged. Base URL: https://api.sendregistered.com/v1.

Test mode. Keys that start with sr_test_ run the full flow with test credit and return a sample proof PDF. Swap in your sr_live_ key when you go live; nothing else changes.
  1. Create a test key

    In your account under API keys, choose New key, mode Test and the scopes read and write. Copy the key now: we show it once.

  2. Upload the PDF

    Send an A4 PDF up to 8 MB. We check that the address sits in the envelope window and that every page can be printed. You get a document id back.

  3. Create and pay the letter

    Pass the document id, the product code and the recipient. With "pay": true the letter is paid from your credit in the same call. Send an Idempotency-Key so a retry never sends twice.

  4. Follow it

    Add a webhook endpoint in your account. You get letter.printed, letter.posted, letter.awaiting_pickup and letter.delivered, each signed with SendRegistered-Signature. The proof PDF is ready once the letter is posted.

Upload the PDF
curl https://api.sendregistered.com/v1/documents \
  -H "Authorization: Bearer sr_test_4f2a9Kd7Lq" \
  -H "Idempotency-Key: doc-2026-4471" \
  -H "Content-Type: application/json" \
  -d '{
    "filename": "reminder-4471.pdf",
    "pdf_base64": "JVBERi0xLjQK..."
  }'
201 Created
{
  "id": "doc_8Kq2mZ",
  "pages": 2,
  "sha256": "6e340b9cffb37a989ca544e6bb780a2c...",
  "fit": { "ok": true, "warnings": [] }
}
Create the letter
curl https://api.sendregistered.com/v1/letters \
  -H "Authorization: Bearer sr_test_4f2a9Kd7Lq" \
  -H "Idempotency-Key: claim-2026-4471" \
  -H "Content-Type: application/json" \
  -d '{
    "document_id": "doc_8Kq2mZ",
    "destination": "DE",
    "product_id": "de-einwurf",
    "sender": {
      "name": "Nordlicht Legal GmbH",
      "street": "Friedrichstraße 114",
      "postal_code": "10117",
      "city": "Berlin",
      "country": "DE"
    },
    "recipient": {
      "name": "Hausverwaltung Berger GmbH",
      "street": "Kastanienallee 12",
      "postal_code": "10435",
      "city": "Berlin",
      "country": "DE"
    },
    "pay": true,
    "terms": true
  }'
201 Created
{
  "id": "SR-TEST-2026-00001",
  "test": true,
  "status": "received",
  "destination": "DE",
  "product_id": "de-einwurf",
  "pages": 2,
  "currency": "EUR",
  "amount": 795,
  "credit_amount": 795,
  "tracking_number": "RRTEST000001DE"
}
Event sent to your endpoint
{
  "id": "evt_9xL2mK7pQ1vB",
  "type": "letter.delivered",
  "created_at": "2026-11-10T11:21:04Z",
  "livemode": false,
  "data": {
    "id": "SR-TEST-2026-00001",
    "status": "delivered",
    "tracking_number": "RRTEST000001DE",
    "proof_url": "https://api.sendregistered.com/v1/letters/SR-TEST-2026-00001/proof"
  }
}
Getting started › Core concepts

Authentication, idempotency, limits & webhooks

Pass your API key in the Authorization: Bearer sr_live_... (or sr_test_...) header on every call to https://api.sendregistered.com/v1.

Test and live keys

Keys prefixed with sr_test_ run in an isolated sandbox with €1,000 of test credit, deterministic tracking numbers, sample proof PDFs, and test-only webhooks (livemode: false). Live keys (sr_live_) require a verified business account and debit your prepaid EUR credit balance.

Idempotency

Every write call (POST /v1/documents, POST /v1/letters, POST /v1/letters/{id}/pay, POST /v1/letters/{id}/cancel) requires an Idempotency-Key header (8–200 characters), kept for 24 hours. Repeating the same key with the same body replays the original response; reusing a key with a different payload returns 409 idempotency_conflict.

Spending limits

Each API key and each connected MCP assistant has its own optional daily EUR limit and monthly EUR limit in API keys. When a letter would exceed either limit, the API returns 409 limit_exceeded before touching your credit balance.

Webhooks & signature verification

Register HTTPS endpoints in API keys for: letter.paid, letter.printed, letter.posted, letter.awaiting_pickup, letter.delivered, letter.failed, letter.cancelled, balance.low. Every delivery carries a SendRegistered-Signature: t=<unix_ts>,v1=<hmac_sha256> header signed with the endpoint's whsec_... secret over "<t>.<raw_body>". Reject timestamps older than 5 minutes (300 seconds). Failed deliveries retry with exponential backoff for up to 3 days (72 hours).

Verify SendRegistered-Signature (Node)
import { createHmac, timingSafeEqual } from "node:crypto";

export function verifyWebhook(rawBody, header, secret) {
  const parts = Object.fromEntries(
    header.split(",").map((p) => p.split("="))
  );
  const age = Math.abs(Date.now() / 1000 - Number(parts.t));
  if (!parts.t || !parts.v1 || age > 300) return false;

  const expected = createHmac("sha256", secret)
    .update(`${parts.t}.${rawBody}`)
    .digest("hex");
  return timingSafeEqual(
    Buffer.from(parts.v1, "hex"),
    Buffer.from(expected, "hex")
  );
}
Resources › Letters

Create a letter

POST/v1/letters

Creates a registered letter from an uploaded document. With pay set to true the letter is paid from your credit and goes to print on the next posting run. Needs the write scope.

Body (from OpenAPI 3.1 schema)

destinationstringrequired

Two-letter destination country code (DE, FR, NL, BE, ES, GB, CH, US).

DEFRBEESCHNLGBUS
product_idstring

Product code from GET /v1/destinations, such as de-einwurf or fr-lrar. Defaults to the country's primary registered product.

colorboolean

Print in colour. Default false.

duplexboolean
acknowledgementboolean
document_idstringrequired

Id of a document from POST /v1/documents. A document is used for one letter.

senderobjectrequired

Return address printed on the letter.

namestringrequired

Person or company, up to 2 lines.

streetstringrequired

Street and house number.

zipstringrequired
citystringrequired

City or town.

countrystringrequired

Two-letter ISO country code.

statestring

State or province (required for US).

attnstring
recipientobjectrequired

The address printed in the envelope window. We check that it is complete for the country.

namestringrequired

Person or company, up to 2 lines.

streetstringrequired

Street and house number.

zipstringrequired
citystringrequired

City or town.

countrystringrequired

Two-letter ISO country code.

statestring

State or province (required for US).

attnstring
coverboolean
fit_approvedboolean
termsboolean

Accept the terms of service for this registered letter (must be true when paying).

topicstring
handwritten_ackboolean
payboolean

Pay from your credit now. Default true. Use false to create the letter and pay later with POST /v1/letters/{id}/pay.

Headers

Idempotency-Keystringrequired

Any unique string (8–200 characters), kept for 24 hours. The same key with the same body returns the first result; a different body returns 409.

Returns

The letter object with status received when paid, or awaiting_confirmation / awaiting_payment when pay is false. Prices are in cents.

Errors

CodeWhat to do
insufficient_creditTop up your credit, or create the letter with "pay": false.
limit_exceededThe key reached its daily or monthly limit. Raise it in your account.
invalid_requestComplete the address or body; the message names the field.
fit_confirmation_requiredThe address is close to the window edge. Pass "confirm_fit": true or upload a new PDF.
credit_not_available_for_currencyLetters to Switzerland (CHF) are paid by card. Use the checkout flow for CHF orders.
Request
curl https://api.sendregistered.com/v1/letters \
  -H "Authorization: Bearer sr_test_4f2a9Kd7Lq" \
  -H "Idempotency-Key: claim-2026-4471" \
  -H "Content-Type: application/json" \
  -d '{
    "document_id": "doc_8Kq2mZ",
    "destination": "DE",
    "product_id": "de-einwurf",
    "sender": {
      "name": "Nordlicht Legal GmbH",
      "street": "Friedrichstraße 114",
      "postal_code": "10117",
      "city": "Berlin",
      "country": "DE"
    },
    "recipient": {
      "name": "Hausverwaltung Berger GmbH",
      "street": "Kastanienallee 12",
      "postal_code": "10435",
      "city": "Berlin",
      "country": "DE"
    },
    "pay": true,
    "terms": true
  }'
Response
{
  "id": "SR-TEST-2026-00001",
  "test": true,
  "status": "received",
  "destination": "DE",
  "product_id": "de-einwurf",
  "pages": 2,
  "currency": "EUR",
  "amount": 795,
  "credit_amount": 795,
  "tracking_number": "RRTEST000001DE"
}
Error shape
{
  "error": {
    "code": "limit_exceeded",
    "message": "Daily spending limit for this API key has been reached.",
    "doc_url": "https://sendregistered.com/developers/api#errors"
  }
}
Resources › OpenAPI 3.1

List destinations and products

GET/v1/destinations

Returns all 8 supported destination countries, available postal products, carrier names and prices in cents.

GET /v1/destinations
curl https://api.sendregistered.com/v1/destinations \
  -H "Authorization: Bearer sr_test_4f2a9Kd7Lq"
Resources › OpenAPI 3.1

Calculate a letter quote

POST/v1/quotes

Quotes a letter in cents for the authenticated business account, applying EU reverse charge or non-EU VAT rules when configured on the account.

Body

destinationstringrequired

Two-letter destination country code (DE, FR, NL, BE, ES, GB, CH, US).

DEFRBEESCHNLGBUS
product_idstring

Product code from GET /v1/destinations, such as de-einwurf or fr-lrar. Defaults to the country's primary registered product.

colorboolean

Print in colour. Default false.

duplexboolean
acknowledgementboolean
pagesintegerrequired

Number of A4 pages in the PDF (1 to 20).

sender_countrystring
POST /v1/quotes
curl -X POST https://api.sendregistered.com/v1/quotes \
  -H "Authorization: Bearer sr_test_4f2a9Kd7Lq"
Resources › OpenAPI 3.1

Get prepaid credit balance

GET/v1/balance

Returns the account's prepaid credit balance in EUR cents (`paid`, `bonus`, `subscription`, `total` and active `lots`).

GET /v1/balance
curl https://api.sendregistered.com/v1/balance \
  -H "Authorization: Bearer sr_test_4f2a9Kd7Lq"
Resources › OpenAPI 3.1

Upload a PDF document

POST/v1/documents

Uploads a base64-encoded PDF (up to 8 MB, 1–20 pages) and checks whether the pages fit the printable area and envelope window.

Body

filenamestring

Original PDF filename (must end with .pdf).

content_base64stringrequired
POST /v1/documents
curl -X POST https://api.sendregistered.com/v1/documents \
  -H "Authorization: Bearer sr_test_4f2a9Kd7Lq"
Resources › OpenAPI 3.1

List recent letters

GET/v1/letters

Returns up to 100 letters created through the API in the key's mode (`live` or `test`).

GET /v1/letters
curl https://api.sendregistered.com/v1/letters \
  -H "Authorization: Bearer sr_test_4f2a9Kd7Lq"
Resources › OpenAPI 3.1

Get a letter

GET/v1/letters/{id}

Returns status, price, timestamps and tracking number for one letter.

GET /v1/letters/{id}
curl https://api.sendregistered.com/v1/letters/{id} \
  -H "Authorization: Bearer sr_test_4f2a9Kd7Lq"
Resources › OpenAPI 3.1

Pay an unpaid letter from credit

POST/v1/letters/{id}/pay

Pays an existing `awaiting_confirmation` or `awaiting_payment` letter from prepaid credit within the API key's spending limit.

Body

termsbooleanrequired

Accept the terms of service for this registered letter (must be true when paying).

POST /v1/letters/{id}/pay
curl -X POST https://api.sendregistered.com/v1/letters/{id}/pay \
  -H "Authorization: Bearer sr_test_4f2a9Kd7Lq"
Resources › OpenAPI 3.1

Cancel a letter before printing

POST/v1/letters/{id}/cancel

Cancels an unpaid draft or withdraws a paid letter before it has been printed, returning credit to the balance.

POST /v1/letters/{id}/cancel
curl -X POST https://api.sendregistered.com/v1/letters/{id}/cancel \
  -H "Authorization: Bearer sr_test_4f2a9Kd7Lq"
Resources › OpenAPI 3.1

Get proof certificate facts or PDF

GET/v1/letters/{id}/proof

Returns proof hashes, timestamps and tracking JSON, or streams the proof certificate PDF when `?format=pdf` or `Accept: application/pdf` is passed.

GET /v1/letters/{id}/proof
curl https://api.sendregistered.com/v1/letters/{id}/proof \
  -H "Authorization: Bearer sr_test_4f2a9Kd7Lq"
SendRegistered API v1 Documentation — Quickstart, Reference & Webhooks