Buni.aiDocs

Dead letters and polling

Pull new items from one of your APIs on a timer with polling triggers, and inspect or replay events that could not be delivered.

Two tools for when pushing events to Buni.ai does not fit:

  • A polling trigger makes Buni.ai call one of your endpoints on a timer and run the project's flow once for each new item.
  • Dead letters are events that could not be delivered. You can list them and replay each one once.

Both use the /flows/{projectId}/... endpoints and need a token with the flow:trigger scope, which the app offers for chatbot projects.

Automation projects

Automation workflows start from triggers configured on the canvas instead. See Automation triggers. Failed automation runs are also recorded as dead letters, but reading them through these endpoints needs a flow:trigger token, which the app does not offer for automation projects.

Polling triggers

Register one

curl -X POST "https://www.buni.ai/api/v1/orgs/$ORG_ID/flows/$PROJECT_ID/polling" \
  -H "Authorization: Bearer $BUNI_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "source": "crm",
    "pollKey": "new-leads",
    "pollEndpoint": "https://crm.example.com/api/leads?status=new",
    "dedupeField": "id",
    "authHeader": "Bearer crm_example_token",
    "intervalMs": 300000
  }'
FieldRequiredDefaultMeaning
sourceYes-A label. Added to every item as source.
pollKeyYes-Unique name within the project. Registering an existing key updates it.
pollEndpointYes-URL Buni.ai calls with GET.
dedupeFieldNoidItem field used to recognise items already processed.
authHeaderNo-Sent as the Authorization header.
intervalMsNo60000Milliseconds between polls.

The response is 201 with the stored trigger under data. The first poll is due straight away.

What happens on each poll

  1. Buni.ai sends GET pollEndpoint with Content-Type: application/json and your authHeader.
  2. The response can be an array of items, an object with a data array, or a single object.
  3. Items whose dedupeField value was already seen are skipped.
  4. Every other item runs the project's flow, with the item's fields plus source and _pollKey as the payload.
  5. The next poll is scheduled intervalMs later.

Design your endpoint to return only items not yet delivered, for example with a created-after filter. Between polls Buni.ai remembers only the last processed dedupeField value, not the full history, so an endpoint that keeps returning older items would have them processed again.

Each item goes through the same trigger checks as POST /flows/{projectId}/trigger, so it must contain the keys the Trigger node expects. See Project API settings.

A failed poll (non-2xx, or a response that is not JSON) and each item whose run fails are written to dead letters. The poll schedule carries on either way.

List and delete

# All polling triggers, or one with ?pollKey=
curl "https://www.buni.ai/api/v1/orgs/$ORG_ID/flows/$PROJECT_ID/polling?pollKey=new-leads" \
  -H "Authorization: Bearer $BUNI_API_TOKEN"

# Stop polling
curl -X DELETE "https://www.buni.ai/api/v1/orgs/$ORG_ID/flows/$PROJECT_ID/polling?pollKey=new-leads" \
  -H "Authorization: Bearer $BUNI_API_TOKEN"

The stored trigger includes lastSeenValue, lastPolledAt and nextPollAt, useful for checking that polling is running. It also returns the authHeader you stored, so treat these responses as sensitive.

Dead letters

An event becomes a dead letter when it could not be delivered:

targetTypeWritten whenrequestPayload
pollingA poll request failed.pollKey and pollEndpoint.
pollingA polled item's flow run failed.The item.
FLOWAn automation run failed after all retry attempts.The original request.

List them

curl "https://www.buni.ai/api/v1/orgs/$ORG_ID/flows/$PROJECT_ID/dead-letters?unresolvedOnly=true&limit=50" \
  -H "Authorization: Bearer $BUNI_API_TOKEN"
Query parameterDefaultMeaning
sourceAllOnly events from this source.
unresolvedOnlyfalsetrue hides events that were already replayed.
limit50Page size, up to 200.
offset0Items to skip.
{
  "data": [
    {
      "id": "clxa0dl0q0001ab12cd34ef80",
      "source": "crm",
      "targetType": "polling",
      "triggerKey": "new-leads",
      "requestPayload": { "id": "lead_9922", "name": "Kofi Boateng" },
      "failureReason": "Flow invocation failed",
      "attemptCount": 1,
      "replayedAt": null,
      "replayStatus": null,
      "createdAt": "2026-09-24T09:55:01.000Z"
    }
  ],
  "total": 1,
  "limit": 50,
  "offset": 0
}

Events are newest first.

Replay one

Fix the cause first (publish the flow, correct the data), then replay:

curl -X POST "https://www.buni.ai/api/v1/orgs/$ORG_ID/flows/$PROJECT_ID/dead-letters?id=$DEAD_LETTER_ID" \
  -H "Authorization: Bearer $BUNI_API_TOKEN"

The stored requestPayload runs through the flow again. 200 {"success": true} means it worked, and replayStatus becomes SUCCESS.

Each event can be replayed once, whether or not the replay succeeds. A failed replay returns 422 with the reason and sets replayStatus to FAILED: <reason>; a second attempt returns 422 Event has already been replayed. To try again, send the payload yourself with POST /flows/{projectId}/trigger.

Do not replay a failed-poll event (payload of pollKey and pollEndpoint): it would run the flow with that payload. The next scheduled poll retries the fetch on its own.

Last reviewed 24 September 2026

On this page