---
title: API overview
description: Base URL, content type, and the shape of every response.
---

The ZevSend API is a REST API. All requests and responses are
JSON, all endpoints are versioned, and all errors share a single
shape so you can write one error handler for the whole surface.

## Base URL

```text
https://api.zevsend.com
```

There is no separate sandbox host. Test-mode API keys
(`sk_test_…`) route to the same endpoints; the key implies the
mode.

## Versioning

The API is versioned by URL prefix. The current version is `v1`:

```text
POST https://api.zevsend.com/v1/emails
POST https://api.zevsend.com/v1/sms
POST https://api.zevsend.com/v1/whatsapp
```

Backwards-incompatible changes ship under a new prefix (`v2`).
Existing prefixes keep working — we'll give you at least 12
months' notice before sunsetting one.

## Authentication

Pass your API key as a Bearer token in the `Authorization`
header. See [Authentication](/api/auth) for details.

```bash
curl https://api.zevsend.com/v1/emails \
  -H "Authorization: Bearer sk_test_..."
```

## Content type

Every request must set `Content-Type: application/json`. Every
response is JSON. Empty responses still set
`Content-Type: application/json` for parser symmetry.

## Response shape

### Success

Successful POST endpoints return `202 Accepted` with the
identifier of the resource that was created:

```json
{
  "id": "eml_01HXYZ...",
  "to": "you@example.com",
  "status": "sending",
  "sandbox": true,
  "created_at": "2025-05-24T12:34:56.789Z"
}
```

`202` rather than `201` because the send is asynchronous — by
the time you read this, the message is on its way but hasn't
necessarily been accepted by the upstream network yet.

### Error

Every error response is shaped the same way. See
[Errors](/api/errors).

```json
{
  "error": {
    "code": "invalid_phone",
    "message": "Recipient must be a phone number in international format, e.g. +2348012345678.",
    "param": "to",
    "type": "validation_error",
    "request_id": "req_01HXYZ..."
  }
}
```

## Identifiers

Every resource has a stable, opaque public id with a type
prefix:

| Prefix    | Resource                |
| --------- | ----------------------- |
| `tm_…`    | Team                    |
| `usr_…`   | User                    |
| `sk_…`    | API key                 |
| `dom_…`   | Domain                  |
| `tpl_…`   | Template                |
| `eml_…`   | Email message           |
| `sms_…`   | SMS message             |
| `wam_…`   | WhatsApp message        |

Ids are stable for the lifetime of the resource and safe to
store in your own database.

## Timestamps

All timestamps are ISO 8601 in UTC, to millisecond precision:

```text
2025-05-24T12:34:56.789Z
```

## Pagination

List endpoints (delivered through the GraphQL surface that
powers the dashboard) use cursor-based pagination via the
`before` parameter. The REST send endpoints are write-only,
so they don't paginate.