DMWire Docs
Early access

REST API reference

For scripts and your own software. Agents use the same operations through the MCP server.

Authentication

Every call takes your key in a header:

Request
curl https://api.dmwire.ai/v1/usage \
  -H "X-API-Key: $DMWIRE_API_KEY"
Response (HTTP 200, captured 2026-10-17)
{
  "plan": "free",
  "status": "active",
  "day": "2026-10-17",
  "sends": 0,
  "sends_cap": 50,
  "new_contacts": 0,
  "new_contacts_cap": 10,
  "accounts_total": 0,
  "accounts_connected": 0,
  "accounts_cap": 1
}

Authorization: Bearer works the same way:

Request
curl https://api.dmwire.ai/v1/usage \
  -H "Authorization: Bearer $DMWIRE_API_KEY"
Response (HTTP 200, captured 2026-10-17)
{
  "plan": "free",
  "status": "active",
  "day": "2026-10-17",
  "sends": 0,
  "sends_cap": 50,
  "new_contacts": 0,
  "new_contacts_cap": 10,
  "accounts_total": 0,
  "accounts_connected": 0,
  "accounts_cap": 1
}

A wrong key:

Request
curl https://api.dmwire.ai/v1/usage \
  -H "X-API-Key: dmw_live_this_key_does_not_exist"
Response (HTTP 401, captured 2026-10-17)
{
  "success": false,
  "error_code": 401,
  "error": "Invalid API key"
}

Errors

Refusals carry a machine readable error_code and a human error message. Daily limit refusals (HTTP 429) carry retry_after_s. The full list of send refusals is on Limits and account safety.

Request
curl https://api.dmwire.ai/v1/messages/does-not-exist \
  -H "X-API-Key: $DMWIRE_API_KEY"
Response (HTTP 404, captured 2026-10-17)
{
  "error_code": "message_not_found",
  "error": "Message not found"
}

Sending a message

POST /messages answers 202 with the message id and status queued. Then follow it with GET /messages/{id} or the message.sent, message.delivered, message.read and message.failed webhooks. Run before any account was connected, it is refused like this:

Request
curl \
  -X POST https://api.dmwire.ai/v1/messages \
  -H "X-API-Key: $DMWIRE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"to": {"phone": "+31612345678"}, "text": "Hi Ana, your order is ready for pickup."}'
Response (HTTP 409, captured 2026-10-17)
{
  "error_code": "no_connected_account",
  "error": "No connected WhatsApp or Telegram account"
}

Reading past messages

GET /messages lists the most recent messages on your accounts, sent and received, newest first. It is REST only for now: the MCP server has no tool for it, agents use wait_for_messages for new messages instead. A fresh account has none yet:

Request
curl "https://api.dmwire.ai/v1/messages?limit=5" \
  -H "X-API-Key: $DMWIRE_API_KEY"
Response (HTTP 200, captured 2026-10-17)
{
  "messages": [],
  "next_cursor": null
}

All operations

The OpenAPI document itself is at https://api.dmwire.ai/v1/docs/openapi.yaml, ready for any OpenAPI tool.

Generated from the live OpenAPI document at api.dmwire.ai/v1/docs/openapi.yaml (version 1.0.0, read 2026-10-17). Base URL https://api.dmwire.ai/v1. Send your key in the X-API-Key header or as Authorization: Bearer.

Messages

GET/messages

List Recent Messages · list_messages, REST only (no MCP tool yet)

The most recent messages on your accounts, sent and received, newest first (up to 100 per call, 50 by default). Filter by direction or account_id. When next_cursor is not null, pass it as before to read the next page. For waiting on NEW messages use wait_for_messages.

Parameters

NameInTypeRequiredWhat it is
limitqueryinteger (default 50, max 100)no
directionquerystringno
account_idquerystringno
beforequerystringnoThe next_cursor of the previous page

Responses

  • 200 The messages, newest first
  • 400 Invalid limit, direction or cursor

POST/messages

Send a Message · MCP tool send_message

