Skip to main content

REST API v1

API Reference

All 84 endpoints. Click any one to see the fields you send and the shape you get back. Prefer to generate a client? Take the OpenAPI spec.

Base URL https://launch.email/api/v1 Auth Authorization: Bearer <key> Guides and concepts

Identity

Who the presented key belongs to

GET /me

Returns the owning team, the key's scopes, and the applicable rate limit.

Response

data object
data.team object
data.api_key object or null
data.rate_limit object

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl http://tweak.email/api/v1/me \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": {
        "team": {
            "id": 9,
            "name": "Acme",
            "plan": "business"
        },
        "api_key": {
            "id": 4,
            "name": "CRM sync",
            "scopes": [
                "contacts:read",
                "contacts:write"
            ],
            "legacy": false
        },
        "rate_limit": {
            "requests_per_minute": 600
        }
    }
}

Contacts

Contacts, lists, tags, and segments

GET /contacts

Requires scope contacts:read

Cursor-paginated. Filterable by status, tag, list, segment, and modification time.

Query parameters

per_page integer default 25
Records per page (1–100, default 25).
cursor string
The `next_cursor` value from a previous response.
status string
Filter by contact status.
active pending unsubscribed bounced
tag_id integer
Only contacts carrying this tag.
list_id integer
Only contacts on this list.
segment_id integer
Only contacts matching this saved segment.
updated_since string
ISO 8601 timestamp. Only contacts modified since. Use this to run an incremental sync.
include string
Comma-separated relations to embed: tags, lists.

Response

data array of object
data.id integer
data.email string
data.first_name string or null
data.last_name string or null
data.status string
active pending unsubscribed bounced
data.metadata object
data.subscribed_at string or null
data.unsubscribed_at string or null
data.confirmed_at string or null
data.consent_source string or null
data.soft_bounce_count integer
data.created_at string or null
data.updated_at string or null
per_page integer
next_cursor string or null
prev_cursor string or null
next_page_url string or null
prev_page_url string or null
has_more boolean

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl http://tweak.email/api/v1/contacts \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": [
        {
            "id": 42,
            "email": "jane@example.com",
            "first_name": "Jane",
            "last_name": "Okonkwo",
            "status": "active",
            "metadata": {
                "company": "Acme",
                "city": "Copenhagen"
            },
            "subscribed_at": "2026-08-01T09:15:00+00:00",
            "unsubscribed_at": null,
            "confirmed_at": null,
            "consent_source": "signup_form",
            "soft_bounce_count": 0,
            "created_at": "2026-08-01T09:15:00+00:00",
            "updated_at": "2026-08-09T14:02:00+00:00"
        }
    ],
    "per_page": 1,
    "next_cursor": "string",
    "prev_cursor": "string",
    "next_page_url": "string",
    "prev_page_url": "string",
    "has_more": true
}
POST /contacts

Requires scope contacts:write

Upserts on email address. An existing contact that has unsubscribed or bounced keeps that status regardless of what is sent. Use `status_if_new` to control only what a brand-new contact is created as.

Body

email string Required
first_name string
last_name string
metadata object
Arbitrary key/value data, addressable as merge tags.
status_if_new string
Status for a contact that does not already exist. Has no effect on an existing contact.
active pending
tag_ids array of integer
list_ids array of integer
consent_source string
Where consent was captured. Recorded for compliance evidence.
consent_ip string

Response

data object
data.id integer
data.email string
data.first_name string or null
data.last_name string or null
data.status string
active pending unsubscribed bounced
data.metadata object
data.subscribed_at string or null
data.unsubscribed_at string or null
data.confirmed_at string or null
data.consent_source string or null
data.soft_bounce_count integer
data.created_at string or null
data.updated_at string or null

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X POST http://tweak.email/api/v1/contacts \
  -H "Authorization: Bearer $TWEAK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"email":"jane@example.com","first_name":"Jane","last_name":"Okonkwo","metadata":{"company":"Acme","plan":"pro"},"status_if_new":"active","tag_ids":[3,8],"list_ids":[1],"consent_source":"signup_form","consent_ip":"203.0.113.24"}'

Request body

{
    "email": "jane@example.com",
    "first_name": "Jane",
    "last_name": "Okonkwo",
    "metadata": {
        "company": "Acme",
        "plan": "pro"
    },
    "status_if_new": "active",
    "tag_ids": [
        3,
        8
    ],
    "list_ids": [
        1
    ],
    "consent_source": "signup_form",
    "consent_ip": "203.0.113.24"
}

Response 200

{
    "data": {
        "id": 42,
        "email": "jane@example.com",
        "first_name": "Jane",
        "last_name": "Okonkwo",
        "status": "active",
        "metadata": {
            "company": "Acme",
            "city": "Copenhagen"
        },
        "subscribed_at": "2026-08-01T09:15:00+00:00",
        "unsubscribed_at": null,
        "confirmed_at": null,
        "consent_source": "signup_form",
        "soft_bounce_count": 0,
        "created_at": "2026-08-01T09:15:00+00:00",
        "updated_at": "2026-08-09T14:02:00+00:00"
    }
}
POST /contacts/bulk

Requires scope contacts:write

Up to 1,000 per call. Returns a per-row result so a partial success is legible.

Body

contacts array of object Required
contacts.email string Required
contacts.first_name string
contacts.last_name string
contacts.metadata object
Arbitrary key/value data, addressable as merge tags.
contacts.status_if_new string
Status for a contact that does not already exist. Has no effect on an existing contact.
active pending
contacts.tag_ids array of integer
contacts.list_ids array of integer
contacts.consent_source string
Where consent was captured. Recorded for compliance evidence.
contacts.consent_ip string
tag_ids array of integer
Applied to every contact in the batch.
list_ids array of integer
Applied to every contact in the batch.

Response

data array of object
data.email string
data.id integer
data.created boolean
data.status string
created integer
updated integer

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X POST http://tweak.email/api/v1/contacts/bulk \
  -H "Authorization: Bearer $TWEAK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"contacts":[{"email":"jane@example.com","first_name":"Jane","last_name":"Okonkwo","metadata":{"company":"Acme","plan":"pro"},"status_if_new":"active","tag_ids":[3,8],"list_ids":[1],"consent_source":"signup_form","consent_ip":"203.0.113.24"}],"tag_ids":[1],"list_ids":[1]}'

Request body

{
    "contacts": [
        {
            "email": "jane@example.com",
            "first_name": "Jane",
            "last_name": "Okonkwo",
            "metadata": {
                "company": "Acme",
                "plan": "pro"
            },
            "status_if_new": "active",
            "tag_ids": [
                3,
                8
            ],
            "list_ids": [
                1
            ],
            "consent_source": "signup_form",
            "consent_ip": "203.0.113.24"
        }
    ],
    "tag_ids": [
        1
    ],
    "list_ids": [
        1
    ]
}

Response 200

{
    "data": [
        {
            "email": "string",
            "id": 1,
            "created": true,
            "status": "string"
        }
    ],
    "created": 1,
    "updated": 1
}
GET /contacts/{contact}

Requires scope contacts:read

Accepts either a numeric id or an email address.

Path parameters

contact string Required
Contact id, or the contact's email address.

Response

data object
data.id integer
data.email string
data.first_name string or null
data.last_name string or null
data.status string
active pending unsubscribed bounced
data.metadata object
data.subscribed_at string or null
data.unsubscribed_at string or null
data.confirmed_at string or null
data.consent_source string or null
data.soft_bounce_count integer
data.created_at string or null
data.updated_at string or null

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl http://tweak.email/api/v1/contacts/:contact \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": {
        "id": 42,
        "email": "jane@example.com",
        "first_name": "Jane",
        "last_name": "Okonkwo",
        "status": "active",
        "metadata": {
            "company": "Acme",
            "city": "Copenhagen"
        },
        "subscribed_at": "2026-08-01T09:15:00+00:00",
        "unsubscribed_at": null,
        "confirmed_at": null,
        "consent_source": "signup_form",
        "soft_bounce_count": 0,
        "created_at": "2026-08-01T09:15:00+00:00",
        "updated_at": "2026-08-09T14:02:00+00:00"
    }
}
PATCH /contacts/{contact}

Requires scope contacts:write

Setting `status` to `unsubscribed` also creates a suppression; setting it back to `active` lifts only the unsubscribe suppression, never a bounce or complaint.

Path parameters

contact string Required
Contact id, or the contact's email address.

Body

first_name string or null
last_name string or null
metadata object
status string
active pending unsubscribed
tag_ids array of integer
Replaces the contact's tags.
list_ids array of integer
Replaces the contact's list memberships.

Response

data object
data.id integer
data.email string
data.first_name string or null
data.last_name string or null
data.status string
active pending unsubscribed bounced
data.metadata object
data.subscribed_at string or null
data.unsubscribed_at string or null
data.confirmed_at string or null
data.consent_source string or null
data.soft_bounce_count integer
data.created_at string or null
data.updated_at string or null

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X PATCH http://tweak.email/api/v1/contacts/:contact \
  -H "Authorization: Bearer $TWEAK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"first_name":"string","last_name":"string","metadata":{},"status":"active","tag_ids":[1],"list_ids":[1]}'

Request body

{
    "first_name": "string",
    "last_name": "string",
    "metadata": {},
    "status": "active",
    "tag_ids": [
        1
    ],
    "list_ids": [
        1
    ]
}

Response 200

{
    "data": {
        "id": 42,
        "email": "jane@example.com",
        "first_name": "Jane",
        "last_name": "Okonkwo",
        "status": "active",
        "metadata": {
            "company": "Acme",
            "city": "Copenhagen"
        },
        "subscribed_at": "2026-08-01T09:15:00+00:00",
        "unsubscribed_at": null,
        "confirmed_at": null,
        "consent_source": "signup_form",
        "soft_bounce_count": 0,
        "created_at": "2026-08-01T09:15:00+00:00",
        "updated_at": "2026-08-09T14:02:00+00:00"
    }
}
DELETE /contacts/{contact}

Requires scope contacts:write

Soft delete. For GDPR erasure use the erase endpoint instead.

Path parameters

contact string Required
Contact id, or the contact's email address.

Response

data object
data.id integer
data.deleted boolean

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X DELETE http://tweak.email/api/v1/contacts/:contact \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": {
        "id": 42,
        "deleted": true
    }
}
POST /contacts/{contact}/tags

