# API Reference

**Base URLs**

All API requests should be made to the following base URLs:

{% tabs %}
{% tab title="Production" %}
To send SMSes to the public, please use our production environment.

```url
https://postman.gov.sg/api/v2
```

<mark style="color:red;">**Do not use this for testing, please use our test or loadtest environments instead. Non-compliance will be reported to your agency's CIO.**</mark>
{% endtab %}

{% tab title="Test" %}
To send SMSes to yourself during the integration phase, please use our test environment.

```url
https://test.postman.gov.sg/api/v2
```

<mark style="color:red;">**Do not use this to send messages to the public, please use the production environment instead. Non-compliance will be reported to your agency's CIO.**</mark>

If you are planning to load test our systems, please use the loadtest environment instead.
{% endtab %}

{% tab title="Loadtest" %}
To use Postman for any load testing, please use our loadtest environment.

*Note that load testing is optional. Postman meets our internal load test standards and we have successfully supported multiple nationwide campaigns without any issues.*

```url
https://loadtest.postman.gov.sg/api/v2
```

<mark style="color:red;">**Please make a load test booking before conducting any load tests.**</mark>
{% endtab %}
{% endtabs %}

***

**Authentication**

The Postman v2 API uses API keys and static IP whitelisting to authenticate requests. Authentication is performed with HTTP Bearer Auth.

```
Authorization: Bearer YOUR_API_KEY
```

All API calls must be made over HTTPS. Calls over plain HTTP will fail. Requests without authentication will return HTTP 401.

***

**API Endpoints**

**Single send (for a single recipient)**

<table><thead><tr><th width="101.01171875">HTTP Method</th><th width="341.32421875">Endpoint</th><th>Description</th></tr></thead><tbody><tr><td><code>POST</code></td><td><code>/campaigns/&#x3C;campaignId>/messages</code></td><td>Send a single message to one recipient. Use this for time-sensitive, critical SMSes like OTPs or weather alerts. Returns the created message object immediately, but you must query the Retrieve Message endpoint to get the delivery status.</td></tr><tr><td><code>POST</code></td><td><code>/campaigns/&#x3C;campaignId>/messages/&#x3C;messageId>/retry</code></td><td>Retry a single failed message. The message retains its original message ID. Only works if the message <code>latestStatus</code> is <code>failure</code>. Maximum 3 retry attempts per message.</td></tr><tr><td><code>GET</code></td><td><code>/campaigns/&#x3C;campaignId>/messages/&#x3C;messageId></code></td><td>Retrieve a single message and its delivery status. Webhooks are not supported; you must poll this endpoint to check status changes.</td></tr><tr><td><code>GET</code></td><td><code>/campaigns/&#x3C;campaignId>/messages</code></td><td>Retrieve all messages and their delivery statuses for a campaign, with campaign template information. Supports searching by recipient phone number (substring match). Returns paginated results.</td></tr></tbody></table>

**Batch send (for multiple recipients)**

<table><thead><tr><th width="140.35546875">HTTP Method</th><th>Endpoint</th><th>Description</th></tr></thead><tbody><tr><td><code>POST</code></td><td><code>/campaigns/&#x3C;campaignId>/batch/messages</code></td><td>Send messages to multiple recipients in a single API request. Upload a CSV file via <code>multipart/form-data</code>. The CSV must include <code>recipient</code>, <code>language</code>, and columns for each template parameter. Test environment has a 20-row CSV limit.</td></tr><tr><td><code>POST</code></td><td><code>/campaigns/&#x3C;campaignId>/batch/&#x3C;batchId>/retry</code></td><td>Retry all failed messages in a batch. Only works if batch status is <code>messages_enqueued</code> or <code>messages_enqueuing_failed</code>. Will fail if any message in the batch still has <code>latestStatus</code> of <code>created</code>. Returns HTTP 201 with no response body.</td></tr><tr><td><code>GET</code></td><td><code>/campaigns/&#x3C;campaignId>/batch/&#x3C;batchId>/messages</code></td><td>Retrieve all messages and their delivery statuses for a batch. Supports searching by recipient phone number (substring match). Returns paginated results using cursor-based pagination.</td></tr></tbody></table>

***

**Pagination**

The Retrieve Batch and Retrieve Campaign Message endpoints use cursor-based pagination.

| Parameter | Description                                        |
| --------- | -------------------------------------------------- |
| `limit`   | Number of results per page                         |
| `search`  | Filter by recipient phone number (substring match) |
| `before`  | Cursor for fetching the previous page              |
| `after`   | Cursor for fetching the next page                  |

The response includes a `pageData` object:

```json
{
  "pageData": {
    "hasNextPage": false,
    "hasPreviousPage": false,
    "startCursor": "...",
    "endCursor": "..."
  }
}
```

Use `after` with `endCursor` to get the next page. Use `before` with `startCursor` to get the previous page.

***

**Message Statuses**

| Status          | Description                                                                                                                                                                                                                                 |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `created`       | Postman has created the message record but has not yet sent it to the messaging service provider.                                                                                                                                           |
| `enqueued`      | The message is in the queue, waiting to be sent to the messaging service provider.                                                                                                                                                          |
| `sending`       | The message has been taken out of the queue and is being sent to the messaging service provider.                                                                                                                                            |
| `sent`          | Postman has sent the message to the messaging service provider, but has not yet received a delivery confirmation.                                                                                                                           |
| `sent_to_telco` | The messaging service provider confirms the message has been sent to the recipient's telco. The message may or may not have reached the recipient's phone. If status remains here beyond 48 hours, a further update is unlikely.            |
| `success`       | The message has been delivered to the recipient. This is a terminal status.                                                                                                                                                                 |
| `failure`       | The message failed to send due to an error in Postman or the messaging service. This is a terminal status. See [Message Delivery Errors](https://postman-v2.guides.gov.sg/general-notes-for-api-users/message-delivery-errors) for details. |

***

**Rate Limits**

The default rate limit is **10 TPS (transactions per second) per campaign ID**. This is defined as the number of API calls per second, not the number of messages sent per second. The rate limit is shared across all API endpoints for a campaign.

Requests that exceed the rate limit are dropped (not queued) and return HTTP 429. You must retry these requests yourself.

To request a higher TPS, we require evidence of historical usage from your old systems where rate limits have been hit.

***


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://postman-v2.guides.gov.sg/technical-users-api/api-reference.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
