Recipe: export your history and keep it in sync

Last updated: 11 November 2026 · 10 min read

This recipe combines two jobs: getting the workspace's whole history once as a file, and then keeping your own database in step with Clomni. Use it when moving to another system, keeping an archive or filling an analytics warehouse.

Steps

  1. 1

    What you get

    • Conversations, messages and contacts in one gzip file, one object per line.
    • After that, only the objects that changed, a few minutes behind, or right away by webhook.
    • A way to recover events missed while your server was down, from the last 30 days.
  2. 2

    Scopes you need

    • exports:run (high risk): bulk export. In the review describe the purpose, the system the file goes to, how often you export and how long you keep the file and how you delete it.
    • For ongoing sync: conversations:read, messages:read, contacts:read (medium risk). Take only the resources you need.
    • For missed events: events:read (medium risk), together with each topic's read scope.

    The "Data export" preset selects exports:run and events:read.

  3. 3

    1. Start the export

    resources takes one or more of conversations, messages, contacts; without it all three are exported. since and until are ISO 8601 times and filter on updated_at.

    curl -X POST "https://api.clomni.ai/v1/exports" \
      -H "Authorization: Bearer clomni_pat_xxx" \
      -H "Content-Type: application/json" \
      -d '{"resources": ["conversations", "messages", "contacts"], "since": "2026-01-01T00:00:00Z", "until": "2026-11-01T00:00:00Z"}'

    The answer is 202 Accepted with the job's id and status: "queued".

  4. 4

    2. Wait until it is ready

    Check every 15-30 seconds:

    curl "https://api.clomni.ai/v1/exports/15" \
      -H "Authorization: Bearer clomni_pat_xxx"

    status: queued, running, done, failed. When it is done, the answer has download_url and download_expires_at. The link works for 1 hour: if it has expired, read the export again and you get a new link. When it is failed, the reason is in error.

  5. 5

    3. Read the file

    The file is gzipped JSON Lines: each line is {"type": ..., "data": {...}}. type is conversation, message or contact, and data is the same object the sync endpoints return. Read the file line by line instead of loading it all into memory:

    curl -s "$DOWNLOAD_URL" | gunzip | head -n 3

    attachments[].url in a message is a short-lived link. If you need the files, download them as soon as the export is ready. If a link has expired, read the message again with GET /v1/conversations/{conversation_id}/messages to get a fresh one.

  6. 6

    4. Then fetch only what changed

    Do not repeat the export every day. After loading the file, use the sync endpoints:

    curl "https://api.clomni.ai/v1/sync/messages?updated_since=2026-11-01T00:00:00Z&limit=100" \
      -H "Authorization: Bearer clomni_pat_xxx"
    • GET /v1/sync/conversations, GET /v1/sync/messages and GET /v1/sync/contacts return objects ordered by (updated_at, id).
    • For the next page send next_cursor as after; when has_more is false, you are done.
    • Store the largest updated_at, start next time 2 minutes earlier than it, and write objects by id.
    • Running every 5-15 minutes is enough. The limit is 60 requests a minute per token, so use limit=100.

    To get new messages right away add the message.created webhook and let the sync fill the gaps. See App webhooks and events: setup, topics, signature verification.

  7. 7

    5. Recover missed events

    If your server was down, take the last 30 days of events from the feed, with the same ids as the webhooks:

    curl "https://api.clomni.ai/v1/events?types=message.created&limit=100" \
      -H "Authorization: Bearer clomni_pat_xxx"

    Each topic's read scope is needed as well: events:read alone returns an empty list. Events are written only while the workspace has an active developer token or installation, so events from before the token was created are not in the feed.

  8. 8

    For a reporting dashboard

    If Power BI or another BI tool only needs totals, use reports:read (low risk) instead of an export: conversation counts, first response and resolution times, totals per agent, inbox and team. Times are in Unix seconds:

    curl "https://api.clomni.ai/v1/reports?metric=conversations_count&type=account&since=1793491200&until=1794096000&group_by=day&timezone_offset=4" \
      -H "Authorization: Bearer clomni_pat_xxx"

    All report endpoints: Scopes and endpoints: reports, CSAT, SLA.

  9. 9

    Limits and data protection

    • One export runs at a time per workspace: a second request gets 409 conflict.
    • 6 exports per 24 hours: over the limit you get 429 rate_limited. Do not retry automatically.
    • An unknown resource or a wrong time format returns 400 invalid_request.
    • The file holds customers' personal data and messages. Store it encrypted, limit access, and delete it after the period you named in the review. When the app is deleted, data taken from Clomni must be deleted within 30 days.
  10. 10

    Common mistakes

    • The export is repeated every day and the daily limit runs out. Export once, then use sync.
    • The whole file is loaded into memory. Read it line by line.
    • download_url is used after it expired. GET /v1/exports/{export_id} gives a new link.
    • In a sync object the conversation id is taken for the dashboard number. The internal ID is in id, the dashboard number in number (in a message, conversation_number).
    • The dashboard number is passed to the conversation_id parameter of /v1/sync/messages. It expects the internal id of the sync conversation object.
    • ISO 8601 and Unix seconds get mixed up: sync and exports use ISO 8601, the older lists and reports use Unix seconds.
    • The regular lists (GET /v1/conversations) are paged through to copy everything. The order shifts between pages and objects are lost or come twice. Use the sync endpoints.

    All export and event endpoints: Scopes and endpoints: calls, webhooks, events, exports.

Document