Requires scope contacts:write

Adding a tag fires any tag-triggered sequence enrolment, exactly as it does in the app.

Path parameters

contact string Required
Contact id or email address.

Body

tag_ids array of integer Required

Response

data object
data.id integer
data.email string
data.first_name string or null
data.last_name string or null
data.status string
active pending unsubscribed bounced
data.metadata object
data.subscribed_at string or null
data.unsubscribed_at string or null
data.confirmed_at string or null
data.consent_source string or null
data.soft_bounce_count integer
data.created_at string or null
data.updated_at string or null

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X POST http://tweak.email/api/v1/contacts/:contact/tags \
  -H "Authorization: Bearer $TWEAK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"tag_ids":[1]}'

Request body

{
    "tag_ids": [
        1
    ]
}

Response 200

{
    "data": {
        "id": 42,
        "email": "jane@example.com",
        "first_name": "Jane",
        "last_name": "Okonkwo",
        "status": "active",
        "metadata": {
            "company": "Acme",
            "city": "Copenhagen"
        },
        "subscribed_at": "2026-08-01T09:15:00+00:00",
        "unsubscribed_at": null,
        "confirmed_at": null,
        "consent_source": "signup_form",
        "soft_bounce_count": 0,
        "created_at": "2026-08-01T09:15:00+00:00",
        "updated_at": "2026-08-09T14:02:00+00:00"
    }
}
DELETE /contacts/{contact}/tags/{tag}

Requires scope contacts:write

Path parameters

contact string Required
Contact id or email address.
tag integer Required
Tag id.

Response

data object
data.id integer
data.email string
data.first_name string or null
data.last_name string or null
data.status string
active pending unsubscribed bounced
data.metadata object
data.subscribed_at string or null
data.unsubscribed_at string or null
data.confirmed_at string or null
data.consent_source string or null
data.soft_bounce_count integer
data.created_at string or null
data.updated_at string or null

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X DELETE http://tweak.email/api/v1/contacts/:contact/tags/:tag \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": {
        "id": 42,
        "email": "jane@example.com",
        "first_name": "Jane",
        "last_name": "Okonkwo",
        "status": "active",
        "metadata": {
            "company": "Acme",
            "city": "Copenhagen"
        },
        "subscribed_at": "2026-08-01T09:15:00+00:00",
        "unsubscribed_at": null,
        "confirmed_at": null,
        "consent_source": "signup_form",
        "soft_bounce_count": 0,
        "created_at": "2026-08-01T09:15:00+00:00",
        "updated_at": "2026-08-09T14:02:00+00:00"
    }
}
POST /contacts/{contact}/erase

Requires scope contacts:write

Permanently removes the contact and anonymises their delivery events. The suppression record is deliberately retained so an erased opt-out is never lost.

Path parameters

contact string Required
Contact id or email address.

Response

data object
data.contacts_deleted integer
data.events_anonymized integer

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X POST http://tweak.email/api/v1/contacts/:contact/erase \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": {
        "contacts_deleted": 1,
        "events_anonymized": 1
    }
}
GET /lists

Requires scope contacts:read

Query parameters

per_page integer default 25
Records per page (1–100, default 25).
cursor string
The `next_cursor` value from a previous response.

Response

data array of object
data.id integer
data.name string
data.description string or null
data.is_default boolean
data.opt_in_mode string
single double
data.contacts_count integer
per_page integer
next_cursor string or null
prev_cursor string or null
next_page_url string or null
prev_page_url string or null
has_more boolean

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl http://tweak.email/api/v1/lists \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": [
        {
            "id": 1,
            "name": "string",
            "description": "string",
            "is_default": true,
            "opt_in_mode": "single",
            "contacts_count": 1
        }
    ],
    "per_page": 1,
    "next_cursor": "string",
    "prev_cursor": "string",
    "next_page_url": "string",
    "prev_page_url": "string",
    "has_more": true
}
POST /lists

Requires scope contacts:write

Body

name string Required
description string
opt_in_mode string
Double opt-in creates new contacts as `pending` until they confirm.
single double

Response

data object
data.id integer
data.name string
data.description string or null
data.is_default boolean
data.opt_in_mode string
single double
data.contacts_count integer

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X POST http://tweak.email/api/v1/lists \
  -H "Authorization: Bearer $TWEAK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"string","description":"string","opt_in_mode":"single"}'

Request body

{
    "name": "string",
    "description": "string",
    "opt_in_mode": "single"
}

Response 200

{
    "data": {
        "id": 1,
        "name": "string",
        "description": "string",
        "is_default": true,
        "opt_in_mode": "single",
        "contacts_count": 1
    }
}
GET /lists/{list}

Requires scope contacts:read

Path parameters

list integer Required
List id.

Response

data object
data.id integer
data.name string
data.description string or null
data.is_default boolean
data.opt_in_mode string
single double
data.contacts_count integer

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl http://tweak.email/api/v1/lists/:list \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": {
        "id": 1,
        "name": "string",
        "description": "string",
        "is_default": true,
        "opt_in_mode": "single",
        "contacts_count": 1
    }
}
PATCH /lists/{list}

Requires scope contacts:write

Path parameters

list integer Required
List id.

Body

name string Required
description string
opt_in_mode string
Double opt-in creates new contacts as `pending` until they confirm.
single double

Response

data object
data.id integer
data.name string
data.description string or null
data.is_default boolean
data.opt_in_mode string
single double
data.contacts_count integer

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X PATCH http://tweak.email/api/v1/lists/:list \
  -H "Authorization: Bearer $TWEAK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"string","description":"string","opt_in_mode":"single"}'

Request body

{
    "name": "string",
    "description": "string",
    "opt_in_mode": "single"
}

Response 200

{
    "data": {
        "id": 1,
        "name": "string",
        "description": "string",
        "is_default": true,
        "opt_in_mode": "single",
        "contacts_count": 1
    }
}
DELETE /lists/{list}

Requires scope contacts:write

The default list cannot be deleted.

Path parameters

list integer Required
List id.

Response

data object
data.id integer
data.deleted boolean

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X DELETE http://tweak.email/api/v1/lists/:list \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": {
        "id": 42,
        "deleted": true
    }
}
GET /lists/{list}/contacts

Requires scope contacts:read

Path parameters

list integer Required
List id.

Query parameters

per_page integer default 25
Records per page (1–100, default 25).
cursor string
The `next_cursor` value from a previous response.

Response

data array of object
data.id integer
data.email string
data.first_name string or null
data.last_name string or null
data.status string
active pending unsubscribed bounced
data.metadata object
data.subscribed_at string or null
data.unsubscribed_at string or null
data.confirmed_at string or null
data.consent_source string or null
data.soft_bounce_count integer
data.created_at string or null
data.updated_at string or null
per_page integer
next_cursor string or null
prev_cursor string or null
next_page_url string or null
prev_page_url string or null
has_more boolean

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl http://tweak.email/api/v1/lists/:list/contacts \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": [
        {
            "id": 42,
            "email": "jane@example.com",
            "first_name": "Jane",
            "last_name": "Okonkwo",
            "status": "active",
            "metadata": {
                "company": "Acme",
                "city": "Copenhagen"
            },
            "subscribed_at": "2026-08-01T09:15:00+00:00",
            "unsubscribed_at": null,
            "confirmed_at": null,
            "consent_source": "signup_form",
            "soft_bounce_count": 0,
            "created_at": "2026-08-01T09:15:00+00:00",
            "updated_at": "2026-08-09T14:02:00+00:00"
        }
    ],
    "per_page": 1,
    "next_cursor": "string",
    "prev_cursor": "string",
    "next_page_url": "string",
    "prev_page_url": "string",
    "has_more": true
}
POST /lists/{list}/contacts

Requires scope contacts:write

Ids belonging to another team are silently skipped and reported in the `skipped` count.

Path parameters

list integer Required
List id.

Body

contact_ids array of integer Required

Response

data object
data.list_id integer
data.attached integer
data.skipped integer
Ids that did not resolve to a contact on your team.

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X POST http://tweak.email/api/v1/lists/:list/contacts \
  -H "Authorization: Bearer $TWEAK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"contact_ids":[1]}'

Request body

{
    "contact_ids": [
        1
    ]
}

Response 200

{
    "data": {
        "list_id": 1,
        "attached": 1,
        "skipped": 1
    }
}
DELETE /lists/{list}/contacts/{contact}

Requires scope contacts:write

Detaches the membership only. The contact itself is untouched.

Path parameters

list integer Required
List id.
contact integer Required
Contact id.

Response

data object
data.list_id integer
data.contact_id integer
data.detached boolean

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X DELETE http://tweak.email/api/v1/lists/:list/contacts/:contact \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": {
        "list_id": 7,
        "contact_id": 42,
        "detached": true
    }
}
GET /tags

Requires scope contacts:read

Query parameters

per_page integer default 25
Records per page (1–100, default 25).
cursor string
The `next_cursor` value from a previous response.

Response

data array of object
data.id integer
data.name string
data.slug string
data.color string or null
data.contacts_count integer
per_page integer
next_cursor string or null
prev_cursor string or null
next_page_url string or null
prev_page_url string or null
has_more boolean

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl http://tweak.email/api/v1/tags \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": [
        {
            "id": 1,
            "name": "string",
            "slug": "string",
            "color": "string",
            "contacts_count": 1
        }
    ],
    "per_page": 1,
    "next_cursor": "string",
    "prev_cursor": "string",
    "next_page_url": "string",
    "prev_page_url": "string",
    "has_more": true
}
POST /tags

Requires scope contacts:write

Body

name string Required
color string

Response

data object
data.id integer
data.name string
data.slug string
data.color string or null
data.contacts_count integer

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X POST http://tweak.email/api/v1/tags \
  -H "Authorization: Bearer $TWEAK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"string","color":"string"}'

Request body

{
    "name": "string",
    "color": "string"
}

Response 200

{
    "data": {
        "id": 1,
        "name": "string",
        "slug": "string",
        "color": "string",
        "contacts_count": 1
    }
}
GET /tags/{tag}

Requires scope contacts:read

Path parameters

tag integer Required
Tag id.

Response

data object
data.id integer
data.name string
data.slug string
data.color string or null
data.contacts_count integer

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl http://tweak.email/api/v1/tags/:tag \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": {
        "id": 1,
        "name": "string",
        "slug": "string",
        "color": "string",
        "contacts_count": 1
    }
}
PATCH /tags/{tag}