Queues a text message (optionally with one media URL) from a connected account. Address the recipient by to.phone (international format) or to.contact_id. account_id may be omitted when exactly one account is connected. On WhatsApp a new phone number creates the contact; on Telegram only an existing contact can be messaged. Answers 202 with the message id; read get_message for the delivery status. Refusals carry error_code: no_connected_account (409), ambiguous_account (400), account_not_found (404), contact_not_found (404), telegram_requires_existing_contact (422), contact_channel_mismatch (422), contact_do_not_disturb (422), contact_private (422), account_suspended (403), loop_guard (429), opener_burst (429), daily_send_cap (429), new_contact_cap (429). A 429 carries retry_after_s.

Request body (JSON)

FieldTypeRequiredWhat it is
account_idstringnoThe account to send from (see list_accounts). Optional when one account is connected.
toobjectyes
to.phonestringno
to.contact_idstringno
textstringyes
media_urlstringnoAn https URL of an image, video, audio file or document to attach.

Responses

  • 202 Queued for delivery
  • 400 Invalid request
  • 403 Account suspended
  • 409 No connected account
  • 422 The contact cannot be messaged
  • 429 A daily cap, the loop guard or the burst guard was hit

GET/messages/wait

Wait for New Messages · MCP tool wait_for_messages

Long poll for incoming messages. Returns as soon as at least one message newer than cursor arrives (up to 50 per call), or an empty list when timeout_s passes. Always pass the returned cursor into the next call; without a cursor the wait starts from now. At most 2 waits may be open at once per account (429 wait_concurrency).

Parameters

NameInTypeRequiredWhat it is
cursorquerystringnoThe opaque cursor returned by the previous call.
account_idquerystringnoOnly messages received on this account.
timeout_squeryinteger (default 25, max 55)no

Responses

  • 200 New messages (possibly none) and the cursor for the next call
  • 400 Invalid cursor or timeout
  • 429 Too many concurrent waits

GET/messages/{id}

Get a Message · MCP tool get_message

Reads one message (sent or received) with its current status. Use it after send_message to see whether the message was sent, delivered, read or failed.

Parameters

NameInTypeRequiredWhat it is
idpathstringyes

Responses

  • 200 The message
  • 404 No such message on this account

Accounts

GET/accounts

List Connected Accounts · MCP tool list_accounts

Lists the WhatsApp Web and Telegram accounts connected to your account. status is one of connected, connecting, disconnected or restricted. limits shows today's sends and new contacts against the caps; ramp_day is how far the account is into its warm-up ramp (null when the account has no ramp).

Responses

  • 200 The connected accounts
  • 404 This API is not enabled for the account

POST/channels/telegram/connect

Start a connection session · MCP tool connect_telegram

Begins a connection session for an account phone number. In code mode the connection service sends a one-time login code to the account and reports code_required; in qr mode it returns a login token and QR URL to display. Poll the status endpoint until the channel reports connected.

Request body (JSON)

FieldTypeRequiredWhat it is
phone_numberstringyesThe account phone number to connect, in E.164 format.
modecode | qrnoLogin method. 'code' sends a one-time login code to the account; 'qr' returns a login token and QR URL to display for scanning.
force_newbooleannoWhen true, discards any existing session and starts fresh.

Responses

  • 200 Session started.
  • 400 Invalid or missing request fields.
  • 403 This channel is not enabled for the account, or the plan lacks a channels tier.
  • 409 This account is already connected elsewhere.

POST/channels/telegram/connect/{phoneNumber}/verify-code

Submit the login code · MCP tool submit_telegram_code

Submits the one-time login code for a pending session. On success the status becomes connected; when the account has two-factor enabled the status becomes password_required and the password must be submitted next.

Parameters

NameInTypeRequiredWhat it is
phoneNumberpathstringyesThe account phone number being connected, in E.164 format.

Request body (JSON)

FieldTypeRequiredWhat it is
codestringyesThe one-time login code received by the account.

Responses

  • 200 Code accepted.
  • 400 Missing or invalid login code.
  • 403 This channel is not enabled for the account.

POST/channels/telegram/connect/{phoneNumber}/verify-password

Submit the two-factor password · MCP tool submit_telegram_password

Submits the two-factor password for a session that reported password_required. On success the status becomes connected and the channel is live.

Parameters

NameInTypeRequiredWhat it is
phoneNumberpathstringyesThe account phone number being connected, in E.164 format.

Request body (JSON)

FieldTypeRequiredWhat it is
passwordstringyesThe account's two-factor password.

