---
title: "Send an SMS"
method: POST
path: "/messages"
tags: ["Messages"]
---

# Send an SMS

`POST /messages`

## Request

- Base URL: `https://api.hypamoon.com/api/v1`
- URL: `https://api.hypamoon.com/api/v1/messages`
- Auth: one of:
  - HTTP bearer
  - OAuth 2 (authorization code, authorization URL `https://app.hypamoon.com/oauth/authorize`, token URL `https://api.hypamoon.com/oauth/token`, scopes: `messages:write`)

Sends one transactional SMS: an order confirmation, a shipping update with track and trace, an appointment reminder. Not for marketing: promotional SMS needs the recipient's prior consent under marketing law, and this endpoint is not built for bulk. A message goes to a mobile number in a country your project can text; an unsupported destination returns destination_not_allowed with a reason. It comes from an alphanumeric sender (your project name, or from); your phone numbers cannot send SMS. At most 6 segments per message, 30 messages per minute and 200 per day per project. A new live project starts lower (20 per day, 60 after 7 days and a first top-up, the full limit after 30 days and €25 paid). The same number gets at most 3 messages in 24 hours per project and 10 across all projects: 429 message_limit_reached with scope per_number or per_number_platform, retry_at and a user_message; test numbers do not count. A live key needs the company verification level (company details, spending cap, payment method, a verified phone and one payment confirmed with your bank: iDEAL or a card with 3D Secure); a business may also need its registration number checked against the business register, and a personal account may need our approval of its identity documents (the number_documents level); otherwise the request returns verification_required. Live messages are deducted from your prepaid balance per segment (the rate is under Billing in the portal; test mode is free) and count toward the spending cap. If the balance is too low for this message, the request returns insufficient_balance; if this month's spending plus this message would exceed the cap, it returns billing_blocked. In both cases nothing is sent. The response says queued; message.delivered or message.failed follows as a webhook, and GET /messages/{id} shows the status. With a test key nothing is sent: use a test number from +447700900000 to +447700900999; the message is delivered immediately, and +447700900999 simulates a failure. Send an Idempotency-Key (one per order event, like order-10432-shipped) so a retry never sends the SMS twice.

## Headers

- `Idempotency-Key` string

## Request body

- MessageInput: A transactional SMS to one recipient.
  - `to` string, required: The recipient in E.164. Live: a mobile number in a country your project can text (otherwise destination_not_allowed with a reason). Test mode: a test number from +447700900000 to +447700900999.
  - `body` string, required: The text. At most 6 SMS segments: 918 characters in plain text (GSM-7), 402 with an emoji or another character outside GSM-7. Typographic quotes and dashes are replaced by plain ones.
  - `from` string: Optional sender name: 1 to 11 letters, digits and spaces, with at least one letter. Default: your project name. A phone number is not possible.
  - `reference` string: Optional: your own id for this message, like an order number. Comes back in the message and its webhooks.

## Response `201`

The message was accepted (or, in test mode, simulated).

- Message: An SMS message. The same shape in POST /messages, GET /messages, GET /messages/{id} and the message webhooks.
  - `id` string, uuid, required: The id of the message.
  - `to` string, required: The recipient, in E.164.
  - `from` string, required: The sender the recipient sees: an alphanumeric name of up to 11 characters.
  - `body` string, required: The text as it was sent, after typographic quotes and dashes were made SMS-safe.
  - `segments` integer, required: How many SMS segments the text took. A segment is 160 GSM-7 or 70 UCS-2 characters (153 and 67 when split).
  - `encoding` 'gsm7' | 'ucs2' | 'null', nullable, required: gsm7, or ucs2 when the text has a character outside GSM-7 (an emoji, for example), which makes every segment shorter.
  - `status` 'queued' | 'sent' | 'delivered' | 'failed', required: queued: accepted. sent: handed to the mobile network. delivered: the phone confirmed it. failed: it did not arrive; see error.
  - `error` string, nullable, required: With status failed: a short code, like delivery_failed or sending_failed. Otherwise null.
  - `reference` string, nullable, required: Your own id for this message, as you sent it (an order number, for example).
  - `created_at` string, date-time, required: When we accepted the message.
  - `status_updated_at` string, date-time, nullable, required: When the status last changed.
  - `test` boolean, required: true for a message sent with a test key to a test number. It never reaches a phone.

## Other responses

- `400`: Bad Request: idempotency_key_invalid, invalid_json.
- `401`: Unauthorized: unauthorized, missing_api_key, invalid_api_key, api_key_revoked, project_deleted.
- `402`: Payment Required: payment_mandate_missing, billing_blocked, insufficient_balance.
- `403`: Forbidden: project_not_enabled, key_mode_mismatch, missing_scope, verification_required, phone_verification_required.
- `409`: Conflict: idempotency_key_reused, idempotency_request_in_progress.
- `422`: Unprocessable Content: validation_failed, destination_not_allowed, message_too_long, sender_not_allowed, company_details_missing, spend_cap_missing.
- `429`: Too Many Requests: rate_limited, message_limit_reached.
- `500`: Internal Server Error: internal_error.
- `502`: Bad Gateway: upstream_error.
- `503`: Service Unavailable: service_unavailable, telephony_unavailable.

---

[API](https://skmtc.dev/hypamoon/apis/hypamoon-api.md) · [All operations](https://skmtc.dev/hypamoon/apis/hypamoon-api/llms.txt) · [OpenAPI document](https://skmtc.dev/hypamoon/apis/hypamoon-api/revisions/9f0b90004c06?raw)