Requires scope contacts:write

Path parameters

tag integer Required
Tag id.

Body

name string Required
color string

Response

data object
data.id integer
data.name string
data.slug string
data.color string or null
data.contacts_count integer

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X PATCH http://tweak.email/api/v1/tags/:tag \
  -H "Authorization: Bearer $TWEAK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"string","color":"string"}'

Request body

{
    "name": "string",
    "color": "string"
}

Response 200

{
    "data": {
        "id": 1,
        "name": "string",
        "slug": "string",
        "color": "string",
        "contacts_count": 1
    }
}
DELETE /tags/{tag}

Requires scope contacts:write

Path parameters

tag integer Required
Tag id.

Response

data object
data.id integer
data.deleted boolean

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X DELETE http://tweak.email/api/v1/tags/:tag \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": {
        "id": 42,
        "deleted": true
    }
}
GET /segments

Requires scope contacts:read

Query parameters

per_page integer default 25
Records per page (1–100, default 25).
cursor string
The `next_cursor` value from a previous response.

Response

data array of object
data.id integer
data.name string
data.definition object
per_page integer
next_cursor string or null
prev_cursor string or null
next_page_url string or null
prev_page_url string or null
has_more boolean

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl http://tweak.email/api/v1/segments \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": [
        {
            "id": 1,
            "name": "string",
            "definition": {
                "tag_ids": [
                    1
                ],
                "date_from": "2026-08-09",
                "date_to": "2026-08-09",
                "search": "string",
                "company": "string",
                "location": "string",
                "engagement": {
                    "type": "opened",
                    "days": 1
                }
            }
        }
    ],
    "per_page": 1,
    "next_cursor": "string",
    "prev_cursor": "string",
    "next_page_url": "string",
    "prev_page_url": "string",
    "has_more": true
}
POST /segments

Requires scope contacts:write

Body

name string Required
definition object
definition.tag_ids array of integer
definition.date_from string or null
definition.date_to string or null
definition.search string or null
Matches email, first name, or last name.
definition.company string or null
Matches the contact metadata `company` field.
definition.location string or null
Matches metadata city, country, or location.
definition.engagement object or null
Restrict to contacts by email engagement over a trailing window. Machine opens (Apple MPP and bot prefetches) are excluded. Note that only the SendGrid integration flags them, so on other providers positive open conditions may still be over-inclusive.

Response

data object
data.id integer
data.name string
data.definition object

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X POST http://tweak.email/api/v1/segments \
  -H "Authorization: Bearer $TWEAK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"string","definition":{"tag_ids":[1],"date_from":"2026-08-09","date_to":"2026-08-09","search":"string","company":"string","location":"string","engagement":{"type":"opened","days":1}}}'

Request body

{
    "name": "string",
    "definition": {
        "tag_ids": [
            1
        ],
        "date_from": "2026-08-09",
        "date_to": "2026-08-09",
        "search": "string",
        "company": "string",
        "location": "string",
        "engagement": {
            "type": "opened",
            "days": 1
        }
    }
}

Response 200

{
    "data": {
        "id": 1,
        "name": "string",
        "definition": {
            "tag_ids": [
                1
            ],
            "date_from": "2026-08-09",
            "date_to": "2026-08-09",
            "search": "string",
            "company": "string",
            "location": "string",
            "engagement": {
                "type": "opened",
                "days": 1
            }
        }
    }
}
POST /segments/preview

Requires scope contacts:read

Read-only. Returns the resolved contact count plus a 10-record sample, so a definition can be iterated on before it is committed.

Body

definition object
definition.tag_ids array of integer
definition.date_from string or null
definition.date_to string or null
definition.search string or null
Matches email, first name, or last name.
definition.company string or null
Matches the contact metadata `company` field.
definition.location string or null
Matches metadata city, country, or location.
definition.engagement object or null
Restrict to contacts by email engagement over a trailing window. Machine opens (Apple MPP and bot prefetches) are excluded. Note that only the SendGrid integration flags them, so on other providers positive open conditions may still be over-inclusive.

Response

data object
data.count integer
Active contacts the definition resolves to.
data.filters object
data.sample array of object

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X POST http://tweak.email/api/v1/segments/preview \
  -H "Authorization: Bearer $TWEAK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"definition":{"tag_ids":[1],"date_from":"2026-08-09","date_to":"2026-08-09","search":"string","company":"string","location":"string","engagement":{"type":"opened","days":1}}}'

Request body

{
    "definition": {
        "tag_ids": [
            1
        ],
        "date_from": "2026-08-09",
        "date_to": "2026-08-09",
        "search": "string",
        "company": "string",
        "location": "string",
        "engagement": {
            "type": "opened",
            "days": 1
        }
    }
}

Response 200

{
    "data": {
        "count": 1,
        "filters": {
            "tag_ids": [
                1
            ],
            "date_from": "2026-08-09",
            "date_to": "2026-08-09",
            "search": "string",
            "company": "string",
            "location": "string",
            "engagement": {
                "type": "opened",
                "days": 1
            }
        },
        "sample": [
            {
                "id": 42,
                "email": "jane@example.com",
                "first_name": "Jane",
                "last_name": "Okonkwo",
                "status": "active",
                "metadata": {
                    "company": "Acme",
                    "city": "Copenhagen"
                },
                "subscribed_at": "2026-08-01T09:15:00+00:00",
                "unsubscribed_at": null,
                "confirmed_at": null,
                "consent_source": "signup_form",
                "soft_bounce_count": 0,
                "created_at": "2026-08-01T09:15:00+00:00",
                "updated_at": "2026-08-09T14:02:00+00:00"
            }
        ]
    }
}
GET /segments/{segment}

Requires scope contacts:read

Path parameters

segment integer Required
Segment id.

Response

data object
data.id integer
data.name string
data.definition object

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl http://tweak.email/api/v1/segments/:segment \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": {
        "id": 1,
        "name": "string",
        "definition": {
            "tag_ids": [
                1
            ],
            "date_from": "2026-08-09",
            "date_to": "2026-08-09",
            "search": "string",
            "company": "string",
            "location": "string",
            "engagement": {
                "type": "opened",
                "days": 1
            }
        }
    }
}
PATCH /segments/{segment}

Requires scope contacts:write

Path parameters

segment integer Required
Segment id.

Body

name string Required
definition object
definition.tag_ids array of integer
definition.date_from string or null
definition.date_to string or null
definition.search string or null
Matches email, first name, or last name.
definition.company string or null
Matches the contact metadata `company` field.
definition.location string or null
Matches metadata city, country, or location.
definition.engagement object or null
Restrict to contacts by email engagement over a trailing window. Machine opens (Apple MPP and bot prefetches) are excluded. Note that only the SendGrid integration flags them, so on other providers positive open conditions may still be over-inclusive.

Response

data object
data.id integer
data.name string
data.definition object

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X PATCH http://tweak.email/api/v1/segments/:segment \
  -H "Authorization: Bearer $TWEAK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"string","definition":{"tag_ids":[1],"date_from":"2026-08-09","date_to":"2026-08-09","search":"string","company":"string","location":"string","engagement":{"type":"opened","days":1}}}'

Request body

{
    "name": "string",
    "definition": {
        "tag_ids": [
            1
        ],
        "date_from": "2026-08-09",
        "date_to": "2026-08-09",
        "search": "string",
        "company": "string",
        "location": "string",
        "engagement": {
            "type": "opened",
            "days": 1
        }
    }
}

Response 200

{
    "data": {
        "id": 1,
        "name": "string",
        "definition": {
            "tag_ids": [
                1
            ],
            "date_from": "2026-08-09",
            "date_to": "2026-08-09",
            "search": "string",
            "company": "string",
            "location": "string",
            "engagement": {
                "type": "opened",
                "days": 1
            }
        }
    }
}
DELETE /segments/{segment}

Requires scope contacts:write

Path parameters

segment integer Required
Segment id.

Response

data object
data.id integer
data.deleted boolean

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X DELETE http://tweak.email/api/v1/segments/:segment \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": {
        "id": 42,
        "deleted": true
    }
}
POST /segments/{segment}/preview

Requires scope contacts:read

Read-only: resolved count plus a sample.

Path parameters

segment integer Required
Segment id.

Response

data object
data.count integer
Active contacts the definition resolves to.
data.filters object
data.sample array of object

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X POST http://tweak.email/api/v1/segments/:segment/preview \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": {
        "count": 1,
        "filters": {
            "tag_ids": [
                1
            ],
            "date_from": "2026-08-09",
            "date_to": "2026-08-09",
            "search": "string",
            "company": "string",
            "location": "string",
            "engagement": {
                "type": "opened",
                "days": 1
            }
        },
        "sample": [
            {
                "id": 42,
                "email": "jane@example.com",
                "first_name": "Jane",
                "last_name": "Okonkwo",
                "status": "active",
                "metadata": {
                    "company": "Acme",
                    "city": "Copenhagen"
                },
                "subscribed_at": "2026-08-01T09:15:00+00:00",
                "unsubscribed_at": null,
                "confirmed_at": null,
                "consent_source": "signup_form",
                "soft_bounce_count": 0,
                "created_at": "2026-08-01T09:15:00+00:00",
                "updated_at": "2026-08-09T14:02:00+00:00"
            }
        ]
    }
}

Campaigns

Campaign authoring and sending

GET /campaigns

Requires scope campaigns:read

Query parameters

per_page integer default 25
Records per page (1–100, default 25).
cursor string
The `next_cursor` value from a previous response.
status string
Filter by campaign status.

Response

