Documentation Index
Fetch the complete documentation index at: https://docs.truagents.com/llms.txt
Use this file to discover all available pages before exploring further.
Work in Progress — This API design is under active development. The current per-organization unsubscribe model may conflict with multi-org setups where clients expect a unified suppression list across all their organizations, with optional per-org overrides. The final design needs to account for this before implementation.
Summary
The Unsubscribe API lets external systems query and update contact communication preferences (email, SMS, phone) across multiple TruAgents organizations through a single authenticated API key.
This is the right integration path when a client manages several organizations and needs to programmatically sync suppression lists or manage unsubscribe state across channels.
Who this is for
Technical admins and developers integrating external compliance or suppression systems with TruAgents.
Where it fits in the product
- Administration → API Keys for key creation and management
- Contacts for the underlying unsubscribe preferences being read and written
Prerequisites
Before using the Unsubscribe API:
- A teammate account with access to the target organizations (via managed organizations)
- An API key created through the admin UI, scoped to the desired organizations
- The API key token (shown once at creation — store it securely)
Authentication
All requests require a Bearer token in the Authorization header:
Authorization: Bearer <api_token>
The API key determines which organizations the caller can access. Requests targeting an organization outside the key’s scope return 403 Forbidden.
Future versions may support additional authentication methods such as OAuth 2.0 (client credentials) and mutual TLS (mTLS) for clients with specific security requirements.
Endpoints
Base URL: https://app.truagents.com/api/v1/unsubscribe
curl -X GET "https://app.truagents.com/api/v1/unsubscribe?channel=email&limit=50" \
-H "Authorization: Bearer <api_token>"
Returns contacts that are unsubscribed from at least one channel, across the key’s authorized organizations.
Query parameters
| Parameter | Type | Required | Description |
|---|
org_slug | string | No | Filter to a specific organization. Omit to query all orgs in the key’s scope. |
channel | string | No | Filter by channel: email, sms, or phone. Only returns contacts unsubscribed from this channel. |
since | ISO 8601 | No | Only return contacts whose unsubscribe status changed on or after this timestamp. |
until | ISO 8601 | No | Only return contacts whose unsubscribe status changed on or before this timestamp. |
cursor | string | No | Cursor for pagination. Use next_cursor from the previous response. |
limit | integer | No | Results per page (default: 100, max: 1000). |
Response
{
"data": [
{
"org_slug": "acme-corp",
"email": "john@example.com",
"phone": "+15551234567",
"unsubscribed_from_email": true,
"unsubscribed_from_sms": false,
"unsubscribed_from_phone": false,
"unsubscribed_at": "2026-04-15T10:30:00Z"
}
],
"next_cursor": "eyJpZCI6ImNseDEyMyIsIm9yZyI6ImFjbWUtY29ycCJ9",
"has_more": true
}
- Only contacts with at least one
true unsubscribe field are returned.
- Results are ordered by
unsubscribed_at descending (most recent changes first).
unsubscribed_at is the timestamp of the most recent unsubscribe status change.
next_cursor is null when there are no more results.
Update unsubscribe status
curl -X POST "https://app.truagents.com/api/v1/unsubscribe" \
-H "Authorization: Bearer <api_token>" \
-H "Content-Type: application/json" \
-d '{
"items": [
{
"email": "john@example.com",
"unsubscribed_from_email": true,
"unsubscribed_from_sms": true
},
{
"phone": "+15559876543",
"org_slug": "acme-west",
"unsubscribed_from_phone": true
}
]
}'
Sets unsubscribe status for one or more contacts. Supports batch operations up to 10,000 items per request.
Request body
| Field | Type | Required | Description |
|---|
items | array | Yes | Array of unsubscribe operations (max 10,000). |
Each item in the items array:
| Field | Type | Required | Description |
|---|
email | string | Yes* | Contact email. At least one of email or phone is required. Contact is matched by email within the organization. |
phone | string | Yes* | Contact phone. At least one of email or phone is required. Used for matching if email is not provided. |
org_slug | string | No | Target organization. Omit to apply across all orgs in the key’s scope. |
unsubscribed_from_email | boolean | No | Set email unsubscribe status. Omit to leave unchanged. |
unsubscribed_from_sms | boolean | No | Set SMS unsubscribe status. Omit to leave unchanged. |
unsubscribed_from_phone | boolean | No | Set phone unsubscribe status. Omit to leave unchanged. |
At least one unsubscribe field must be provided per item.
Response
{
"processed": 2,
"updated": [
{ "org_slug": "acme-corp", "email": "john@example.com" },
{ "org_slug": "acme-west", "phone": "+15559876543" }
],
"not_found": [
{ "org_slug": "acme-east", "email": "john@example.com" }
],
"skipped_items": []
}
- The operation is not atomic — each item is processed independently. Partial failures do not roll back successful updates.
processed is the total number of successful operations.
updated lists contacts where a match was found and unsubscribe status was changed.
not_found lists organizations where no matching contact exists. This is not an error — the contact may simply not exist in that org.
skipped_items lists items that were skipped due to conflicts (see below).
Contacts are matched within each organization using the same rules as the Contacts API:
- If
email is provided, the contact is matched by email (unique per organization).
- If only
phone is provided, the contact is matched by phone (unique per organization).
- If both
email and phone are provided and they match different existing contacts within the same organization, the item is skipped as a conflict.
Skipped items appear in the skipped_items array with a reason:
{
"skipped_items": [
{
"email": "john@example.com",
"phone": "+15559999999",
"org_slug": "acme-corp",
"reason": "email and phone match different existing contacts"
}
]
}
Error responses
| Status | Description |
|---|
| 401 | Missing, invalid, expired, or inactive API key. |
| 403 | The requested org_slug is not in the key’s authorized scope. |
| 400 | Missing required fields, invalid parameters, or batch size exceeds 10,000. |
| 422 | No unsubscribe fields provided in one or more items. |
API key management
API keys are created and managed through the TruAgents admin UI.
Creating an API key
- Navigate to Administration → API Keys.
- Enter a label (e.g., “Production Suppression Sync”).
- Select the organizations this key should have access to. Only organizations in your managed organizations list are available.
- Optionally set an expiration date.
- Copy the generated token immediately — it is shown only once and cannot be retrieved later.
Key details visible in admin
- Label and token prefix (e.g.,
abcdef12...) for identification
- Scoped organizations
- Created date and last used timestamp
- Active/inactive status
Teammate deactivation
When a teammate account is deactivated, all API keys owned by that teammate are automatically deactivated. Re-activating the teammate does not restore the keys — new keys must be created.
Security best practices
- Store API tokens in a secrets manager, not in code or configuration files.
- Scope keys to the minimum set of organizations needed.
- Set expiration dates and rotate keys periodically.
- Deactivate unused keys rather than deleting them, to preserve the audit trail.
- Monitor
last_used_at to identify stale keys.
Common mistakes
- Forgetting to copy the API token at creation time — it cannot be shown again.
- Using an API key scoped to one organization and expecting it to work across others.
- Omitting all unsubscribe fields in a POST item — at least one of
unsubscribed_from_email, unsubscribed_from_sms, or unsubscribed_from_phone is required per item.
- Sending both
email and phone that belong to different contacts in the same org — the item is skipped as a conflict.
Related pages