Skip to main content

Authentication

The SendSeven API supports three authentication methods. Choose the one that fits your use case:

MethodUse CaseLifespanX-Tenant-ID Required?
API TokenYour own scripts, automations, server-to-serverUp to 365 daysNo (tenant is embedded in the token)
OAuth AppThird-party apps acting on behalf of a userAccess: 1 hour, Refresh: until revokedNo (tenant is embedded in the token)
Bearer Token (JWT)SendSeven web/mobile app sessionsShort-livedYes

For API integrations, use API Tokens. They are the simplest, most secure option and don't require the X-Tenant-ID header.


API tokens are the primary authentication method for integrations, scripts, bots, and automation. Each token is scoped to a specific tenant and has fine-grained permissions.

Create tokens at: Settings > API Tokens

Token format​

s7_api_<32 hexadecimal characters>

Example: s7_api_a1b2c3d4e5f6789012345678abcdef00

Creating a token​

  1. Go to Settings > API Tokens
  2. Click Create Token
  3. Fill in:
    • Name: A descriptive name (e.g., "CRM Integration", "Marketing Bot")
    • Scopes: Select only the permissions this token needs
    • Expiration: Choose a duration (up to 365 days)
  4. Click Create
  5. Copy the token immediately - it will only be displayed once

Using the token​

Include the token in the Authorization header. No X-Tenant-ID is needed - the tenant is embedded in the token itself:

curl -X GET "https://api.sendseven.com/api/v1/contacts?page=1&page_size=20" \
-H "Authorization: Bearer s7_api_a1b2c3d4e5f6789012345678abcdef00" \
-H "Content-Type: application/json"

Python​

import requests

API_TOKEN = "s7_api_a1b2c3d4e5f6789012345678abcdef00"
BASE_URL = "https://api.sendseven.com/api/v1"

headers = {
"Authorization": f"Bearer {API_TOKEN}",
"Content-Type": "application/json",
}

response = requests.get(f"{BASE_URL}/contacts", headers=headers)
data = response.json()

for contact in data["items"]:
print(contact["name"], contact["email"])

JavaScript (Node.js)​

const API_TOKEN = "s7_api_a1b2c3d4e5f6789012345678abcdef00";
const BASE_URL = "https://api.sendseven.com/api/v1";

const response = await fetch(`${BASE_URL}/contacts`, {
headers: {
"Authorization": `Bearer ${API_TOKEN}`,
"Content-Type": "application/json",
},
});

const data = await response.json();
console.log(data.items);

Token lifetime and team membership​

A token acts as the team member who created it, with at most that member's permissions. When that member is removed from the workspace or deactivated, all of their API tokens (and OAuth tokens they authorized) stop working immediately and return 401. Create integration tokens with an account that will stay in the workspace, and replace a leaving colleague's tokens before you remove them.

Contact visibility​

A workspace API token sees every contact in the workspace, whoever created it. A member's contact visibility level does not limit their API tokens. An OAuth app, on the other hand, acts as the member who authorized it and follows that member's level: contacts hidden from the member are hidden from the app too. The same goes for the MCP server: connected by signing in, it follows the member's level; connected with an API key, it sees all contacts, like any API token.

This has a consequence to plan for: a member whose contact visibility is limited but whose role holds the permission to create API tokens (api:create, shown in the role editor as API > Create) can create a token that sees every contact. Keep that permission off roles whose contact visibility you limit.

Token scopes​

Scopes control what actions a token can perform. Always select the minimum scopes needed.

Scopes follow the pattern resource:action:

PatternMeaning
resource:readView/list resources
resource:createCreate new resources
resource:updateModify existing resources
resource:deleteRemove resources
resource:publishPut a resource live (flows:publish, automation:publish for Conversational Agents)
resource:manageFull administrative access
resource:*All actions on a resource

Common scope combinations​

Send messages only:

messages:create, conversations:read, contacts:read

Read-only dashboard:

conversations:read, contacts:read, messages:read, campaigns:read

Marketing automation:

contacts:read, contacts:create, contacts:update, campaigns:read, campaigns:create, campaigns:update, lists:read, lists:update

Full CRM integration:

contacts:*, custom_fields:*, conversations:*, messages:*, tags:*, notes:*

Build and publish Conversational Agents (leave out automation:publish to build and test without going live):