data array of object
data.id integer
data.name string
data.subject string or null
data.preheader string or null
data.from_name string or null
data.from_email string or null
data.reply_to string or null
data.status string
draft scheduled screening held queuing sending paused sent partial cancelled failed
data.audience object
data.template_id integer or null
data.ab_test object
data.total_recipients integer
data.sent_count integer
data.failed_count integer
data.failure_reason string or null
data.scheduled_at string or null
data.sent_at string or null
per_page integer
next_cursor string or null
prev_cursor string or null
next_page_url string or null
prev_page_url string or null
has_more boolean

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl http://tweak.email/api/v1/campaigns \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": [
        {
            "id": 118,
            "name": "August product update",
            "subject": "What's new this month",
            "preheader": "Three things we shipped",
            "from_name": "Jane at Acme",
            "from_email": "hello@acme.com",
            "reply_to": "support@acme.com",
            "status": "sent",
            "audience": {
                "source": "list",
                "contact_list_id": 1,
                "filters": null
            },
            "template_id": 12,
            "ab_test": {
                "enabled": false,
                "percentage": null,
                "winner_metric": null,
                "delay_minutes": null,
                "winner_variant_id": null
            },
            "total_recipients": 12480,
            "sent_count": 12463,
            "failed_count": 17,
            "failure_reason": null,
            "scheduled_at": null,
            "sent_at": "2026-08-09T10:00:00+00:00"
        }
    ],
    "per_page": 1,
    "next_cursor": "string",
    "prev_cursor": "string",
    "next_page_url": "string",
    "prev_page_url": "string",
    "has_more": true
}
POST /campaigns

Requires scope campaigns:write

Created as a draft. Set the body separately via the content endpoint.

Body

name string Required
subject string
preheader string
from_name string
from_email string
Must sit on a fully verified sending domain, or the send is refused.
reply_to string
audience_source string
list bigquery
contact_list_id integer or null
segment_id integer or null
Copies the segment's filter definition onto the campaign.
audience_filters object
audience_filters.tag_ids array of integer
audience_filters.date_from string or null
audience_filters.date_to string or null
audience_filters.search string or null
Matches email, first name, or last name.
audience_filters.company string or null
Matches the contact metadata `company` field.
audience_filters.location string or null
Matches metadata city, country, or location.
audience_filters.engagement object or null
Restrict to contacts by email engagement over a trailing window. Machine opens (Apple MPP and bot prefetches) are excluded. Note that only the SendGrid integration flags them, so on other providers positive open conditions may still be over-inclusive.
template_id integer or null
ab_test_enabled boolean
ab_test_percentage integer
ab_winner_metric string
opens clicks
ab_test_delay_minutes integer

Response

data object
data.id integer
data.name string
data.subject string or null
data.preheader string or null
data.from_name string or null
data.from_email string or null
data.reply_to string or null
data.status string
draft scheduled screening held queuing sending paused sent partial cancelled failed
data.audience object
data.template_id integer or null
data.ab_test object
data.total_recipients integer
data.sent_count integer
data.failed_count integer
data.failure_reason string or null
data.scheduled_at string or null
data.sent_at string or null

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X POST http://tweak.email/api/v1/campaigns \
  -H "Authorization: Bearer $TWEAK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"string","subject":"string","preheader":"string","from_name":"string","from_email":"jane@example.com","reply_to":"jane@example.com","audience_source":"list","contact_list_id":1,"segment_id":1,"audience_filters":{"tag_ids":[1],"date_from":"2026-08-09","date_to":"2026-08-09","search":"string","company":"string","location":"string","engagement":{"type":"opened","days":1}},"template_id":1,"ab_test_enabled":true,"ab_test_percentage":1,"ab_winner_metric":"opens","ab_test_delay_minutes":1}'

Request body

{
    "name": "string",
    "subject": "string",
    "preheader": "string",
    "from_name": "string",
    "from_email": "jane@example.com",
    "reply_to": "jane@example.com",
    "audience_source": "list",
    "contact_list_id": 1,
    "segment_id": 1,
    "audience_filters": {
        "tag_ids": [
            1
        ],
        "date_from": "2026-08-09",
        "date_to": "2026-08-09",
        "search": "string",
        "company": "string",
        "location": "string",
        "engagement": {
            "type": "opened",
            "days": 1
        }
    },
    "template_id": 1,
    "ab_test_enabled": true,
    "ab_test_percentage": 1,
    "ab_winner_metric": "opens",
    "ab_test_delay_minutes": 1
}

Response 200

{
    "data": {
        "id": 118,
        "name": "August product update",
        "subject": "What's new this month",
        "preheader": "Three things we shipped",
        "from_name": "Jane at Acme",
        "from_email": "hello@acme.com",
        "reply_to": "support@acme.com",
        "status": "sent",
        "audience": {
            "source": "list",
            "contact_list_id": 1,
            "filters": null
        },
        "template_id": 12,
        "ab_test": {
            "enabled": false,
            "percentage": null,
            "winner_metric": null,
            "delay_minutes": null,
            "winner_variant_id": null
        },
        "total_recipients": 12480,
        "sent_count": 12463,
        "failed_count": 17,
        "failure_reason": null,
        "scheduled_at": null,
        "sent_at": "2026-08-09T10:00:00+00:00"
    }
}
GET /campaigns/{campaign}

Requires scope campaigns:read

Path parameters

campaign integer Required
Campaign id.

Response

data object
data.id integer
data.name string
data.subject string or null
data.preheader string or null
data.from_name string or null
data.from_email string or null
data.reply_to string or null
data.status string
draft scheduled screening held queuing sending paused sent partial cancelled failed
data.audience object
data.template_id integer or null
data.ab_test object
data.total_recipients integer
data.sent_count integer
data.failed_count integer
data.failure_reason string or null
data.scheduled_at string or null
data.sent_at string or null

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl http://tweak.email/api/v1/campaigns/:campaign \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": {
        "id": 118,
        "name": "August product update",
        "subject": "What's new this month",
        "preheader": "Three things we shipped",
        "from_name": "Jane at Acme",
        "from_email": "hello@acme.com",
        "reply_to": "support@acme.com",
        "status": "sent",
        "audience": {
            "source": "list",
            "contact_list_id": 1,
            "filters": null
        },
        "template_id": 12,
        "ab_test": {
            "enabled": false,
            "percentage": null,
            "winner_metric": null,
            "delay_minutes": null,
            "winner_variant_id": null
        },
        "total_recipients": 12480,
        "sent_count": 12463,
        "failed_count": 17,
        "failure_reason": null,
        "scheduled_at": null,
        "sent_at": "2026-08-09T10:00:00+00:00"
    }
}
PATCH /campaigns/{campaign}

Requires scope campaigns:write

Refused with 422 once the campaign is screening, sending, or sent.

Path parameters

campaign integer Required
Campaign id.

Body

name string Required
subject string
preheader string
from_name string
from_email string
Must sit on a fully verified sending domain, or the send is refused.
reply_to string
audience_source string
list bigquery
contact_list_id integer or null
segment_id integer or null
Copies the segment's filter definition onto the campaign.
audience_filters object
audience_filters.tag_ids array of integer
audience_filters.date_from string or null
audience_filters.date_to string or null
audience_filters.search string or null
Matches email, first name, or last name.
audience_filters.company string or null
Matches the contact metadata `company` field.
audience_filters.location string or null
Matches metadata city, country, or location.
audience_filters.engagement object or null
Restrict to contacts by email engagement over a trailing window. Machine opens (Apple MPP and bot prefetches) are excluded. Note that only the SendGrid integration flags them, so on other providers positive open conditions may still be over-inclusive.
template_id integer or null
ab_test_enabled boolean
ab_test_percentage integer
ab_winner_metric string
opens clicks
ab_test_delay_minutes integer

Response

data object
data.id integer
data.name string
data.subject string or null
data.preheader string or null
data.from_name string or null
data.from_email string or null
data.reply_to string or null
data.status string
draft scheduled screening held queuing sending paused sent partial cancelled failed
data.audience object
data.template_id integer or null
data.ab_test object
data.total_recipients integer
data.sent_count integer
data.failed_count integer
data.failure_reason string or null
data.scheduled_at string or null
data.sent_at string or null

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X PATCH http://tweak.email/api/v1/campaigns/:campaign \
  -H "Authorization: Bearer $TWEAK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"string","subject":"string","preheader":"string","from_name":"string","from_email":"jane@example.com","reply_to":"jane@example.com","audience_source":"list","contact_list_id":1,"segment_id":1,"audience_filters":{"tag_ids":[1],"date_from":"2026-08-09","date_to":"2026-08-09","search":"string","company":"string","location":"string","engagement":{"type":"opened","days":1}},"template_id":1,"ab_test_enabled":true,"ab_test_percentage":1,"ab_winner_metric":"opens","ab_test_delay_minutes":1}'

Request body

{
    "name": "string",
    "subject": "string",
    "preheader": "string",
    "from_name": "string",
    "from_email": "jane@example.com",
    "reply_to": "jane@example.com",
    "audience_source": "list",
    "contact_list_id": 1,
    "segment_id": 1,
    "audience_filters": {
        "tag_ids": [
            1
        ],
        "date_from": "2026-08-09",
        "date_to": "2026-08-09",
        "search": "string",
        "company": "string",
        "location": "string",
        "engagement": {
            "type": "opened",
            "days": 1
        }
    },
    "template_id": 1,
    "ab_test_enabled": true,
    "ab_test_percentage": 1,
    "ab_winner_metric": "opens",
    "ab_test_delay_minutes": 1
}

Response 200

{
    "data": {
        "id": 118,
        "name": "August product update",
        "subject": "What's new this month",
        "preheader": "Three things we shipped",
        "from_name": "Jane at Acme",
        "from_email": "hello@acme.com",
        "reply_to": "support@acme.com",
        "status": "sent",
        "audience": {
            "source": "list",
            "contact_list_id": 1,
            "filters": null
        },
        "template_id": 12,
        "ab_test": {
            "enabled": false,
            "percentage": null,
            "winner_metric": null,
            "delay_minutes": null,
            "winner_variant_id": null
        },
        "total_recipients": 12480,
        "sent_count": 12463,
        "failed_count": 17,
        "failure_reason": null,
        "scheduled_at": null,
        "sent_at": "2026-08-09T10:00:00+00:00"
    }
}
DELETE /campaigns/{campaign}

Requires scope campaigns:write

Path parameters

campaign integer Required
Campaign id.

Response

data object
data.id integer
data.deleted boolean

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X DELETE http://tweak.email/api/v1/campaigns/:campaign \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": {
        "id": 42,
        "deleted": true
    }
}
PUT /campaigns/{campaign}/content

Requires scope campaigns:write

Supplying `template_id` copies that template's body in, so a later edit to the template cannot change a campaign somebody already reviewed.

Path parameters

campaign integer Required
Campaign id.

Body

html_content string or null
plain_content string or null
blocks_json array or null
template_id integer or null

Response