Responses

  • 200 Password accepted.
  • 400 Missing or invalid password.
  • 403 This channel is not enabled for the account.

GET/channels/telegram/connect/{phoneNumber}/status

Get live connection status · MCP tool get_telegram_status

Returns the live connection status for a session, polled from the connection service. Poll this until the status is connected or an error/disconnected status. Reports not_initialized when no session exists.

Parameters

NameInTypeRequiredWhat it is
phoneNumberpathstringyesThe account phone number, in E.164 format.

Responses

  • 200 Current connection status.
  • 404 No connection record exists for this phone number.

DELETE/channels/telegram/{phoneNumber}

Disconnect the channel · MCP tool disconnect_telegram

Tears down the connection session and removes the account record. Idempotent: the record is removed even when the connection service is unreachable, so repeated calls succeed.

Parameters

NameInTypeRequiredWhat it is
phoneNumberpathstringyesThe account phone number to disconnect, in E.164 format.

Responses

  • 200 Channel removed.
  • 404 No connection record exists for this phone number.

POST/channels/whatsapp-web/connections

Start a WhatsApp Web pairing session · MCP tool connect_whatsapp

Begins pairing a WhatsApp number by QR code. Creates or resets the connection and returns a session whose QR code you then fetch and have the end user scan. Poll the status endpoint until the connection reports connected.

Request body (JSON)

FieldTypeRequiredWhat it is
phone_numberstringyesThe WhatsApp number to connect, in E.164 format (for example +15551230000).
link_methodqr | pairing_codenoHow the phone is linked. 'qr' (default) shows a QR code to scan; 'pairing_code' returns an 8-character code to type on the phone under Linked devices, Link with phone number instead.
force_newbooleannoDiscard any existing session for this number and start a fresh pairing.
import_contactsbooleannoImport the device's existing contacts on first connection.
pause_ai_for_imported_contactsbooleannoWhen importing contacts, keep automated replies paused for them.
import_existing_chatsbooleannoImport existing chat history on first connection. Requires import_contacts to be true.
mark_imported_contacts_as_privatebooleannoWhen importing contacts, create them as private (no messages stored or sent for them). Incompatible with import_existing_chats.

Responses

  • 200 Pairing session started.
  • 400 Missing or invalid request fields.
  • 401 Authentication required or invalid.
  • 403 The account's plan does not include channel connections.
  • 404 The referenced account could not be found.
  • 409 This number is already connected.
  • 503 The connection service is temporarily at capacity.

GET/channels/whatsapp-web/connections/{phoneNumber}/qr

Get the pairing QR code · MCP tool get_whatsapp_qr

Returns the current QR code for a pairing session so it can be rendered for the end user to scan. The code is short-lived; poll this endpoint every 10 to 15 seconds until the status reports connected, and restart the connection if the code expires.

Parameters

NameInTypeRequiredWhat it is
phoneNumberpathstringyesThe connected number in E.164 format.

Responses

  • 200 QR code returned.
  • 400 This number cannot be paired with WhatsApp Web.
  • 401 Authentication required or invalid.
  • 404 The connection was not found, or the QR code is not ready yet.
  • 410 The QR code expired. Restart the connection to generate a new one.
  • 503 The QR service is temporarily unavailable.

GET/channels/whatsapp-web/connections/{phoneNumber}/status

Get the connection status · MCP tool get_whatsapp_status

Returns the live connection status for a pairing session. The terminal success state is connected (the service may also report open). Treat disconnected and not_initialized as terminal failure states. Poll this endpoint after the end user scans the QR code to confirm the connection.

Parameters

NameInTypeRequiredWhat it is
phoneNumberpathstringyesThe connected number in E.164 format.

Responses

  • 200 Connection status returned.
  • 401 Authentication required or invalid.
  • 404 The connection was not found.
  • 502 The connection service could not be reached.

DELETE/channels/whatsapp-web/connections/{phoneNumber}

Disconnect a WhatsApp Web connection · MCP tool disconnect_whatsapp

Disconnects the pairing session and removes the connection record. The operation is idempotent and always succeeds locally even if the connection service is unreachable.

Parameters

NameInTypeRequiredWhat it is
phoneNumberpathstringyesThe connected number in E.164 format.

