OAuth 2.0 is the recommended authentication method for new Transactional Email API v2 integrations. It gives you per-scope permissions, IP allowlisting, short-lived tokens, and credential rotation without touching your send code.
OAuth traffic reaches the API through the Insider Gateway at https://gw.useinsider.com, which handles authentication, routing, and rate limiting before passing the request to the email service. The gateway resolves your account from the token, so no request needs a customer or tenant parameter.
The integration consists of three steps:
Create credentials in the InOne panel and select the scopes you need.
Get an access token by exchanging the Client ID and Secret for a short-lived Bearer token.
Call the API by sending a request to https://gw.useinsider.com/api/em/v2/tx/... with that token.
Only users with Administrator permission can generate credentials. If your account cannot complete this operation, consult the Insider One team.
1. Create a Client ID and Secret
This is a one-time setup.
Navigate to your username > Settings > InOne Settings > Integration Settings.
Scroll to the OAuth 2.0 Credentials section and click the Generate OAuth 2.0 Credential button. Credentials you created earlier are listed here.
Enter a credential name (e.g., my-backend-integration) and select the scopes this credential is allowed to use. A token can only access the scopes granted to its credential.
Set the token duration.
Click the Continue button.
Optionally authorize trusted IP addresses, as single IPs or CIDR ranges, to apply an IP restriction. If you set one, tokens are issued only to and accepted only from those addresses. Click the Authorize and Generate button.
Click Copy to copy the Client ID in ins-{uuid} format, and the Client Secret, a 60-character string, before closing the prompt.
The Client Secret is displayed only once. Store it securely. If it is lost or leaked, revoke the credential and create a new one.
Each user can generate up to 10 tokens per minute. Requests over that limit are blocked and return an error.
Each scope also carries its own rate limit, expressed as requests per window plus a burst allowance, configured when the credential is created. See Rate limiting below.
To edit or delete a credential, use the Edit or Delete button next to it in the same panel section. Editing is limited to the API scope and the IP address authorization.
Scopes
Each endpoint requires its own scope.
Scope | Method | Gateway endpoint | Purpose |
|---|---|---|---|
em-tx-v2-send | POST | /api/em/v2/tx/send | Sends a transactional email |
em-tx-v2-validate | POST | /api/em/v2/tx/validate | Validates template syntax and dry-run render |
em-tx-v2-status-get | GET | /api/em/v2/tx/messages/{message_id} | Gets the delivery status of a message |
em-tx-v2-categ-create | POST | /api/em/v2/tx/categories | Creates a category |
em-tx-v2-categ-list | GET | /api/em/v2/tx/categories | Lists categories |
em-tx-v2-categ-get | GET | /api/em/v2/tx/categories/{id} | Gets a single category |
2. Get an access token
Exchange your credentials for a JWT access token. Request only the scopes you need, and request every scope you need. The token will contain exactly the scopes in this call, and each must already be granted to the credential.
Request
curl -X POST --location 'https://gw.useinsider.com/auth/token' \
--header 'Content-Type: application/json' \
--data '{
"client_id": "ins-{your_client_id}",
"client_secret": "{your_client_secret}",
"scopes": [
"em-tx-v2-send",
"em-tx-v2-status-get"
]
}'Responses
200
{
"access_token": "{jwt}",
"token_type": "Bearer",
"expires_in_sec": 4500
}401
This response is returned when the Client ID or Secret is wrong, when a requested scope is not granted to the credential, or when the calling IP is not in the allowlist. The response is intentionally identical for all three cases, so check all three when troubleshooting.
Requesting fewer scopes than you use is the most common integration error. A credential may have a scope granted, but each token only carries the scopes explicitly listed in its own token request. Calling an endpoint whose scope was omitted returns R6, not a permissions error on the credential.
Reuse, refresh, and revoke tokens
Reuse the token until it expires. The default lifetime is 4500 seconds, that is 75 minutes. Do not request a new token per API call.
On a 401 with code R5 (Expired Token), request a new token and retry the call.
To invalidate a token before it expires, call POST https://gw.useinsider.com/auth/revoke/token with the Authorization: Bearer header. Subsequent calls with that token return R9 error.
3. Call the API
Every call has the same shape as follows:
curl --location 'https://gw.useinsider.com/api/em/v2/tx/send' \
--header 'Authorization: Bearer {your_access_token}' \
--header 'Content-Type: application/json' \
--data '{
...
}'Request and response bodies are identical to the API key versions documented on each endpoint page. Only the base URL, the path, and the auth header differ.
Your request must use the method documented for the resource. A GET against a POST-only endpoint returns R6 with HTTP 405, because the path matches a scope but the method does not. A path that matches no scope at all returns R6 with HTTP 401.
Gateway error codes
Errors raised by the gateway itself use a compact envelope:
{
"code": "",
"message": ""
}Code | HTTP | Meaning | What to do |
|---|---|---|---|
R1 | 401 | Invalid Token: missing, malformed, or bad signature | Check the Authorization: Bearer header. |
R3 | 429 | Rate Limited: scope quota exceeded | Back off and retry after the window. |
R4 | 403 | IP Restricted: the caller IP is not in the allowlist, or could not be determined | Call from an allowlisted IP, or update the allowlist. |
R5 | 401 | Expired Token | Request a new token. |
R6 | 401 | Invalid Request: no scope in the token matches the request path | Verify the URL and confirm the scope was requested at token generation. |
R6 | 405 | Invalid Request: the path matches a scope, but the method does not | Use the method documented for that resource. |
R8 | 500 | Internal Server Error: the gateway failed before reaching the service | Retry; if it persists, contact support. |
R9 | 401 | Revoked Token | Request a new token. |
R10 | 401 | Inactive Client: the credential is disabled | Contact support. |
A gateway error means the request never reached the email service, so nothing was queued or sent.
Service-level errors, meaning validation failures, not-found responses, and conflicts, use a different envelope and are documented in Error Codes.
Rate limit
Gateway rate limits are enforced per credential and per scope, and the token carries the limits. Defaults are set when the credential is created; the typical default is 100 requests per 60 seconds with a burst allowance of 10.
On a breach, the gateway returns the following with HTTP 429.
{
"code": "R3",
"message": "Rate Limited"
}No rate-limit response headers exist; you can rely on the JSON body.
This limit is separate from and evaluated before the service-level send limit of 10,000 requests per second per customer described in Transactional Emails.
Quick start
# 1. Create a credential in the panel
# (username > Settings > InOne Settings > Integration Settings > OAuth 2.0 Credentials)
# and select the scopes you need.
# 2. Get a token, valid for 75 minutes
TOKEN=$(curl -s https://gw.useinsider.com/auth/token \
-H 'Content-Type: application/json' \
-d '{"client_id":"ins-...","client_secret":"...","scopes":["em-tx-v2-send","em-tx-v2-status-get"]}' \
| jq -r .access_token)
# 3. Send
curl https://gw.useinsider.com/api/em/v2/tx/send \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{
"subject":"Hi {{ name }}",
"from":{"email":"orders@yourbrand.com"},
"recipients":[{"email":"jane@example.com","fields":{"name":"Jane"}}],
"content":[{"type":"text/html","value":"<p>Hello {{ name }}</p>"}]
}'
# 4. Track
curl https://gw.useinsider.com/api/em/v2/tx/messages/{message_id} \
-H "Authorization: Bearer $TOKEN"