data object
data.id integer
data.name string
data.subject string or null
data.preheader string or null
data.from_name string or null
data.from_email string or null
data.reply_to string or null
data.status string
draft scheduled screening held queuing sending paused sent partial cancelled failed
data.audience object
data.template_id integer or null
data.ab_test object
data.total_recipients integer
data.sent_count integer
data.failed_count integer
data.failure_reason string or null
data.scheduled_at string or null
data.sent_at string or null

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X PUT http://tweak.email/api/v1/campaigns/:campaign/content \
  -H "Authorization: Bearer $TWEAK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"html_content":"string","plain_content":"string","blocks_json":[{}],"template_id":1}'

Request body

{
    "html_content": "string",
    "plain_content": "string",
    "blocks_json": [
        {}
    ],
    "template_id": 1
}

Response 200

{
    "data": {
        "id": 118,
        "name": "August product update",
        "subject": "What's new this month",
        "preheader": "Three things we shipped",
        "from_name": "Jane at Acme",
        "from_email": "hello@acme.com",
        "reply_to": "support@acme.com",
        "status": "sent",
        "audience": {
            "source": "list",
            "contact_list_id": 1,
            "filters": null
        },
        "template_id": 12,
        "ab_test": {
            "enabled": false,
            "percentage": null,
            "winner_metric": null,
            "delay_minutes": null,
            "winner_variant_id": null
        },
        "total_recipients": 12480,
        "sent_count": 12463,
        "failed_count": 17,
        "failure_reason": null,
        "scheduled_at": null,
        "sent_at": "2026-08-09T10:00:00+00:00"
    }
}
POST /campaigns/{campaign}/variants

Requires scope campaigns:write

Variants are replaced wholesale, and A/B testing is switched on.

Path parameters

campaign integer Required
Campaign id.

Body

variants array of object Required
variants.label string Required
variants.subject string Required
variants.from_name string

Response

data array of object
data.id integer
data.label string
data.subject string
data.from_name string or null
data.is_winner boolean
data.sent integer
data.opened integer
data.clicked integer
data.open_rate number
data.click_rate number

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X POST http://tweak.email/api/v1/campaigns/:campaign/variants \
  -H "Authorization: Bearer $TWEAK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"variants":[{"label":"string","subject":"string","from_name":"string"}]}'

Request body

{
    "variants": [
        {
            "label": "string",
            "subject": "string",
            "from_name": "string"
        }
    ]
}

Response 200

{
    "data": [
        {
            "id": 1,
            "label": "string",
            "subject": "string",
            "from_name": "string",
            "is_winner": true,
            "sent": 1,
            "opened": 1,
            "clicked": 1,
            "open_rate": 1,
            "click_rate": 1
        }
    ]
}
POST /campaigns/{campaign}/preflight

Requires scope campaigns:read

Read-only. Returns every reason a send would currently be refused, plus the estimated recipient count.

Path parameters

campaign integer Required
Campaign id.

Response

data object
data.campaign_id integer
data.status string
data.launchable boolean
data.blockers array of string
data.estimated_recipients integer or null
Null for a BigQuery audience, which is resolved at send time.

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X POST http://tweak.email/api/v1/campaigns/:campaign/preflight \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": {
        "campaign_id": 1,
        "status": "string",
        "launchable": true,
        "blockers": [
            "string"
        ],
        "estimated_recipients": 1
    }
}
POST /campaigns/{campaign}/send

Requires scope campaigns:send

Hands the campaign to abuse screening, which releases it to the send pipeline. Returns 422 with a `blockers` array if any send gate fails.

Send an `Idempotency-Key` header: a retried send is the one mistake in this API that cannot be undone.

Path parameters

campaign integer Required
Campaign id.

Response

data object
data.id integer
data.name string
data.subject string or null
data.preheader string or null
data.from_name string or null
data.from_email string or null
data.reply_to string or null
data.status string
draft scheduled screening held queuing sending paused sent partial cancelled failed
data.audience object
data.template_id integer or null
data.ab_test object
data.total_recipients integer
data.sent_count integer
data.failed_count integer
data.failure_reason string or null
data.scheduled_at string or null
data.sent_at string or null

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X POST http://tweak.email/api/v1/campaigns/:campaign/send \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": {
        "id": 118,
        "name": "August product update",
        "subject": "What's new this month",
        "preheader": "Three things we shipped",
        "from_name": "Jane at Acme",
        "from_email": "hello@acme.com",
        "reply_to": "support@acme.com",
        "status": "sent",
        "audience": {
            "source": "list",
            "contact_list_id": 1,
            "filters": null
        },
        "template_id": 12,
        "ab_test": {
            "enabled": false,
            "percentage": null,
            "winner_metric": null,
            "delay_minutes": null,
            "winner_variant_id": null
        },
        "total_recipients": 12480,
        "sent_count": 12463,
        "failed_count": 17,
        "failure_reason": null,
        "scheduled_at": null,
        "sent_at": "2026-08-09T10:00:00+00:00"
    }
}
POST /campaigns/{campaign}/schedule

Requires scope campaigns:send

Runs the same gates as an immediate send.

Path parameters

campaign integer Required
Campaign id.

Body

send_at string Required
Must be in the future. Interpreted as UTC unless an offset is given.

Response

data object
data.id integer
data.name string
data.subject string or null
data.preheader string or null
data.from_name string or null
data.from_email string or null
data.reply_to string or null
data.status string
draft scheduled screening held queuing sending paused sent partial cancelled failed
data.audience object
data.template_id integer or null
data.ab_test object
data.total_recipients integer
data.sent_count integer
data.failed_count integer
data.failure_reason string or null
data.scheduled_at string or null
data.sent_at string or null

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X POST http://tweak.email/api/v1/campaigns/:campaign/schedule \
  -H "Authorization: Bearer $TWEAK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"send_at":"2026-08-09T10:00:00+00:00"}'

Request body

{
    "send_at": "2026-08-09T10:00:00+00:00"
}

Response 200

{
    "data": {
        "id": 118,
        "name": "August product update",
        "subject": "What's new this month",
        "preheader": "Three things we shipped",
        "from_name": "Jane at Acme",
        "from_email": "hello@acme.com",
        "reply_to": "support@acme.com",
        "status": "sent",
        "audience": {
            "source": "list",
            "contact_list_id": 1,
            "filters": null
        },
        "template_id": 12,
        "ab_test": {
            "enabled": false,
            "percentage": null,
            "winner_metric": null,
            "delay_minutes": null,
            "winner_variant_id": null
        },
        "total_recipients": 12480,
        "sent_count": 12463,
        "failed_count": 17,
        "failure_reason": null,
        "scheduled_at": null,
        "sent_at": "2026-08-09T10:00:00+00:00"
    }
}
POST /campaigns/{campaign}/cancel

Requires scope campaigns:send

Only a draft, scheduled, or paused campaign can be cancelled: once chunks are dispatched the messages are already gone.

Path parameters

campaign integer Required
Campaign id.

Response

data object
data.id integer
data.name string
data.subject string or null
data.preheader string or null
data.from_name string or null
data.from_email string or null
data.reply_to string or null
data.status string
draft scheduled screening held queuing sending paused sent partial cancelled failed
data.audience object
data.template_id integer or null
data.ab_test object
data.total_recipients integer
data.sent_count integer
data.failed_count integer
data.failure_reason string or null
data.scheduled_at string or null
data.sent_at string or null

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X POST http://tweak.email/api/v1/campaigns/:campaign/cancel \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": {
        "id": 118,
        "name": "August product update",
        "subject": "What's new this month",
        "preheader": "Three things we shipped",
        "from_name": "Jane at Acme",
        "from_email": "hello@acme.com",
        "reply_to": "support@acme.com",
        "status": "sent",
        "audience": {
            "source": "list",
            "contact_list_id": 1,
            "filters": null
        },
        "template_id": 12,
        "ab_test": {
            "enabled": false,
            "percentage": null,
            "winner_metric": null,
            "delay_minutes": null,
            "winner_variant_id": null
        },
        "total_recipients": 12480,
        "sent_count": 12463,
        "failed_count": 17,
        "failure_reason": null,
        "scheduled_at": null,
        "sent_at": "2026-08-09T10:00:00+00:00"
    }
}
POST /campaigns/{campaign}/test

Requires scope campaigns:send

Up to 5 addresses. Counts against the plan's email allowance, because these are real sends.

Path parameters

campaign integer Required
Campaign id.

Body

emails array of string Required

Response

data object
data.sent array of string
data.failed array of object

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X POST http://tweak.email/api/v1/campaigns/:campaign/test \
  -H "Authorization: Bearer $TWEAK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"emails":["jane@example.com"]}'

Request body

{
    "emails": [
        "jane@example.com"
    ]
}

Response 200

{
    "data": {
        "sent": [
            "string"
        ],
        "failed": [
            {}
        ]
    }
}

Reporting

Delivery events and campaign performance

GET /campaigns/{campaign}/report

Requires scope events:read

Opens exclude machine/bot opens (Apple MPP), so the rates reflect human engagement.

Path parameters

campaign integer Required
Campaign id.

Response

data object
data.campaign_id integer
data.name string
data.subject string or null
data.status string
data.sent_at string or null
data.metrics object

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl http://tweak.email/api/v1/campaigns/:campaign/report \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": {
        "campaign_id": 1,
        "name": "string",
        "subject": "string",
        "status": "string",
        "sent_at": "2026-08-09T10:00:00+00:00",
        "metrics": {
            "recipients": 12480,
            "sent": 12463,
            "delivered": 12301,
            "opened": 5238,
            "clicked": 1104,
            "bounced": 162,
            "unsubscribed": 38,
            "complained": 3,
            "delivery_rate": 98.7,
            "open_rate": 42.6,
            "click_rate": 9,
            "ctor": 21.1,
            "bounce_rate": 1.3,
            "unsubscribe_rate": 0.3,
            "complaint_rate": 0.02
        }
    }
}
GET /campaigns/{campaign}/report/variants

Requires scope events:read

Path parameters

campaign integer Required
Campaign id.

Response

data array of object
data.id integer
data.label string
data.subject string
data.from_name string or null
data.is_winner boolean
data.sent integer
data.opened integer
data.clicked integer
data.open_rate number
data.click_rate number

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl http://tweak.email/api/v1/campaigns/:campaign/report/variants \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": [
        {
            "id": 1,
            "label": "string",
            "subject": "string",
            "from_name": "string",
            "is_winner": true,
            "sent": 1,
            "opened": 1,
            "clicked": 1,
            "open_rate": 1,
            "click_rate": 1
        }
    ]
}
GET /campaigns/{campaign}/recipients

