API v2 to v3 Migration

Migrate your integration from the legacy v2 API to the current v3 API.

Key Differences

Featurev2v3
Base URLapi.sent.dm/v2api.sent.dm/v3
Auth Headerx-sender-id + x-api-keyx-api-key only
Request Bodyrecipients, template_id, template_variablesto, template (object with id/name/parameters), channel
Response FormatFlat dataEnvelope with success, data, error, meta
Rate LimitsVaries200 req/min (standard), 10 req/min (sensitive)
Sandbox Modetest_mode: truesandbox: true
TemplatesSimple textStructured components
ContactsBasicChannel intelligence

Authentication Changes

v2 (Legacy)

GET /v2/messages
x-sender-id: your-sender-id
x-api-key: your-api-key

v3 (Current)

GET /v3/messages
x-api-key: your-api-key

Request Format Changes

Sending Messages

v2 (Legacy)

{
  "recipients": ["+1234567890"],
  "template_id": "tmpl_123",
  "template_variables": {
    "name": "John",
    "order_id": "12345"
  },
  "channels": ["sms"],
  "sandbox": true
}

v3 (Current)

{
  "to": ["+1234567890"],
  "template": {
    "id": "tmpl_123",
    "name": "order_confirmation",
    "parameters": {
      "name": "John",
      "order_id": "12345"
    }
  },
  "channel": ["sms"],
  "sandbox": false
}

Key Changes:

  • recipientsto
  • template_idtemplate.id (inside template object)
  • template_variablestemplate.parameters
  • Added template.name (optional)
  • channelschannel
  • test_mode renamed to sandbox

Response Format Changes

v2 (Legacy)

{
  "data": {
    "messages": [
      {
        "id": "msg_123",
        "recipient": "+1234567890",
        "status": "queued",
        "contact_id": "contact_456"
      }
    ]
  }
}

v3 (Current)

{
  "success": true,
  "data": {
    "status": "QUEUED",
    "template_id": "tmpl_123",
    "template_name": "order_confirmation",
    "recipients": [
      {
        "message_id": "msg_123",
        "to": "+1234567890",
        "channel": "sms"
      }
    ]
  },
  "error": null,
  "meta": {
    "request_id": "req_abc123",
    "timestamp": "2026-03-04T11:28:25.2096416+00:00",
    "version": "v3"
  }
}

Key Changes:

  • Response is now wrapped in an envelope with success, data, error, meta
  • messagesrecipients array
  • idmessage_id
  • recipientto
  • Added meta.request_id for support tickets

Error Format Changes

v2 (Legacy)

{
  "error": {
    "code": "insufficient_balance",
    "message": "Account balance is insufficient"
  }
}

v3 (Current)

{
  "success": false,
  "data": null,
  "error": {
    "code": "BUSINESS_003",
    "message": "Account balance is insufficient to send this message",
    "details": null,
    "doc_url": "https://docs.sent.dm/errors/BUSINESS_003"
  },
  "meta": {
    "request_id": "req_abc123",
    "timestamp": "2026-03-04T11:28:25.2096416+00:00",
    "version": "v3"
  }
}

Key Changes:

  • Error codes are now prefixed (e.g., BUSINESS_003, AUTH_001, VALIDATION_002)
  • Added doc_url with link to error documentation
  • Error is part of the standard envelope format

Webhook Event Changes

v2 (Legacy)

{
  "field": "messages",
  "id": "msg_123",
  "status": "DELIVERED",
  "channel": "sms",
  "to": "+1234567890",
  "from": "+1987654321",
  "template_id": "tmpl_123",
  "timestamp": "2025-01-15T08:30:15Z"
}

v3 (Current)

{
  "field": "messages",
  "timestamp": "2025-01-15T08:30:15Z",
  "payload": {
    "account_id": "7ba7b820-9dad-11d1-80b4-00c04fd430c8",
    "message_id": "8ba7b830-9dad-11d1-80b4-00c04fd430c8",
    "message_status": "DELIVERED",
    "channel": "sms",
    "inbound_number": "+1234567890",
    "outbound_number": "+1987654321",
    "template_id": "9ba7b840-9dad-11d1-80b4-00c04fd430c8"
  }
}

Key Changes:

  • Added payload wrapper — status fields are now nested under payload
  • idpayload.message_id
  • statuspayload.message_status
  • topayload.inbound_number
  • frompayload.outbound_number
  • Added payload.account_id for multi-account setups
  • Top-level template_id moved into payload.template_id

Endpoint Mapping

v2 Endpointv3 EndpointChanges
POST /v2/messagesPOST /v3/messagesNew request/response format
GET /v2/messages/{id}GET /v3/messages/{id}Response uses envelope format
POST /v2/contactsPOST /v3/contactsNew response envelope
GET /v2/contactsGET /v3/contactsResponse uses envelope format
POST /v2/templatesPOST /v3/templatesNew template structure

Idempotency Changes

v2 (Legacy)

{
  "recipients": ["+1234567890"],
  "template_id": "tmpl_123",
  "idempotency_key": "order_123_456"
}

v3 (Current)

curl -X POST "https://api.sent.dm/v3/messages" \
  -H "x-api-key: $SENT_API_KEY" \
  -H "Idempotency-Key: order_123_456" \
  -d '{
    "to": ["+1234567890"],
    "template": {"id": "tmpl_123"}
  }'

Key Changes:

  • Idempotency key is now sent as Idempotency-Key header, not request body
  • Keys are cached for 24 hours

Migration Process

Migration Steps

  1. Update Base URL - Change from /v2 to /v3
  2. Update Authentication - Remove x-sender-id header, keep only x-api-key
  3. Update Request Format - Change recipients to to, template_id to template.id, etc.
  4. Update Response Handling - Handle the new envelope format with success, data, error, meta
  5. Update Error Handling - Use new error codes (e.g., BUSINESS_003 instead of insufficient_balance)
  6. Update Webhook Handlers - Adjust for new nested event structure (payload wrapper added; use payload.message_id and payload.message_status)
  7. Update Idempotency - Move key from body to Idempotency-Key header
  8. Test in Sandbox Mode - Validate all functionality with sandbox: true
  9. Deploy Gradually - Use feature flags for rollout

The v2 API is deprecated and will be sunset. Migrate to v3 as soon as possible.


On this page