Tidenda

Pushing documents in

Push a wire with one request, read the response, retry safely and fix the common errors.

On this page

Send wires, planning items and articles into Tidenda from your own systems with one HTTP request each. This guide is for developers building an importer or feed connector.

curl -s -X POST "https://<public-api-host>/v1/documents" \
  -H "Authorization: Bearer $TIDENDA_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "3b2c1a40-f128-4cb6-b8c2-19a4d8d7e2f5",
    "type": "core/newswire",
    "title": "Cabinet reshuffle expected ahead of Thursday vote",
    "meta": {
      "priority": 3,
      "origin": "wire",
      "source": "acme-wire",
      "sourceItemId": "item-20260706-0142"
    },
    "content": { "text": "The prime minister is expected to name three new ministers." },
    "links": []
  }'

Get a key

Ask an owner or admin of the organisation to create a key in Settings → API keys with the documents:create scope and nothing else. Copy it when it is shown; it is not shown again. Keep it in a secret store and pass it to the importer as an environment variable, here TIDENDA_KEY.

Push a wire

The request above creates a wire. Every field in it is required:

  • id: a UUID you generate, such as crypto.randomUUID(). Store it with the source item so a retry sends the same one.
  • type: core/newswire.
  • title: a string. Tidenda stores it as one paragraph of rich text.
  • meta.priority: 1 to 6, 1 most urgent.
  • meta.origin: wire, pressrelease or media.
  • meta.source: a stable name for the feed, such as the agency.
  • meta.sourceItemId: the feed's own id for this item.
  • content.text: the body, as a string or a rich-text node array. A string becomes a single paragraph; send nodes to keep paragraphs apart. The node format is in the Document reference.
  • links: an empty array is fine.

Optional, when the feed has them: meta.sourceUrl (the link to the original), meta.byline (the author line) and content.attachments (files as links). The Document reference has their shapes.

Leave out meta.status and the other workflow fields. Tidenda sets them: every pushed document enters its workflow at draft. A body with any other meta.status is refused with 400 INVALID_STATUS, so a push can never publish on its own.

Send only the fields the Document reference defines. A field Tidenda does not know, such as a misspelt meta.sorce, is refused with 400 UNKNOWN_FIELDS and listed in the error's details.

Push a planning item or an article

The same endpoint accepts core/planning-item and core/article, shaped as in the Document reference. Each type's rules apply: a planning item needs a startdate and an enddate in meta.time; an article needs a target or slot time and links to its planning item and assignment. Both stay at draft until an editor moves them on. No other type can be pushed; any other type is refused with 400 UNSUPPORTED_TYPE.

Read the response

{ "ok": true, "data": { "id": "3b2c1a40-f128-4cb6-b8c2-19a4d8d7e2f5" } }

201 Created means the wire is stored. In the same request Tidenda moved it from draft to usable: it appears in the Wires view, a signed snapshot is made, and any webhook watching wires fires. See Wires for what editors do with it next.

Idempotency

Retries are safe, and there are two guards.

A repeated source item. If a wire with the same meta.source and meta.sourceItemId exists, the response is 200 with the existing wire's id, and nothing is created:

{ "ok": true, "data": { "id": "3b2c1a40-f128-4cb6-b8c2-19a4d8d7e2f5", "idempotent": true } }

This holds even when the retry carries a new id, so a feed that cannot remember its UUIDs still does not create duplicates. Treat 200 and 201 alike: the wire is there. Wires are kept and cannot be deleted, so a source item that arrived once is always found.

A repeated id. Any other create with an id already in use returns 409 CONFLICT and changes nothing. If the document with that id was deleted, the answer is 409 DOCUMENT_DELETED: deleted ids are never reused, so send the item under a new id.

Common errors

Response Usual cause Fix
400 INVALID_PAYLOAD A missing or wrong field. The message names it, for example meta.sourceItemId: Required. Correct the body. Retrying unchanged fails again.
400 UNKNOWN_FIELDS A field the type does not define, often a misspelling. details lists each one. Rename or remove the fields.
400 UNSUPPORTED_TYPE A type other than core/newswire, core/planning-item or core/article. Push only those types.
400 INVALID_STATUS meta.status set to anything other than draft. Leave meta.status out.
401 AUTH_ERROR No Authorization header, or a revoked or mistyped key. Check the header and the key.
403 FORBIDDEN The key lacks documents:create. Ask for a key with the scope.
409 CONFLICT The id is taken by a different item. Generate a new id for it.
409 DOCUMENT_DELETED The id belonged to a deleted document. Send the item under a new id.
429 RATE_LIMITED Too many requests from the key or the address. Wait Retry-After seconds.
5xx A failure on Tidenda's side. Retry with the same body and backoff.

Retry only 429 and 5xx. Every status, limit and header is in the API reference.

Read it back

GET /v1/documents serves published articles, images, audio, tags and site configuration, so a wire itself is not on it. Use a webhook on core/newswire to receive each wire as it publishes, or look for it in the Wires view.

When an editor turns the wire into an article and publishes it, read the article with a key holding publisher:read:

curl -s "https://<public-api-host>/v1/documents?type=core/article&updatedSince=2026-07-06T00:00:00Z" \
  -H "Authorization: Bearer $TIDENDA_READ_KEY"

Articles written from a wire carry a link back to it, with "type": "core/newswire" and "rel": "source".