> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tracklysms.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Test the Demo API

> Use a dedicated demo key to discover sample data, approve a simulated SMS and read its result.

<Note>
  The isolated demo is being prepared for rollout. These steps require an activated
  demo account and the deployed demo service; a regular Trackly account does not
  automatically have access.
</Note>

The demo API uses synthetic senders, contacts and messages. You do not need a
registered number. No SMS reaches a carrier, and simulated sends incur no SMS
charges. The supported workflow includes a real human approval step.

## Create a key

Sign in to your demo account and open [Demo API keys](https://app.tracklysms.com/demo/api-keys).
Name and create a key, then copy it before leaving the page. The secret appears
only once. Keys expire after seven days; you can keep up to five active keys.
Revoke a key from the same page when finished.

Use this base URL:

```text theme={null}
https://mcp.tracklysms.com/demo/v2
```

Send the key in the `X-Api-Key` header. Keep it in your local secret store or
Postman's secret variable storage. Do not put it in a URL, source control or chat.
Demo keys cannot authenticate against the production API.

If key creation times out, refresh the list, revoke the key whose secret you did
not receive, then create another. Do not automatically retry key creation.

## Discover sample data

The examples assume `TRACKLY_DEMO_API_KEY` is already set securely in your local
environment:

```bash theme={null}
curl 'https://mcp.tracklysms.com/demo/v2/auth/whoami' \
  -H "X-Api-Key: $TRACKLY_DEMO_API_KEY"

curl 'https://mcp.tracklysms.com/demo/v2/agent/setup' \
  -H "X-Api-Key: $TRACKLY_DEMO_API_KEY"
```

Confirm the intended account and `execution_environment: "reviewer_demo"`.
Use the returned `sender.phone_number` and `contacts[0].phone_number` as the
message's `list_number` and `to`. Other recipients are rejected.

## Prepare and approve a simulated SMS

Save a JSON file named `demo-hold.json`, replacing the placeholders with the
returned sample numbers:

```json theme={null}
{
  "message": {
    "list_number": "SAMPLE_SENDER",
    "to": "SAMPLE_RECIPIENT",
    "body": "This is a simulated Trackly API test."
  },
  "note": "API integration test"
}
```

Create one hold using a unique, stable idempotency key for this exact message:

```bash theme={null}
curl 'https://mcp.tracklysms.com/demo/v2/pending-sends' \
  -H "X-Api-Key: $TRACKLY_DEMO_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: demo-message-001' \
  --data-binary @demo-hold.json
```

Save the returned hold `id`. Open [Demo send approvals](https://app.tracklysms.com/demo/send-approvals)
as the demo owner, inspect the exact message and approve it. An API key cannot
approve a hold. Read `GET /pending-sends/<id>` until that same hold reports
`approved`, then execute it with the key that created it:

```bash theme={null}
curl -X POST 'https://mcp.tracklysms.com/demo/v2/pending-sends/HOLD_ID/send' \
  -H "X-Api-Key: $TRACKLY_DEMO_API_KEY" \
  -H 'Content-Type: application/json' \
  --data '{}'
```

Use the returned message ID with `GET /messages/<id>` or inspect
`GET /messages?api_key=me`. These records are simulated outcomes, not proof of
carrier delivery. To cancel before execution, use `DELETE /pending-sends/<id>`.

## Supported operations and limits

| Operation                   | Route under the demo base URL                                                                         |
| --------------------------- | ----------------------------------------------------------------------------------------------------- |
| Identity and setup          | `GET /auth/whoami`, `GET /agent/setup`                                                                |
| Sample senders              | `GET /lists`                                                                                          |
| Validate a sample message   | `POST /messages/preflight`                                                                            |
| Create and inspect holds    | `POST /pending-sends`, `GET /pending-sends`, `GET /pending-sends/<id>`                                |
| Execute an approved hold    | `POST /pending-sends/<id>/send`                                                                       |
| Cancel a hold               | `DELETE /pending-sends/<id>`                                                                          |
| Simulated message history   | `GET /messages`, `GET /messages/<id>`                                                                 |
| Private registration drafts | `POST /agent/number-requests`, `GET /agent/number-requests/<id>`, `PATCH /agent/number-requests/<id>` |

Limits are shared across MCP connections and API keys: 30 requests per minute,
two concurrent requests, 20 open holds and 100 simulated executions per rolling
24 hours per account. Retained sample records have separate capacity limits.
New keys do not reset allowances. Requests have a 64 KiB body limit.

Billing, provisioning, webhooks, paid previews, real recipients, bulk sends and
immediate sends are unavailable. Registration drafts remain private samples.

Honor `Retry-After` when supplied. After an uncertain hold creation, reconcile
using the same idempotency key and exact body. After uncertain execution, read
the same hold and its message result before taking another action. Never create
a replacement message to resolve an unknown outcome. If the demo is unavailable,
stop; switching to the production API is not a recovery step.