Responses

  • 200 Disconnected. status is "removed" when the number was deleted from the account.
  • 401 Authentication required or invalid.
  • 404 The connection was not found.

Usage

GET/usage

Get Today's Usage · MCP tool get_usage

Today's sends and new contacts (UTC day) against the plan caps.

Responses

  • 200 Today's usage

Webhooks

GET/webhooks

List Webhook Subscriptions · MCP tool list_webhooks

Returns every webhook subscription configured on the account, including the events each one listens to. The returned id (or the exact name) can be used as the webhookId path parameter in the other webhook endpoints.

Responses

  • 200 The account's webhook subscriptions
  • 401 Missing or invalid credentials
  • 403 Webhooks are not enabled for this account

POST/webhooks

Create Webhook Subscription · MCP tool create_webhook

Creates a new webhook subscription. The URL must use HTTPS and be publicly reachable. The subscribed_to array selects which event types are delivered to the URL, use GET /webhooks/events to discover the valid values. Optionally pass a name so the subscription can be addressed by a stable identifier later.

Request body (JSON)

FieldTypeRequiredWhat it is
urlstringyesHTTPS URL that will receive event payloads via POST.
subscribed_toarrayyesEvent types to subscribe to. Must contain at least one valid event name.
namestringnoOptional display name. Also usable as the webhookId path parameter. Defaults to a timestamped name.
retries_enabledbooleannoRetry failed deliveries (1m, 5m, 30m, 2h). Off by default. See the Retries section for the duplicate-delivery caveat.
enabledbooleannoAccount on/off switch for the subscription. Defaults to true (on). Pass false to create it switched off.
generate_signing_secretbooleannoWhen true, an HMAC signing secret is minted for the new subscription (turning signing on) and returned once as a top-level signing_secret field in the response. Store it then, it is never returned in full again by create/list/update; only GET /webhooks/{webhookId}/signing-secret exposes it afterwards. You can also turn signing on later via POST /webhooks/{webhookId}/signing-secret.

Responses

  • 201 Subscription created
  • 400 Validation error (missing url, empty or invalid subscribed_to, or a URL that is not allowed)
  • 403 Webhooks are not enabled for this account

GET/webhooks/events

List Subscribable Event Types · MCP tool list_webhook_events

Returns the full list of event types that webhook subscriptions can listen to. Use these exact strings in the subscribed_to field when creating or updating a subscription. The events are (message.received, message.sent, message.delivered, message.read, message.failed, account.connected, account.disconnected, account.restricted, account.limit_reached), plus a descriptions map; subscribing to an event outside the account's set returns 400.

Responses

  • 200 The valid event types
  • 401 Missing or invalid credentials
  • 403 Webhooks are not enabled for this account

PUT/webhooks/{webhookId}

Update Webhook Subscription · MCP tool update_webhook

Updates an existing webhook subscription. Provide at least one of url, subscribed_to or name; omitted fields keep their current values. When the URL changes, delivery for the new URL is automatically re-enabled so a previously failing endpoint gets a fresh start.

Parameters

NameInTypeRequiredWhat it is
webhookIdpathstringyesThe subscription id (from the id field) or its exact name.

Request body (JSON)

FieldTypeRequiredWhat it is
urlstringnoNew HTTPS delivery URL.
subscribed_toarraynoReplacement event list. Must contain at least one valid event name.
namestringnoNew display name.
retries_enabledbooleannoTurn delivery retries on or off for this subscription.
enabledbooleannoAccount on/off switch. Set false to switch the subscription off (suppress delivery), true to switch it back on. Signing is managed separately via the signing-secret routes, not here.

Responses

  • 200 Subscription updated
  • 403 Webhooks are not enabled for this account
  • 404 No subscription with that id or name exists on this account

DELETE/webhooks/{webhookId}

Delete Webhook Subscription · MCP tool delete_webhook

Removes a webhook subscription so its URL stops receiving event payloads. Delivery-health counters for the URL are reset, so re-adding the same URL later starts with a clean record.

Parameters

NameInTypeRequiredWhat it is
webhookIdpathstringyesThe subscription id (from the id field) or its exact name.

Responses

  • 200 Subscription deleted
  • 403 Webhooks are not enabled for this account
  • 404 No subscription with that id or name exists on this account