Requires scope events:read

Who received the campaign and whether they opened or clicked.

Path parameters

campaign integer Required
Campaign id.

Query parameters

per_page integer default 25
Records per page (1–100, default 25).
cursor string
The `next_cursor` value from a previous response.
filter string
Narrow to a delivery outcome.
all opened clicked bounced pending sent

Response

data array of object
data.contact_id integer or null
data.email string or null
data.status string
data.sent_at string or null
data.opened_at string or null
data.clicked_at string or null
data.error_message string or null
per_page integer
next_cursor string or null
prev_cursor string or null
next_page_url string or null
prev_page_url string or null
has_more boolean

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl http://tweak.email/api/v1/campaigns/:campaign/recipients \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": [
        {
            "contact_id": 1,
            "email": "string",
            "status": "string",
            "sent_at": "string",
            "opened_at": "string",
            "clicked_at": "string",
            "error_message": "string"
        }
    ],
    "per_page": 1,
    "next_cursor": "string",
    "prev_cursor": "string",
    "next_page_url": "string",
    "prev_page_url": "string",
    "has_more": true
}
GET /events

Requires scope events:read

The read side of the event pipeline, bounded by a 180-day retention window. Machine opens are excluded unless explicitly requested.

Query parameters

per_page integer default 25
Records per page (1–100, default 25).
cursor string
The `next_cursor` value from a previous response.
event string
Filter by event type.
delivered bounced deferred dropped spam_report unsubscribed opened clicked queued sent
email string
Filter by recipient address.
campaign_id integer
Filter by campaign.
contact_id integer
Filter by contact.
since string
ISO 8601 lower bound.
until string
ISO 8601 upper bound.
include_machine_opens boolean
Include Apple MPP and bot prefetch opens.

Response

data array of object
data.id integer
data.email string
data.event string
data.campaign_id integer or null
data.contact_id integer or null
data.provider string or null
data.source string or null
data.is_machine_open boolean
data.metadata object
data.created_at string or null
per_page integer
next_cursor string or null
prev_cursor string or null
next_page_url string or null
prev_page_url string or null
has_more boolean

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl http://tweak.email/api/v1/events \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": [
        {
            "id": 90211,
            "email": "jane@example.com",
            "event": "clicked",
            "campaign_id": 118,
            "contact_id": 42,
            "provider": "postal",
            "source": "webhook",
            "is_machine_open": false,
            "metadata": {
                "url": "https://acme.com/changelog"
            },
            "created_at": "2026-08-09T10:04:12+00:00"
        }
    ],
    "per_page": 1,
    "next_cursor": "string",
    "prev_cursor": "string",
    "next_page_url": "string",
    "prev_page_url": "string",
    "has_more": true
}
POST /events

Requires scope events:write

Up to 1,000 per call. Events flow through the same pipeline as provider webhooks: campaign stats update, suppressions are created, contact statuses sync.

Body

events array of object Required
events.email string Required
events.event string Required
delivered bounced deferred dropped spam_report unsubscribed opened clicked queued sent
events.campaign_id integer or null
events.contact_id integer or null
events.provider string
events.source string
events.metadata object

Response

status string
processed integer

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X POST http://tweak.email/api/v1/events \
  -H "Authorization: Bearer $TWEAK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"events":[{"email":"jane@example.com","event":"delivered","campaign_id":1,"contact_id":1,"provider":"string","source":"string","metadata":{}}]}'

Request body

{
    "events": [
        {
            "email": "jane@example.com",
            "event": "delivered",
            "campaign_id": 1,
            "contact_id": 1,
            "provider": "string",
            "source": "string",
            "metadata": {}
        }
    ]
}

Response 200

{
    "status": "string",
    "processed": 1
}

Templates

Reusable email templates

GET /templates

Requires scope campaigns:read

Includes the platform's system starter templates alongside your own.

Query parameters

per_page integer default 25
Records per page (1–100, default 25).
cursor string
The `next_cursor` value from a previous response.
scope string
Which templates to return.
all system team
category string
Filter by category.

Response

data array of object
data.id integer
data.name string
data.category string or null
data.style string or null
data.description string or null
data.is_system boolean
data.html_content string or null
Only returned when fetching a single template.
per_page integer
next_cursor string or null
prev_cursor string or null
next_page_url string or null
prev_page_url string or null
has_more boolean

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl http://tweak.email/api/v1/templates \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": [
        {
            "id": 1,
            "name": "string",
            "category": "string",
            "style": "string",
            "description": "string",
            "is_system": true,
            "html_content": "string"
        }
    ],
    "per_page": 1,
    "next_cursor": "string",
    "prev_cursor": "string",
    "next_page_url": "string",
    "prev_page_url": "string",
    "has_more": true
}
POST /templates

Requires scope campaigns:write

Body

name string Required
category string
style string
description string
html_content string
blocks_json array of object

Response

data object
data.id integer
data.name string
data.category string or null
data.style string or null
data.description string or null
data.is_system boolean
data.html_content string or null
Only returned when fetching a single template.

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X POST http://tweak.email/api/v1/templates \
  -H "Authorization: Bearer $TWEAK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"string","category":"string","style":"string","description":"string","html_content":"string","blocks_json":[{}]}'

Request body

{
    "name": "string",
    "category": "string",
    "style": "string",
    "description": "string",
    "html_content": "string",
    "blocks_json": [
        {}
    ]
}

Response 200

{
    "data": {
        "id": 1,
        "name": "string",
        "category": "string",
        "style": "string",
        "description": "string",
        "is_system": true,
        "html_content": "string"
    }
}
GET /templates/{template}

Requires scope campaigns:read

Unlike the listing, this includes the full body.

Path parameters

template integer Required
Template id.

Response

data object
data.id integer
data.name string
data.category string or null
data.style string or null
data.description string or null
data.is_system boolean
data.html_content string or null
Only returned when fetching a single template.

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl http://tweak.email/api/v1/templates/:template \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": {
        "id": 1,
        "name": "string",
        "category": "string",
        "style": "string",
        "description": "string",
        "is_system": true,
        "html_content": "string"
    }
}
PATCH /templates/{template}

Requires scope campaigns:write

System templates cannot be modified.

Path parameters

template integer Required
Template id.

Body

name string Required
category string
style string
description string
html_content string
blocks_json array of object

Response

data object
data.id integer
data.name string
data.category string or null
data.style string or null
data.description string or null
data.is_system boolean
data.html_content string or null
Only returned when fetching a single template.

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X PATCH http://tweak.email/api/v1/templates/:template \
  -H "Authorization: Bearer $TWEAK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"string","category":"string","style":"string","description":"string","html_content":"string","blocks_json":[{}]}'

Request body

{
    "name": "string",
    "category": "string",
    "style": "string",
    "description": "string",
    "html_content": "string",
    "blocks_json": [
        {}
    ]
}

Response 200

{
    "data": {
        "id": 1,
        "name": "string",
        "category": "string",
        "style": "string",
        "description": "string",
        "is_system": true,
        "html_content": "string"
    }
}
DELETE /templates/{template}

Requires scope campaigns:write

Path parameters

template integer Required
Template id.

Response

data object
data.id integer
data.deleted boolean

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X DELETE http://tweak.email/api/v1/templates/:template \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": {
        "id": 42,
        "deleted": true
    }
}

Sequences

Automated sequences and enrolment

GET /sequences

Requires scope campaigns:read

Query parameters

per_page integer default 25
Records per page (1–100, default 25).
cursor string
The `next_cursor` value from a previous response.

Response

data array of object
data.id integer
data.name string
data.description string or null
data.status string
data.trigger_type string or null
data.subscribers_count integer
per_page integer
next_cursor string or null
prev_cursor string or null
next_page_url string or null
prev_page_url string or null
has_more boolean

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl http://tweak.email/api/v1/sequences \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": [
        {
            "id": 1,
            "name": "string",
            "description": "string",
            "status": "string",
            "trigger_type": "string",
            "subscribers_count": 1
        }
    ],
    "per_page": 1,
    "next_cursor": "string",
    "prev_cursor": "string",
    "next_page_url": "string",
    "prev_page_url": "string",
    "has_more": true
}
GET /sequences/{sequence}

Requires scope campaigns:read

Path parameters

sequence integer Required
Sequence id.

Response

data object
data.id integer
data.name string
data.description string or null
data.status string
data.trigger_type string or null
data.subscribers_count integer

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl http://tweak.email/api/v1/sequences/:sequence \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": {
        "id": 1,
        "name": "string",
        "description": "string",
        "status": "string",
        "trigger_type": "string",
        "subscribers_count": 1
    }
}
GET /sequences/{sequence}/subscribers

Requires scope campaigns:read

Path parameters

sequence integer Required
Sequence id.

Query parameters

per_page integer default 25
Records per page (1–100, default 25).
cursor string
The `next_cursor` value from a previous response.

Response

data array of object
per_page integer
next_cursor string or null
prev_cursor string or null
next_page_url string or null
prev_page_url string or null
has_more boolean

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl http://tweak.email/api/v1/sequences/:sequence/subscribers \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": [
        {}
    ],
    "per_page": 1,
    "next_cursor": "string",
    "prev_cursor": "string",
    "next_page_url": "string",
    "prev_page_url": "string",
    "has_more": true
}
POST /sequences/{sequence}/subscribers

Requires scope contacts:write

Accepts contact ids or email addresses. This is how you trigger onboarding from your own signup flow.

Path parameters

sequence integer Required
Sequence id.

Body

contact_ids array of integer
emails array of string

Response

data object
data.sequence_id integer
data.matched integer
data.enrolled integer
data.skipped integer
Matched but not eligible: already enrolled, unsubscribed, or bounced.

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X POST http://tweak.email/api/v1/sequences/:sequence/subscribers \
  -H "Authorization: Bearer $TWEAK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"contact_ids":[1],"emails":["jane@example.com"]}'

Request body

{
    "contact_ids": [
        1
    ],
    "emails": [
        "jane@example.com"
    ]
}

Response 200

{
    "data": {
        "sequence_id": 1,
        "matched": 1,
        "enrolled": 1,
        "skipped": 1
    }
}
DELETE /sequences/{sequence}/subscribers/{contact}

Requires scope contacts:write

