Pulse Messaging API (1.0.0)

Download OpenAPI specification:

Tenant-aware SMS and RCS messaging API.

Base URL: https://messaging.pulseplatform.com/v1

All endpoints require a tenant API key supplied in the x-api-key header. API keys are provided by your account manager.

Authentication

Pass your API key in every request:

x-api-key: <your-api-key>

All resources are strictly tenant-scoped: you can only read and send messages that belong to your own tenant.

Sending messages

POST /messages accepts 1–100 destinations in a single call and returns 202 Accepted immediately. Each destination is queued and dispatched asynchronously. Poll GET /messages/{messageId} or use the Reporting API to track delivery.

Sending a template message (templateType + templateId) requires the template to already exist — templates are created and managed in the Pulse UI. There is no API to create, list, or update templates; templateId must reference one provisioned there.

Rate limits

/messages* endpoints: 100 requests/sec, burst 200. Exceeding it returns 429 Too Many Requests (see POST /messages).

/reporting/* endpoints have a separate, lower limit — see the Reporting section.

Idempotency

Supply an Idempotency-Key header to make submissions safe to retry. The key is scoped per-destination (key#to), so re-sending the same request returns the original message IDs without duplicate sends.

Caveat: if the reservation succeeds but the downstream write fails, retrying with the same key returns the original ID but nothing was enqueued. The endpoint returns 500 in this case — retry with a fresh key.

Messages

Send SMS and RCS messages, and query their delivery status. Messages are visible here immediately after submission and retained for 90 days.

Use these endpoints for real-time status lookups — e.g. checking whether a specific message was delivered. For filtering, aggregation, or historical queries beyond 90 days, use the Reporting endpoints instead.

Send messages

Submit 1–100 messages in a single request. Each destination is queued and dispatched asynchronously — the response is 202 Accepted, not delivery confirmation.

Supply Idempotency-Key to make the request safe to retry without duplicate sends. The key is scoped per-destination (key#to).

Authorizations:
ApiKeyAuth
header Parameters
Idempotency-Key
string

Optional deduplication key. Re-sending with the same key and destinations returns the original message IDs. If omitted, every call creates new messages.

Request Body schema: application/json
required
One of
channel
required
string
Value: "SMS"
templateType
required
string
Value: "textplode"

Template provider.

templateId
required
string non-empty ^[A-Za-z0-9._-]+$

Identifier of a template already provisioned in the Pulse UI. Restricted charset (no path separators).

Numeric sender ID (string) or Alphanumeric sender ID (string)

Sender ID shown to the recipient. Caps: 11 alphanumeric chars or 15 numeric. If omitted, the tenant's default SMS sender is used.

required
Array of objects (TemplateDestination) [ 1 .. 100 ] items

Responses

Response Schema: application/json
Array
messageId
required
string

Unique message identifier. Use this to poll status.

status
required
string
Value: "queued"

Always queued for a new submission.

createdAt
required
string <date-time>
Response Schema: application/json
error
required
string

Stable machine-readable error code (e.g. bad_request, not_found, internal).

message
string

Human-readable detail. Not always present.

Response Schema: application/json
error
required
string

Stable machine-readable error code (e.g. bad_request, not_found, internal).

message
string

Human-readable detail. Not always present.

Response Schema: application/json
message
string
Response Schema: application/json
error
required
string

Stable machine-readable error code (e.g. bad_request, not_found, internal).

message
string

Human-readable detail. Not always present.

Request samples

Content type
application/json
Example
{
  • "channel": "SMS",
  • "sender": "AcmeCorp",
  • "destinations": [
    • {
      • "to": "+447700900001"
      },
    • {
      • "to": "+447700900002"
      }
    ],
  • "content": {
    • "body": {
      • "type": "TEXT",
      • "text": "Your verification code is 123456. Valid for 10 minutes."
      }
    }
}

Response samples

Content type
application/json
[
  • {
    • "messageId": "01HVXXXXXXXXXXXXXXXXXXXXXX",
    • "status": "queued",
    • "createdAt": "2025-06-19T10:00:00.000Z"
    },
  • {
    • "messageId": "01HVYYYYYYYYYYYYYYYYYYYYYY",
    • "status": "queued",
    • "createdAt": "2025-06-19T10:00:00.001Z"
    }
]

List messages

Returns a paginated list of your messages, newest first, from the operational store (90-day retention).

Use from + to to restrict the time range. Both must be supplied together or both omitted. Use cursor from the previous response to page forward.

Authorizations:
ApiKeyAuth
query Parameters
from
string <date-time>

Start of time range (inclusive). Requires to.

to
string <date-time>

End of time range (exclusive). Requires from.

limit
integer [ 1 .. 100 ]
Default: 50
cursor
string

Opaque pagination cursor from a previous response's nextCursor.

Responses

Response Schema: application/json
required
Array of objects (MessageSummary)
nextCursor
string

Opaque pagination cursor. Pass as cursor in the next request.

Response Schema: application/json
error
required
string

Stable machine-readable error code (e.g. bad_request, not_found, internal).

message
string

Human-readable detail. Not always present.

Response Schema: application/json
error
required
string

Stable machine-readable error code (e.g. bad_request, not_found, internal).

message
string

Human-readable detail. Not always present.

Response Schema: application/json
error
required
string

Stable machine-readable error code (e.g. bad_request, not_found, internal).

message
string

Human-readable detail. Not always present.

Response samples

Content type
application/json
{
  • "items": [
    • {
      • "messageId": "01HVXXXXXXXXXXXXXXXXXXXXXX",
      • "status": "delivered",
      • "channel": "SMS",
      • "sentTo": "+447700900001",
      • "sentFrom": "AcmeCorp",
      • "createdAt": "2025-06-19T10:00:00.000Z",
      • "submittedAt": "2025-06-19T10:00:01.000Z",
      • "deliveredAt": "2025-06-19T10:00:03.000Z",
      • "failedAt": null,
      • "errorCode": null,
      • "source": "direct",
      • "templateType": null,
      • "templateId": null
      }
    ],
  • "nextCursor": "eyJjcmVhdGVkQXQiOiIyMDI1LTA2LTE5VDEwOjAwOjAwLjAwMFoiLCJtZXNzYWdlSWQiOiIwMUhWWFhYWFhYWFhYWFhYWFhYWFhYWFgifQ"
}

Get a message

Fetch the current status of a single message by ID (tenant-scoped).

Authorizations:
ApiKeyAuth
path Parameters
messageId
required
string

Responses

Response Schema: application/json
messageId
required
string
status
required
string (MessageStatus)
Enum: "queued" "submitted" "delivered" "failed" "rejected" "expired"

Lifecycle state of a message:

  • queued — accepted, waiting to be sent to the provider
  • submitted — dispatched to the carrier, awaiting delivery confirmation
  • delivered — confirmed delivered to the handset
  • failed — delivery failed (undeliverable number, network error)
  • rejected — rejected by the provider or network
  • expired — message TTL elapsed before delivery
channel
required
string (Channel)
Enum: "SMS" "RCS"
sentTo
required
string (E164) ^\+[1-9]\d{7,14}$

E.164 phone number (e.g. +447700900000)

sentFrom
required
string

Sender ID used for this message

createdAt
required
string <date-time>
submittedAt
string or null <date-time>
deliveredAt
string or null <date-time>
failedAt
string or null <date-time>
errorCode
string or null
Enum: "rejected" "undeliverable" "expired" "invalid_request" null

Generic, provider-agnostic reason for a terminal failure. Null unless the message failed. rejected = refused by the network/provider, undeliverable = accepted but could not be delivered, expired = validity period elapsed, invalid_request = the send request was rejected.

source
required
string
Enum: "direct" "template"

Whether the message was sent directly or compiled from a template.

templateType
string or null

Template provider (e.g. textplode). Null for direct sends.

templateId
string or null

Template identifier. Null for direct sends.

Response Schema: application/json
error
required
string

Stable machine-readable error code (e.g. bad_request, not_found, internal).

message
string

Human-readable detail. Not always present.

Response Schema: application/json
error
required
string

Stable machine-readable error code (e.g. bad_request, not_found, internal).

message
string

Human-readable detail. Not always present.

Response Schema: application/json
error
required
string

Stable machine-readable error code (e.g. bad_request, not_found, internal).

message
string

Human-readable detail. Not always present.

Response samples

Content type
application/json
{
  • "messageId": "01HVXXXXXXXXXXXXXXXXXXXXXX",
  • "status": "delivered",
  • "channel": "SMS",
  • "sentTo": "+447700900001",
  • "sentFrom": "AcmeCorp",
  • "createdAt": "2025-06-19T10:00:00.000Z",
  • "submittedAt": "2025-06-19T10:00:01.000Z",
  • "deliveredAt": "2025-06-19T10:00:03.000Z",
  • "failedAt": null,
  • "errorCode": null,
  • "source": "direct",
  • "templateType": null,
  • "templateId": null
}

Reporting

Query message history from the reporting store. The store is dual-tiered: a fast hot tier for recent data, and a complete cold tier for all-time history. The tier is chosen transparently based on your date filters — you always get the same response shape.

Hot tier

  • Window: rolling 24 months from today
  • Latency: typically < 100 ms
  • Use: real-time filtering, dashboards, keyset-paginated lists

Queries that fall entirely within the 24-month window are served from the hot tier. If no from/to filters are supplied, the hot tier is used (most-recent-first scan).

Cold tier

  • Scope: all messages ever sent
  • Latency: seconds (query compilation + data scan)
  • Use: historical analysis, compliance queries

A query is routed to the cold tier when:

  • to ≤ 24-month boundary (query is entirely in the past), or
  • from < 24-month boundary (query spans the boundary)

Rate limits

Reporting has its own usage plan, separate from /messages*: 10 requests/sec, burst 20. Exceeding it returns 429 Too Many Requests.

List messages (reporting)

Filter and paginate your message history from the reporting store. The hot/cold tier is chosen automatically based on your from/to filters — see the section header for routing rules.

Content cap: when includeContent=true, limit is capped at 25.

Authorizations:
ApiKeyAuth
query Parameters
from
string <date-time>

Start of time range (inclusive). Requires to.

to
string <date-time>

End of time range (exclusive). Requires from.

status
string (MessageStatus)
Enum: "queued" "submitted" "delivered" "failed" "rejected" "expired"

Lifecycle state of a message:

  • queued — accepted, waiting to be sent to the provider
  • submitted — dispatched to the carrier, awaiting delivery confirmation
  • delivered — confirmed delivered to the handset
  • failed — delivery failed (undeliverable number, network error)
  • rejected — rejected by the provider or network
  • expired — message TTL elapsed before delivery
channel
string (Channel)
Enum: "SMS" "RCS"
sentFrom
string
sentTo
string (E164) ^\+[1-9]\d{7,14}$
Example: sentTo=+447700900000

E.164 phone number (e.g. +447700900000)

limit
integer [ 1 .. 100 ]
Default: 20

Max results per page. Capped at 25 when includeContent=true.

cursor
string

Opaque keyset cursor from a previous response's nextCursor.

includeContent
string
Default: "false"
Enum: "true" "false"

When true, each item includes content, idempotencyKey, and providerMetadata. Limit is capped at 25.

Responses

Response Schema: application/json
required
Array of objects (ReportMessage)
nextCursor
string

Opaque keyset cursor. Pass as cursor in the next request.

Response Schema: application/json
error
required
string

Stable machine-readable error code (e.g. bad_request, not_found, internal).

message
string

Human-readable detail. Not always present.

Response Schema: application/json
error
required
string

Stable machine-readable error code (e.g. bad_request, not_found, internal).

message
string

Human-readable detail. Not always present.

Response Schema: application/json
message
string
Response Schema: application/json
error
required
string

Stable machine-readable error code (e.g. bad_request, not_found, internal).

message
string

Human-readable detail. Not always present.

Response samples

Content type
application/json
{
  • "items": [
    • {
      • "messageId": "01HVXXXXXXXXXXXXXXXXXXXXXX",
      • "channel": "SMS",
      • "status": "delivered",
      • "sentFrom": "AcmeCorp",
      • "sentTo": "+447700900001",
      • "createdAt": "2025-06-19T10:00:00.000Z",
      • "submittedAt": "2025-06-19T10:00:01.000Z",
      • "deliveredAt": "2025-06-19T10:00:03.000Z",
      • "failedAt": null,
      • "source": "template",
      • "templateType": "textplode",
      • "templateId": "welcome-sms"
      }
    ],
  • "nextCursor": "eyJjIjoiMjAyNS0wNi0xOVQxMDowMDowMC4wMDBaIiwibSI6IjAxSFZYWFhYWFhYWFhYWFhYWFhYWFhYWFgifQ"
}

Get a message (reporting)

Fetch a single message from the reporting store by ID (tenant-scoped).

Looks up the message in the hot tier first. On a miss (message older than 24 months), falls back transparently to the cold tier. The response shape is identical either way.

Authorizations:
ApiKeyAuth
path Parameters
messageId
required
string
query Parameters
includeContent
string
Default: "false"
Enum: "true" "false"

When true, adds content, idempotencyKey, and providerMetadata to the response.

Responses

Response Schema: application/json
messageId
required
string
channel
required
string (Channel)
Enum: "SMS" "RCS"
status
required
string (MessageStatus)
Enum: "queued" "submitted" "delivered" "failed" "rejected" "expired"

Lifecycle state of a message:

  • queued — accepted, waiting to be sent to the provider
  • submitted — dispatched to the carrier, awaiting delivery confirmation
  • delivered — confirmed delivered to the handset
  • failed — delivery failed (undeliverable number, network error)
  • rejected — rejected by the provider or network
  • expired — message TTL elapsed before delivery
sentFrom
required
string
sentTo
required
string
createdAt
required
string <date-time>
submittedAt
string or null <date-time>
deliveredAt
string or null <date-time>
failedAt
string or null <date-time>
errorCode
string or null
Enum: "rejected" "undeliverable" "expired" "invalid_request" null

Generic, provider-agnostic reason for a terminal failure. Null unless the message failed. rejected = refused by the network/provider, undeliverable = accepted but could not be delivered, expired = validity period elapsed, invalid_request = the send request was rejected.

source
required
string
Enum: "direct" "template"

Whether the message was sent directly or compiled from a template.

templateType
string or null

Template provider (e.g. textplode). Null for direct sends.

templateId
string or null

Template identifier. Null for direct sends.

content
string or null

Full message body. Only present when includeContent=true.

idempotencyKey
string or null

Idempotency key used at submission. Only present when includeContent=true.

providerMetadata
object or null

Provider-specific metadata object. Only present when includeContent=true.

Response Schema: application/json
error
required
string

Stable machine-readable error code (e.g. bad_request, not_found, internal).

message
string

Human-readable detail. Not always present.

Response Schema: application/json
error
required
string

Stable machine-readable error code (e.g. bad_request, not_found, internal).

message
string

Human-readable detail. Not always present.

Response Schema: application/json
message
string
Response Schema: application/json
error
required
string

Stable machine-readable error code (e.g. bad_request, not_found, internal).

message
string

Human-readable detail. Not always present.

Response samples

Content type
application/json
{
  • "messageId": "01HVXXXXXXXXXXXXXXXXXXXXXX",
  • "channel": "SMS",
  • "status": "delivered",
  • "sentFrom": "AcmeCorp",
  • "sentTo": "+447700900001",
  • "createdAt": "2025-06-19T10:00:00.000Z",
  • "submittedAt": "2025-06-19T10:00:01.000Z",
  • "deliveredAt": "2025-06-19T10:00:03.000Z",
  • "failedAt": null,
  • "source": "direct",
  • "templateType": null,
  • "templateId": null
}