POST/webhooks/{webhookId}/test

Send Test Payload · MCP tool test_webhook

Sends a sample payload to the subscription's URL so you can verify your receiver end-to-end. Optionally pass an event to control which event type the sample payload simulates. Test deliveries never affect the subscription's health counters. The response reports whether the delivery succeeded; a failed test returns delivered:false together with the failure details instead of an error status.

Parameters

NameInTypeRequiredWhat it is
webhookIdpathstringyesThe subscription id (from the id field) or its exact name.

Request body (JSON)

FieldTypeRequiredWhat it is
eventstringnoEvent type to simulate. Must be one of the values from GET /webhooks/events. Defaults to a delivery event.

Responses

  • 200 Test attempted, check the delivered flag for the outcome
  • 403 Webhooks are not enabled for this account
  • 404 No subscription with that id or name exists on this account

GET/webhooks/{webhookId}/health

Get Webhook Delivery Health · MCP tool get_webhook_health

Returns the delivery-health record for the subscription's URL: how many deliveries have succeeded and failed, whether delivery is currently paused after repeated failures, and the details of the most recent failure. Returns health:null when no deliveries have been attempted yet.

Parameters

NameInTypeRequiredWhat it is
webhookIdpathstringyesThe subscription id (from the id field) or its exact name.

Responses

  • 200 The delivery-health record for the subscription's URL
  • 403 Webhooks are not enabled for this account
  • 404 No subscription with that id or name exists on this account

POST/webhooks/{webhookId}/reenable

Re-enable Webhook Delivery · MCP tool reenable_webhook

Resumes delivery for a webhook whose URL was paused automatically after repeated failures. Resets the paused flag and failure counters. No delivery attempt is made, use the test endpoint afterwards to confirm the receiver is healthy again.

Parameters

NameInTypeRequiredWhat it is
webhookIdpathstringyesThe subscription id (from the id field) or its exact name.

Responses

  • 200 Delivery re-enabled
  • 403 Webhooks are not enabled for this account
  • 404 No subscription with that id or name exists on this account

GET/webhooks/{webhookId}/signing-secret

Read Webhook Signing Secret · MCP tool get_webhook_signing_secret

Returns the subscription's HMAC signing secret so you can configure signature verification on your receiver. The secret is symmetric, we hold the same value your endpoint needs, so it is readable rather than write-once. When signing is off, signing_enabled is false and signing_secret is null. Signed deliveries carry an `X-Webhook-Signature` header (`v1=<hex>`), an HMAC-SHA256 of `<X-Webhook-Timestamp>.<raw request body>` keyed with this secret. Verify against the raw body, reject stale timestamps, and compare in constant time.

Parameters

NameInTypeRequiredWhat it is
webhookIdpathstringyesThe subscription id (from the id field) or its exact name.

Responses

  • 200 The subscription's signing state
  • 403 Webhooks are not enabled for this account
  • 404 No subscription with that id or name exists on this account

POST/webhooks/{webhookId}/signing-secret

Generate or Rotate Webhook Signing Secret · MCP tool rotate_webhook_signing_secret

Mints a new signing secret for the subscription, or replaces the existing one. Creating a secret is how signing is turned on. The new secret is returned in the response. Rotation is a hard cutover, not a grace period: the very next delivery is signed with the new secret only. When rotating a live endpoint, accept both the old and new secret briefly so deliveries in flight during the change still verify.

Parameters

NameInTypeRequiredWhat it is
webhookIdpathstringyesThe subscription id (from the id field) or its exact name.

Responses

  • 200 Signing secret generated or rotated
  • 403 Webhooks are not enabled for this account
  • 404 No subscription with that id or name exists on this account

DELETE/webhooks/{webhookId}/signing-secret

Turn Off Webhook Signing · MCP tool turn_off_webhook_signing

Removes the subscription's signing secret, turning signing off. Subsequent deliveries carry no signature headers, exactly as the webhook behaved before signing was enabled.

Parameters

NameInTypeRequiredWhat it is
webhookIdpathstringyesThe subscription id (from the id field) or its exact name.

Responses

  • 200 Signing turned off
  • 403 Webhooks are not enabled for this account
  • 404 No subscription with that id or name exists on this account

Last checked against the live service on 2026-10-17.