Stops any pending steps. `removed` is false when the contact was not enrolled.

Path parameters

sequence integer Required
Sequence id.
contact integer Required
Contact id.

Response

data object
data.sequence_id integer
data.contact_id integer
data.removed boolean

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X DELETE http://tweak.email/api/v1/sequences/:sequence/subscribers/:contact \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": {
        "sequence_id": 3,
        "contact_id": 42,
        "removed": true
    }
}

Waitlists

Waitlists and signups

GET /waitlists

Requires scope contacts:read

Query parameters

per_page integer default 25
Records per page (1–100, default 25).
cursor string
The `next_cursor` value from a previous response.

Response

data array of object
data.id integer
data.name string
data.slug string
data.status string
data.public_url string
data.signups_count integer
per_page integer
next_cursor string or null
prev_cursor string or null
next_page_url string or null
prev_page_url string or null
has_more boolean

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl http://tweak.email/api/v1/waitlists \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": [
        {
            "id": 1,
            "name": "string",
            "slug": "string",
            "status": "string",
            "public_url": "string",
            "signups_count": 1
        }
    ],
    "per_page": 1,
    "next_cursor": "string",
    "prev_cursor": "string",
    "next_page_url": "string",
    "prev_page_url": "string",
    "has_more": true
}
GET /waitlists/{waitlist}

Requires scope contacts:read

Path parameters

waitlist integer Required
Waitlist id.

Response

data object
data.id integer
data.name string
data.slug string
data.status string
data.public_url string
data.signups_count integer

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl http://tweak.email/api/v1/waitlists/:waitlist \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": {
        "id": 1,
        "name": "string",
        "slug": "string",
        "status": "string",
        "public_url": "string",
        "signups_count": 1
    }
}
GET /waitlists/{waitlist}/signups

Requires scope contacts:read

Path parameters

waitlist integer Required
Waitlist id.

Query parameters

per_page integer default 25
Records per page (1–100, default 25).
cursor string
The `next_cursor` value from a previous response.

Response

data array of object
data.id integer
data.email string
data.name string or null
data.position integer or null
data.status string
data.referral_code string
data.referrals_count integer
per_page integer
next_cursor string or null
prev_cursor string or null
next_page_url string or null
prev_page_url string or null
has_more boolean

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl http://tweak.email/api/v1/waitlists/:waitlist/signups \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": [
        {
            "id": 1,
            "email": "string",
            "name": "string",
            "position": 1,
            "status": "string",
            "referral_code": "string",
            "referrals_count": 1
        }
    ],
    "per_page": 1,
    "next_cursor": "string",
    "prev_cursor": "string",
    "next_page_url": "string",
    "prev_page_url": "string",
    "has_more": true
}
POST /waitlists/{waitlist}/signups

Requires scope contacts:write

Queue position is assigned server-side.

Path parameters

waitlist integer Required
Waitlist id.

Body

email string Required
name string
referral_code string
The referring signup's code, if this signup came through a referral.
metadata object

Response

data object
data.id integer
data.email string
data.name string or null
data.position integer or null
data.status string
data.referral_code string
data.referrals_count integer

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X POST http://tweak.email/api/v1/waitlists/:waitlist/signups \
  -H "Authorization: Bearer $TWEAK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"email":"jane@example.com","name":"string","referral_code":"string","metadata":{}}'

Request body

{
    "email": "jane@example.com",
    "name": "string",
    "referral_code": "string",
    "metadata": {}
}

Response 200

{
    "data": {
        "id": 1,
        "email": "string",
        "name": "string",
        "position": 1,
        "status": "string",
        "referral_code": "string",
        "referrals_count": 1
    }
}
POST /waitlists/{waitlist}/invite

Requires scope contacts:write

Either specific ids, or `count` to take the next N from the front of the queue.

Path parameters

waitlist integer Required
Waitlist id.

Body

signup_ids array of integer
count integer
Invite the next N by queue position.

Response

data object
data.waitlist_id integer
data.invited integer
data.signup_ids array of integer

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X POST http://tweak.email/api/v1/waitlists/:waitlist/invite \
  -H "Authorization: Bearer $TWEAK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"signup_ids":[1],"count":1}'

Request body

{
    "signup_ids": [
        1
    ],
    "count": 1
}

Response 200

{
    "data": {
        "waitlist_id": 1,
        "invited": 1,
        "signup_ids": [
            1
        ]
    }
}

Suppressions

The do-not-mail list

GET /suppressions

Requires scope suppressions:read

Query parameters

per_page integer default 25
Records per page (1–100, default 25).
cursor string
The `next_cursor` value from a previous response.
reason string
Filter by reason.
hard_bounce soft_bounce spam_report unsubscribe manual
email string
Exact address match.

Response

data array of object
data.id integer
data.email string
data.reason string
hard_bounce soft_bounce spam_report unsubscribe manual
data.source string or null
data.campaign_id integer or null
per_page integer
next_cursor string or null
prev_cursor string or null
next_page_url string or null
prev_page_url string or null
has_more boolean

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl http://tweak.email/api/v1/suppressions \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": [
        {
            "id": 1,
            "email": "string",
            "reason": "hard_bounce",
            "source": "string",
            "campaign_id": 1
        }
    ],
    "per_page": 1,
    "next_cursor": "string",
    "prev_cursor": "string",
    "next_page_url": "string",
    "prev_page_url": "string",
    "has_more": true
}
POST /suppressions

Requires scope suppressions:write

Upserts on address.

Body

email string Required
reason string Required
hard_bounce spam_report unsubscribe manual
metadata object

Response

data object
data.id integer
data.email string
data.reason string
hard_bounce soft_bounce spam_report unsubscribe manual
data.source string or null
data.campaign_id integer or null

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X POST http://tweak.email/api/v1/suppressions \
  -H "Authorization: Bearer $TWEAK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"email":"jane@example.com","reason":"hard_bounce","metadata":{}}'

Request body

{
    "email": "jane@example.com",
    "reason": "hard_bounce",
    "metadata": {}
}

Response 200

{
    "data": {
        "id": 1,
        "email": "string",
        "reason": "hard_bounce",
        "source": "string",
        "campaign_id": 1
    }
}
DELETE /suppressions

Requires scope suppressions:write

The address becomes eligible for future sends.

Body

email string Required

Response

data object
data.status string

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X DELETE http://tweak.email/api/v1/suppressions \
  -H "Authorization: Bearer $TWEAK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"email":"jane@example.com"}'

Request body

{
    "email": "jane@example.com"
}

Response 200

{
    "data": {
        "status": "ok"
    }
}

Transactional

One-off transactional sending

POST /send

Requires scope transactional:send

Honours suppressions, sender-domain verification, and the plan's email allowance. Platform-wide suppressions (confirmed hard bounces and complaints) cannot be bypassed.

Body

to string Required
to_name string
from_email string Required
Must be on a fully verified sending domain.
from_name string
reply_to string
subject string Required
Merge tags are substituted here too.
html string
Required unless template_id is given.
text string
Derived from the HTML when omitted.
template_id integer
variables object
Values for {{merge_tags}} in the subject and body.
ignore_suppression boolean
Waives your own suppression list for a genuinely operational message. Never waives platform-wide suppressions.

Response

data object
data.status string
sent sandboxed
data.to string
data.subject string
data.delivered boolean

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X POST http://tweak.email/api/v1/send \
  -H "Authorization: Bearer $TWEAK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"to":"jane@example.com","to_name":"string","from_email":"jane@example.com","from_name":"string","reply_to":"jane@example.com","subject":"string","html":"string","text":"string","template_id":1,"variables":{},"ignore_suppression":true}'

Request body

{
    "to": "jane@example.com",
    "to_name": "string",
    "from_email": "jane@example.com",
    "from_name": "string",
    "reply_to": "jane@example.com",
    "subject": "string",
    "html": "string",
    "text": "string",
    "template_id": 1,
    "variables": {},
    "ignore_suppression": true
}

Response 200

{
    "data": {
        "status": "sent",
        "to": "string",
        "subject": "string",
        "delivered": true
    }
}

AI

Copy polish, subject lines, and deliverability scoring

POST /ai/polish

Requires scope ai:write

Rewrites for a requested tone and goal, and returns concrete suggestions plus a quality score. Counts against the plan's monthly AI allowance.

Body

content string Required
tone string
professional casual friendly formal persuasive
goal string
clarity engagement conversion brevity warmth

Response

data object
data.id integer
data.tweaked_content string
data.ai_suggestions array of string
data.quality_score number
data.model_used string or null
data.tokens_used integer

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X POST http://tweak.email/api/v1/ai/polish \
  -H "Authorization: Bearer $TWEAK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"content":"string","tone":"professional","goal":"clarity"}'

Request body

{
    "content": "string",
    "tone": "professional",
    "goal": "clarity"
}

Response 200

{
    "data": {
        "id": 1,
        "tweaked_content": "string",
        "ai_suggestions": [
            "string"
        ],
        "quality_score": 1,
        "model_used": "string",
        "tokens_used": 1
    }
}
POST /ai/subject-lines

Requires scope ai:write

Set `use_history` to ground the scoring in this team's own historical open rates rather than generic heuristics.

Body

subject string Required
use_history boolean
Ground scoring in this team's real historical open rates.

Response

data object
data.id integer
data.variations array of object
data.winning_subject string
data.original_score number
data.best_score number

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X POST http://tweak.email/api/v1/ai/subject-lines \
  -H "Authorization: Bearer $TWEAK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"subject":"string","use_history":true}'

Request body

{
    "subject": "string",
    "use_history": true
}

Response 200

{
    "data": {
        "id": 1,
        "variations": [
            {}
        ],
        "winning_subject": "string",
        "original_score": 1,
        "best_score": 1
    }
}
POST /ai/deliverability

Requires scope ai:write

Returns a spam score, specific issues, and a pass/warn/fail verdict. Useful as a pre-send check in CI.

Body

content string Required
subject string
use_account_signals boolean
Weight the assessment by your account's real bounce, complaint, and domain-auth signals. Defaults to true.

Response

data object
data.id integer
data.spam_score number
0–100; lower is better.
data.issues array of object
data.checks_passed array of object
data.verdict string
pass warn fail

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X POST http://tweak.email/api/v1/ai/deliverability \
  -H "Authorization: Bearer $TWEAK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"content":"string","subject":"string","use_account_signals":true}'

