REST API · v1

Send Message API

Submit outbound SMS messages using your project API key. The endpoint accepts a message submission, persists the logical message record, and queues delivery asynchronously.

Response202 Accepted (async)
AuthX-API-Key header
Content-Typeapplication/json

Note: 202 Accepted means the platform queued the message — not that the carrier has delivered it. Current v1 limitation: API key auth is supported for message submission only. Read endpoints require Sanctum auth.

Endpoint

Send a POST request to a single path. The project context is supplied via the id field in the request body, not in the URL.

POST/v1/send-message

# Project context is passed via the request body id field

Full URL example

https://api.lomisend.com/v1/send-message

Authentication

Send the project API key in the X-API-Key header. Keys follow the format {prefix}_{type}_{64_hex_characters}.

sms_live_<64 hex>

Live key — real delivery

sms_test_<64 hex>

Test key — sandboxed

HTTP headers
Content-Type: application/json
Accept: application/json
X-API-Key: sms_live_your_64_hex_character_key_here
X-Request-ID: your-request-id   # optional but echoed in error responses

X-Request-ID is optional but useful — RFC 7807 error responses echo it back as request_id, making it easy to correlate failures in your logs.

Request body

JSON object with the following fields:

FieldTypeRequired
idstringYes
tostringYes
sender_idstringConditional
bodystringYes
1

id is a client assertion only. The backend compares it against the authenticated API key project and derives execution context from the key snapshot.

2

sender_id is matched by sender name/value. Legacy UUID-style sender payloads are rejected.

3

If a live-key request omits sender_id, the project must have an active default sender ID or the request fails with 422.

4

encoding and metadata must not be provided. Both fields are rejected if the client sends them.

Live key example

LIVE

Use a live key after sender IDs, subscription access, and billing are ready.

request.sh
bash
curl -X POST "https://api.lomisend.com/v1/send-message" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: sms_live_your_64_hex_character_key_here" \
  -H "X-Request-ID: msg-001" \
  -d '{
    "id": "01926d3e-8f1c-7a2b-b8e5-3f4a5c6d7e8f",
    "to": "+251911234567",
    "sender_id": "MyBrand",
    "body": "Hello from our platform!"
  }'

202 Accepted response

response.json
json
{
  "data": {
    "id": "01JRXXXXXXXXXXXXXXXXXXXXX",
    "to_number": "+251911234567",
    "sender_address": "MyBrand",
    "body": "Hello from our platform!",
    "segment_count": 1,
    "attempt_count": 1,
    "status": "pending",
    "created_at": "2026-03-18T12:00:00+00:00",
    "mode": "live",
    "charged_from": "quota",
    "cost_cents": 0
  }
}

Test key example

TEST

Test keys use the same endpoint but are fully sandboxed. Use them while building your integration.

✓

sender_id must equal the configured platform test sender name

✓

to must already be approved for that project

✓

Accepted responses return mode: "test"

✓

No subscription or billing cycle required

test-request.sh
bash
curl -X POST "https://api.lomisend.com/v1/send-message" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: sms_test_your_64_hex_character_key_here" \
  -d '{
    "id": "01926d3e-8f1c-7a2b-b8e5-3f4a5c6d7e8f",
    "to": "+251911000001",
    "sender_id": "PlatformTest",
    "body": "Test mode send"
  }'

202 Accepted response

response.json
json
{
  "data": {
    "id": "01JRXXXXXXXXXXXXXXXXXXXXX",
    "to_number": "+251911000001",
    "sender_address": "PlatformTest",
    "body": "Test mode send",
    "segment_count": 1,
    "attempt_count": 1,
    "status": "pending",
    "created_at": "2026-03-18T12:00:00+00:00",
    "mode": "test",
    "charged_from": "wallet",
    "cost_cents": 7
  }
}

Response fields

Successful responses wrap the message object under data.

FieldType
idstring
to_numberstring
sender_addressstring
bodystring
segment_countinteger
attempt_countinteger
statusstring
created_atstring
modestring
charged_fromstring | null
cost_centsinteger

Error handling

The API uses RFC 7807 problem responses. Handle errors by slug, not only by status code, as multiple slugs can share the same HTTP status.

error-response.json
json
{
  "type": "https://api.lomisend.com/errors/validation-failed",
  "title": "Validation Failed",
  "status": 422,
  "detail": "The given data was invalid.",
  "errors": {
    "to": ["A recipient phone number is required."]
  },
  "instance": "/v1/send-message",
  "request_id": "msg-001"
}
StatusSlug
401unauthenticated
401invalid-api-key-format
401invalid-api-key
401api-key-expired
401api-key-rotation-expired
402insufficient-balance
402no-billing-cycle
403subscription-required
403workspace-suspended
403api-key-insufficient-scope
422validation-failed
422test-sender-id-required
422recipient-not-approved-for-test
500invalid-overage-rate
500platform-not-configured

Validation rules

  • ·id is required and must be the target project UUID
  • ·to must be E.164 format — e.g. +251911234567
  • ·body is required
  • ·sender_id fails when the value is unknown, inactive, belongs to another project, or no default sender is available
  • ·encoding is rejected if the client provides it — encoding is resolved internally
  • ·metadata is rejected if the client provides it — metadata is generated internally when needed

Live vs test keys

The same endpoint handles both key types. Behavior differs in several ways:

BehaviorLive keyTest key
Requires active subscription✓—
Requires open billing cycle

unless wallet can't cover test rate

✓—
Sender resolutionProject sender or active defaultPlatform test sender only
Recipient restrictionNormal send rulesMust be approved for project
mode in responselivetest
1

Use a test key while building your integration.

2

Move to a live key after sender IDs, subscription, and billing are ready.

3

Do not hardcode sender UUIDs — the contract expects sender names.

Integration notes

Checklist for a reliable integration:

1

Treat 202 as asynchronous acceptance only

The carrier has not delivered the message yet. Poll delivery status or use webhooks to track the outcome.

2

Persist the message id

Keep the returned message id on your side as your platform reference for support and correlation.

3

Log X-Request-ID

If you send X-Request-ID, keep it in your logs. It is echoed in RFC 7807 error responses as request_id.

4

Handle errors by slug

Match RFC 7807 errors on the slug field, not only HTTP status code. Multiple slugs share the same status.

5

Default sender for live traffic

If you omit sender_id for live requests, ensure the project has one active default sender configured or the request will fail with 422.

Ready to send your first message?

Create a free account, pick up your API key from the dashboard, and you can send your first SMS in minutes.

© 2026 Lomisend · API reference v1