Docs

Sending & Receiving

How to send and receive messages through agrirouter in production integrations, with addressing, retries, chunk reassembly, and feed confirmation

This page covers the integration-level concerns around sending and receiving messages: addressing modes, retries, chunk reassembly on the receive side, and feed confirmation. The walkthrough-style introductions live in the getting-started tutorials and are the right starting point the first time through.

For the conceptual messaging model, see Messaging.

Sending a payload end to end

Loading diagram...

Every outbound message is a single HTTPS request to POST /messages. The envelope is carried in HTTP headers, and the payload is the raw request body with Content-Type: application/octet-stream. See Send Your First Message for the full header reference.

A successful 200 response means agrirouter has accepted the message for routing. It does not confirm delivery to any recipient. There is no asynchronous delivery acknowledgement event for the sender.

POST /messages — API playground1 min

Addressing modes

Choose between direct addressing and publish on a per-message basis using two headers.

Set x-agrirouter-is-publish: false and provide x-agrirouter-direct-recipients with a comma-separated list of recipient endpoint UUIDs. The message is delivered only to those endpoints, provided a route exists from the sender to each recipient for this message type.

Use direct addressing for interactive flows where the user picks the target, for example sending an application map from an FMIS to a specific machine.

Retries and idempotency

x-agrirouter-context-id is an application-generated identifier for the payload (max 50 characters, unique per payload). When retrying the same payload after a transport failure, reuse the same context ID so agrirouter can deduplicate. Generate a fresh context ID for a new payload.

For transient failures (network errors, 5xx responses, 429), back off exponentially before retrying. For validation failures (400, 403), fix the request and send with the same context ID; there is no point retrying an invalid payload as-is.

The gateway does not return a Retry-After header on 429, so the backoff schedule is up to the client. See Rate limits for how the limits are scoped and how to find the concrete number for your application.

Chunking

Payloads larger than the internal chunk size are split by agrirouter on the way out. The sender does not implement chunking. Two headers make this work:

  • content-length: total payload size in bytes. The API uses this to decide whether to split.
  • x-agrirouter-context-id: shared across all resulting chunks, so the recipient can reassemble.

The maximum payload size accepted by the API is 256 MB. Payloads exceeding that limit are rejected with 413.

Receiving through the SSE stream

Events are delivered through a single Server-Sent Events stream. Open GET /events with a valid access token and keep the connection open; events stream as they occur. There is no polling API, no webhook callback, and no push-notification fallback.

The stream covers two families of events. The data-flow events tell you about messages and files arriving on your feeds; the tenant-state events tell you about authorizations and endpoint visibility:

EventMeaning
MESSAGE_RECEIVEDA new message has arrived in the feed of one of your endpoints.
FILE_RECEIVEDA chunked file payload (TaskData, Shape, PDF, image, video) has been fully reassembled by agrirouter and is ready to download.
ENDPOINT_DELETEDOne of your endpoints was deleted, either by your application or by the account owner.
ENDPOINTS_LIST_CHANGEDThe set of endpoints visible to your application in a tenant changed, or a visible endpoint's capabilities or routes changed.
AUTHORIZATION_ADDEDA user granted your application a new authorization for a tenant.
AUTHORIZATION_REVOKEDA user revoked an authorization. Access to the tenant for the given scope is already gone when the event is delivered.

See Receive Your First Message for the wire format and a sample MESSAGE_RECEIVED event, and the Events catalog for the per-event payloads.

GET /events — API playground1 min

Replay on reconnect

Long-lived SSE connections are the simplest model, but many integrations cannot hold one open: batch jobs, mobile clients, processes that cycle through restarts. When you open a fresh SSE connection, the gateway replays every unconfirmed event that arrived on your endpoints while you were disconnected, then continues with live events. You do not need a cursor; reconnecting is enough to catch up.

Confirming events promptly matters: confirmed events drop out of the replay window, so the next reconnect only replays genuinely missed events.

Downloading the payload

Both MESSAGE_RECEIVED and FILE_RECEIVED events may include the payload directly as payload (base64 inline, for small payloads) or as a payload_uri link to download (for larger payloads). Exactly one of the two is present.

payload_uri links are time-limited and expire after at most 15 minutes. Download the payload as soon as you receive the event.

The payload_uri is pre-signed and does not need an Authorization header. The response body is the raw binary (application/octet-stream) in the original format.

Chunked file reassembly

For chunked message types (TaskData, Shape, PDF, images, videos), agrirouter reassembles the chunks server-side and emits a single FILE_RECEIVED event when the whole payload has arrived. The event carries a message_ids array listing the agrirouter message IDs of the individual chunks, plus one payload_uri (or inline payload) for the reassembled file.

Your application does not see the intermediate chunks as separate events. You download the reassembled payload once and confirm every ID in message_ids so the chunks drop out of the feed.

Confirming messages

Every event you handle must be confirmed with POST /confirmations, otherwise it keeps replaying on reconnect and accumulates in your endpoint's feed. A confirmation is a (endpoint_id, message_id) pair; a single request can carry many.

A successful 202 means the confirmation was accepted for processing. The feed is updated asynchronously, so a just-confirmed message may still appear in the replay window for a brief interval.

POST /confirmations — API playground1 min

Unconfirmed events accumulate in your feed and will replay on every reconnect. Confirm events after your application has processed them.

Error handling

ErrorCauseResolution
400 on sendMalformed headers, unsupported message type, or missing required field.Validate the request against the API spec before retrying.
400 on sendNo route exists from the sender to a specified direct recipient.Ask the account owner to configure a route for the sender, recipient, and message type.
403 on sendThe endpoint ID in the request does not belong to a tenant the access token is authorized for.Confirm the access token matches the endpoint's tenant; confirm the endpoint has not been deleted.
413 on sendPayload exceeds the 256 MB limit.Split the data at the application level before sending.
Event not arrivingThe recipient's capabilities or the account's routes do not cover the message type.Verify the recipient's capabilities and confirm the account owner has configured a route.
payload_uri returns 403 or 404The 15-minute expiry window has passed.Trigger a fresh event, or re-request via the SSE stream on reconnect.

See Errors for the full HTTP status code list and response body shape.

Next steps

On this page