Skip to main content

Send A Text Message

Requires messages.send scope. Use either sender_phone or sender_number_id.

Send Media

Send one attachment per request using multipart/form-data and the media field. Use content as an optional caption for image, document, and audio. The caption is delivered with the same message as the attachment.
Use audio for files selected or uploaded by an API integration. Reserve voice for recorded voice notes. Captions on legacy voice messages remain accepted for backward compatibility, but new integrations should send captioned audio as audio.

Image With A Caption

Uploaded Audio With A Caption

duration is optional for audio. This example intentionally omits it.
cURL

Recorded Voice Note

Recorded voice notes require their duration in seconds and should not include a caption in new integrations.
cURL
When using FormData in a browser or Node.js client, do not set the multipart Content-Type header manually. The HTTP client must add the boundary.

Media Storage And URLs

Sinjapp validates each attachment and stores it in managed R2 object storage. Read the returned media URL from data.response_payload.media_url; treat it as opaque. Do not construct /storage/chat/... URLs or rewrite the returned host.

Read Message Logs

Requires messages.read scope. Returns 25 logs per page, newest first. The records are in data.data; pagination metadata is in data. Use ?page=2 for the next page. Each record includes the current delivery_status from Sinjapp.

Delivery And Read Status

After sending, save data.id, the tenant message log ID. Use it to check that message later:
Requires messages.read. Replace {messageLog} with data.id from the send response, not data.message_id or data.response_payload.message_id, which identify the underlying chat message. status and sent_at retain their existing meaning: Sinjapp accepted and stored the outgoing message. Use delivery_status for delivery and reading: The send response, list response, and single-message response include delivery_status. Each GET reads the current recorded state; delivery does not mean a push notification was merely accepted by a push provider. The recipient’s app must report delivery or reading before the corresponding state is available.

Check One Message

Example response fields after reading:
Poll this GET endpoint from your server with a delay and an application-defined timeout; stop when the required state is reached. Polling reads status and does not send another message. A timeout is not proof of delivery failure. The Tenant API does not currently emit delivery webhooks or provide separate delivered_at / read_at timestamps. An ID that is not a message log in the current tenant returns 404. A key without messages.read returns 403; missing or invalid credentials return 401. See authentication and the Postman collection.