API referenceLetters

Get one letter with its delivery-event timeline

Returns the full letter, including the complete to/from addresses (list items carry only city and country), the price, and an inline events timeline holding the 100 most recent events, newest first.

Endpoint
GET https://api.dairo.app/v1/letters/{id}

Returns the full letter, including the complete to/from addresses (list items carry only city and country), the price, and an inline events timeline holding the 100 most recent events, newest first. Fetching an in-flight letter refreshes its delivery status, so polling this endpoint always reflects current tracking; the status lifecycle explains each value. Responds 404 when the id is unknown or belongs to another project.

Scope: letters:read. Send the API key as a bearer token; Scopes lists what each one reaches.

Request

cURL
curl "https://api.dairo.app/v1/letters/3fa85f64-5717-4562-b3fc-2c963f66afa6" \
  -H "Authorization: Bearer $DAIRO_API_KEY"

Path parameters

NameTypeRequiredDescription
idstringyesThe letter's ID.

Response

200 Success. Body: application/json, Letter.

FieldTypeRequiredDescription
object"letter"yes
idstringyes
statusLetterStatusyes
fileNamestring or nullno
pageCountinteger or nullno
toPostalAddressno
fromPostalAddress or nullno
printLetterPrintOptionsno
deliveryLetterDeliveryno
paperTypesarray of LetterPaperTypeno
autoSendbooleanno
priceLetterMoney or nullno
metadataobjectno
lastEventTypestring or nullnoThe type of the newest event on the letter's timeline (e.g. processing, canceled); null until the letter has an event.
lastEventAtstring (date-time) or nullnoWhen the newest timeline event occurred; null until the letter has an event.
submittedAtstring (date-time) or nullno
canceledAtstring (date-time) or nullno
errorstring or nullno
createdAtstring (date-time) or nullno
updatedAtstring (date-time) or nullno
eventsarray of LetterEventno
paymentSlip"qr", "sepaDe", "sepaAt", nullnoThe chosen payment-slip overlay, or null for a normal letter.
dryRunbooleannoTrue for a validate/price-only letter that is never mailed or charged.
providerMode"test", "live"notest: the letter is validated and priced but never printed, mailed, or charged (a dry run, or the account's provider mode is test). live: it will be printed and posted.
notificationsbooleannoOwner milestone-email preference for this letter.
paymentLetterPayment or nullnoThe structured payment object the slip was generated from (owner records), or null.
batchIdstring or nullnoThe owning batch id for a batch-member letter; null for a single send. Pairs with the ?batchId= list filter.
200
{
  "object": "letter",
  "id": "string",
  "status": "draft",
  "fileName": "letter.pdf",
  "pageCount": null,
  "to": {
    "name": "Ada Lovelace",
    "company": "Acme GmbH",
    "street": "Hauptstraße",
    "houseNumber": "1",
    "poBox": null,
    "addressLine2": null,
    "postalCode": "10115",
    "city": "Berlin",
    "country": "DE"
  },
  "from": {
    "name": "Ada Lovelace",
    "company": "Acme GmbH",
    "street": "Hauptstraße",
    "houseNumber": "1",
    "poBox": null,
    "addressLine2": null,
    "postalCode": "10115",
    "city": "Berlin",
    "country": "DE"
  },
  "print": {
    "mode": "color",
    "sides": "simplex",
    "addressPlacement": "left"
  },
  "delivery": "economy",
  "paperTypes": [
    "standard"
  ],
  "autoSend": true,
  "price": {
    "currency": "EUR",
    "amount": 0,
    "walletAmount": 0,
    "walletCurrency": "string",
    "walletRate": 0
  },
  "metadata": {},
  "lastEventType": null,
  "lastEventAt": "2026-10-19T09:30:00Z",
  "submittedAt": "2026-10-19T09:30:00Z",
  "canceledAt": "2026-10-19T09:30:00Z",
  "error": null,
  "createdAt": "2026-10-19T09:30:00Z",
  "updatedAt": "2026-10-19T09:30:00Z",
  "events": [
    {
      "object": "letter_event",
      "eventId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "letterId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "type": "string",
      "code": null,
      "description": null,
      "producer": null,
      "location": null,
      "reason": null,
      "hasImage": true,
      "occurredAt": "2026-10-19T09:30:00Z",
      "recordedAt": "2026-10-19T09:30:00Z"
    }
  ],
  "paymentSlip": "qr",
  "dryRun": true,
  "providerMode": "test",
  "notifications": true,
  "payment": {
    "type": "qr",
    "creditor": {
      "name": "Ada Lovelace",
      "iban": "string",
      "bic": null,
      "street": "Hauptstraße",
      "houseNumber": "1",
      "postalCode": "10115",
      "city": "Berlin",
      "country": "DE"
    },
    "amount": 0,
    "currency": "CHF",
    "reference": null,
    "message": null,
    "debtor": {
      "name": "Ada Lovelace",
      "street": "Hauptstraße",
      "houseNumber": "1",
      "postalCode": "10115",
      "city": "Berlin",
      "country": "DE"
    }
  },
  "batchId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}

Errors

Every error has the same body, {"error": {"type", "code", "message", "param"}}; branch on code. Errors lists every code.

StatusMeaning
400The request is malformed or a value is invalid (invalid_request, invalid_domain, idempotency_key_mismatch).
401The API key is missing or invalid.
403The key lacks the scope this endpoint needs (scope_missing) or may not do this (not_permitted).
404No such resource in this account (resource_not_found).
422The request is well-formed but a field failed validation (validation_failed).
429Rate limit, plan limit, budget or spend cap reached (rate_limited, plan_limit_reached, budget_exceeded, spend_cap_reached).
500An unexpected error; retry with backoff, then contact support (internal_error).

On this page