Authentication
Every public API request requires a Bearer token in the Authorization header. Below: how to issue a token, which scopes to give it, and what to do on 401 and 403 errors.
Creating a token
- In the dashboard, go to Integrations → API → Create API key.
- Give the key a name and tick the scopes on a least-privilege basis — the full list is in Scopes below. You can change the scopes later with the Edit permissions button on the API key's page — the change also applies to a token already issued.
- Copy the token from the dialog that opens.
In the dashboard this entity is called an "API key"; the token is its secret value, issued when the key is created. Throughout the docs we use both terms: "API key" for the entity, "token" for the value.
The token is displayed only at the moment it's issued — when the API key is created or rotated. Save it right away: there's no way to view it again. If the token is lost, issue a new one with the Rotate token button on the API key's page.
Sending the token
Add the Authorization: Bearer <token> header to every request. The example reads lists, so the token needs the contacts.read scope:
- TypeScript
- Go
- Python
- cURL
async function main() {
const response = await fetch('https://api.emailmassivo.com/api/v1/public/lists', {
headers: {
'Authorization': `Bearer ${process.env.API_TOKEN}`,
},
});
console.log(response.status, await response.text());
}
main().catch(console.error);
package main
import (
"fmt"
"io"
"log"
"net/http"
"os"
)
func main() {
req, err := http.NewRequest("GET", "https://api.emailmassivo.com/api/v1/public/lists", nil)
if err != nil {
log.Fatal(err)
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("API_TOKEN"))
resp, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
out, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
fmt.Println(resp.StatusCode, string(out))
}
import os
import requests
response = requests.get(
'https://api.emailmassivo.com/api/v1/public/lists',
headers={'Authorization': f'Bearer {os.environ["API_TOKEN"]}'},
)
print(response.status_code, response.text)
curl -sS -w '\n%{http_code}\n' https://api.emailmassivo.com/api/v1/public/lists \
-H "Authorization: Bearer $API_TOKEN"
The token starts with rs_ck_v1_ and is as good as a password: keep it in environment variables or a secret manager, not in a repository and not in logs.
Scopes
A single token can hold multiple scopes. Scopes are grouped by public API section.
Contacts and lists
contacts.read— read lists, contacts, variables, and send history.contacts.write— CRUD on lists, contacts, and variables; imports; subscription management.
Transactional emails
email.send— send transactional emails viaPOST /api/v1/public/emails.email.read— read emails, their recipients and events viaGET /api/v1/public/emails/{emailId}and the sending history.
Sending keys
sending_keys.read— read sending keys, their state and statistics.sending_keys.write— create, update and delete sending keys, including changing the default key.
Campaigns
campaigns.read— read campaigns and their analytics.
Templates
templates.read— read HTML templates.templates.write— CRUD on templates.
Senders and domains
senders.read— read the list of senders.domains.read— read the list of domains and their verification status.
Webhooks
webhooks.read— read configured webhooks.webhooks.write— CRUD on webhooks.
Files
files.read— download previously uploaded files.
Segments
segments.read— read segments and the available filters.segments.write— CRUD on segments.
Gotchas
Changing a token and handling a leak.
Click Rotate token on the API key's page: a new token appears, and the previous one keeps working for 24 hours — until the date in the "Rotation active until …" banner. Replace the token in every client within that time. If you rotate again during those 24 hours, the oldest token is disabled immediately.
Click Revoke token on the API key's page — all of the key's tokens stop working immediately. Then click Issue and give the new token to your clients. Rotation doesn't fit here: after it, the leaked token keeps working for another 24 hours.
Handling errors
| HTTP | error.code | Cause | What to do |
|---|---|---|---|
| 401 | INVALID_API_TOKEN | The token wasn't accepted: the header isn't in the form Bearer <token>, the token was copied incompletely, it was revoked, 24 hours have passed since rotation, or the API key was deleted or blocked | Check the header and that the token was copied in full. If the token was revoked or lost, issue a new one on the API key's page. If the key is blocked, contact support |
| 401 | ACCOUNT_BANNED | The account is blocked | Contact support |
| 403 | SCOPE_REQUIRED | The token is missing a required scope. message names the missing scope | Add the scope with the Edit permissions button on the API key's page and retry the request |
| 403 | PUBLIC_API_DISABLED | Public API access is disabled at the account level | Contact support |
Example responses:
{
"ok": false,
"error": {
"code": "INVALID_API_TOKEN",
"message": "Provided API token is invalid."
},
"meta": { "requestId": "550e8400-e29b-41d4-a716-446655440000", "timestamp": "2026-09-30T10:15:00.120Z" }
}
{
"ok": false,
"error": {
"code": "SCOPE_REQUIRED",
"message": "Required scope is missing: email.send"
},
"meta": { "requestId": "550e8400-e29b-41d4-a716-446655440000", "timestamp": "2026-09-30T10:15:00.120Z" }
}
Per-endpoint error tables live on their own pages; for sending emails, see Send error codes.
See also
- Introduction — the overall request model.
- Quickstart — your first working request.
- API reference — endpoint parameters and responses.