Send a message or note
POST /hooks/api_v1.php?r=messages uses the same provider, consent, quiet-hour, idempotency, and billing path as Dial Dozer’s UI and automations.
Required scope: messages:write
curl --fail-with-body -X POST \ "https://app.dialdozer.com/hooks/api_v1.php?r=messages" \ -H "X-Api-Key: $DIALDOZER_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "lead_id": 48219, "channel": "sms", "body": "Hi Maya — your appointment is confirmed for tomorrow.", "operation_id": "confirm-48219-20260717" }'| Field | Type | Required | Notes |
|---|---|---|---|
lead_id | integer | yes | Must exist inside the key’s organization. |
channel | string | yes | Exactly sms, email, or note. |
body | string | yes | Empty content is rejected by the shared send path. Email content is handled as HTML with escaped merge values. |
subject | string | email only | Defaults to Message from {company} if omitted. |
operation_id | string | yes | Idempotency identity: 1–96 characters using letters, digits, _ . : -. Missing/invalid values return bad_operation_id. Reuse it only for a retry of the same send. |
Success commonly returns:
{"ok":true,"message_id":901}Provider/gate results are intentionally returned rather than hidden. A request can receive HTTP 200 with ok: false, for example {"ok":false,"reason":"empty_body","message_id":null}. Quiet-hour deferral can include a queued message_id and defer_until Unix timestamp.
Billing gate reasons billing_not_configured, billing_unavailable, billing_frozen, subscription_required, and insufficient_credits use HTTP 402. Other delivery/gate failures currently remain HTTP 200; always inspect ok and reason, not only status.
Notes are stored internally and do not call a provider. SMS/email require the relevant contact channel, consent/configuration, and available billing balance.