Skip to content

POST /devices/{id}/messages

Sends text, an image or a file from a number you rent. Which one a multipart body carries is decided by the file’s own content type, not by a field you set: an image is rendered inline with its caption, a document arrives as a file the recipient opens, named.

Scope send and an active/past_due rental for this device
Body application/json with phone + message, or multipart/form-data with file + phone + optional caption
Idempotency Required — Idempotency-Key, 1–128 characters
Field Type Required Validation
phone string yes E.164 after stripping separators
message string yes Non-empty; trimmed length at most 4096
Terminal window
curl -X POST https://app.maukirim.com/api/v1/devices/gwd_…/messages \
-H "Authorization: Bearer mk_live_…" -H "Content-Type: application/json" \
-H "Idempotency-Key: reply-8821-1" \
-d '{"phone": "+6281234567890", "message": "Your order is on the way."}'
Part Type Required Validation
file File yes JPEG/PNG inline images (at most 5 MiB), or named files (PDF, DOCX, XLSX, PPTX, CSV, TXT, ZIP, WebP, GIF, MP3, ICP, ICS; at most 16 MiB). WebP, GIF and MP3 are files, not inline images or voice notes, and require matching .webp, .gif or .mp3 filenames. Known formats are checked against their bytes; opaque .icp is accepted by extension only. Use application/octet-stream with a .icp filename; .ics uses text/calendar.
phone string yes E.164
caption string no At most 1024 characters; omitted when blank. An image shows it under the picture; a document shows it above the file
Terminal window
curl -X POST https://app.maukirim.com/api/v1/devices/gwd_…/messages \
-H "Authorization: Bearer mk_live_…" \
-H "Idempotency-Key: reply-8821-2" \
-F "file=@receipt.png;type=image/png" \
-F "phone=+6281234567890" -F "caption=Your receipt"

The same call with a document. The filename you send is the filename the recipient reads, so send the real name rather than a placeholder:

Terminal window
curl -X POST https://app.maukirim.com/api/v1/devices/gwd_…/messages \
-H "Authorization: Bearer mk_live_…" \
-H "Idempotency-Key: invoice-8821-1" \
-F "file=@Invoice-8821.pdf;type=application/pdf" \
-F "phone=+6281234567890" -F "caption=Your invoice"

200 — a text send returns the queued batch:

{
"ok": true,
"batchId": "gwb_…",
"created": true,
"progress": {
"batchId": "gwb_…", "total": 1,
"counts": { "queued": 1, "sending": 0, "accepted": 0, "failed": 0, "uncertain": 0, "cancelled": 0 },
"terminal": false,
"items": [{ "id": "gwi_…", "recipient": "+6281234567890", "kind": "text",
"sendState": "queued", "deliveryState": null, "attempts": 0,
"messageId": null, "errorCode": null, "completedAt": null }]
}
}

A multipart send is the same object plus the id of the upload that was stored for it:

{ "ok": true, "media": { "id": "gwm_…" }, "batchId": "gwb_…", "created": true, "progress": { "…": "…" } }
Field Meaning
media.id The stored upload, present only for a multipart send. media is absent for text.
created false when the Idempotency-Key replayed an identical request — the earlier batch is returned
progress A snapshot, not a subscription. There is no batch-status endpoint; delivery state arrives on your webhook.
items[].sendState queued → sending → accepted/failed. uncertain means the attempt may or may not have arrived and was not retried.
items[].deliveryState The recipient’s receipt, which arrives later and is separate from sendState

The message body and caption are never echoed back.

HTTP Code Condition
400 invalid_input Missing/blank/E.164-invalid phone; missing/empty message; missing file part; attachment of an unsupported type, empty, over its size limit, or whose bytes do not match the declared type; non-string caption; Idempotency-Key missing; invalid item kind
404 rental_not_found Guard failure (not your device, or no active rental)
404 device_not_found Device unknown at enqueue
404 gateway_not_found The device’s gateway row is missing
409 gateway_disabled The gateway is switched off
409 batch_idempotency_conflict Same key, different normalized request
410 media_unavailable Media unknown, owned by another account, expired (7 days), or no bucket configured
413 batch_too_large message over 4096, caption over 1024, or Idempotency-Key over 128
401/403 auth codes Needs scope send
500 server_error Unexpected