Request body

{
    "content": "string",
    "subject": "string",
    "use_account_signals": true
}

Response 200

{
    "data": {
        "id": 1,
        "spam_score": 1,
        "issues": [
            {}
        ],
        "checks_passed": [
            {}
        ],
        "verdict": "pass"
    }
}
GET /ai/usage

Response

data object
data.period_start string
data.period_end string
data.ai_tweaks object
data.subject_tests object
data.emails object

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl http://tweak.email/api/v1/ai/usage \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": {
        "period_start": "2026-08-09T10:00:00+00:00",
        "period_end": "2026-08-09T10:00:00+00:00",
        "ai_tweaks": {},
        "subject_tests": {},
        "emails": {}
    }
}

Webhooks

Outbound event subscriptions

GET /webhooks

Requires scope webhooks:read

Query parameters

per_page integer default 25
Records per page (1–100, default 25).
cursor string
The `next_cursor` value from a previous response.

Response

data array of object
data.id integer
data.url string
data.description string or null
data.events array of string
data.is_active boolean
data.last_delivered_at string or null
data.consecutive_failures integer
data.secret string
Returned only on creation and rotation.
per_page integer
next_cursor string or null
prev_cursor string or null
next_page_url string or null
prev_page_url string or null
has_more boolean

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl http://tweak.email/api/v1/webhooks \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": [
        {
            "id": 1,
            "url": "string",
            "description": "string",
            "events": [
                "string"
            ],
            "is_active": true,
            "last_delivered_at": "2026-08-09T10:00:00+00:00",
            "consecutive_failures": 1,
            "secret": "string"
        }
    ],
    "per_page": 1,
    "next_cursor": "string",
    "prev_cursor": "string",
    "next_page_url": "string",
    "prev_page_url": "string",
    "has_more": true
}
POST /webhooks

Requires scope webhooks:write

The response is the only time the signing secret is returned. Payloads are signed as `Tweak-Signature: t={timestamp},v1={hmac}` where the HMAC is SHA-256 over `{timestamp}.{raw body}`.

Body

url string Required
Must be publicly routable. Private and reserved IPs are rejected.
description string
events array of string Required
Event types, or ["*"] for all.

Response

data object
data.id integer
data.url string
data.description string or null
data.events array of string
data.is_active boolean
data.last_delivered_at string or null
data.consecutive_failures integer
data.secret string
Returned only on creation and rotation.

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X POST http://tweak.email/api/v1/webhooks \
  -H "Authorization: Bearer $TWEAK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com/hook","description":"string","events":["string"]}'

Request body

{
    "url": "https://example.com/hook",
    "description": "string",
    "events": [
        "string"
    ]
}

Response 200

{
    "data": {
        "id": 1,
        "url": "string",
        "description": "string",
        "events": [
            "string"
        ],
        "is_active": true,
        "last_delivered_at": "2026-08-09T10:00:00+00:00",
        "consecutive_failures": 1,
        "secret": "string"
    }
}
GET /webhooks/event-types

Requires scope webhooks:read

Response

data array of object
data.type string
data.description string

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl http://tweak.email/api/v1/webhooks/event-types \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": [
        {
            "type": "string",
            "description": "string"
        }
    ]
}
GET /webhooks/{endpoint}

Requires scope webhooks:read

Path parameters

endpoint integer Required
Webhook endpoint id.

Response

data object
data.id integer
data.url string
data.description string or null
data.events array of string
data.is_active boolean
data.last_delivered_at string or null
data.consecutive_failures integer
data.secret string
Returned only on creation and rotation.

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl http://tweak.email/api/v1/webhooks/:endpoint \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": {
        "id": 1,
        "url": "string",
        "description": "string",
        "events": [
            "string"
        ],
        "is_active": true,
        "last_delivered_at": "2026-08-09T10:00:00+00:00",
        "consecutive_failures": 1,
        "secret": "string"
    }
}
PATCH /webhooks/{endpoint}

Requires scope webhooks:write

Path parameters

endpoint integer Required
Webhook endpoint id.

Body

url string
description string
events array of string
is_active boolean

Response

data object
data.id integer
data.url string
data.description string or null
data.events array of string
data.is_active boolean
data.last_delivered_at string or null
data.consecutive_failures integer
data.secret string
Returned only on creation and rotation.

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X PATCH http://tweak.email/api/v1/webhooks/:endpoint \
  -H "Authorization: Bearer $TWEAK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com/hook","description":"string","events":["string"],"is_active":true}'

Request body

{
    "url": "https://example.com/hook",
    "description": "string",
    "events": [
        "string"
    ],
    "is_active": true
}

Response 200

{
    "data": {
        "id": 1,
        "url": "string",
        "description": "string",
        "events": [
            "string"
        ],
        "is_active": true,
        "last_delivered_at": "2026-08-09T10:00:00+00:00",
        "consecutive_failures": 1,
        "secret": "string"
    }
}
DELETE /webhooks/{endpoint}

Requires scope webhooks:write

Path parameters

endpoint integer Required
Webhook endpoint id.

Response

data object
data.id integer
data.deleted boolean

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X DELETE http://tweak.email/api/v1/webhooks/:endpoint \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": {
        "id": 42,
        "deleted": true
    }
}
GET /webhooks/{endpoint}/deliveries

Requires scope webhooks:read

What was sent and what your endpoint answered, for debugging.

Path parameters

endpoint integer Required
Webhook endpoint id.

Query parameters

per_page integer default 25
Records per page (1–100, default 25).
cursor string
The `next_cursor` value from a previous response.

Response

data array of object
data.id integer
data.event_type string
data.event_id string
data.payload object
data.response_status integer or null
data.response_body string or null
data.attempt integer
data.succeeded boolean
data.error string or null
per_page integer
next_cursor string or null
prev_cursor string or null
next_page_url string or null
prev_page_url string or null
has_more boolean

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl http://tweak.email/api/v1/webhooks/:endpoint/deliveries \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": [
        {
            "id": 1,
            "event_type": "string",
            "event_id": "string",
            "payload": {},
            "response_status": 1,
            "response_body": "string",
            "attempt": 1,
            "succeeded": true,
            "error": "string"
        }
    ],
    "per_page": 1,
    "next_cursor": "string",
    "prev_cursor": "string",
    "next_page_url": "string",
    "prev_page_url": "string",
    "has_more": true
}
POST /webhooks/{endpoint}/test

Requires scope webhooks:write

Lets you verify signature checking without provoking a real bounce.

Path parameters

endpoint integer Required
Webhook endpoint id.

Response

data object
data.status string

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X POST http://tweak.email/api/v1/webhooks/:endpoint/test \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": {
        "status": "ok"
    }
}
POST /webhooks/{endpoint}/rotate-secret

Requires scope webhooks:write

Returns the new secret once.

Path parameters

endpoint integer Required
Webhook endpoint id.

Response

data object
data.id integer
data.url string
data.description string or null
data.events array of string
data.is_active boolean
data.last_delivered_at string or null
data.consecutive_failures integer
data.secret string
Returned only on creation and rotation.

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X POST http://tweak.email/api/v1/webhooks/:endpoint/rotate-secret \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": {
        "id": 1,
        "url": "string",
        "description": "string",
        "events": [
            "string"
        ],
        "is_active": true,
        "last_delivered_at": "2026-08-09T10:00:00+00:00",
        "consecutive_failures": 1,
        "secret": "string"
    }
}

API keys

Credential management

GET /api-keys

Secrets are never returned; only a masked prefix.

Query parameters

per_page integer default 25
Records per page (1–100, default 25).
cursor string
The `next_cursor` value from a previous response.

Response

data array of object
data.id integer
data.name string
data.masked_key string
data.scopes array of string
data.last_used_at string or null
data.expires_at string or null
data.revoked_at string or null
per_page integer
next_cursor string or null
prev_cursor string or null
next_page_url string or null
prev_page_url string or null
has_more boolean

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl http://tweak.email/api/v1/api-keys \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": [
        {
            "id": 1,
            "name": "string",
            "masked_key": "string",
            "scopes": [
                "string"
            ],
            "last_used_at": "2026-08-09T10:00:00+00:00",
            "expires_at": "2026-08-09T10:00:00+00:00",
            "revoked_at": "2026-08-09T10:00:00+00:00"
        }
    ],
    "per_page": 1,
    "next_cursor": "string",
    "prev_cursor": "string",
    "next_page_url": "string",
    "prev_page_url": "string",
    "has_more": true
}
POST /api-keys

The secret is returned exactly once. A key cannot grant scopes it does not itself hold.

Body

name string Required
scopes array of string
Defaults to every scope the minting key holds.
expires_at string

Response

data object
data.id integer
data.name string
data.masked_key string
data.scopes array of string
data.last_used_at string or null
data.expires_at string or null
data.revoked_at string or null
data.key string
The secret. Returned exactly once.

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X POST http://tweak.email/api/v1/api-keys \
  -H "Authorization: Bearer $TWEAK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"string","scopes":["contacts:read"],"expires_at":"2026-08-09T10:00:00+00:00"}'

Request body

{
    "name": "string",
    "scopes": [
        "contacts:read"
    ],
    "expires_at": "2026-08-09T10:00:00+00:00"
}

Response 200

{
    "data": {
        "id": 1,
        "name": "string",
        "masked_key": "string",
        "scopes": [
            "string"
        ],
        "last_used_at": "2026-08-09T10:00:00+00:00",
        "expires_at": "2026-08-09T10:00:00+00:00",
        "revoked_at": "2026-08-09T10:00:00+00:00",
        "key": "string"
    }
}
GET /api-keys/scopes

Response

data array of object
data.scope string
data.description string

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl http://tweak.email/api/v1/api-keys/scopes \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": [
        {
            "scope": "string",
            "description": "string"
        }
    ]
}
DELETE /api-keys/{key}

Revoked rather than deleted, so the audit record survives.

Path parameters

key integer Required
API key id.

Response

data object
data.status string

Errors

403
The key lacks a required scope, or the plan does not include API access.
404
No such record for this team.
422
The request was understood but could not be applied.

Every endpoint can also return 401 (bad credential) and 429 (rate limited).

Request

curl -X DELETE http://tweak.email/api/v1/api-keys/:key \
  -H "Authorization: Bearer $TWEAK_API_KEY"

Response 200

{
    "data": {
        "status": "ok"
    }
}