automation:read, automation:create, automation:update, automation:publish, knowledge_base:read, knowledge_base:create, custom_fields:read, custom_fields:create

Workspace scopes​

Two scopes act on your billing account rather than on one workspace. Both only work for an owner of the billing account.

ScopeWhat it allowsNotes
tenants:createCreate new workspaces (POST /tenants), and with an API token also billing accountsIncluded in *:* and tenants:* for API tokens. OAuth apps must request it by name, and can only add workspaces to their own billing account; they can never create a billing account. API tokens created before 27 October 2026 keep this ability without it (replace the token to remove it). See Creating Sub-Accounts.
tenants:manageAct on other workspaces of the same billing account with the X-Tenant-ID headerAPI tokens only, never OAuth apps. Must be listed by name; *:* doesn't include it. See Cross-Account API Access.

Insufficient scope error​

If your token lacks a required scope:

{
"detail": "Missing required permission(s): campaigns:create",
"code": "missing_scope",
"required_scopes": ["campaigns:create"],
"require_all": false,
"reason": "token_scope"
}

The response is a 403. required_scopes lists the scopes the endpoint accepts. reason is token_scope when the token itself lacks the scope (create a new token with it, or edit the token's scopes) and role when the signed-in user's role doesn't grant it. See Error handling.


2. OAuth Apps​

OAuth apps allow third-party applications to act on behalf of a SendSeven user. Use this when building integrations that need to access multiple users' accounts (e.g., Zapier, Make.com, CRM connectors).

Manage OAuth apps at: Settings > OAuth Apps

How it differs from API tokens​

API TokenOAuth App
Who creates itThe account owner, for their own useA developer, for any user to authorize
CredentialsA single token stringClient ID + Client Secret
User interactionNone - token works immediatelyUser must authorize the app via a consent screen
Multi-tenantScoped to one tenantCan be authorized by users across different tenants
Best forYour own integrationsApps you distribute to other SendSeven customers
Contact visibilityAll contactsThe authorizing member's level (details)

OAuth apps cannot create, change, regenerate or delete API tokens, and cannot register or manage OAuth apps. These calls return 403 with the code oauth_not_allowed.

Actions that need a signed-in user​

A few account-level actions can only be done by a person signed in to the SendSeven app. API tokens, OAuth apps and embed tokens get 403 with the code token_not_allowed, whatever scopes they carry and even when the token was created by the owner:

EndpointAction
DELETE /api/v1/tenants/{tenant_id}Deactivate (delete) a workspace
DELETE /api/v1/users/meDelete your own user account
DELETE /api/v1/billing-accounts/{billing_account_id}Delete a billing account
POST /api/v1/billing-accounts/{billing_account_id}/transfer-ownershipTransfer billing-account ownership
POST, PUT, DELETE on /api/v1/billing-accounts/{billing_account_id}/users…Add, re-role or remove billing-account users
POST /api/v1/billing-accounts/{billing_account_id}/cancel-subscriptionCancel the subscription
POST /api/v1/billing/cancel, /billing/cancel-subscription, /billing/cancel-deletion, /billing/reactivateCancel, schedule or undo deletion, reactivate
POST /api/v1/billing/subscribe (and GET /billing/subscribe/preview)Only while the account is cancelled or scheduled for deletion

The /billing/* actions above are also limited to the billing-account owner: other members get 403 with the code billing_owner_required.

{ "detail": { "error": "...", "code": "token_not_allowed" } }

Setting up an OAuth App​

  1. Go to Settings > OAuth Apps
  2. Click Create App
  3. Fill in:
    • App Name: Your application name (shown on the consent screen)
    • Redirect URIs: URLs where users will be redirected after authorization
    • Scopes: Permissions your app will request
  4. Note your Client ID and Client Secret

Authorization Code Flow​

Step 1: Redirect the user to the authorization endpoint:

https://api.sendseven.com/api/v1/oauth/authorize?
response_type=code&
client_id=YOUR_CLIENT_ID&
redirect_uri=https://yourapp.com/callback&
scope=contacts:read messages:create&
state=random_state_value&
tenant_id=OPTIONAL_TENANT_ID

The optional tenant_id parameter pre-selects a specific workspace on the consent screen. This is useful when re-authorizing for a known tenant (e.g., after token expiry).

Step 2: User authorizes your application on the SendSeven consent screen.

Step 3: Receive the authorization code at your redirect URI:

https://yourapp.com/callback?code=AUTH_CODE&state=random_state_value

Step 4: Exchange the code for an access token:

curl -X POST "https://api.sendseven.com/api/v1/oauth/token" \
-H "Content-Type: application/json" \
-d '{
"grant_type": "authorization_code",
"client_id": "YOUR_CLIENT_ID",
"client_secret": "YOUR_CLIENT_SECRET",
"code": "AUTH_CODE",
"redirect_uri": "https://yourapp.com/callback"
}'

Response:

{
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"refresh_token": "v1.refresh.abc123...",
"expires_in": 3600,
"token_type": "Bearer",
"scope": "contacts:read messages:create",
"tenant_id": "64f3a695-6ce7-4822-b3ae-dc20d2967c26",
"tenant_name": "My Company"
}

The tenant_id and tenant_name fields tell you which workspace was authorized. Use these to store tokens per-tenant when a user belongs to multiple workspaces. See the OAuth guide for details.

Step 5: Use the access token in API requests (no X-Tenant-ID needed):

curl -X GET "https://api.sendseven.com/api/v1/contacts" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "Content-Type: application/json"

Refreshing tokens​

Access tokens expire after 1 hour. Use the refresh token to get a new one:

curl -X POST "https://api.sendseven.com/api/v1/oauth/token" \
-H "Content-Type: application/json" \
-d '{
"grant_type": "refresh_token",
"client_id": "YOUR_CLIENT_ID",
"client_secret": "YOUR_CLIENT_SECRET",
"refresh_token": "v1.refresh.abc123..."
}'

The refresh token is not rotated and does not expire; it works until the connection is revoked. Each authorization is its own connection, so connecting the same app again (for example from a second client) does not invalidate the first connection's refresh token. See Several connections.


3. Bearer Tokens (JWT)​

Bearer tokens are short-lived JWT tokens issued by Auth0 for authenticated web and mobile app sessions. These are used internally by the SendSeven dashboard and mobile app.

You typically don't need this method for API integrations. Use API Tokens instead.

Bearer tokens are the only authentication method that requires the X-Tenant-ID header, because the JWT itself doesn't contain tenant information:

curl -X GET "https://api.sendseven.com/api/v1/contacts" \
-H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..." \
-H "X-Tenant-ID: your_tenant_id" \
-H "Content-Type: application/json"
When is X-Tenant-ID needed?

Only with Bearer (JWT) tokens. API Tokens and OAuth tokens have the tenant embedded, so no X-Tenant-ID header is required. If you're using API Tokens (recommended), you can ignore this header entirely.


Security Best Practices​

Best Practices
  • Store tokens in environment variables or a secrets manager
  • Use the minimum scopes required for your integration
  • Rotate tokens regularly
  • Revoke tokens that are no longer in use
  • Never embed tokens in client-side code
Never Do
  • Commit tokens to version control
  • Share tokens via email or chat
  • Grant tokens more scopes than necessary

Environment variable storage​

# .env file (never commit this!)
SENDSEVEN_API_TOKEN=s7_api_a1b2c3d4e5f6789012345678abcdef00
import os
token = os.environ["SENDSEVEN_API_TOKEN"]

Troubleshooting​

ErrorCauseSolution
401 "Invalid or expired API token"Token expired, revoked or malformed, or its creator is no longer an active member of the workspaceVerify format s7_api_<32hex>, check expiration, create a new token with an active member
401 "Invalid or expired token"OAuth access token expired or revoked, or the user who authorized it left the workspaceRefresh the token, or have an active member authorize again
401 "OAuth access token expired. Please reconnect your account."OAuth refresh no longer possibleRun the authorization flow again
403 "Not authenticated"No Authorization headerInclude Authorization: Bearer <token>
401 "Invalid authorization header" / "Invalid token format"Malformed Authorization header or tokenSend Authorization: Bearer <token> with the full token
403 "Missing required permission(s): ..."Token lacks a required scopeAdd the missing scope or create a new token
503 "Authentication temporarily unavailable, please retry"Temporary problem checking the tokenRetry with backoff
400 missing tenantUsing a JWT without X-Tenant-IDAdd X-Tenant-ID header, or switch to API Tokens

Authentication and scope errors carry a message string in detail. For the error shapes other endpoints use, see Error Handling.