API Reference
Complete REST API reference with request/response examples for all endpoints.
Response envelope
All API responses use a consistent envelope:
{
"status": "ok",
"time": "2026-04-06T10:00:00.000000000Z",
"request_id": "01jqk...",
"data": {}
}
| Field | Description |
|---|---|
status |
"ok" on success, "error" on failure |
time |
Server timestamp (RFC3339 nanoseconds) |
request_id |
Unique request identifier (base32-encoded UUIDv7) |
data |
Response payload (object or array). Reads return it; creates return the new id at the top level instead |
On error, data is omitted and an error field contains the message:
{
"status": "error",
"time": "2026-04-06T10:00:00.000000000Z",
"request_id": "01jqk...",
"error": "contact not found"
}
GET /v1/who
Returns information about the authenticated API key and tenant.
curl -H "Authorization: Bearer $API_KEY" https://connect.ataca.io/v1/who
{
"status": "ok",
"data": {
"tenant": "acme",
"key_name": "production-key",
"created_by": "[email protected]"
}
}
POST /v1/contacts
Create a new contact.
| Field | Type | Required | Description |
|---|---|---|---|
number |
string | yes | Phone number in E.164 format, for example +14155552671 |
email |
string | no | Email address |
reference |
string | no | Your custom identifier for this contact |
number is required. email and reference are optional.
curl -X POST https://connect.ataca.io/v1/contacts \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"number": "+1234567890", "email": "[email protected]", "reference": "cust-001"}'
{
"status": "ok",
"id": "01jqk...",
"time": "2026-04-06T10:00:00.000000000Z",
"request_id": "acme-b7k9m2n4p6"
}
The response carries the new contact's id only. Fetch the contact with GET /v1/contacts/{id}.
Uniqueness: Contacts are unique per tenant by number and by reference. Attempting to create a duplicate returns HTTP 409 Conflict.
GET /v1/contacts
List contacts with pagination.
| Query param | Default | Description |
|---|---|---|
page |
1 | Page number |
page_size |
20 | Items per page (max 100) |
curl -H "Authorization: Bearer $API_KEY" "https://connect.ataca.io/v1/contacts?page=1&page_size=10"
{
"status": "ok",
"data": {
"contacts": [
{
"id": "01jqk...",
"number": "+1234567890",
"email": "[email protected]",
"reference": "cust-001",
"created_at": "2026-04-06T10:00:00.000000000Z"
}
],
"total": 42,
"page": 1,
"page_size": 10
}
}
GET /v1/contacts/{id}
Get a single contact by ID.
curl -H "Authorization: Bearer $API_KEY" https://connect.ataca.io/v1/contacts/01jqk...
{
"status": "ok",
"data": {
"id": "01jqk...",
"number": "+1234567890",
"email": "[email protected]",
"reference": "cust-001",
"created_at": "2026-04-06T10:00:00.000000000Z"
}
}
Returns HTTP 404 if the contact does not exist or belongs to a different tenant.
GET /v1/templates
List all templates with aggregated placeholder information across channels.
curl -H "Authorization: Bearer $API_KEY" https://connect.ataca.io/v1/templates
{
"status": "ok",
"data": {
"templates": [
{
"id": "01jqk...",
"name": "welcome",
"description": "Welcome message for new users",
"channels": ["WHATSAPP", "EMAIL", "SMS"],
"placeholders": [
{"name": "first_name", "required": true},
{"name": "discount", "required": false, "default": "10%"}
],
"created_at": "2026-04-06T10:00:00.000000000Z",
"updated_at": "2026-04-06T10:00:00.000000000Z"
}
]
}
}
Placeholders are aggregated from all channel bodies. A placeholder is required if it appears without a default in any channel body.
POST /v1/send
Send a message to a contact using a template.
| Field | Type | Required | Description |
|---|---|---|---|
contact_id |
string | yes | Contact ID (base32-encoded) |
template |
string | yes | Template name |
data |
object | no | Placeholder values |
file_id |
string | no | An uploaded file's id. Its link becomes the file_url placeholder |
curl -X POST https://connect.ataca.io/v1/send \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"contact_id": "01jqk...",
"template": "welcome",
"data": {"first_name": "Alice", "discount": "20%"}
}'
{
"status": "ok",
"id": "01jqk...",
"time": "2026-04-06T10:01:00.000000000Z",
"request_id": "acme-j8k2m4n6p8"
}
The response carries the new message's id only. The message is enqueued for async delivery. The delivery orchestrator processes it through your configured cascade policy. Check delivery status via the dashboard or webhook callbacks.
POST /v1/files
Upload a file to attach to messages. Send one multipart form part named file. The default size limit is 10 MB.
curl -X POST https://connect.ataca.io/v1/files \
-H "Authorization: Bearer $API_KEY" \
-F "[email protected];type=application/pdf"
{
"status": "ok",
"file": {
"id": "k7m2p9q4r1s8t3v6",
"url": "https://connect.ataca.io/f/k7m2p9q4r1s8t3v6",
"name": "invoice.pdf",
"content_type": "application/pdf",
"size": 48213,
"expires_at": "2026-04-13T10:01:00Z"
}
}
Pass the id as file_id on POST /v1/send and reference {{file_url}} in the template body. The link is public: anyone who has it can fetch the file. The random id is what keeps it private.
A file expires seven days after upload by default (files.ttl_days). After that, or after a delete, its link answers 410 Gone and POST /v1/send rejects its file_id with 400 file expired or deleted. An hourly sweep removes the bytes of expired files.
DELETE /v1/files/{id}
Revoke a file before it expires. Its bytes are removed at once and its link answers 410 Gone from then on. Deleting a file that is already gone succeeds; an id that is not yours answers 404.
curl -X DELETE https://connect.ataca.io/v1/files/k7m2p9q4r1s8t3v6 \
-H "Authorization: Bearer $API_KEY"
{
"status": "ok",
"id": "k7m2p9q4r1s8t3v6",
"time": "2026-04-06T10:05:00.000000000Z",
"request_id": "acme-j8k2m4n6p9"
}
GET /f/{id}
Fetch an uploaded file. No authentication; rate limited per IP. Images, PDF, plain text, audio, and video are served inline. Everything else downloads as an opaque attachment, so nothing uploaded can run in a browser on this origin. An expired or deleted file answers 410 Gone; an unknown id answers 404.
Pagination
List endpoints support page and page_size query parameters. Responses include a total count for computing page ranges.
| Parameter | Default | Max | Description |
|---|---|---|---|
page |
1 | — | 1-indexed page number |
page_size |
20 | 100 | Number of items per page |