Authentication
API tokens
Section titled “API tokens”Every request carries a workspace API token in the Authorization header:
Authorization: Bearer upm_...- A token belongs to one workspace. Everything you read or change is in that workspace.
- Tokens are created under Integrations, API, Generate new token by users with the Administrator or Manager role. The value is shown once; Echo stores only a hash of it.
- The token list in the app shows each token’s first characters, its access, its allowed IP addresses and when it was last used.
- A workspace can have at most 50 active tokens.
- Use the token only in your own backend. The API sends no CORS headers, so it can’t be called from a browser anyway.
The GET /openapi.yaml document is the only endpoint that needs no token.
Access levels
Section titled “Access levels”A token has one of two access levels, chosen when it is created (it can’t be changed later):
| Access | What it allows |
|---|---|
| Read only | Every GET endpoint the creator’s role allows. |
| Full access | Reads and writes, as far as the creator’s role allows. |
A token always acts with its creator’s current role: the access level can only narrow it. Each endpoint needs a right in one area:
| Endpoints | Read needs | Write needs |
|---|---|---|
| Subscribers, groups, segments, fields, imports | Subscribers: view | Subscribers: manage |
| Campaigns | Campaigns: view | Campaigns: manage |
| Automations | Automations: view | Automations: manage |
| Webhooks | Settings: view | Settings: manage |
GET /timezones, POST /batch |
any valid token | any valid token |
The built-in Administrator and Manager roles have every right above. A request without the right answers 403 forbidden:
{"error":{"code":"forbidden","message":"You don't have permission to do this."}}Some answers depend on the rights too:
- Webhook URLs are shown in full only to a token with Settings: manage. Others see the origin only, for example
"url":"https://hooks.example.com/…". - In campaign activity and workflow runs, the subscriber’s
emailand thesearchparameter need Subscribers: view. Without it, the rows carry the subscriber’sidonly andsearchanswers403.
Allowed IP addresses
Section titled “Allowed IP addresses”A token can be limited to up to 20 IP addresses or ranges (for example 203.0.113.7 or 203.0.113.0/24). A request from any other address answers:
HTTP/1.1 403 ForbiddenContent-Type: application/json
{"error":{"code":"ip_not_allowed","message":"This API token can't be used from your IP address."}}When a token stops working
Section titled “When a token stops working”Echo checks the token on every request, so these take effect at once:
| Change | Answer |
|---|---|
| The token is revoked | 401 unauthenticated |
| The creator is removed from the workspace, or their user is disabled | 401 unauthenticated (the app marks the token Inactive) |
| The creator’s role changes | The new role applies from the next request |
| The workspace is suspended | 403 workspace_suspended |
| The workspace requires two-factor authentication and the creator hasn’t set it up | 403 twofa_enforced (the token works again once they set it up) |
Changes made with a token are recorded in the workspace’s activity log under the token’s name.
Authentication errors
Section titled “Authentication errors”A missing, malformed, unknown or revoked token:
curl -i "$ECHO_API/subscribers"HTTP/1.1 401 UnauthorizedContent-Type: application/jsonWww-Authenticate: Bearer realm="upmail"
{"error":{"code":"unauthenticated","message":"Missing, unknown or revoked API token."}}Failed authentication doesn’t count against the rate limit, and its answer has no X-RateLimit-* headers.