API referenceLetters

Cancel a letter that has not yet been dispatched

Cancels a letter and returns it with status: "canceled".

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

Cancels a letter and returns it with status: "canceled". A letter is cancelable while it is draft, queued, processing, printable, or submitted; once it is in_transit or in a terminal state the call responds 409 with code letter_not_cancelable, and an unknown id is a 404. Cancellation is a status transition, so it emits a letter.status_changed webhook event.

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

Request

cURL
curl -X POST "https://api.dairo.app/v1/letters/3fa85f64-5717-4562-b3fc-2c963f66afa6/cancel" \
  -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