Nitrosend API
v1.1.2https://api.nitrosend.comProductionhttp://localhost:8000Local developmentMulti-channel marketing automation API. Send email campaigns, build automation flows, manage contacts and segments, track events, and configure your Brand Kit — all via a single REST API.
Authentication
All /v1/my/* endpoints require authentication via Bearer token.
Two token types are accepted (tried in order):
- API Key —
Authorization: Bearer nskey_live_... - JWT —
Authorization: Bearer <jwt>(obtained fromPOST /v1/login)
Pagination
Paginated endpoints return these headers:
X-Total-Count— total recordsX-Total-Pages— total pagesX-Page-Number— current pageX-Next-Page— next page (omitted on last page)X-Prev-Page— previous page (omitted on first page)
Use page and limit (or per) query params to control pagination.
Maximum limit is 100, default is 30.
Error Responses
All errors return a consistent JSON shape:
{
"code": 422,
"message": "Description of error",
"error": true,
"validation_errors": { "field": ["error message"] }
}The validation_errors key is only present on 422 responses.
Authentication
BearerAuthhttpAuthentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
Scheme: bearer
Auth
Login, logout, and registration
Create a new account
Body
userobjectrequiredResponse
Account created
Validation failed
curl -X POST 'https://api.nitrosend.com/v1/signup' \
-H 'Content-Type: application/json' \
-d '{
"user": {
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"mobile": "string",
"invite_token": "string",
"password": "********",
"password_confirmation": "********"
}
}'const response = await fetch('https://api.nitrosend.com/v1/signup', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"user": {
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"mobile": "string",
"invite_token": "string",
"password": "********",
"password_confirmation": "********"
}
}),
});
const data = await response.json();import requests
payload = {
"user": {
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"mobile": "string",
"invite_token": "string",
"password": "********",
"password_confirmation": "********"
}
}
response = requests.post('https://api.nitrosend.com/v1/signup', json=payload)
data = response.json(){
"user": {
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"mobile": "string",
"invite_token": "string",
"password": "********",
"password_confirmation": "********"
}
}{
"id": 0,
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"mobile": "string",
"country_code": "string",
"time_zone": "string",
"admin": true,
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}Sign in and receive a JWT
Body
userobjectrequiredResponse
Signed in
Not authenticated
curl -X POST 'https://api.nitrosend.com/v1/login' \
-H 'Content-Type: application/json' \
-d '{
"user": {
"email": "user@example.com",
"password": "********"
}
}'const response = await fetch('https://api.nitrosend.com/v1/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"user": {
"email": "user@example.com",
"password": "********"
}
}),
});
const data = await response.json();import requests
payload = {
"user": {
"email": "user@example.com",
"password": "********"
}
}
response = requests.post('https://api.nitrosend.com/v1/login', json=payload)
data = response.json(){
"user": {
"email": "user@example.com",
"password": "********"
}
}{
"id": 0,
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"mobile": "string",
"country_code": "string",
"time_zone": "string",
"admin": true,
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}Sign out and revoke JWT
Response
Signed out
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X DELETE 'https://api.nitrosend.com/v1/logout'const response = await fetch('https://api.nitrosend.com/v1/logout', {
method: 'DELETE',
});
const data = await response.json();import requests
response = requests.delete('https://api.nitrosend.com/v1/logout')
data = response.json()Get OAuth popup context
Returns the account-selection and subscription context used by the
/oauth/connect popup. This endpoint accepts the normal Bearer JWT
and, for popup resume flows, the authenticated browser session cookie
established by Devise/OmniAuth.
Response
Popup context
Not authenticated
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/oauth/me'const response = await fetch('https://api.nitrosend.com/v1/oauth/me', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/oauth/me')
data = response.json(){
"accounts": [
{
"id": 0,
"name": "string",
"can_manage": true,
"needs_subscribe": true
}
],
"plans": [
{
"id": 0,
"name": "string",
"slug": "string",
"base_price_cents": 0,
"interval": "string"
}
],
"stripe_publishable_key": "string"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}Subscribe the selected OAuth popup account
Finalizes plan selection for the /oauth/connect popup before the
browser returns to the Doorkeeper consent screen. This endpoint accepts
the normal Bearer JWT and, for popup resume flows, the authenticated
browser session cookie established by Devise/OmniAuth.
Body
plan_idintegerrequiredaccount_idinteger | nullstripe_tokenstring | nullResponse
Popup can continue to consent
Not authenticated
Account or plan selection failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X POST 'https://api.nitrosend.com/v1/oauth/subscribe' \
-H 'Content-Type: application/json' \
-d '{
"plan_id": 0,
"account_id": 0,
"stripe_token": "string"
}'const response = await fetch('https://api.nitrosend.com/v1/oauth/subscribe', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"plan_id": 0,
"account_id": 0,
"stripe_token": "string"
}),
});
const data = await response.json();import requests
payload = {
"plan_id": 0,
"account_id": 0,
"stripe_token": "string"
}
response = requests.post('https://api.nitrosend.com/v1/oauth/subscribe', json=payload)
data = response.json(){
"plan_id": 0,
"account_id": 0,
"stripe_token": "string"
}{
"next_step": "consent"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}{
"error": "string"
}Create a CSRF-safe OAuth provider launch URL
Mints a short-lived launch URL for Google or GitHub sign-in. The
frontend follows the returned API-origin launch page, which renders the
real POST form to /auth/:provider with a valid Rails authenticity
token. This preserves OmniAuth's POST-only request phase and CSRF
protection for both the app popup flow and the /oauth/connect agent
popup flow.
Body
providerstringgoogle_oauth2githubrequiredauth_intentstringappagentappauth_stepstringloginsignuploginresume_urlstring<uri> | nullRequired when auth_intent=agent; must point to the frontend /oauth/connect route.
Response
Launch URL created
Invalid provider or resume URL
curl -X POST 'https://api.nitrosend.com/v1/oauth/launch' \
-H 'Content-Type: application/json' \
-d '{
"provider": "google_oauth2",
"auth_intent": "app",
"auth_step": "login",
"resume_url": "https://example.com"
}'const response = await fetch('https://api.nitrosend.com/v1/oauth/launch', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"provider": "google_oauth2",
"auth_intent": "app",
"auth_step": "login",
"resume_url": "https://example.com"
}),
});
const data = await response.json();import requests
payload = {
"provider": "google_oauth2",
"auth_intent": "app",
"auth_step": "login",
"resume_url": "https://example.com"
}
response = requests.post('https://api.nitrosend.com/v1/oauth/launch', json=payload)
data = response.json(){
"provider": "google_oauth2",
"auth_intent": "app",
"auth_step": "login",
"resume_url": "https://example.com"
}{
"launch_url": "https://example.com"
}{
"error": "string"
}User
Current user profile
Get current user profile
Response
User profile
Not authenticated
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/user'const response = await fetch('https://api.nitrosend.com/v1/my/user', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/user')
data = response.json(){
"id": 0,
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"mobile": "string",
"country_code": "string",
"time_zone": "string",
"admin": true,
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}Update current user profile
Body
first_namestringlast_namestringemailstring<email>mobilestringtime_zonestring | nullResponse
Updated user
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X PATCH 'https://api.nitrosend.com/v1/my/user' \
-H 'Content-Type: application/json' \
-d '{
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"mobile": "string",
"time_zone": "string"
}'const response = await fetch('https://api.nitrosend.com/v1/my/user', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"mobile": "string",
"time_zone": "string"
}),
});
const data = await response.json();import requests
payload = {
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"mobile": "string",
"time_zone": "string"
}
response = requests.patch('https://api.nitrosend.com/v1/my/user', json=payload)
data = response.json(){
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"mobile": "string",
"time_zone": "string"
}{
"id": 0,
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"mobile": "string",
"country_code": "string",
"time_zone": "string",
"admin": true,
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}Get current impersonation status
Response
Current impersonation state
Not authenticated
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/impersonation'const response = await fetch('https://api.nitrosend.com/v1/my/impersonation', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/impersonation')
data = response.json(){
"impersonating": true,
"impersonator": {
"id": 0,
"email": "user@example.com",
"name": "string"
}
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}Revoke the active impersonation session
Response
Impersonation session revoked
Not authenticated
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X DELETE 'https://api.nitrosend.com/v1/my/impersonation'const response = await fetch('https://api.nitrosend.com/v1/my/impersonation', {
method: 'DELETE',
});
const data = await response.json();import requests
response = requests.delete('https://api.nitrosend.com/v1/my/impersonation')
data = response.json(){
"redirect_url": "https://api.nitrosend.com/adm"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}Account
Account settings and configuration
Get account details
Response
Account with brands and billing
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/account'const response = await fetch('https://api.nitrosend.com/v1/my/account', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/account')
data = response.json(){
"id": 0,
"name": "string",
"avatar": "string",
"banner": "string",
"account_tier": "free",
"safe_mode_enabled": true,
"billing": {
"plan_name": "string",
"overage": {},
"resources": {
"email": {
"used": 0,
"allowance": 0,
"remaining": 0,
"overage_rate": 0
},
"sms": {
"used": 0,
"allowance": 0,
"remaining": 0,
"overage_rate": 0
},
"ai": {
"used": 0,
"allowance": 0,
"remaining": 0,
"overage_rate": 0
}
},
"brands": {
"used": 0,
"limit": 0,
"remaining": 0,
"unlimited": true,
"can_create": true
},
"lifetime": {
"email_sent": 0,
"sms_sent": 0,
"ai_used": 0
}
},
"brands": [
{
"id": 0,
"sid": "string",
"account_id": 0,
"brand_color": "string",
"text_color": "string",
"bg_color": "string",
"radius": 0,
"spacing_density": "compact",
"font_heading": "string",
"font_body": "string",
"brand_document": "string",
"style_notes": "string",
"tone": "string",
"company_description": "string",
"industry": "string",
"example_copy": [
"string"
],
"default_header": {},
"default_footer": {},
"default_theme": {},
"physical_address": "string",
"company_name": "string",
"source_url": "string",
"last_scraped_at": "2024-01-15T09:30:00Z",
"links": [
{
"url": "string",
"icon": "string",
"title": "string"
}
],
"logo": "string",
"complete": true,
"email_from_name": "string",
"email_from_email": "string",
"email_reply_to": "string",
"email_view_online": true,
"test_email_recipients": [
"user@example.com"
],
"onboarding_state": {},
"onboarding": {
"steps": {},
"progress": {
"completed": 0,
"total": 0
}
},
"domain_verified": true,
"can_send": true,
"byo_routing": {
"mismatch": true,
"provider": "string",
"bypassing_domains": [
"string"
],
"message": "string"
},
"subscribed_contacts_count": 0,
"using_sandbox": true,
"sandbox_email": "string",
"sandbox_monthly_cap": 0,
"sandbox_sends_remaining": 0,
"capabilities": {},
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}
],
"team": {
"seat_limit": 0,
"seat_count": 0,
"member_count": 0,
"invite_count": 0,
"current_role": "string",
"can_manage_team": true
},
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}Update account settings
Body
namestringavatarstringSigned blob ID
bannerstringSigned blob ID
Response
Updated account
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X PATCH 'https://api.nitrosend.com/v1/my/account' \
-H 'Content-Type: application/json' \
-d '{
"name": "string",
"avatar": "string",
"banner": "string"
}'const response = await fetch('https://api.nitrosend.com/v1/my/account', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "string",
"avatar": "string",
"banner": "string"
}),
});
const data = await response.json();import requests
payload = {
"name": "string",
"avatar": "string",
"banner": "string"
}
response = requests.patch('https://api.nitrosend.com/v1/my/account', json=payload)
data = response.json(){
"name": "string",
"avatar": "string",
"banner": "string"
}{
"id": 0,
"name": "string",
"avatar": "string",
"banner": "string",
"account_tier": "free",
"safe_mode_enabled": true,
"billing": {
"plan_name": "string",
"overage": {},
"resources": {
"email": {
"used": 0,
"allowance": 0,
"remaining": 0,
"overage_rate": 0
},
"sms": {
"used": 0,
"allowance": 0,
"remaining": 0,
"overage_rate": 0
},
"ai": {
"used": 0,
"allowance": 0,
"remaining": 0,
"overage_rate": 0
}
},
"brands": {
"used": 0,
"limit": 0,
"remaining": 0,
"unlimited": true,
"can_create": true
},
"lifetime": {
"email_sent": 0,
"sms_sent": 0,
"ai_used": 0
}
},
"brands": [
{
"id": 0,
"sid": "string",
"account_id": 0,
"brand_color": "string",
"text_color": "string",
"bg_color": "string",
"radius": 0,
"spacing_density": "compact",
"font_heading": "string",
"font_body": "string",
"brand_document": "string",
"style_notes": "string",
"tone": "string",
"company_description": "string",
"industry": "string",
"example_copy": [
"string"
],
"default_header": {},
"default_footer": {},
"default_theme": {},
"physical_address": "string",
"company_name": "string",
"source_url": "string",
"last_scraped_at": "2024-01-15T09:30:00Z",
"links": [
{
"url": "string",
"icon": "string",
"title": "string"
}
],
"logo": "string",
"complete": true,
"email_from_name": "string",
"email_from_email": "string",
"email_reply_to": "string",
"email_view_online": true,
"test_email_recipients": [
"user@example.com"
],
"onboarding_state": {},
"onboarding": {
"steps": {},
"progress": {
"completed": 0,
"total": 0
}
},
"domain_verified": true,
"can_send": true,
"byo_routing": {
"mismatch": true,
"provider": "string",
"bypassing_domains": [
"string"
],
"message": "string"
},
"subscribed_contacts_count": 0,
"using_sandbox": true,
"sandbox_email": "string",
"sandbox_monthly_cap": 0,
"sandbox_sends_remaining": 0,
"capabilities": {},
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}
],
"team": {
"seat_limit": 0,
"seat_count": 0,
"member_count": 0,
"invite_count": 0,
"current_role": "string",
"can_manage_team": true
},
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}List accessible accounts (paginated)
Parameters
pageinteger1queryperinteger<= 100100queryResponse
Accessible accounts
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/accounts'const response = await fetch('https://api.nitrosend.com/v1/my/accounts', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/accounts')
data = response.json()[
{
"id": 0,
"name": "string",
"avatar": "string",
"banner": "string",
"account_tier": "free",
"safe_mode_enabled": true,
"billing": {
"plan_name": "string",
"overage": {},
"resources": {
"email": {
"used": 0,
"allowance": 0,
"remaining": 0,
"overage_rate": 0
},
"sms": {
"used": 0,
"allowance": 0,
"remaining": 0,
"overage_rate": 0
},
"ai": {
"used": 0,
"allowance": 0,
"remaining": 0,
"overage_rate": 0
}
},
"brands": {
"used": 0,
"limit": 0,
"remaining": 0,
"unlimited": true,
"can_create": true
},
"lifetime": {
"email_sent": 0,
"sms_sent": 0,
"ai_used": 0
}
},
"brands": [
{
"id": 0,
"sid": "string",
"account_id": 0,
"brand_color": "string",
"text_color": "string",
"bg_color": "string",
"radius": 0,
"spacing_density": "compact",
"font_heading": "string",
"font_body": "string",
"brand_document": "string",
"style_notes": "string",
"tone": "string",
"company_description": "string",
"industry": "string",
"example_copy": [
"string"
],
"default_header": {},
"default_footer": {},
"default_theme": {},
"physical_address": "string",
"company_name": "string",
"source_url": "string",
"last_scraped_at": "2024-01-15T09:30:00Z",
"links": [
{
"url": "string",
"icon": "string",
"title": "string"
}
],
"logo": "string",
"complete": true,
"email_from_name": "string",
"email_from_email": "string",
"email_reply_to": "string",
"email_view_online": true,
"test_email_recipients": [
"user@example.com"
],
"onboarding_state": {},
"onboarding": {
"steps": {},
"progress": {
"completed": 0,
"total": 0
}
},
"domain_verified": true,
"can_send": true,
"byo_routing": {
"mismatch": true,
"provider": "string",
"bypassing_domains": [
"string"
],
"message": "string"
},
"subscribed_contacts_count": 0,
"using_sandbox": true,
"sandbox_email": "string",
"sandbox_monthly_cap": 0,
"sandbox_sends_remaining": 0,
"capabilities": {},
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}
],
"team": {
"seat_limit": 0,
"seat_count": 0,
"member_count": 0,
"invite_count": 0,
"current_role": "string",
"can_manage_team": true
},
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}
]Get team metadata for the current account
Response
Team metadata
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/account/team'const response = await fetch('https://api.nitrosend.com/v1/my/account/team', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/account/team')
data = response.json(){
"account": {
"id": 0,
"name": "string",
"avatar": "string",
"banner": "string",
"account_tier": "free",
"safe_mode_enabled": true,
"billing": {
"plan_name": "string",
"overage": {},
"resources": {
"email": {
"used": 0,
"allowance": 0,
"remaining": 0,
"overage_rate": 0
},
"sms": {
"used": 0,
"allowance": 0,
"remaining": 0,
"overage_rate": 0
},
"ai": {
"used": 0,
"allowance": 0,
"remaining": 0,
"overage_rate": 0
}
},
"brands": {
"used": 0,
"limit": 0,
"remaining": 0,
"unlimited": true,
"can_create": true
},
"lifetime": {
"email_sent": 0,
"sms_sent": 0,
"ai_used": 0
}
},
"brands": [
{
"id": 0,
"sid": "string",
"account_id": 0,
"brand_color": "string",
"text_color": "string",
"bg_color": "string",
"radius": 0,
"spacing_density": "compact",
"font_heading": "string",
"font_body": "string",
"brand_document": "string",
"style_notes": "string",
"tone": "string",
"company_description": "string",
"industry": "string",
"example_copy": [
"string"
],
"default_header": {},
"default_footer": {},
"default_theme": {},
"physical_address": "string",
"company_name": "string",
"source_url": "string",
"last_scraped_at": "2024-01-15T09:30:00Z",
"links": [
{
"url": "string",
"icon": "string",
"title": "string"
}
],
"logo": "string",
"complete": true,
"email_from_name": "string",
"email_from_email": "string",
"email_reply_to": "string",
"email_view_online": true,
"test_email_recipients": [
"user@example.com"
],
"onboarding_state": {},
"onboarding": {
"steps": {},
"progress": {
"completed": 0,
"total": 0
}
},
"domain_verified": true,
"can_send": true,
"byo_routing": {
"mismatch": true,
"provider": "string",
"bypassing_domains": [
"string"
],
"message": "string"
},
"subscribed_contacts_count": 0,
"using_sandbox": true,
"sandbox_email": "string",
"sandbox_monthly_cap": 0,
"sandbox_sends_remaining": 0,
"capabilities": {},
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}
],
"team": {
"seat_limit": 0,
"seat_count": 0,
"member_count": 0,
"invite_count": 0,
"current_role": "string",
"can_manage_team": true
},
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
},
"memberships": [
{
"id": 0,
"role": "member",
"user_id": 0,
"email": "user@example.com",
"name": "string",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}
],
"invites": [
{
"id": 0,
"account_id": 0,
"email": "user@example.com",
"role": "member",
"token": "string",
"status": "pending",
"accepted_at": "2024-01-15T09:30:00Z",
"revoked_at": "2024-01-15T09:30:00Z",
"expires_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}
],
"accessible_accounts": [
{
"id": 0,
"name": "string",
"avatar": "string",
"banner": "string",
"account_tier": "free",
"safe_mode_enabled": true,
"billing": {
"plan_name": "string",
"overage": {},
"resources": {
"email": {
"used": 0,
"allowance": 0,
"remaining": 0,
"overage_rate": 0
},
"sms": {
"used": 0,
"allowance": 0,
"remaining": 0,
"overage_rate": 0
},
"ai": {
"used": 0,
"allowance": 0,
"remaining": 0,
"overage_rate": 0
}
},
"brands": {
"used": 0,
"limit": 0,
"remaining": 0,
"unlimited": true,
"can_create": true
},
"lifetime": {
"email_sent": 0,
"sms_sent": 0,
"ai_used": 0
}
},
"brands": [
{
"id": 0,
"sid": "string",
"account_id": 0,
"brand_color": "string",
"text_color": "string",
"bg_color": "string",
"radius": 0,
"spacing_density": "compact",
"font_heading": "string",
"font_body": "string",
"brand_document": "string",
"style_notes": "string",
"tone": "string",
"company_description": "string",
"industry": "string",
"example_copy": [
"string"
],
"default_header": {},
"default_footer": {},
"default_theme": {},
"physical_address": "string",
"company_name": "string",
"source_url": "string",
"last_scraped_at": "2024-01-15T09:30:00Z",
"links": [
{
"url": "string",
"icon": "string",
"title": "string"
}
],
"logo": "string",
"complete": true,
"email_from_name": "string",
"email_from_email": "string",
"email_reply_to": "string",
"email_view_online": true,
"test_email_recipients": [
"user@example.com"
],
"onboarding_state": {},
"onboarding": {
"steps": {},
"progress": {
"completed": 0,
"total": 0
}
},
"domain_verified": true,
"can_send": true,
"byo_routing": {
"mismatch": true,
"provider": "string",
"bypassing_domains": [
"string"
],
"message": "string"
},
"subscribed_contacts_count": 0,
"using_sandbox": true,
"sandbox_email": "string",
"sandbox_monthly_cap": 0,
"sandbox_sends_remaining": 0,
"capabilities": {},
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}
],
"team": {
"seat_limit": 0,
"seat_count": 0,
"member_count": 0,
"invite_count": 0,
"current_role": "string",
"can_manage_team": true
},
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}
]
}List account memberships (paginated)
Parameters
pageinteger1queryperinteger<= 100100queryResponse
Memberships
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/account/memberships'const response = await fetch('https://api.nitrosend.com/v1/my/account/memberships', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/account/memberships')
data = response.json()[
{
"id": 0,
"role": "member",
"user_id": 0,
"email": "user@example.com",
"name": "string",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}
]Remove a membership
Parameters
idintegerrequiredpathResponse
Removed membership
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X DELETE 'https://api.nitrosend.com/v1/my/account/memberships/{id}'const response = await fetch('https://api.nitrosend.com/v1/my/account/memberships/{id}', {
method: 'DELETE',
});
const data = await response.json();import requests
response = requests.delete('https://api.nitrosend.com/v1/my/account/memberships/{id}')
data = response.json(){
"id": 0,
"role": "member",
"user_id": 0,
"email": "user@example.com",
"name": "string",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}Update a membership role
Body
rolestringmemberadminParameters
idintegerrequiredpathResponse
Updated membership
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X PATCH 'https://api.nitrosend.com/v1/my/account/memberships/{id}' \
-H 'Content-Type: application/json' \
-d '{
"role": "member"
}'const response = await fetch('https://api.nitrosend.com/v1/my/account/memberships/{id}', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"role": "member"
}),
});
const data = await response.json();import requests
payload = {
"role": "member"
}
response = requests.patch('https://api.nitrosend.com/v1/my/account/memberships/{id}', json=payload)
data = response.json(){
"role": "member"
}{
"id": 0,
"role": "member",
"user_id": 0,
"email": "user@example.com",
"name": "string",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}List account invites (paginated)
Parameters
pageinteger1queryperinteger<= 100100queryResponse
Invites
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/account/invites'const response = await fetch('https://api.nitrosend.com/v1/my/account/invites', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/account/invites')
data = response.json()[
{
"id": 0,
"account_id": 0,
"email": "user@example.com",
"role": "member",
"token": "string",
"status": "pending",
"accepted_at": "2024-01-15T09:30:00Z",
"revoked_at": "2024-01-15T09:30:00Z",
"expires_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}
]Create an account invite
Body
emailstring<email>requiredrolestringmemberadminResponse
Created invite
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X POST 'https://api.nitrosend.com/v1/my/account/invites' \
-H 'Content-Type: application/json' \
-d '{
"email": "user@example.com",
"role": "member"
}'const response = await fetch('https://api.nitrosend.com/v1/my/account/invites', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"email": "user@example.com",
"role": "member"
}),
});
const data = await response.json();import requests
payload = {
"email": "user@example.com",
"role": "member"
}
response = requests.post('https://api.nitrosend.com/v1/my/account/invites', json=payload)
data = response.json(){
"email": "user@example.com",
"role": "member"
}{
"id": 0,
"account_id": 0,
"email": "user@example.com",
"role": "member",
"token": "string",
"status": "pending",
"accepted_at": "2024-01-15T09:30:00Z",
"revoked_at": "2024-01-15T09:30:00Z",
"expires_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}Revoke an invite
Parameters
idintegerrequiredpathResponse
Revoked invite
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X DELETE 'https://api.nitrosend.com/v1/my/account/invites/{id}'const response = await fetch('https://api.nitrosend.com/v1/my/account/invites/{id}', {
method: 'DELETE',
});
const data = await response.json();import requests
response = requests.delete('https://api.nitrosend.com/v1/my/account/invites/{id}')
data = response.json(){
"id": 0,
"account_id": 0,
"email": "user@example.com",
"role": "member",
"token": "string",
"status": "pending",
"accepted_at": "2024-01-15T09:30:00Z",
"revoked_at": "2024-01-15T09:30:00Z",
"expires_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}Accept an invite token
Parameters
idstringrequiredpathResponse
Accepted invite
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X POST 'https://api.nitrosend.com/v1/my/account/invites/{id}/accept'const response = await fetch('https://api.nitrosend.com/v1/my/account/invites/{id}/accept', {
method: 'POST',
});
const data = await response.json();import requests
response = requests.post('https://api.nitrosend.com/v1/my/account/invites/{id}/accept')
data = response.json(){
"id": 0,
"account_id": 0,
"email": "user@example.com",
"role": "member",
"token": "string",
"status": "pending",
"accepted_at": "2024-01-15T09:30:00Z",
"revoked_at": "2024-01-15T09:30:00Z",
"expires_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}Billing
Subscription billing and checkout
Create a subscription
Body
plan_idintegerrequiredstripe_tokenstring | nullStripe card token for paid-plan creation.
coupon_codestring | nullCustomer-entered Stripe promotion code or coupon ID.
Response
Subscription created
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X POST 'https://api.nitrosend.com/v1/my/subscription' \
-H 'Content-Type: application/json' \
-d '{
"plan_id": 0,
"stripe_token": "string",
"coupon_code": "string"
}'const response = await fetch('https://api.nitrosend.com/v1/my/subscription', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"plan_id": 0,
"stripe_token": "string",
"coupon_code": "string"
}),
});
const data = await response.json();import requests
payload = {
"plan_id": 0,
"stripe_token": "string",
"coupon_code": "string"
}
response = requests.post('https://api.nitrosend.com/v1/my/subscription', json=payload)
data = response.json(){
"plan_id": 0,
"stripe_token": "string",
"coupon_code": "string"
}{
"id": 0,
"plan_id": 0,
"plan_name": "string",
"status": "pending",
"interval": "month",
"currency": "string",
"subtotal_cents": 0,
"tax_cents": 0,
"total_cents": 0,
"base_price_cents": 0,
"discount_cents": 0,
"next_payment_cents": 0,
"discount_end_at": "2024-01-15T09:30:00Z",
"activated": true
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}Change the current subscription plan
Body
plan_idintegerrequiredcoupon_codestring | nullCustomer-entered Stripe promotion code or coupon ID.
Response
Subscription updated
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X PUT 'https://api.nitrosend.com/v1/my/subscription/change' \
-H 'Content-Type: application/json' \
-d '{
"plan_id": 0,
"coupon_code": "string"
}'const response = await fetch('https://api.nitrosend.com/v1/my/subscription/change', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"plan_id": 0,
"coupon_code": "string"
}),
});
const data = await response.json();import requests
payload = {
"plan_id": 0,
"coupon_code": "string"
}
response = requests.put('https://api.nitrosend.com/v1/my/subscription/change', json=payload)
data = response.json(){
"plan_id": 0,
"coupon_code": "string"
}{
"id": 0,
"plan_id": 0,
"plan_name": "string",
"status": "pending",
"interval": "month",
"currency": "string",
"subtotal_cents": 0,
"tax_cents": 0,
"total_cents": 0,
"base_price_cents": 0,
"discount_cents": 0,
"next_payment_cents": 0,
"discount_end_at": "2024-01-15T09:30:00Z",
"activated": true
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}Preview a promotion code or coupon for a subscription plan
Validates a customer-entered Stripe promotion code or coupon ID against
a paid plan and returns display totals for the checkout summary. The
final subscription create/change request must still send coupon_code;
preview data is not trusted as payment input.
Body
plan_idintegerrequiredcoupon_codestringrequiredCustomer-entered Stripe promotion code or coupon ID.
Response
Coupon preview
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X POST 'https://api.nitrosend.com/v1/my/subscription/coupon_preview' \
-H 'Content-Type: application/json' \
-d '{
"plan_id": 0,
"coupon_code": "string"
}'const response = await fetch('https://api.nitrosend.com/v1/my/subscription/coupon_preview', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"plan_id": 0,
"coupon_code": "string"
}),
});
const data = await response.json();import requests
payload = {
"plan_id": 0,
"coupon_code": "string"
}
response = requests.post('https://api.nitrosend.com/v1/my/subscription/coupon_preview', json=payload)
data = response.json(){
"plan_id": 0,
"coupon_code": "string"
}{
"code": "string",
"discount_label": "string",
"discount_cents": 0,
"subtotal_cents": 0,
"tax_cents": 0,
"total_cents": 0,
"total_after_discount_cents": 0,
"currency": "string"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}Contacts
Contact management
List contacts (paginated)
Parameters
pageinteger1querylimitinteger<= 10050querysearchstringqueryFull-text search across name, email, phone
filtersSegmentFilterExpressionqueryCanonical structured audience filters from the registry exposed by
/v1/my/flows/spec and nitro://schema. search remains a separate
full-text lookup; filters are applied through the same fail-closed
validator used for segments.
list_idintegerqueryLegacy shortcut for a contact_list in [id] filter.
tagstringqueryLegacy shortcut for a contact_tag eq tag filter. Tags are stored
as an array of strings under data.tags. For richer tag targeting,
use canonical filters.
sortstringcreated_atemails_sentunique_opensclicksopen_rateclick_ratelast_opened_atlast_clicked_atratingqueryColumn to sort by. created_at orders by the contact's creation date;
the rest are the per-contact engagement rollup fields (see
Contact.engagement). Contacts with no rollup row always sort last.
Any unrecognised value falls back to the default newest-first order.
directionstringascdescdescquerySort direction. Only applies when sort is set.
Response
Paginated contacts
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/contacts'const response = await fetch('https://api.nitrosend.com/v1/my/contacts', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/contacts')
data = response.json()[
{
"id": 0,
"brand_id": 0,
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"first_name": "string",
"last_name": "string",
"source": "string",
"country_code": "string",
"flag_emoji": "string",
"data": {
"tags": [
"vip",
"newsletter"
],
"plan": "pro"
},
"subscribed_phone": true,
"subscribed_email": true,
"email": "user@example.com",
"subscribed": {
"email": true,
"phone": true
},
"verification_status": "verified",
"enrichment_status": "enriched",
"mailbox_provider": "gmail",
"list_ids": [
0
],
"last_interacted_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z",
"engagement": {
"rating": "engaged",
"emails_sent": 0,
"unique_opens": 0,
"clicks": 0,
"open_rate": 0,
"click_rate": 0,
"last_opened_at": "2024-01-15T09:30:00Z",
"last_clicked_at": "2024-01-15T09:30:00Z"
},
"channels": [
{
"id": 0,
"contact_id": 0,
"kind": "email",
"value": "string",
"subscribed": true,
"verified": true,
"opt_in_at": "2024-01-15T09:30:00Z",
"opt_out_at": "2024-01-15T09:30:00Z",
"sent_count": 0,
"fail_count": 0,
"data": {},
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}
]
}
]Create a contact
Body
first_namestringlast_namestringemailstring<email>Normalized to lowercase. If the submitted identifiers resolve cleanly to one existing contact in this brand, that contact is updated (200) instead of duplicated. If email and phone identify different contacts in this brand, the request is rejected (422). Creates/updates the email channel with opt_in.
phonestringE.164 format. Creates/updates phone channel with opt_in
sourcestringcountry_codestringlist_idsArray<integer>dataobjectCustom key-value data. The reserved key tags holds an
array of string labels used for segmentation, e.g.
{"tags": ["vip", "newsletter"]}.
Merge-on-resolve behavior (create path only): when the
submitted email or phone resolves cleanly to an existing
contact, data is merged into the contact's existing data
rather than replaced. Blank incoming values are ignored;
caller-supplied non-reserved keys overwrite their
counterparts; the reserved enrichment keys apollo, pdl,
attio, hubspot, stripe, shopify, and nitro are
preserved from the stored contact;
and tags from both sides are unioned. The update endpoint
(PATCH /v1/my/contacts/{id}) replaces data wholesale
instead.
channels_attributesArray<object>Response
Existing contact updated in place. Returned when the submitted email and/or phone resolves cleanly to one existing contact in this brand.
Contact created
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X POST 'https://api.nitrosend.com/v1/my/contacts' \
-H 'Content-Type: application/json' \
-d '{
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"phone": "string",
"source": "string",
"country_code": "string",
"list_ids": [
0
],
"data": {
"tags": [
"vip",
"newsletter"
],
"plan": "pro"
},
"channels_attributes": [
{
"kind": "email",
"value": "string",
"subscribed": true
}
]
}'const response = await fetch('https://api.nitrosend.com/v1/my/contacts', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"phone": "string",
"source": "string",
"country_code": "string",
"list_ids": [
0
],
"data": {
"tags": [
"vip",
"newsletter"
],
"plan": "pro"
},
"channels_attributes": [
{
"kind": "email",
"value": "string",
"subscribed": true
}
]
}),
});
const data = await response.json();import requests
payload = {
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"phone": "string",
"source": "string",
"country_code": "string",
"list_ids": [
0
],
"data": {
"tags": [
"vip",
"newsletter"
],
"plan": "pro"
},
"channels_attributes": [
{
"kind": "email",
"value": "string",
"subscribed": True
}
]
}
response = requests.post('https://api.nitrosend.com/v1/my/contacts', json=payload)
data = response.json(){
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"phone": "string",
"source": "string",
"country_code": "string",
"list_ids": [
0
],
"data": {
"tags": [
"vip",
"newsletter"
],
"plan": "pro"
},
"channels_attributes": [
{
"kind": "email",
"value": "string",
"subscribed": true
}
]
}{
"id": 0,
"brand_id": 0,
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"first_name": "string",
"last_name": "string",
"source": "string",
"country_code": "string",
"flag_emoji": "string",
"data": {
"tags": [
"vip",
"newsletter"
],
"plan": "pro"
},
"subscribed_phone": true,
"subscribed_email": true,
"email": "user@example.com",
"subscribed": {
"email": true,
"phone": true
},
"verification_status": "verified",
"enrichment_status": "enriched",
"mailbox_provider": "gmail",
"list_ids": [
0
],
"last_interacted_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z",
"engagement": {
"rating": "engaged",
"emails_sent": 0,
"unique_opens": 0,
"clicks": 0,
"open_rate": 0,
"click_rate": 0,
"last_opened_at": "2024-01-15T09:30:00Z",
"last_clicked_at": "2024-01-15T09:30:00Z"
},
"channels": [
{
"id": 0,
"contact_id": 0,
"kind": "email",
"value": "string",
"subscribed": true,
"verified": true,
"opt_in_at": "2024-01-15T09:30:00Z",
"opt_out_at": "2024-01-15T09:30:00Z",
"sent_count": 0,
"fail_count": 0,
"data": {},
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}
]
}{
"id": 0,
"brand_id": 0,
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"first_name": "string",
"last_name": "string",
"source": "string",
"country_code": "string",
"flag_emoji": "string",
"data": {
"tags": [
"vip",
"newsletter"
],
"plan": "pro"
},
"subscribed_phone": true,
"subscribed_email": true,
"email": "user@example.com",
"subscribed": {
"email": true,
"phone": true
},
"verification_status": "verified",
"enrichment_status": "enriched",
"mailbox_provider": "gmail",
"list_ids": [
0
],
"last_interacted_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z",
"engagement": {
"rating": "engaged",
"emails_sent": 0,
"unique_opens": 0,
"clicks": 0,
"open_rate": 0,
"click_rate": 0,
"last_opened_at": "2024-01-15T09:30:00Z",
"last_clicked_at": "2024-01-15T09:30:00Z"
},
"channels": [
{
"id": 0,
"contact_id": 0,
"kind": "email",
"value": "string",
"subscribed": true,
"verified": true,
"opt_in_at": "2024-01-15T09:30:00Z",
"opt_out_at": "2024-01-15T09:30:00Z",
"sent_count": 0,
"fail_count": 0,
"data": {},
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}
]
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}Get a contact
Parameters
idintegerrequiredpathResponse
Contact with channels
Resource not found
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/contacts/{id}'const response = await fetch('https://api.nitrosend.com/v1/my/contacts/{id}', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/contacts/{id}')
data = response.json(){
"id": 0,
"brand_id": 0,
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"first_name": "string",
"last_name": "string",
"source": "string",
"country_code": "string",
"flag_emoji": "string",
"data": {
"tags": [
"vip",
"newsletter"
],
"plan": "pro"
},
"subscribed_phone": true,
"subscribed_email": true,
"email": "user@example.com",
"subscribed": {
"email": true,
"phone": true
},
"verification_status": "verified",
"enrichment_status": "enriched",
"mailbox_provider": "gmail",
"list_ids": [
0
],
"last_interacted_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z",
"engagement": {
"rating": "engaged",
"emails_sent": 0,
"unique_opens": 0,
"clicks": 0,
"open_rate": 0,
"click_rate": 0,
"last_opened_at": "2024-01-15T09:30:00Z",
"last_clicked_at": "2024-01-15T09:30:00Z"
},
"channels": [
{
"id": 0,
"contact_id": 0,
"kind": "email",
"value": "string",
"subscribed": true,
"verified": true,
"opt_in_at": "2024-01-15T09:30:00Z",
"opt_out_at": "2024-01-15T09:30:00Z",
"sent_count": 0,
"fail_count": 0,
"data": {},
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}
]
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}Delete a contact
Parameters
idintegerrequiredpathResponse
Deleted contact
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X DELETE 'https://api.nitrosend.com/v1/my/contacts/{id}'const response = await fetch('https://api.nitrosend.com/v1/my/contacts/{id}', {
method: 'DELETE',
});
const data = await response.json();import requests
response = requests.delete('https://api.nitrosend.com/v1/my/contacts/{id}')
data = response.json(){
"id": 0,
"brand_id": 0,
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"first_name": "string",
"last_name": "string",
"source": "string",
"country_code": "string",
"flag_emoji": "string",
"data": {
"tags": [
"vip",
"newsletter"
],
"plan": "pro"
},
"subscribed_phone": true,
"subscribed_email": true,
"email": "user@example.com",
"subscribed": {
"email": true,
"phone": true
},
"verification_status": "verified",
"enrichment_status": "enriched",
"mailbox_provider": "gmail",
"list_ids": [
0
],
"last_interacted_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z",
"engagement": {
"rating": "engaged",
"emails_sent": 0,
"unique_opens": 0,
"clicks": 0,
"open_rate": 0,
"click_rate": 0,
"last_opened_at": "2024-01-15T09:30:00Z",
"last_clicked_at": "2024-01-15T09:30:00Z"
},
"channels": [
{
"id": 0,
"contact_id": 0,
"kind": "email",
"value": "string",
"subscribed": true,
"verified": true,
"opt_in_at": "2024-01-15T09:30:00Z",
"opt_out_at": "2024-01-15T09:30:00Z",
"sent_count": 0,
"fail_count": 0,
"data": {},
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}
]
}Update a contact
Body
first_namestringlast_namestringemailstring<email>Changing the email to one already owned by a different contact in the brand is rejected (422).
phonestringsourcestringcountry_codestringlist_idsArray<integer>dataobjectCustom key-value data. The reserved key tags holds an
array of string labels used for segmentation — e.g.
{"tags": ["vip", "newsletter"]}.
The data object is replaced wholesale on update.
Sending a partial data hash will overwrite any other
keys currently stored (e.g. data.plan, enrichment
metadata). Reserved enrichment namespaces include apollo,
pdl, attio, hubspot, stripe, shopify, and derived
nitro. To change a single key, GET the contact, merge
your change into the existing data, then PATCH the full
merged object back. For add/remove tag semantics across
many contacts, use the nitro_manage_audience MCP tool
with operation: "bulk_tag".
channels_attributesArray<object>Parameters
idintegerrequiredpathResponse
Updated contact
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X PATCH 'https://api.nitrosend.com/v1/my/contacts/{id}' \
-H 'Content-Type: application/json' \
-d '{
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"phone": "string",
"source": "string",
"country_code": "string",
"list_ids": [
0
],
"data": {
"tags": [
"vip",
"newsletter"
],
"plan": "pro"
},
"channels_attributes": [
{
"id": 0,
"kind": "email",
"value": "string",
"subscribed": true,
"_destroy": true
}
]
}'const response = await fetch('https://api.nitrosend.com/v1/my/contacts/{id}', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"phone": "string",
"source": "string",
"country_code": "string",
"list_ids": [
0
],
"data": {
"tags": [
"vip",
"newsletter"
],
"plan": "pro"
},
"channels_attributes": [
{
"id": 0,
"kind": "email",
"value": "string",
"subscribed": true,
"_destroy": true
}
]
}),
});
const data = await response.json();import requests
payload = {
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"phone": "string",
"source": "string",
"country_code": "string",
"list_ids": [
0
],
"data": {
"tags": [
"vip",
"newsletter"
],
"plan": "pro"
},
"channels_attributes": [
{
"id": 0,
"kind": "email",
"value": "string",
"subscribed": True,
"_destroy": True
}
]
}
response = requests.patch('https://api.nitrosend.com/v1/my/contacts/{id}', json=payload)
data = response.json(){
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"phone": "string",
"source": "string",
"country_code": "string",
"list_ids": [
0
],
"data": {
"tags": [
"vip",
"newsletter"
],
"plan": "pro"
},
"channels_attributes": [
{
"id": 0,
"kind": "email",
"value": "string",
"subscribed": true,
"_destroy": true
}
]
}{
"id": 0,
"brand_id": 0,
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"first_name": "string",
"last_name": "string",
"source": "string",
"country_code": "string",
"flag_emoji": "string",
"data": {
"tags": [
"vip",
"newsletter"
],
"plan": "pro"
},
"subscribed_phone": true,
"subscribed_email": true,
"email": "user@example.com",
"subscribed": {
"email": true,
"phone": true
},
"verification_status": "verified",
"enrichment_status": "enriched",
"mailbox_provider": "gmail",
"list_ids": [
0
],
"last_interacted_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z",
"engagement": {
"rating": "engaged",
"emails_sent": 0,
"unique_opens": 0,
"clicks": 0,
"open_rate": 0,
"click_rate": 0,
"last_opened_at": "2024-01-15T09:30:00Z",
"last_clicked_at": "2024-01-15T09:30:00Z"
},
"channels": [
{
"id": 0,
"contact_id": 0,
"kind": "email",
"value": "string",
"subscribed": true,
"verified": true,
"opt_in_at": "2024-01-15T09:30:00Z",
"opt_out_at": "2024-01-15T09:30:00Z",
"sent_count": 0,
"fail_count": 0,
"data": {},
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}
]
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}Re-enrich a contact via email verification + Apollo
Queues the contact for email verification and Apollo enrichment. Consumes 2 validation allowance units. Requires the contact to have an email channel.
Parameters
idintegerrequiredpathResponse
Enrichment queued
Contact has no email or validation allowance exhausted
Not authenticated
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X POST 'https://api.nitrosend.com/v1/my/contacts/{id}/enrich'const response = await fetch('https://api.nitrosend.com/v1/my/contacts/{id}/enrich', {
method: 'POST',
});
const data = await response.json();import requests
response = requests.post('https://api.nitrosend.com/v1/my/contacts/{id}/enrich')
data = response.json(){
"id": 0,
"brand_id": 0,
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"first_name": "string",
"last_name": "string",
"source": "string",
"country_code": "string",
"flag_emoji": "string",
"data": {
"tags": [
"vip",
"newsletter"
],
"plan": "pro"
},
"subscribed_phone": true,
"subscribed_email": true,
"email": "user@example.com",
"subscribed": {
"email": true,
"phone": true
},
"verification_status": "verified",
"enrichment_status": "enriched",
"mailbox_provider": "gmail",
"list_ids": [
0
],
"last_interacted_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z",
"engagement": {
"rating": "engaged",
"emails_sent": 0,
"unique_opens": 0,
"clicks": 0,
"open_rate": 0,
"click_rate": 0,
"last_opened_at": "2024-01-15T09:30:00Z",
"last_clicked_at": "2024-01-15T09:30:00Z"
},
"channels": [
{
"id": 0,
"contact_id": 0,
"kind": "email",
"value": "string",
"subscribed": true,
"verified": true,
"opt_in_at": "2024-01-15T09:30:00Z",
"opt_out_at": "2024-01-15T09:30:00Z",
"sent_count": 0,
"fail_count": 0,
"data": {},
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}
]
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}Unified activity timeline for a contact
Read-only, keyset-paginated feed merging the contact's lifecycle
events and email activities into one chronological stream (newest
first). Entries are normalised and whitelisted — raw rows are never
exposed. Page using the cursor returned as next_cursor.
Parameters
idintegerrequiredpathcursorstringqueryOpaque keyset cursor from a prior next_cursor.
limitinteger<= 10025queryResponse
A page of timeline entries, newest first
Not authenticated
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/contacts/{id}/timeline'const response = await fetch('https://api.nitrosend.com/v1/my/contacts/{id}/timeline', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/contacts/{id}/timeline')
data = response.json(){
"entries": [
{
"id": "string",
"kind": "event",
"type": "string",
"title": "string",
"occurred_at": "2024-01-15T09:30:00Z",
"meta": {}
}
],
"next_cursor": "string"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}List the field catalog for this account
Returns the structured field catalog: one row per known field for this account,
with key, category, type, label, promotion state, and async fill-rate.
Fields are lazily registered the first time a key is seen (import, API write,
or enrichment). Use PATCH /v1/my/contacts/fields/:id to update promoted
or label.
Response
Field catalog rows ordered by category and label
Not authenticated
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/contacts/fields'const response = await fetch('https://api.nitrosend.com/v1/my/contacts/fields', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/contacts/fields')
data = response.json()[
{
"id": 0,
"key": "string",
"category": "contact",
"field_type": "string",
"label": "string",
"promoted": true,
"fill_rate": "75.0",
"fill_rate_refreshed_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}
]{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}Update a field catalog row (owner/admin only)
Updates the promoted flag and/or the human-readable label for a field
catalog row. Restricted to account owners and admins. The key, category,
and field_type of a row are immutable.
Body
promotedbooleanPin this field as a default column in the contacts grid.
labelstringOverride the human-readable label for this field.
Parameters
idintegerrequiredpathResponse
Updated field catalog row
Not authenticated
Not authorized
Resource not found
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X PATCH 'https://api.nitrosend.com/v1/my/contacts/fields/{id}' \
-H 'Content-Type: application/json' \
-d '{
"promoted": true,
"label": "string"
}'const response = await fetch('https://api.nitrosend.com/v1/my/contacts/fields/{id}', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"promoted": true,
"label": "string"
}),
});
const data = await response.json();import requests
payload = {
"promoted": True,
"label": "string"
}
response = requests.patch('https://api.nitrosend.com/v1/my/contacts/fields/{id}', json=payload)
data = response.json(){
"promoted": true,
"label": "string"
}{
"id": 0,
"key": "string",
"category": "contact",
"field_type": "string",
"label": "string",
"promoted": true,
"fill_rate": "75.0",
"fill_rate_refreshed_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}Imports
Bulk CSV import jobs
Reserve a direct-upload blob
Creates an Active Storage direct-upload reservation and returns a
signed_id, presigned upload URL, and required upload headers. For CSV
imports, send purpose: import, PUT the file bytes to
direct_upload.url, then submit the returned signed_id to
POST /v1/my/imports. For image media assets, send purpose: image
or purpose: media_asset, PUT the image bytes to direct_upload.url,
then submit the returned signed_id to POST /v1/my/images.
Body
purposestringimportimagemedia_assetSet to import for CSV contact imports, or image/media_asset for image media assets.
blobobjectrequiredResponse
Direct-upload reservation
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X POST 'https://api.nitrosend.com/v1/direct_uploads' \
-H 'Content-Type: application/json' \
-d '{
"purpose": "import",
"blob": {
"filename": "contacts.csv",
"byte_size": 1048576,
"checksum": "string",
"content_type": "text/csv",
"metadata": {}
}
}'const response = await fetch('https://api.nitrosend.com/v1/direct_uploads', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"purpose": "import",
"blob": {
"filename": "contacts.csv",
"byte_size": 1048576,
"checksum": "string",
"content_type": "text/csv",
"metadata": {}
}
}),
});
const data = await response.json();import requests
payload = {
"purpose": "import",
"blob": {
"filename": "contacts.csv",
"byte_size": 1048576,
"checksum": "string",
"content_type": "text/csv",
"metadata": {}
}
}
response = requests.post('https://api.nitrosend.com/v1/direct_uploads', json=payload)
data = response.json(){
"purpose": "import",
"blob": {
"filename": "contacts.csv",
"byte_size": 1048576,
"checksum": "string",
"content_type": "text/csv",
"metadata": {}
}
}{
"signed_id": "string",
"filename": "string",
"byte_size": 0,
"content_type": "string",
"direct_upload": {
"url": "https://example.com",
"headers": {}
}
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}List import jobs
Parameters
pageinteger1querylimitinteger<= 10025queryResponse
Paginated import jobs
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/imports'const response = await fetch('https://api.nitrosend.com/v1/my/imports', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/imports')
data = response.json()[
{
"id": 0,
"resource": "contacts",
"parser": "default",
"status": "pending",
"total_rows": 0,
"success_rows": 0,
"failed_rows": 0,
"progress": {
"status": "pending",
"pct": 0,
"stages": [
{
"key": "string",
"label": "string",
"count": 0,
"state": "done"
}
]
},
"import_errors": [
[
0
]
],
"columns": {},
"options": {},
"assigned_list_ids": [
0
],
"assigned_lists": [
{
"id": 0,
"name": "string"
}
],
"guardrail": {
"tier": "auto",
"status": "ok",
"contact_us_ceiling": 250000,
"sends_held": true
},
"started_at": "2024-01-15T09:30:00Z",
"ended_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z"
}
]Start a CSV import
Enqueues an import job from an Active Storage direct-upload signed_id.
Create the blob through POST /v1/direct_uploads with purpose=import,
PUT the file to the returned direct-upload URL, then submit the returned
signed_id here. Poll GET /v1/my/imports/{id} for status, row counts, and row-level errors.
For contact imports, pass options as a JSON object or JSON string
with list_ids to assign imported contacts to one or more lists,
e.g. {"list_ids":[88]}.
Body
signed_idstringrequiredActive Storage blob signed ID returned by /v1/direct_uploads.
resourcestringcontactscontactsparserstringdefaultdefaultdry_runbooleanfalsecolumnsobject | stringCSV column mapping as a JSON object or JSON string.
optionsobject | stringImport options as a JSON object or JSON string.
Response
Import queued
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X POST 'https://api.nitrosend.com/v1/my/imports' \
-H 'Content-Type: application/json' \
-d '{
"signed_id": "string",
"resource": "contacts",
"parser": "default",
"dry_run": false,
"columns": {
"email": "Email",
"first_name": "First Name"
},
"options": {
"list_ids": [
88
]
}
}'const response = await fetch('https://api.nitrosend.com/v1/my/imports', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"signed_id": "string",
"resource": "contacts",
"parser": "default",
"dry_run": false,
"columns": {
"email": "Email",
"first_name": "First Name"
},
"options": {
"list_ids": [
88
]
}
}),
});
const data = await response.json();import requests
payload = {
"signed_id": "string",
"resource": "contacts",
"parser": "default",
"dry_run": False,
"columns": {
"email": "Email",
"first_name": "First Name"
},
"options": {
"list_ids": [
88
]
}
}
response = requests.post('https://api.nitrosend.com/v1/my/imports', json=payload)
data = response.json(){
"signed_id": "string",
"resource": "contacts",
"parser": "default",
"dry_run": false,
"columns": {
"email": "Email",
"first_name": "First Name"
},
"options": {
"list_ids": [
88
]
}
}{
"id": 0,
"resource": "contacts",
"parser": "default",
"status": "pending",
"total_rows": 0,
"success_rows": 0,
"failed_rows": 0,
"progress": {
"status": "pending",
"pct": 0,
"stages": [
{
"key": "string",
"label": "string",
"count": 0,
"state": "done"
}
]
},
"import_errors": [
[
0
]
],
"columns": {},
"options": {},
"assigned_list_ids": [
0
],
"assigned_lists": [
{
"id": 0,
"name": "string"
}
],
"guardrail": {
"tier": "auto",
"status": "ok",
"contact_us_ceiling": 250000,
"sends_held": true
},
"started_at": "2024-01-15T09:30:00Z",
"ended_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}Get import schema metadata
Parameters
resourcestringcontactsqueryOptional resource name. Omit to list all schemas.
Response
Import schema metadata
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/imports/spec'const response = await fetch('https://api.nitrosend.com/v1/my/imports/spec', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/imports/spec')
data = response.json(){
"resource": "contacts",
"parser": "default",
"ui": {},
"required_rules": {},
"fields": [
{}
],
"guardrails": {
"max_file_size_bytes": 94371840,
"max_file_size_mb": 90,
"auto_max_rows": 20000,
"contact_us_max_rows": 250000,
"max_active_imports": 3,
"create_rate_limit_per_minute": 10,
"direct_upload_rate_limit_per_minute": 30
}
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}Get import job status
Parameters
idintegerrequiredpathResponse
Import job with status, counts, and row errors
Resource not found
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/imports/{id}'const response = await fetch('https://api.nitrosend.com/v1/my/imports/{id}', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/imports/{id}')
data = response.json(){
"id": 0,
"resource": "contacts",
"parser": "default",
"status": "pending",
"total_rows": 0,
"success_rows": 0,
"failed_rows": 0,
"progress": {
"status": "pending",
"pct": 0,
"stages": [
{
"key": "string",
"label": "string",
"count": 0,
"state": "done"
}
]
},
"import_errors": [
[
0
]
],
"columns": {},
"options": {},
"assigned_list_ids": [
0
],
"assigned_lists": [
{
"id": 0,
"name": "string"
}
],
"guardrail": {
"tier": "auto",
"status": "ok",
"contact_us_ceiling": 250000,
"sends_held": true
},
"started_at": "2024-01-15T09:30:00Z",
"ended_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}Delete an import record
Parameters
idintegerrequiredpathResponse
Deleted import
Resource not found
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X DELETE 'https://api.nitrosend.com/v1/my/imports/{id}'const response = await fetch('https://api.nitrosend.com/v1/my/imports/{id}', {
method: 'DELETE',
});
const data = await response.json();import requests
response = requests.delete('https://api.nitrosend.com/v1/my/imports/{id}')
data = response.json(){
"id": 0,
"resource": "contacts",
"parser": "default",
"status": "pending",
"total_rows": 0,
"success_rows": 0,
"failed_rows": 0,
"progress": {
"status": "pending",
"pct": 0,
"stages": [
{
"key": "string",
"label": "string",
"count": 0,
"state": "done"
}
]
},
"import_errors": [
[
0
]
],
"columns": {},
"options": {},
"assigned_list_ids": [
0
],
"assigned_lists": [
{
"id": 0,
"name": "string"
}
],
"guardrail": {
"tier": "auto",
"status": "ok",
"contact_us_ceiling": 250000,
"sends_held": true
},
"started_at": "2024-01-15T09:30:00Z",
"ended_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}Cancel a pending or processing import
Parameters
idintegerrequiredpathResponse
Canceled import
Resource not found
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X POST 'https://api.nitrosend.com/v1/my/imports/{id}/cancel'const response = await fetch('https://api.nitrosend.com/v1/my/imports/{id}/cancel', {
method: 'POST',
});
const data = await response.json();import requests
response = requests.post('https://api.nitrosend.com/v1/my/imports/{id}/cancel')
data = response.json(){
"id": 0,
"resource": "contacts",
"parser": "default",
"status": "pending",
"total_rows": 0,
"success_rows": 0,
"failed_rows": 0,
"progress": {
"status": "pending",
"pct": 0,
"stages": [
{
"key": "string",
"label": "string",
"count": 0,
"state": "done"
}
]
},
"import_errors": [
[
0
]
],
"columns": {},
"options": {},
"assigned_list_ids": [
0
],
"assigned_lists": [
{
"id": 0,
"name": "string"
}
],
"guardrail": {
"tier": "auto",
"status": "ok",
"contact_us_ceiling": 250000,
"sends_held": true
},
"started_at": "2024-01-15T09:30:00Z",
"ended_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}Exports
Contact CSV export jobs
List export jobs
Parameters
pageinteger1querylimitinteger<= 10025queryResponse
Paginated export jobs
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/exports'const response = await fetch('https://api.nitrosend.com/v1/my/exports', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/exports')
data = response.json()[
{
"id": 0,
"resource": "contacts",
"format": "csv",
"status": "pending",
"total_rows": 0,
"rows_written": 0,
"error_message": "string",
"ready": true,
"download_path": "string",
"progress": {
"status": "pending",
"pct": 0,
"stages": [
{
"key": "string",
"label": "string",
"count": 0,
"state": "done"
}
]
},
"started_at": "2024-01-15T09:30:00Z",
"ended_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z"
}
]Start a contact export
Enqueues an export job that builds a CSV of the brand's contacts and
attaches it to the export record. The same filters as GET /v1/my/contacts are supported (search, list_id, tag). Custom
fields stored on contacts are emitted as additional CSV columns.
Poll GET /v1/my/exports/{id} until ready is true, then download
the file from the returned download_path.
Body
resourcestringcontactscontactssearchstringFree-text filter, matching the contacts list search.
list_idintegerRestrict the export to contacts in this list.
tagstringRestrict the export to contacts with this tag.
Response
Export queued
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X POST 'https://api.nitrosend.com/v1/my/exports' \
-H 'Content-Type: application/json' \
-d '{
"resource": "contacts",
"search": "string",
"list_id": 0,
"tag": "string"
}'const response = await fetch('https://api.nitrosend.com/v1/my/exports', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"resource": "contacts",
"search": "string",
"list_id": 0,
"tag": "string"
}),
});
const data = await response.json();import requests
payload = {
"resource": "contacts",
"search": "string",
"list_id": 0,
"tag": "string"
}
response = requests.post('https://api.nitrosend.com/v1/my/exports', json=payload)
data = response.json(){
"resource": "contacts",
"search": "string",
"list_id": 0,
"tag": "string"
}{
"id": 0,
"resource": "contacts",
"format": "csv",
"status": "pending",
"total_rows": 0,
"rows_written": 0,
"error_message": "string",
"ready": true,
"download_path": "string",
"progress": {
"status": "pending",
"pct": 0,
"stages": [
{
"key": "string",
"label": "string",
"count": 0,
"state": "done"
}
]
},
"started_at": "2024-01-15T09:30:00Z",
"ended_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}Get an export job
Parameters
idintegerrequiredpathResponse
Export job
Resource not found
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/exports/{id}'const response = await fetch('https://api.nitrosend.com/v1/my/exports/{id}', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/exports/{id}')
data = response.json(){
"id": 0,
"resource": "contacts",
"format": "csv",
"status": "pending",
"total_rows": 0,
"rows_written": 0,
"error_message": "string",
"ready": true,
"download_path": "string",
"progress": {
"status": "pending",
"pct": 0,
"stages": [
{
"key": "string",
"label": "string",
"count": 0,
"state": "done"
}
]
},
"started_at": "2024-01-15T09:30:00Z",
"ended_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}Download a completed export file
Returns the CSV file once the export status is complete.
Parameters
idintegerrequiredpathResponse
CSV file
Resource not found
Export is not ready
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/exports/{id}/download'const response = await fetch('https://api.nitrosend.com/v1/my/exports/{id}/download', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/exports/{id}/download')
data = response.json()"<binary>"{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}Lists
Contact lists
List contact lists (paginated)
Parameters
namestringqueryExact case-insensitive list name filter
pageinteger1querylimitinteger<= 10025queryResponse
Paginated contact lists
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/lists'const response = await fetch('https://api.nitrosend.com/v1/my/lists', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/lists')
data = response.json()[
{
"id": 0,
"account_id": 0,
"brand_id": 0,
"name": "string",
"contacts_count": 0,
"segment_id": 0,
"stale": true,
"last_populated_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}
]Create a contact list
Body
namestringrequiredsegment_idinteger | nullcontact_idsArray<integer>Response
List created
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X POST 'https://api.nitrosend.com/v1/my/lists' \
-H 'Content-Type: application/json' \
-d '{
"name": "string",
"segment_id": 0,
"contact_ids": [
0
]
}'const response = await fetch('https://api.nitrosend.com/v1/my/lists', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "string",
"segment_id": 0,
"contact_ids": [
0
]
}),
});
const data = await response.json();import requests
payload = {
"name": "string",
"segment_id": 0,
"contact_ids": [
0
]
}
response = requests.post('https://api.nitrosend.com/v1/my/lists', json=payload)
data = response.json(){
"name": "string",
"segment_id": 0,
"contact_ids": [
0
]
}{
"id": 0,
"account_id": 0,
"brand_id": 0,
"name": "string",
"contacts_count": 0,
"segment_id": 0,
"stale": true,
"last_populated_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}Get a contact list
Parameters
idintegerrequiredpathResponse
Contact list
Resource not found
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/lists/{id}'const response = await fetch('https://api.nitrosend.com/v1/my/lists/{id}', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/lists/{id}')
data = response.json(){
"id": 0,
"account_id": 0,
"brand_id": 0,
"name": "string",
"contacts_count": 0,
"segment_id": 0,
"stale": true,
"last_populated_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}Delete a contact list
Parameters
idintegerrequiredpathResponse
Deleted list
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X DELETE 'https://api.nitrosend.com/v1/my/lists/{id}'const response = await fetch('https://api.nitrosend.com/v1/my/lists/{id}', {
method: 'DELETE',
});
const data = await response.json();import requests
response = requests.delete('https://api.nitrosend.com/v1/my/lists/{id}')
data = response.json(){
"id": 0,
"account_id": 0,
"brand_id": 0,
"name": "string",
"contacts_count": 0,
"segment_id": 0,
"stale": true,
"last_populated_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}Update a contact list
Body
namestringsegment_idinteger | nullcontact_idsArray<integer>Parameters
idintegerrequiredpathResponse
Updated list
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X PATCH 'https://api.nitrosend.com/v1/my/lists/{id}' \
-H 'Content-Type: application/json' \
-d '{
"name": "string",
"segment_id": 0,
"contact_ids": [
0
]
}'const response = await fetch('https://api.nitrosend.com/v1/my/lists/{id}', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "string",
"segment_id": 0,
"contact_ids": [
0
]
}),
});
const data = await response.json();import requests
payload = {
"name": "string",
"segment_id": 0,
"contact_ids": [
0
]
}
response = requests.patch('https://api.nitrosend.com/v1/my/lists/{id}', json=payload)
data = response.json(){
"name": "string",
"segment_id": 0,
"contact_ids": [
0
]
}{
"id": 0,
"account_id": 0,
"brand_id": 0,
"name": "string",
"contacts_count": 0,
"segment_id": 0,
"stale": true,
"last_populated_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}Get delete warning metadata for a contact list
Parameters
idintegerrequiredpathResponse
Flows connected to this list
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/lists/{id}/delete_warning'const response = await fetch('https://api.nitrosend.com/v1/my/lists/{id}/delete_warning', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/lists/{id}/delete_warning')
data = response.json(){
"campaign_names": [
"string"
],
"flow_names": [
"string"
]
}Add or remove existing contacts from a list by email
Public REST equivalent of the list membership batch primitive. The
endpoint resolves existing contacts by email within the current brand
and adds or removes memberships idempotently. It does not create
contacts; emails with no current-brand contact are returned in
not_found.
Body
actionstringaddremoverequiredAdd existing contacts to the list or remove them from it.
emailsArray<string>requiredParameters
idintegerrequiredpathResponse
Bulk list membership result
Resource not found
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X POST 'https://api.nitrosend.com/v1/my/lists/{id}/contacts/bulk' \
-H 'Content-Type: application/json' \
-d '{
"action": "add",
"emails": [
"user@example.com"
]
}'const response = await fetch('https://api.nitrosend.com/v1/my/lists/{id}/contacts/bulk', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"action": "add",
"emails": [
"user@example.com"
]
}),
});
const data = await response.json();import requests
payload = {
"action": "add",
"emails": [
"user@example.com"
]
}
response = requests.post('https://api.nitrosend.com/v1/my/lists/{id}/contacts/bulk', json=payload)
data = response.json(){
"action": "add",
"emails": [
"user@example.com"
]
}{
"action": "add",
"list_id": 0,
"added": 0,
"removed": 0,
"already_in_list": [
"user@example.com"
],
"not_in_list": [
"user@example.com"
],
"not_found": [
"user@example.com"
],
"invalid_emails": [
"string"
]
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}Segments
Dynamic contact segments
List all segments (paginated)
Parameters
pageinteger1queryperinteger<= 100100queryResponse
Segments
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/segments'const response = await fetch('https://api.nitrosend.com/v1/my/segments', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/segments')
data = response.json()[]Create a segment
Body
namestringrequiredfiltersSegmentFilterExpressionResponse
Segment created
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X POST 'https://api.nitrosend.com/v1/my/segments' \
-H 'Content-Type: application/json' \
-d '{
"name": "string"
}'const response = await fetch('https://api.nitrosend.com/v1/my/segments', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "string"
}),
});
const data = await response.json();import requests
payload = {
"name": "string"
}
response = requests.post('https://api.nitrosend.com/v1/my/segments', json=payload)
data = response.json(){
"name": "string"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}Get a segment
Parameters
idintegerrequiredpathResponse
Segment
Resource not found
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/segments/{id}'const response = await fetch('https://api.nitrosend.com/v1/my/segments/{id}', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/segments/{id}')
data = response.json(){
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}Delete a segment
Parameters
idintegerrequiredpathResponse
Deleted segment
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X DELETE 'https://api.nitrosend.com/v1/my/segments/{id}'const response = await fetch('https://api.nitrosend.com/v1/my/segments/{id}', {
method: 'DELETE',
});
const data = await response.json();import requests
response = requests.delete('https://api.nitrosend.com/v1/my/segments/{id}')
data = response.json()Update a segment
Body
namestringfiltersSegmentFilterExpressionParameters
idintegerrequiredpathResponse
Updated segment
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X PATCH 'https://api.nitrosend.com/v1/my/segments/{id}' \
-H 'Content-Type: application/json' \
-d '{
"name": "string"
}'const response = await fetch('https://api.nitrosend.com/v1/my/segments/{id}', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "string"
}),
});
const data = await response.json();import requests
payload = {
"name": "string"
}
response = requests.patch('https://api.nitrosend.com/v1/my/segments/{id}', json=payload)
data = response.json(){
"name": "string"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}Count contacts matching filters
Preview how many contacts match a set of segment filters without creating or saving a segment.
Body
filtersSegmentFilterExpressionResponse
Contact count
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X POST 'https://api.nitrosend.com/v1/my/segments/count' \
-H 'Content-Type: application/json' \
-d '{}'const response = await fetch('https://api.nitrosend.com/v1/my/segments/count', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({}),
});
const data = await response.json();import requests
payload = {}
response = requests.post('https://api.nitrosend.com/v1/my/segments/count', json=payload)
data = response.json(){}{
"count": 0
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}Preview contacts matching filters
Preview a prospective segment without saving it. Returns a live count,
a bounded contact sample, and bounded overlap with existing segments.
Invalid filters fail closed with invalid_filter.
Body
filtersSegmentFilterExpressionResponse
Segment preview
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X POST 'https://api.nitrosend.com/v1/my/segments/preview' \
-H 'Content-Type: application/json' \
-d '{}'const response = await fetch('https://api.nitrosend.com/v1/my/segments/preview', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({}),
});
const data = await response.json();import requests
payload = {}
response = requests.post('https://api.nitrosend.com/v1/my/segments/preview', json=payload)
data = response.json(){}{
"count": 0,
"sample": [
{
"id": 0,
"email": "string",
"name": "string"
}
],
"overlap": [
{
"segment_id": 0,
"name": "string",
"overlap_count": 0
}
]
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}Campaigns
Email and SMS campaigns
List campaigns (paginated)
Parameters
pageinteger1querylimitinteger<= 10025queryResponse
Paginated campaigns
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/campaigns'const response = await fetch('https://api.nitrosend.com/v1/my/campaigns', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/campaigns')
data = response.json()[
{
"id": 0,
"account_id": 0,
"brand_id": 0,
"status": "draft",
"approval_state": "string",
"channel": "email",
"name": "string",
"data": {},
"scheduled_at": "2024-01-15T09:30:00Z",
"sent_count": 0,
"dashboard_url": "https://example.com",
"preview_url": "https://example.com",
"recipient_snapshot": {
"requested_recipients": 0,
"dispatched_recipients": 0,
"blocked_recipients": 0,
"requested_send_units": 0,
"dispatched_send_units": 0,
"units_per_recipient": 0,
"send_token": "string",
"started_at": "2024-01-15T09:30:00Z",
"completed_at": "2024-01-15T09:30:00Z"
},
"last_send_recipients": 0,
"delivery": {
"campaign_send_token": "string",
"status": "sending",
"recipients": 0,
"sent": 0,
"failed": 0,
"pending": 0
},
"engagement": {
"sent": 0,
"opens": 0,
"total_opens": 0,
"open_rate": 0,
"account": {
"sent": 0,
"opens": 0,
"total_opens": 0,
"open_rate": 0
}
},
"editable": true,
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z",
"trigger": {
"id": 0,
"flow_id": 0,
"event": "string",
"audience_type": "lists",
"segment_id": 0,
"contact_list_id": 0,
"contact_list_ids": [
0
],
"exclude_segment_ids": [
0
],
"exclude_contact_list_ids": [
0
],
"data": {},
"triggered_count": 0,
"last_triggered_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
},
"template": {
"id": 0,
"name": "string",
"flow_id": 0,
"action_id": 0,
"version": 0,
"subject": "string",
"body": "string",
"preheader": "string",
"from_name": "string",
"from_email": "string",
"reply_to": "string",
"design": {
"sections": [
{
"type": "header",
"props": {},
"styles": {
"background_color": "string",
"padding": "string",
"align": "left",
"font_size": 0,
"text_color": "string",
"border_radius": 0
}
}
],
"theme": {
"brand_color": "string",
"bg_color": "string",
"text_color": "string",
"font_body": "string",
"font_heading": "string",
"logo_url": "string"
}
},
"variables": {},
"generation_id": 0,
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
},
"templates": [
{
"id": 0,
"name": "string",
"flow_id": 0,
"action_id": 0,
"version": 0,
"subject": "string",
"body": "string",
"preheader": "string",
"from_name": "string",
"from_email": "string",
"reply_to": "string",
"design": {
"sections": [
{
"type": "header",
"props": {},
"styles": {
"background_color": "string",
"padding": "string",
"align": "left",
"font_size": 0,
"text_color": "string",
"border_radius": 0
}
}
],
"theme": {
"brand_color": "string",
"bg_color": "string",
"text_color": "string",
"font_body": "string",
"font_heading": "string",
"logo_url": "string"
}
},
"variables": {},
"generation_id": 0,
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}
]
}
]Create a campaign
Body
namestringrequiredchannelstringemailsmsemailResponse
Campaign created
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X POST 'https://api.nitrosend.com/v1/my/campaigns' \
-H 'Content-Type: application/json' \
-d '{
"name": "string",
"channel": "email"
}'const response = await fetch('https://api.nitrosend.com/v1/my/campaigns', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "string",
"channel": "email"
}),
});
const data = await response.json();import requests
payload = {
"name": "string",
"channel": "email"
}
response = requests.post('https://api.nitrosend.com/v1/my/campaigns', json=payload)
data = response.json(){
"name": "string",
"channel": "email"
}{
"id": 0,
"account_id": 0,
"brand_id": 0,
"status": "draft",
"approval_state": "string",
"channel": "email",
"name": "string",
"data": {},
"scheduled_at": "2024-01-15T09:30:00Z",
"sent_count": 0,
"dashboard_url": "https://example.com",
"preview_url": "https://example.com",
"recipient_snapshot": {
"requested_recipients": 0,
"dispatched_recipients": 0,
"blocked_recipients": 0,
"requested_send_units": 0,
"dispatched_send_units": 0,
"units_per_recipient": 0,
"send_token": "string",
"started_at": "2024-01-15T09:30:00Z",
"completed_at": "2024-01-15T09:30:00Z"
},
"last_send_recipients": 0,
"delivery": {
"campaign_send_token": "string",
"status": "sending",
"recipients": 0,
"sent": 0,
"failed": 0,
"pending": 0
},
"engagement": {
"sent": 0,
"opens": 0,
"total_opens": 0,
"open_rate": 0,
"account": {
"sent": 0,
"opens": 0,
"total_opens": 0,
"open_rate": 0
}
},
"editable": true,
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z",
"trigger": {
"id": 0,
"flow_id": 0,
"event": "string",
"audience_type": "lists",
"segment_id": 0,
"contact_list_id": 0,
"contact_list_ids": [
0
],
"exclude_segment_ids": [
0
],
"exclude_contact_list_ids": [
0
],
"data": {},
"triggered_count": 0,
"last_triggered_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
},
"template": {
"id": 0,
"name": "string",
"flow_id": 0,
"action_id": 0,
"version": 0,
"subject": "string",
"body": "string",
"preheader": "string",
"from_name": "string",
"from_email": "string",
"reply_to": "string",
"design": {
"sections": [
{
"type": "header",
"props": {},
"styles": {
"background_color": "string",
"padding": "string",
"align": "left",
"font_size": 0,
"text_color": "string",
"border_radius": 0
}
}
],
"theme": {
"brand_color": "string",
"bg_color": "string",
"text_color": "string",
"font_body": "string",
"font_heading": "string",
"logo_url": "string"
}
},
"variables": {},
"generation_id": 0,
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
},
"templates": [
{
"id": 0,
"name": "string",
"flow_id": 0,
"action_id": 0,
"version": 0,
"subject": "string",
"body": "string",
"preheader": "string",
"from_name": "string",
"from_email": "string",
"reply_to": "string",
"design": {
"sections": [
{
"type": "header",
"props": {},
"styles": {
"background_color": "string",
"padding": "string",
"align": "left",
"font_size": 0,
"text_color": "string",
"border_radius": 0
}
}
],
"theme": {
"brand_color": "string",
"bg_color": "string",
"text_color": "string",
"font_body": "string",
"font_heading": "string",
"logo_url": "string"
}
},
"variables": {},
"generation_id": 0,
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}
]
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}Get a campaign
Parameters
idintegerrequiredpathResponse
Campaign with trigger, template, and templates
Resource not found
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/campaigns/{id}'const response = await fetch('https://api.nitrosend.com/v1/my/campaigns/{id}', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/campaigns/{id}')
data = response.json(){
"id": 0,
"account_id": 0,
"brand_id": 0,
"status": "draft",
"approval_state": "string",
"channel": "email",
"name": "string",
"data": {},
"scheduled_at": "2024-01-15T09:30:00Z",
"sent_count": 0,
"dashboard_url": "https://example.com",
"preview_url": "https://example.com",
"recipient_snapshot": {
"requested_recipients": 0,
"dispatched_recipients": 0,
"blocked_recipients": 0,
"requested_send_units": 0,
"dispatched_send_units": 0,
"units_per_recipient": 0,
"send_token": "string",
"started_at": "2024-01-15T09:30:00Z",
"completed_at": "2024-01-15T09:30:00Z"
},
"last_send_recipients": 0,
"delivery": {
"campaign_send_token": "string",
"status": "sending",
"recipients": 0,
"sent": 0,
"failed": 0,
"pending": 0
},
"engagement": {
"sent": 0,
"opens": 0,
"total_opens": 0,
"open_rate": 0,
"account": {
"sent": 0,
"opens": 0,
"total_opens": 0,
"open_rate": 0
}
},
"editable": true,
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z",
"trigger": {
"id": 0,
"flow_id": 0,
"event": "string",
"audience_type": "lists",
"segment_id": 0,
"contact_list_id": 0,
"contact_list_ids": [
0
],
"exclude_segment_ids": [
0
],
"exclude_contact_list_ids": [
0
],
"data": {},
"triggered_count": 0,
"last_triggered_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
},
"template": {
"id": 0,
"name": "string",
"flow_id": 0,
"action_id": 0,
"version": 0,
"subject": "string",
"body": "string",
"preheader": "string",
"from_name": "string",
"from_email": "string",
"reply_to": "string",
"design": {
"sections": [
{
"type": "header",
"props": {},
"styles": {
"background_color": "string",
"padding": "string",
"align": "left",
"font_size": 0,
"text_color": "string",
"border_radius": 0
}
}
],
"theme": {
"brand_color": "string",
"bg_color": "string",
"text_color": "string",
"font_body": "string",
"font_heading": "string",
"logo_url": "string"
}
},
"variables": {},
"generation_id": 0,
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
},
"templates": [
{
"id": 0,
"name": "string",
"flow_id": 0,
"action_id": 0,
"version": 0,
"subject": "string",
"body": "string",
"preheader": "string",
"from_name": "string",
"from_email": "string",
"reply_to": "string",
"design": {
"sections": [
{
"type": "header",
"props": {},
"styles": {
"background_color": "string",
"padding": "string",
"align": "left",
"font_size": 0,
"text_color": "string",
"border_radius": 0
}
}
],
"theme": {
"brand_color": "string",
"bg_color": "string",
"text_color": "string",
"font_body": "string",
"font_heading": "string",
"logo_url": "string"
}
},
"variables": {},
"generation_id": 0,
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}
]
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}Delete a campaign
Parameters
idintegerrequiredpathResponse
Deleted campaign
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X DELETE 'https://api.nitrosend.com/v1/my/campaigns/{id}'const response = await fetch('https://api.nitrosend.com/v1/my/campaigns/{id}', {
method: 'DELETE',
});
const data = await response.json();import requests
response = requests.delete('https://api.nitrosend.com/v1/my/campaigns/{id}')
data = response.json(){
"id": 0,
"account_id": 0,
"brand_id": 0,
"status": "draft",
"approval_state": "string",
"channel": "email",
"name": "string",
"data": {},
"scheduled_at": "2024-01-15T09:30:00Z",
"sent_count": 0,
"dashboard_url": "https://example.com",
"preview_url": "https://example.com",
"recipient_snapshot": {
"requested_recipients": 0,
"dispatched_recipients": 0,
"blocked_recipients": 0,
"requested_send_units": 0,
"dispatched_send_units": 0,
"units_per_recipient": 0,
"send_token": "string",
"started_at": "2024-01-15T09:30:00Z",
"completed_at": "2024-01-15T09:30:00Z"
},
"last_send_recipients": 0,
"delivery": {
"campaign_send_token": "string",
"status": "sending",
"recipients": 0,
"sent": 0,
"failed": 0,
"pending": 0
},
"engagement": {
"sent": 0,
"opens": 0,
"total_opens": 0,
"open_rate": 0,
"account": {
"sent": 0,
"opens": 0,
"total_opens": 0,
"open_rate": 0
}
},
"editable": true,
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z",
"trigger": {
"id": 0,
"flow_id": 0,
"event": "string",
"audience_type": "lists",
"segment_id": 0,
"contact_list_id": 0,
"contact_list_ids": [
0
],
"exclude_segment_ids": [
0
],
"exclude_contact_list_ids": [
0
],
"data": {},
"triggered_count": 0,
"last_triggered_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
},
"template": {
"id": 0,
"name": "string",
"flow_id": 0,
"action_id": 0,
"version": 0,
"subject": "string",
"body": "string",
"preheader": "string",
"from_name": "string",
"from_email": "string",
"reply_to": "string",
"design": {
"sections": [
{
"type": "header",
"props": {},
"styles": {
"background_color": "string",
"padding": "string",
"align": "left",
"font_size": 0,
"text_color": "string",
"border_radius": 0
}
}
],
"theme": {
"brand_color": "string",
"bg_color": "string",
"text_color": "string",
"font_body": "string",
"font_heading": "string",
"logo_url": "string"
}
},
"variables": {},
"generation_id": 0,
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
},
"templates": [
{
"id": 0,
"name": "string",
"flow_id": 0,
"action_id": 0,
"version": 0,
"subject": "string",
"body": "string",
"preheader": "string",
"from_name": "string",
"from_email": "string",
"reply_to": "string",
"design": {
"sections": [
{
"type": "header",
"props": {},
"styles": {
"background_color": "string",
"padding": "string",
"align": "left",
"font_size": 0,
"text_color": "string",
"border_radius": 0
}
}
],
"theme": {
"brand_color": "string",
"bg_color": "string",
"text_color": "string",
"font_body": "string",
"font_heading": "string",
"logo_url": "string"
}
},
"variables": {},
"generation_id": 0,
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}
]
}Update a campaign
Updates the campaign. When the campaign is no longer editable (see the
editable field on the Campaign schema — false for live/paused/
completed/cancelled/archived, and for scheduled campaigns within 5
minutes of their send time), only name-only payloads and status
transitions (Resume, Cancel) are accepted. Any other attribute returns
422 with error_code: "campaign_locked". Use the /duplicate endpoint
to fork a sent campaign into a new draft.
Body
namestringstatusstringchannelstringemailsmsscheduled_atstring<date-time> | nulltrigger_attributesobjecttemplate_attributesobjectParameters
idintegerrequiredpathResponse
Updated campaign
Template version conflict
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X PATCH 'https://api.nitrosend.com/v1/my/campaigns/{id}' \
-H 'Content-Type: application/json' \
-d '{
"name": "string",
"status": "string",
"channel": "email",
"scheduled_at": "2024-01-15T09:30:00Z",
"trigger_attributes": {
"event": "string",
"audience_type": "lists",
"contact_list_id": 0,
"contact_list_ids": [
0
],
"segment_id": 0,
"exclude_segment_ids": [
0
],
"exclude_contact_list_ids": [
0
],
"data": {}
},
"template_attributes": {
"if_version": 0,
"subject": "string",
"body": "string",
"preheader": "string",
"from_name": "string",
"from_email": "user@example.com",
"reply_to": "user@example.com",
"design": {
"sections": [
{
"type": "header",
"props": {},
"styles": {
"background_color": "string",
"padding": "string",
"align": "left",
"font_size": 0,
"text_color": "string",
"border_radius": 0
}
}
],
"theme": {
"brand_color": "string",
"bg_color": "string",
"text_color": "string",
"font_body": "string",
"font_heading": "string",
"logo_url": "string"
}
}
}
}'const response = await fetch('https://api.nitrosend.com/v1/my/campaigns/{id}', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "string",
"status": "string",
"channel": "email",
"scheduled_at": "2024-01-15T09:30:00Z",
"trigger_attributes": {
"event": "string",
"audience_type": "lists",
"contact_list_id": 0,
"contact_list_ids": [
0
],
"segment_id": 0,
"exclude_segment_ids": [
0
],
"exclude_contact_list_ids": [
0
],
"data": {}
},
"template_attributes": {
"if_version": 0,
"subject": "string",
"body": "string",
"preheader": "string",
"from_name": "string",
"from_email": "user@example.com",
"reply_to": "user@example.com",
"design": {
"sections": [
{
"type": "header",
"props": {},
"styles": {
"background_color": "string",
"padding": "string",
"align": "left",
"font_size": 0,
"text_color": "string",
"border_radius": 0
}
}
],
"theme": {
"brand_color": "string",
"bg_color": "string",
"text_color": "string",
"font_body": "string",
"font_heading": "string",
"logo_url": "string"
}
}
}
}),
});
const data = await response.json();import requests
payload = {
"name": "string",
"status": "string",
"channel": "email",
"scheduled_at": "2024-01-15T09:30:00Z",
"trigger_attributes": {
"event": "string",
"audience_type": "lists",
"contact_list_id": 0,
"contact_list_ids": [
0
],
"segment_id": 0,
"exclude_segment_ids": [
0
],
"exclude_contact_list_ids": [
0
],
"data": {}
},
"template_attributes": {
"if_version": 0,
"subject": "string",
"body": "string",
"preheader": "string",
"from_name": "string",
"from_email": "user@example.com",
"reply_to": "user@example.com",
"design": {
"sections": [
{
"type": "header",
"props": {},
"styles": {
"background_color": "string",
"padding": "string",
"align": "left",
"font_size": 0,
"text_color": "string",
"border_radius": 0
}
}
],
"theme": {
"brand_color": "string",
"bg_color": "string",
"text_color": "string",
"font_body": "string",
"font_heading": "string",
"logo_url": "string"
}
}
}
}
response = requests.patch('https://api.nitrosend.com/v1/my/campaigns/{id}', json=payload)
data = response.json(){
"name": "string",
"status": "string",
"channel": "email",
"scheduled_at": "2024-01-15T09:30:00Z",
"trigger_attributes": {
"event": "string",
"audience_type": "lists",
"contact_list_id": 0,
"contact_list_ids": [
0
],
"segment_id": 0,
"exclude_segment_ids": [
0
],
"exclude_contact_list_ids": [
0
],
"data": {}
},
"template_attributes": {
"if_version": 0,
"subject": "string",
"body": "string",
"preheader": "string",
"from_name": "string",
"from_email": "user@example.com",
"reply_to": "user@example.com",
"design": {
"sections": [
{
"type": "header",
"props": {},
"styles": {
"background_color": "string",
"padding": "string",
"align": "left",
"font_size": 0,
"text_color": "string",
"border_radius": 0
}
}
],
"theme": {
"brand_color": "string",
"bg_color": "string",
"text_color": "string",
"font_body": "string",
"font_heading": "string",
"logo_url": "string"
}
}
}
}{
"id": 0,
"account_id": 0,
"brand_id": 0,
"status": "draft",
"approval_state": "string",
"channel": "email",
"name": "string",
"data": {},
"scheduled_at": "2024-01-15T09:30:00Z",
"sent_count": 0,
"dashboard_url": "https://example.com",
"preview_url": "https://example.com",
"recipient_snapshot": {
"requested_recipients": 0,
"dispatched_recipients": 0,
"blocked_recipients": 0,
"requested_send_units": 0,
"dispatched_send_units": 0,
"units_per_recipient": 0,
"send_token": "string",
"started_at": "2024-01-15T09:30:00Z",
"completed_at": "2024-01-15T09:30:00Z"
},
"last_send_recipients": 0,
"delivery": {
"campaign_send_token": "string",
"status": "sending",
"recipients": 0,
"sent": 0,
"failed": 0,
"pending": 0
},
"engagement": {
"sent": 0,
"opens": 0,
"total_opens": 0,
"open_rate": 0,
"account": {
"sent": 0,
"opens": 0,
"total_opens": 0,
"open_rate": 0
}
},
"editable": true,
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z",
"trigger": {
"id": 0,
"flow_id": 0,
"event": "string",
"audience_type": "lists",
"segment_id": 0,
"contact_list_id": 0,
"contact_list_ids": [
0
],
"exclude_segment_ids": [
0
],
"exclude_contact_list_ids": [
0
],
"data": {},
"triggered_count": 0,
"last_triggered_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
},
"template": {
"id": 0,
"name": "string",
"flow_id": 0,
"action_id": 0,
"version": 0,
"subject": "string",
"body": "string",
"preheader": "string",
"from_name": "string",
"from_email": "string",
"reply_to": "string",
"design": {
"sections": [
{
"type": "header",
"props": {},
"styles": {
"background_color": "string",
"padding": "string",
"align": "left",
"font_size": 0,
"text_color": "string",
"border_radius": 0
}
}
],
"theme": {
"brand_color": "string",
"bg_color": "string",
"text_color": "string",
"font_body": "string",
"font_heading": "string",
"logo_url": "string"
}
},
"variables": {},
"generation_id": 0,
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
},
"templates": [
{
"id": 0,
"name": "string",
"flow_id": 0,
"action_id": 0,
"version": 0,
"subject": "string",
"body": "string",
"preheader": "string",
"from_name": "string",
"from_email": "string",
"reply_to": "string",
"design": {
"sections": [
{
"type": "header",
"props": {},
"styles": {
"background_color": "string",
"padding": "string",
"align": "left",
"font_size": 0,
"text_color": "string",
"border_radius": 0
}
}
],
"theme": {
"brand_color": "string",
"bg_color": "string",
"text_color": "string",
"font_body": "string",
"font_heading": "string",
"logo_url": "string"
}
},
"variables": {},
"generation_id": 0,
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}
]
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}Duplicate a campaign
Creates a new draft campaign that copies the source's audience (trigger.audience_type, contact_list_ids, segment_id, exclude_segment_ids, exclude_contact_list_ids) and template content (design, subject, preheader, body, from_name, from_email, reply_to). Resets status to draft, approval_state to pending_review, scheduled_at to null, and trigger.event to manual. Works on any status — this is how clients fork a sent campaign into a new draft. Sessions, activities, approvals, and metrics are not copied.
Pass cancel_source: true to atomically cancel the source campaign
in the same transaction as the duplicate — useful for 'cancel and
duplicate' flows on paused campaigns.
Body
cancel_sourcebooleanfalseWhen true, cancels the source campaign in the same DB transaction as the duplicate creation.
Parameters
idintegerrequiredpathResponse
New draft campaign
Resource not found
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X POST 'https://api.nitrosend.com/v1/my/campaigns/{id}/duplicate' \
-H 'Content-Type: application/json' \
-d '{
"cancel_source": false
}'const response = await fetch('https://api.nitrosend.com/v1/my/campaigns/{id}/duplicate', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"cancel_source": false
}),
});
const data = await response.json();import requests
payload = {
"cancel_source": False
}
response = requests.post('https://api.nitrosend.com/v1/my/campaigns/{id}/duplicate', json=payload)
data = response.json(){
"cancel_source": false
}{
"id": 0,
"account_id": 0,
"brand_id": 0,
"status": "draft",
"approval_state": "string",
"channel": "email",
"name": "string",
"data": {},
"scheduled_at": "2024-01-15T09:30:00Z",
"sent_count": 0,
"dashboard_url": "https://example.com",
"preview_url": "https://example.com",
"recipient_snapshot": {
"requested_recipients": 0,
"dispatched_recipients": 0,
"blocked_recipients": 0,
"requested_send_units": 0,
"dispatched_send_units": 0,
"units_per_recipient": 0,
"send_token": "string",
"started_at": "2024-01-15T09:30:00Z",
"completed_at": "2024-01-15T09:30:00Z"
},
"last_send_recipients": 0,
"delivery": {
"campaign_send_token": "string",
"status": "sending",
"recipients": 0,
"sent": 0,
"failed": 0,
"pending": 0
},
"engagement": {
"sent": 0,
"opens": 0,
"total_opens": 0,
"open_rate": 0,
"account": {
"sent": 0,
"opens": 0,
"total_opens": 0,
"open_rate": 0
}
},
"editable": true,
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z",
"trigger": {
"id": 0,
"flow_id": 0,
"event": "string",
"audience_type": "lists",
"segment_id": 0,
"contact_list_id": 0,
"contact_list_ids": [
0
],
"exclude_segment_ids": [
0
],
"exclude_contact_list_ids": [
0
],
"data": {},
"triggered_count": 0,
"last_triggered_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
},
"template": {
"id": 0,
"name": "string",
"flow_id": 0,
"action_id": 0,
"version": 0,
"subject": "string",
"body": "string",
"preheader": "string",
"from_name": "string",
"from_email": "string",
"reply_to": "string",
"design": {
"sections": [
{
"type": "header",
"props": {},
"styles": {
"background_color": "string",
"padding": "string",
"align": "left",
"font_size": 0,
"text_color": "string",
"border_radius": 0
}
}
],
"theme": {
"brand_color": "string",
"bg_color": "string",
"text_color": "string",
"font_body": "string",
"font_heading": "string",
"logo_url": "string"
}
},
"variables": {},
"generation_id": 0,
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
},
"templates": [
{
"id": 0,
"name": "string",
"flow_id": 0,
"action_id": 0,
"version": 0,
"subject": "string",
"body": "string",
"preheader": "string",
"from_name": "string",
"from_email": "string",
"reply_to": "string",
"design": {
"sections": [
{
"type": "header",
"props": {},
"styles": {
"background_color": "string",
"padding": "string",
"align": "left",
"font_size": 0,
"text_color": "string",
"border_radius": 0
}
}
],
"theme": {
"brand_color": "string",
"bg_color": "string",
"text_color": "string",
"font_body": "string",
"font_heading": "string",
"logo_url": "string"
}
},
"variables": {},
"generation_id": 0,
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}
]
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}Render a campaign email to HTML
Renders the campaign's current template through the shared preview renderer.
Parameters
idintegerrequiredpathResponse
Rendered HTML
Resource not found
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/campaigns/{id}/render'const response = await fetch('https://api.nitrosend.com/v1/my/campaigns/{id}/render', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/campaigns/{id}/render')
data = response.json(){
"html": "string"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}Get current campaign delivery progress
Polls the current campaign send using the same Campaign::SendProgress
payload exposed on the campaign serializer. Active sends return
status: "sending" with poll_after_seconds; terminal sends return
status: "completed" or status: "paused" when a deliverability guard
stopped the active send. Campaigns that have not started delivery return
status: "not_started". Polling also refreshes server-side progress:
queued reservations older than 15 minutes are marked failed before the
response is returned, so failed/pending can change on a poll even
when no provider webhook has arrived.
Parameters
idintegerrequiredpathResponse
Current campaign delivery progress
Resource not found
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/campaigns/{id}/delivery'const response = await fetch('https://api.nitrosend.com/v1/my/campaigns/{id}/delivery', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/campaigns/{id}/delivery')
data = response.json(){
"campaign_send_token": "string",
"status": "not_started",
"recipients": 0,
"sent": 0,
"failed": 0,
"pending": 0,
"terminal": true,
"poll_after_seconds": 0
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}Send a test email for a campaign
Thin adapter over the same test-send service used by template tests.
Body
emailstring<email>emailsArray<string>send_test_toArray<string>contact_idintegerParameters
idintegerrequiredpathResponse
Test email sent
Resource not found
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X POST 'https://api.nitrosend.com/v1/my/campaigns/{id}/send_test' \
-H 'Content-Type: application/json' \
-d '{
"email": "user@example.com",
"emails": [
"user@example.com"
],
"send_test_to": [
"user@example.com"
],
"contact_id": 0
}'const response = await fetch('https://api.nitrosend.com/v1/my/campaigns/{id}/send_test', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"email": "user@example.com",
"emails": [
"user@example.com"
],
"send_test_to": [
"user@example.com"
],
"contact_id": 0
}),
});
const data = await response.json();import requests
payload = {
"email": "user@example.com",
"emails": [
"user@example.com"
],
"send_test_to": [
"user@example.com"
],
"contact_id": 0
}
response = requests.post('https://api.nitrosend.com/v1/my/campaigns/{id}/send_test', json=payload)
data = response.json(){
"email": "user@example.com",
"emails": [
"user@example.com"
],
"send_test_to": [
"user@example.com"
],
"contact_id": 0
}{
"sent": 0,
"results": [
{
"email": "string",
"success": true
}
]
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}Send a campaign
Transitions the campaign and its flow to live, then delivers.
Optionally update trigger and template attributes in the same request.
To schedule instead of sending now, pass the delivery time as
trigger_attributes.data.deliver_at (RFC 3339); omit it to send
immediately. A top-level scheduled_at (or a nested
trigger_attributes.data.scheduled_at) is not accepted here and
returns 422 scheduled_at_not_accepted rather than being silently
ignored — scheduled_at is the create/update field, not the send field.
Returns 422 campaign_locked if the campaign is not editable
(live, paused, completed, cancelled, archived, or scheduled within
5 minutes of send). Returns 409 duplicate_campaign_schedule or
duplicate_campaign_send when a repeat attempt would create another
schedule or overlap an active send; poll /delivery, cancel, or edit
the existing scheduled campaign instead.
Body
confirm_send_to_allbooleanRequired when trigger_attributes.audience_type or the saved trigger audience_type is all_contacts.
trigger_attributesobjecttemplate_attributesobjectParameters
idintegerrequiredpathResponse
Campaign sent
Template version conflict or duplicate send attempt
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X POST 'https://api.nitrosend.com/v1/my/campaigns/{id}/send' \
-H 'Content-Type: application/json' \
-d '{
"confirm_send_to_all": true,
"trigger_attributes": {
"event": "string",
"audience_type": "lists",
"contact_list_id": 0,
"contact_list_ids": [
0
],
"segment_id": 0,
"exclude_segment_ids": [
0
],
"exclude_contact_list_ids": [
0
],
"data": {}
},
"template_attributes": {
"if_version": 0,
"subject": "string",
"body": "string",
"preheader": "string",
"from_name": "string",
"from_email": "user@example.com",
"reply_to": "user@example.com",
"design": {
"sections": [
{
"type": "header",
"props": {},
"styles": {
"background_color": "string",
"padding": "string",
"align": "left",
"font_size": 0,
"text_color": "string",
"border_radius": 0
}
}
],
"theme": {
"brand_color": "string",
"bg_color": "string",
"text_color": "string",
"font_body": "string",
"font_heading": "string",
"logo_url": "string"
}
}
}
}'const response = await fetch('https://api.nitrosend.com/v1/my/campaigns/{id}/send', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"confirm_send_to_all": true,
"trigger_attributes": {
"event": "string",
"audience_type": "lists",
"contact_list_id": 0,
"contact_list_ids": [
0
],
"segment_id": 0,
"exclude_segment_ids": [
0
],
"exclude_contact_list_ids": [
0
],
"data": {}
},
"template_attributes": {
"if_version": 0,
"subject": "string",
"body": "string",
"preheader": "string",
"from_name": "string",
"from_email": "user@example.com",
"reply_to": "user@example.com",
"design": {
"sections": [
{
"type": "header",
"props": {},
"styles": {
"background_color": "string",
"padding": "string",
"align": "left",
"font_size": 0,
"text_color": "string",
"border_radius": 0
}
}
],
"theme": {
"brand_color": "string",
"bg_color": "string",
"text_color": "string",
"font_body": "string",
"font_heading": "string",
"logo_url": "string"
}
}
}
}),
});
const data = await response.json();import requests
payload = {
"confirm_send_to_all": True,
"trigger_attributes": {
"event": "string",
"audience_type": "lists",
"contact_list_id": 0,
"contact_list_ids": [
0
],
"segment_id": 0,
"exclude_segment_ids": [
0
],
"exclude_contact_list_ids": [
0
],
"data": {}
},
"template_attributes": {
"if_version": 0,
"subject": "string",
"body": "string",
"preheader": "string",
"from_name": "string",
"from_email": "user@example.com",
"reply_to": "user@example.com",
"design": {
"sections": [
{
"type": "header",
"props": {},
"styles": {
"background_color": "string",
"padding": "string",
"align": "left",
"font_size": 0,
"text_color": "string",
"border_radius": 0
}
}
],
"theme": {
"brand_color": "string",
"bg_color": "string",
"text_color": "string",
"font_body": "string",
"font_heading": "string",
"logo_url": "string"
}
}
}
}
response = requests.post('https://api.nitrosend.com/v1/my/campaigns/{id}/send', json=payload)
data = response.json(){
"confirm_send_to_all": true,
"trigger_attributes": {
"event": "string",
"audience_type": "lists",
"contact_list_id": 0,
"contact_list_ids": [
0
],
"segment_id": 0,
"exclude_segment_ids": [
0
],
"exclude_contact_list_ids": [
0
],
"data": {}
},
"template_attributes": {
"if_version": 0,
"subject": "string",
"body": "string",
"preheader": "string",
"from_name": "string",
"from_email": "user@example.com",
"reply_to": "user@example.com",
"design": {
"sections": [
{
"type": "header",
"props": {},
"styles": {
"background_color": "string",
"padding": "string",
"align": "left",
"font_size": 0,
"text_color": "string",
"border_radius": 0
}
}
],
"theme": {
"brand_color": "string",
"bg_color": "string",
"text_color": "string",
"font_body": "string",
"font_heading": "string",
"logo_url": "string"
}
}
}
}{
"id": 0,
"account_id": 0,
"brand_id": 0,
"status": "draft",
"approval_state": "string",
"channel": "email",
"name": "string",
"data": {},
"scheduled_at": "2024-01-15T09:30:00Z",
"sent_count": 0,
"dashboard_url": "https://example.com",
"preview_url": "https://example.com",
"recipient_snapshot": {
"requested_recipients": 0,
"dispatched_recipients": 0,
"blocked_recipients": 0,
"requested_send_units": 0,
"dispatched_send_units": 0,
"units_per_recipient": 0,
"send_token": "string",
"started_at": "2024-01-15T09:30:00Z",
"completed_at": "2024-01-15T09:30:00Z"
},
"last_send_recipients": 0,
"delivery": {
"campaign_send_token": "string",
"status": "sending",
"recipients": 0,
"sent": 0,
"failed": 0,
"pending": 0
},
"engagement": {
"sent": 0,
"opens": 0,
"total_opens": 0,
"open_rate": 0,
"account": {
"sent": 0,
"opens": 0,
"total_opens": 0,
"open_rate": 0
}
},
"editable": true,
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z",
"trigger": {
"id": 0,
"flow_id": 0,
"event": "string",
"audience_type": "lists",
"segment_id": 0,
"contact_list_id": 0,
"contact_list_ids": [
0
],
"exclude_segment_ids": [
0
],
"exclude_contact_list_ids": [
0
],
"data": {},
"triggered_count": 0,
"last_triggered_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
},
"template": {
"id": 0,
"name": "string",
"flow_id": 0,
"action_id": 0,
"version": 0,
"subject": "string",
"body": "string",
"preheader": "string",
"from_name": "string",
"from_email": "string",
"reply_to": "string",
"design": {
"sections": [
{
"type": "header",
"props": {},
"styles": {
"background_color": "string",
"padding": "string",
"align": "left",
"font_size": 0,
"text_color": "string",
"border_radius": 0
}
}
],
"theme": {
"brand_color": "string",
"bg_color": "string",
"text_color": "string",
"font_body": "string",
"font_heading": "string",
"logo_url": "string"
}
},
"variables": {},
"generation_id": 0,
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
},
"templates": [
{
"id": 0,
"name": "string",
"flow_id": 0,
"action_id": 0,
"version": 0,
"subject": "string",
"body": "string",
"preheader": "string",
"from_name": "string",
"from_email": "string",
"reply_to": "string",
"design": {
"sections": [
{
"type": "header",
"props": {},
"styles": {
"background_color": "string",
"padding": "string",
"align": "left",
"font_size": 0,
"text_color": "string",
"border_radius": 0
}
}
],
"theme": {
"brand_color": "string",
"bg_color": "string",
"text_color": "string",
"font_body": "string",
"font_heading": "string",
"logo_url": "string"
}
},
"variables": {},
"generation_id": 0,
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}
]
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}Messages
Transactional email and SMS messages
List messages
Returns all messages by default. Use source_type to narrow to campaign, flow, transactional, or test sends.
Parameters
source_typestringallcampaignflowtransactionaltestqueryFilter by source. Omit or use 'all' for everything.
flow_idintegerqueryFilter to messages from a specific flow
campaign_idintegerqueryFilter to messages from a specific campaign
datestring<date>queryFilter to messages created on this date
channelstringemailsmsquerystatusstringqueuedsentfailedquerypageinteger1querylimitinteger<= 10025queryResponse
Paginated list of messages
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/messages'const response = await fetch('https://api.nitrosend.com/v1/my/messages', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/messages')
data = response.json()[
{
"id": 0,
"channel": "email",
"to": "string",
"subject": "string",
"status": "queued",
"provider_id": "string",
"flow_id": 0,
"source_type": "campaign",
"source_name": "string",
"sent_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z"
}
]Send a transactional message
Send a transactional email or SMS to a single recipient immediately. No campaign, no audience, no approval required. Use for receipts, password resets, OTPs, order confirmations, and system notifications.
Body
channelstringemailsmsrequiredtostringrequiredRecipient email address or E.164 phone number
subjectstringEmail subject line (required for email channel)
bodystringMessage body. Required for SMS. For email this is plain text (HTML in this field is escaped) and serves as the plain-text alternative when html is set. To send HTML, use html or template_id.
htmlstringPre-rendered HTML body for email, used verbatim as the HTML part (not escaped). Use this to send your own fully-rendered HTML. Mutually exclusive with template_id (email only).
template_idintegerLoad email design from an existing template (email only)
contact_idintegerOptional contact to personalize with when rendering a template
fromstringVerified sender email for this email message. May include a display name, for example "Acme hello@example.com".
from_emailstringVerified sender email for this email message. Alias of from.
from_namestringSender display name for this email message
reply_tostringReply-to email address for this email message
headersobjectProvider headers for this email message. Structural and Nitrosend-reserved headers are rejected.
tagsobjectProvider tags for this email message. Nitrosend-reserved tag keys are rejected and system tags are always controlled by Nitrosend.
dataobjectMerge variables
idempotency_keystringIdempotency key (alternative to header)
Parameters
Idempotency-KeystringheaderPrevents duplicate sends on retry. The same key with the same payload returns the original message; the same key with a different payload returns 409.
Response
Existing message returned for idempotency replay
Message created
Idempotency key was already used with a different payload
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X POST 'https://api.nitrosend.com/v1/my/messages' \
-H 'Content-Type: application/json' \
-d '{
"channel": "email",
"to": "string",
"subject": "string",
"body": "string",
"html": "string",
"template_id": 0,
"contact_id": 0,
"from": "string",
"from_email": "string",
"from_name": "string",
"reply_to": "string",
"headers": {},
"tags": {},
"data": {},
"idempotency_key": "string"
}'const response = await fetch('https://api.nitrosend.com/v1/my/messages', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"channel": "email",
"to": "string",
"subject": "string",
"body": "string",
"html": "string",
"template_id": 0,
"contact_id": 0,
"from": "string",
"from_email": "string",
"from_name": "string",
"reply_to": "string",
"headers": {},
"tags": {},
"data": {},
"idempotency_key": "string"
}),
});
const data = await response.json();import requests
payload = {
"channel": "email",
"to": "string",
"subject": "string",
"body": "string",
"html": "string",
"template_id": 0,
"contact_id": 0,
"from": "string",
"from_email": "string",
"from_name": "string",
"reply_to": "string",
"headers": {},
"tags": {},
"data": {},
"idempotency_key": "string"
}
response = requests.post('https://api.nitrosend.com/v1/my/messages', json=payload)
data = response.json(){
"channel": "email",
"to": "string",
"subject": "string",
"body": "string",
"html": "string",
"template_id": 0,
"contact_id": 0,
"from": "string",
"from_email": "string",
"from_name": "string",
"reply_to": "string",
"headers": {},
"tags": {},
"data": {},
"idempotency_key": "string"
}{
"id": 0,
"channel": "email",
"to": "string",
"subject": "string",
"status": "queued",
"provider_id": "string",
"flow_id": 0,
"source_type": "campaign",
"source_name": "string",
"sent_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z"
}{
"id": 0,
"channel": "email",
"to": "string",
"subject": "string",
"status": "queued",
"provider_id": "string",
"flow_id": 0,
"source_type": "campaign",
"source_name": "string",
"sent_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z"
}{
"code": 409,
"message": "string",
"error": true,
"error_code": "idempotency_conflict"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}Get a transactional message
Parameters
idintegerrequiredpathResponse
Message
Resource not found
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/messages/{id}'const response = await fetch('https://api.nitrosend.com/v1/my/messages/{id}', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/messages/{id}')
data = response.json(){
"id": 0,
"channel": "email",
"to": "string",
"subject": "string",
"status": "queued",
"provider_id": "string",
"flow_id": 0,
"source_type": "campaign",
"source_name": "string",
"sent_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}Render a transactional message's HTML for preview
Returns the as-composed HTML for a message — from its template (rendered design), raw html, or the escaped plain-text body — using the same renderer as the send path, for display in a sandboxed iframe. Non-email or unrenderable messages (deleted/design-less template) return a typed empty state (empty: true) rather than an error.
Parameters
idintegerrequiredpathResponse
Rendered preview, or a typed empty state.
Resource not found
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/messages/{id}/preview'const response = await fetch('https://api.nitrosend.com/v1/my/messages/{id}/preview', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/messages/{id}/preview')
data = response.json(){
"html": "string",
"format": "template",
"empty": true,
"reason": "not_previewable"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}Suppressions
Account suppression list and deliverability diagnostics
List suppressions
Returns the authenticated account's current suppression records by default, including bounded provider diagnostics when the source feedback event is available.
Parameters
idintegerqueryFilter to a specific suppression ID
emailstring<email>queryFilter to a specific suppressed email address
reasonstringhard_bouncesoft_bouncecomplaintmanualadminquerysource_providerstringqueryFilter by provider that emitted the source event
activebooleantruequeryDefaults to true. Set false to list expired suppressions.
pageinteger1querylimitinteger<= 10025queryResponse
Paginated list of suppressions
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/suppressions'const response = await fetch('https://api.nitrosend.com/v1/my/suppressions', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/suppressions')
data = response.json()[
{
"id": 0,
"email": "user@example.com",
"reason": "hard_bounce",
"scope": "account_scoped",
"active": true,
"contact_id": 0,
"source_provider": "string",
"source_event_id": "string",
"provider_diagnostic": "string",
"bounce_type": "hard",
"bounce_subtype": "string",
"complaint_feedback_type": "string",
"event_occurred_at": "2024-01-15T09:30:00Z",
"expires_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}
]Templates
Email templates, preview, and component schema
Ingest an image media asset
REST adapter over the same image ingest capability used by MCP. Send
exactly one source: image_data, image_url, multipart file, or a
direct-upload signed_id created with purpose image or media_asset.
The v1 media contract supports media_kind: image only.
Body
application/jsonobjectimage_datastringRaw base64 image bytes or a data URL. PNG, JPEG, or WebP only; decoded size must be under 10MB.
image_urlstring<uri>Public PNG, JPEG, or WebP URL to ingest when Nitro-hosted permanence is desired.
signed_idstringActive Storage blob signed ID returned by /v1/direct_uploads after uploading bytes with purpose image or media_asset.
filenamestringOriginal filename for image_data uploads, or optional filename override for image_url/signed_id sources.
content_typestring | nullOptional MIME type hint when image_data is raw base64 rather than a data URL.
multipart/form-dataobjectfilestring<binary>PNG, JPEG, or WebP file upload. Must be under 10MB.
filenamestringOptional filename override.
content_typestring | nullOptional MIME type override.
Response
Ingested image asset
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X POST 'https://api.nitrosend.com/v1/my/images' \
-H 'Content-Type: application/json' \
-d '{
"image_data": "string",
"image_url": "https://example.com",
"signed_id": "string",
"filename": "string",
"content_type": "string"
}'const response = await fetch('https://api.nitrosend.com/v1/my/images', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"image_data": "string",
"image_url": "https://example.com",
"signed_id": "string",
"filename": "string",
"content_type": "string"
}),
});
const data = await response.json();import requests
payload = {
"image_data": "string",
"image_url": "https://example.com",
"signed_id": "string",
"filename": "string",
"content_type": "string"
}
response = requests.post('https://api.nitrosend.com/v1/my/images', json=payload)
data = response.json(){
"image_data": "string",
"image_url": "https://example.com",
"signed_id": "string",
"filename": "string",
"content_type": "string"
}{
"media_kind": "image",
"media_url": "https://example.com",
"image_url": "https://example.com",
"signed_id": "string",
"filename": "string",
"content_type": "string",
"byte_size": 0,
"width": 0,
"height": 0
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}List all templates (paginated)
Returns a summary view with section counts (not full design).
Parameters
pageinteger1queryperinteger<= 100100queryResponse
Template summaries
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/templates'const response = await fetch('https://api.nitrosend.com/v1/my/templates', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/templates')
data = response.json()[
{
"id": 0,
"name": "string",
"version": 0,
"subject": "string",
"preheader": "string",
"flow_id": 0,
"section_count": 0,
"section_types": [
"string"
],
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}
]Create a standalone template
Body
namestringrequiredsubjectstringpreheaderstringgeneration_idinteger | nullif_versionintegerRequired optimistic concurrency token. Use the current template.version.
designEmailDesignEmail template design document
Response
Created template
Template version conflict
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X POST 'https://api.nitrosend.com/v1/my/templates' \
-H 'Content-Type: application/json' \
-d '{
"name": "string",
"subject": "string",
"preheader": "string",
"generation_id": 0,
"if_version": 0,
"design": {
"sections": [
{
"type": "header",
"props": {},
"styles": {
"background_color": "string",
"padding": "string",
"align": "left",
"font_size": 0,
"text_color": "string",
"border_radius": 0
}
}
],
"theme": {
"brand_color": "string",
"bg_color": "string",
"text_color": "string",
"font_body": "string",
"font_heading": "string",
"logo_url": "string"
}
}
}'const response = await fetch('https://api.nitrosend.com/v1/my/templates', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "string",
"subject": "string",
"preheader": "string",
"generation_id": 0,
"if_version": 0,
"design": {
"sections": [
{
"type": "header",
"props": {},
"styles": {
"background_color": "string",
"padding": "string",
"align": "left",
"font_size": 0,
"text_color": "string",
"border_radius": 0
}
}
],
"theme": {
"brand_color": "string",
"bg_color": "string",
"text_color": "string",
"font_body": "string",
"font_heading": "string",
"logo_url": "string"
}
}
}),
});
const data = await response.json();import requests
payload = {
"name": "string",
"subject": "string",
"preheader": "string",
"generation_id": 0,
"if_version": 0,
"design": {
"sections": [
{
"type": "header",
"props": {},
"styles": {
"background_color": "string",
"padding": "string",
"align": "left",
"font_size": 0,
"text_color": "string",
"border_radius": 0
}
}
],
"theme": {
"brand_color": "string",
"bg_color": "string",
"text_color": "string",
"font_body": "string",
"font_heading": "string",
"logo_url": "string"
}
}
}
response = requests.post('https://api.nitrosend.com/v1/my/templates', json=payload)
data = response.json(){
"name": "string",
"subject": "string",
"preheader": "string",
"generation_id": 0,
"if_version": 0,
"design": {
"sections": [
{
"type": "header",
"props": {},
"styles": {
"background_color": "string",
"padding": "string",
"align": "left",
"font_size": 0,
"text_color": "string",
"border_radius": 0
}
}
],
"theme": {
"brand_color": "string",
"bg_color": "string",
"text_color": "string",
"font_body": "string",
"font_heading": "string",
"logo_url": "string"
}
}
}{
"id": 0,
"name": "string",
"flow_id": 0,
"action_id": 0,
"version": 0,
"subject": "string",
"body": "string",
"preheader": "string",
"from_name": "string",
"from_email": "string",
"reply_to": "string",
"design": {
"sections": [
{
"type": "header",
"props": {},
"styles": {
"background_color": "string",
"padding": "string",
"align": "left",
"font_size": 0,
"text_color": "string",
"border_radius": 0
}
}
],
"theme": {
"brand_color": "string",
"bg_color": "string",
"text_color": "string",
"font_body": "string",
"font_heading": "string",
"logo_url": "string"
}
},
"variables": {},
"generation_id": 0,
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}Get a template with full design
Parameters
idintegerrequiredpathResponse
Full template including design
Resource not found
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/templates/{id}'const response = await fetch('https://api.nitrosend.com/v1/my/templates/{id}', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/templates/{id}')
data = response.json(){
"id": 0,
"name": "string",
"flow_id": 0,
"action_id": 0,
"version": 0,
"subject": "string",
"body": "string",
"preheader": "string",
"from_name": "string",
"from_email": "string",
"reply_to": "string",
"design": {
"sections": [
{
"type": "header",
"props": {},
"styles": {
"background_color": "string",
"padding": "string",
"align": "left",
"font_size": 0,
"text_color": "string",
"border_radius": 0
}
}
],
"theme": {
"brand_color": "string",
"bg_color": "string",
"text_color": "string",
"font_body": "string",
"font_heading": "string",
"logo_url": "string"
}
},
"variables": {},
"generation_id": 0,
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}Delete an unused standalone template
Parameters
idintegerrequiredpathif_versionintegerrequiredqueryRequired optimistic concurrency token. Use the current template.version.
Response
Template deleted
Resource not found
Template version conflict or deletion blocked by message/flow history
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X DELETE 'https://api.nitrosend.com/v1/my/templates/{id}'const response = await fetch('https://api.nitrosend.com/v1/my/templates/{id}', {
method: 'DELETE',
});
const data = await response.json();import requests
response = requests.delete('https://api.nitrosend.com/v1/my/templates/{id}')
data = response.json(){
"deleted": true,
"template_id": 0
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}Update a template
Body
namestringsubjectstringbodystringpreheaderstringif_versionintegerrequiredRequired optimistic concurrency token. Use the current template.version. A stale value returns 409 with current_version and expected_version.
from_namestringfrom_emailstring<email>reply_tostring<email>generation_idinteger | nulldesignEmailDesignEmail template design document
Parameters
idintegerrequiredpathResponse
Updated template
Template version conflict
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X PATCH 'https://api.nitrosend.com/v1/my/templates/{id}' \
-H 'Content-Type: application/json' \
-d '{
"name": "string",
"subject": "string",
"body": "string",
"preheader": "string",
"if_version": 0,
"from_name": "string",
"from_email": "user@example.com",
"reply_to": "user@example.com",
"generation_id": 0,
"design": {
"sections": [
{
"type": "header",
"props": {},
"styles": {
"background_color": "string",
"padding": "string",
"align": "left",
"font_size": 0,
"text_color": "string",
"border_radius": 0
}
}
],
"theme": {
"brand_color": "string",
"bg_color": "string",
"text_color": "string",
"font_body": "string",
"font_heading": "string",
"logo_url": "string"
}
}
}'const response = await fetch('https://api.nitrosend.com/v1/my/templates/{id}', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "string",
"subject": "string",
"body": "string",
"preheader": "string",
"if_version": 0,
"from_name": "string",
"from_email": "user@example.com",
"reply_to": "user@example.com",
"generation_id": 0,
"design": {
"sections": [
{
"type": "header",
"props": {},
"styles": {
"background_color": "string",
"padding": "string",
"align": "left",
"font_size": 0,
"text_color": "string",
"border_radius": 0
}
}
],
"theme": {
"brand_color": "string",
"bg_color": "string",
"text_color": "string",
"font_body": "string",
"font_heading": "string",
"logo_url": "string"
}
}
}),
});
const data = await response.json();import requests
payload = {
"name": "string",
"subject": "string",
"body": "string",
"preheader": "string",
"if_version": 0,
"from_name": "string",
"from_email": "user@example.com",
"reply_to": "user@example.com",
"generation_id": 0,
"design": {
"sections": [
{
"type": "header",
"props": {},
"styles": {
"background_color": "string",
"padding": "string",
"align": "left",
"font_size": 0,
"text_color": "string",
"border_radius": 0
}
}
],
"theme": {
"brand_color": "string",
"bg_color": "string",
"text_color": "string",
"font_body": "string",
"font_heading": "string",
"logo_url": "string"
}
}
}
response = requests.patch('https://api.nitrosend.com/v1/my/templates/{id}', json=payload)
data = response.json(){
"name": "string",
"subject": "string",
"body": "string",
"preheader": "string",
"if_version": 0,
"from_name": "string",
"from_email": "user@example.com",
"reply_to": "user@example.com",
"generation_id": 0,
"design": {
"sections": [
{
"type": "header",
"props": {},
"styles": {
"background_color": "string",
"padding": "string",
"align": "left",
"font_size": 0,
"text_color": "string",
"border_radius": 0
}
}
],
"theme": {
"brand_color": "string",
"bg_color": "string",
"text_color": "string",
"font_body": "string",
"font_heading": "string",
"logo_url": "string"
}
}
}{
"id": 0,
"name": "string",
"flow_id": 0,
"action_id": 0,
"version": 0,
"subject": "string",
"body": "string",
"preheader": "string",
"from_name": "string",
"from_email": "string",
"reply_to": "string",
"design": {
"sections": [
{
"type": "header",
"props": {},
"styles": {
"background_color": "string",
"padding": "string",
"align": "left",
"font_size": 0,
"text_color": "string",
"border_radius": 0
}
}
],
"theme": {
"brand_color": "string",
"bg_color": "string",
"text_color": "string",
"font_body": "string",
"font_heading": "string",
"logo_url": "string"
}
},
"variables": {},
"generation_id": 0,
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}Render an existing template to HTML
Renders the template through the shared preview renderer.
Parameters
idintegerrequiredpathResponse
Rendered HTML
Resource not found
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/templates/{id}/render'const response = await fetch('https://api.nitrosend.com/v1/my/templates/{id}/render', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/templates/{id}/render')
data = response.json(){
"html": "string",
"accessibility": {
"valid": true,
"warnings": [
{
"level": "warning",
"rule": "image_alt_text",
"message": "string",
"suggested_fix": "string",
"count": 0,
"min_ratio": 0
}
]
}
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}Send a test email
Send a test email for the given template. Provide email for an
explicit recipient, contact_id to use a contact's email (with
merge-tag personalization), or omit both to send to the account owner.
Body
emailstring<email>contact_idintegerParameters
idintegerrequiredpathResponse
Test email sent
Resource not found
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X POST 'https://api.nitrosend.com/v1/my/templates/{id}/send_test' \
-H 'Content-Type: application/json' \
-d '{
"email": "user@example.com",
"contact_id": 0
}'const response = await fetch('https://api.nitrosend.com/v1/my/templates/{id}/send_test', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"email": "user@example.com",
"contact_id": 0
}),
});
const data = await response.json();import requests
payload = {
"email": "user@example.com",
"contact_id": 0
}
response = requests.post('https://api.nitrosend.com/v1/my/templates/{id}/send_test', json=payload)
data = response.json(){
"email": "user@example.com",
"contact_id": 0
}{
"sent": 0,
"results": [
{
"email": "string",
"success": true
}
]
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}Render an email design to HTML
Body
documentEmailDesignrequiredEmail template design document
Response
Rendered HTML
Bad request
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X POST 'https://api.nitrosend.com/v1/my/templates/preview' \
-H 'Content-Type: application/json' \
-d '{
"document": {
"sections": [
{
"type": "header",
"props": {},
"styles": {
"background_color": "string",
"padding": "string",
"align": "left",
"font_size": 0,
"text_color": "string",
"border_radius": 0
}
}
],
"theme": {
"brand_color": "string",
"bg_color": "string",
"text_color": "string",
"font_body": "string",
"font_heading": "string",
"logo_url": "string"
}
}
}'const response = await fetch('https://api.nitrosend.com/v1/my/templates/preview', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"document": {
"sections": [
{
"type": "header",
"props": {},
"styles": {
"background_color": "string",
"padding": "string",
"align": "left",
"font_size": 0,
"text_color": "string",
"border_radius": 0
}
}
],
"theme": {
"brand_color": "string",
"bg_color": "string",
"text_color": "string",
"font_body": "string",
"font_heading": "string",
"logo_url": "string"
}
}
}),
});
const data = await response.json();import requests
payload = {
"document": {
"sections": [
{
"type": "header",
"props": {},
"styles": {
"background_color": "string",
"padding": "string",
"align": "left",
"font_size": 0,
"text_color": "string",
"border_radius": 0
}
}
],
"theme": {
"brand_color": "string",
"bg_color": "string",
"text_color": "string",
"font_body": "string",
"font_heading": "string",
"logo_url": "string"
}
}
}
response = requests.post('https://api.nitrosend.com/v1/my/templates/preview', json=payload)
data = response.json(){
"document": {
"sections": [
{
"type": "header",
"props": {},
"styles": {
"background_color": "string",
"padding": "string",
"align": "left",
"font_size": 0,
"text_color": "string",
"border_radius": 0
}
}
],
"theme": {
"brand_color": "string",
"bg_color": "string",
"text_color": "string",
"font_body": "string",
"font_heading": "string",
"logo_url": "string"
}
}
}{
"html": "string",
"accessibility": {
"valid": true,
"warnings": [
{
"level": "warning",
"rule": "image_alt_text",
"message": "string",
"suggested_fix": "string",
"count": 0,
"min_ratio": 0
}
]
}
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}Get the email component schema
Returns the full schema for email design sections including all
component types, their props, required fields, and defaults.
Sourced from config/email_components.yml.
Response
Email component schema
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/templates/spec'const response = await fetch('https://api.nitrosend.com/v1/my/templates/spec', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/templates/spec')
data = response.json(){
"version": 0,
"design_guidelines": "string",
"components": [
{
"type": "string",
"description": "string",
"tips": [
"string"
],
"props": {}
}
],
"style_attributes": [
{
"key": "string",
"label": "string",
"type": "color",
"theme_fallback": "string",
"description": "string",
"values": [
"string"
],
"target": {
"el": "section",
"attr": "string"
}
}
],
"variables": [
"string"
],
"theme_attributes": [
{
"key": "string",
"label": "string",
"type": "color",
"category": "color",
"slot": "string",
"surfaces": [
"string"
],
"min": 0,
"max": 0,
"values": [
"string"
],
"options": [
{
"value": "string",
"label": "string",
"description": "string"
}
],
"transform_table": {},
"column": true,
"value_resolver": "string",
"description": "string"
}
]
}List email starter designs
Returns config-based starter email designs with the current brand's theme merged and an HTML preview rendered for each starter.
Response
Starter designs with brand theme and preview HTML
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/templates/starters'const response = await fetch('https://api.nitrosend.com/v1/my/templates/starters', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/templates/starters')
data = response.json()[
{
"id": "string",
"category": "string",
"name": "string",
"description": "string",
"icon": "string",
"suggested_goals": [
"string"
],
"design": {
"sections": [
{
"type": "header",
"props": {},
"styles": {
"background_color": "string",
"padding": "string",
"align": "left",
"font_size": 0,
"text_color": "string",
"border_radius": 0
}
}
],
"theme": {
"brand_color": "string",
"bg_color": "string",
"text_color": "string",
"font_body": "string",
"font_heading": "string",
"logo_url": "string"
}
},
"preview_html": "string"
}
]AI-generate an email template
Generate a complete email design from a text goal using AI. Returns a sections-based design, subject line, preheader, and inferred category. Supports refine mode by passing existing sections[] for modification.
Body
goalstringrequiredWhat the email should accomplish
categorystringOptional category hint (welcome, newsletter, promotion, etc.)
tonestringOptional tone override (formal, casual, etc.)
sectionsArray<object>Current sections for refine mode — LLM adjusts existing content
Response
Generated email design
Validation error
Rate limit exceeded
Generation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X POST 'https://api.nitrosend.com/v1/my/templates/generate' \
-H 'Content-Type: application/json' \
-d '{
"goal": "Welcome new subscribers and introduce the brand",
"category": "string",
"tone": "string",
"sections": [
{}
]
}'const response = await fetch('https://api.nitrosend.com/v1/my/templates/generate', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"goal": "Welcome new subscribers and introduce the brand",
"category": "string",
"tone": "string",
"sections": [
{}
]
}),
});
const data = await response.json();import requests
payload = {
"goal": "Welcome new subscribers and introduce the brand",
"category": "string",
"tone": "string",
"sections": [
{}
]
}
response = requests.post('https://api.nitrosend.com/v1/my/templates/generate', json=payload)
data = response.json(){
"goal": "Welcome new subscribers and introduce the brand",
"category": "string",
"tone": "string",
"sections": [
{}
]
}{
"design": {},
"subject": "string",
"preheader": "string",
"category": "string",
"prompt_version": "string"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}Flows
Automation flows and step schema
List automation flows (paginated)
Returns standalone flows only (excludes campaign-attached flows).
Parameters
pageinteger1querylimitinteger<= 10025queryResponse
Paginated flows
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/flows'const response = await fetch('https://api.nitrosend.com/v1/my/flows', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/flows')
data = response.json()[]Create a flow
Body
namestringrequiredstatusstringdraftlivepausedarchivedcancelledtriggerFlowTriggerInputstepsArray<FlowStepInput>Response
Flow created
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X POST 'https://api.nitrosend.com/v1/my/flows' \
-H 'Content-Type: application/json' \
-d '{
"name": "string",
"status": "draft",
"trigger": {
"event": "string",
"audience_type": "lists",
"segment_id": 0,
"contact_list_id": 0,
"contact_list_ids": [
0
],
"exclude_segment_ids": [
0
],
"data": {}
},
"steps": []
}'const response = await fetch('https://api.nitrosend.com/v1/my/flows', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "string",
"status": "draft",
"trigger": {
"event": "string",
"audience_type": "lists",
"segment_id": 0,
"contact_list_id": 0,
"contact_list_ids": [
0
],
"exclude_segment_ids": [
0
],
"data": {}
},
"steps": []
}),
});
const data = await response.json();import requests
payload = {
"name": "string",
"status": "draft",
"trigger": {
"event": "string",
"audience_type": "lists",
"segment_id": 0,
"contact_list_id": 0,
"contact_list_ids": [
0
],
"exclude_segment_ids": [
0
],
"data": {}
},
"steps": []
}
response = requests.post('https://api.nitrosend.com/v1/my/flows', json=payload)
data = response.json(){
"name": "string",
"status": "draft",
"trigger": {
"event": "string",
"audience_type": "lists",
"segment_id": 0,
"contact_list_id": 0,
"contact_list_ids": [
0
],
"exclude_segment_ids": [
0
],
"data": {}
},
"steps": []
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}Get a flow
Parameters
idintegerrequiredpathResponse
Flow with full graph
Resource not found
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/flows/{id}'const response = await fetch('https://api.nitrosend.com/v1/my/flows/{id}', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/flows/{id}')
data = response.json(){
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}Delete a flow
Parameters
idintegerrequiredpathResponse
Deleted flow
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X DELETE 'https://api.nitrosend.com/v1/my/flows/{id}'const response = await fetch('https://api.nitrosend.com/v1/my/flows/{id}', {
method: 'DELETE',
});
const data = await response.json();import requests
response = requests.delete('https://api.nitrosend.com/v1/my/flows/{id}')
data = response.json()Update a flow
Supports optimistic concurrency — pass updated_at to reject
the update if the flow was modified externally.
Body
namestringstatusstringdraftlivepausedarchivedcancelledupdated_atstring<date-time>Optimistic concurrency check
triggerFlowTriggerInputstepsArray<FlowStepInput>Parameters
idintegerrequiredpathResponse
Updated flow
Conflict — flow was modified externally, or live activation was already accepted (duplicate_flow_live)
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X PATCH 'https://api.nitrosend.com/v1/my/flows/{id}' \
-H 'Content-Type: application/json' \
-d '{
"name": "string",
"status": "draft",
"updated_at": "2024-01-15T09:30:00Z",
"trigger": {
"event": "string",
"audience_type": "lists",
"segment_id": 0,
"contact_list_id": 0,
"contact_list_ids": [
0
],
"exclude_segment_ids": [
0
],
"data": {}
},
"steps": []
}'const response = await fetch('https://api.nitrosend.com/v1/my/flows/{id}', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "string",
"status": "draft",
"updated_at": "2024-01-15T09:30:00Z",
"trigger": {
"event": "string",
"audience_type": "lists",
"segment_id": 0,
"contact_list_id": 0,
"contact_list_ids": [
0
],
"exclude_segment_ids": [
0
],
"data": {}
},
"steps": []
}),
});
const data = await response.json();import requests
payload = {
"name": "string",
"status": "draft",
"updated_at": "2024-01-15T09:30:00Z",
"trigger": {
"event": "string",
"audience_type": "lists",
"segment_id": 0,
"contact_list_id": 0,
"contact_list_ids": [
0
],
"exclude_segment_ids": [
0
],
"data": {}
},
"steps": []
}
response = requests.patch('https://api.nitrosend.com/v1/my/flows/{id}', json=payload)
data = response.json(){
"name": "string",
"status": "draft",
"updated_at": "2024-01-15T09:30:00Z",
"trigger": {
"event": "string",
"audience_type": "lists",
"segment_id": 0,
"contact_list_id": 0,
"contact_list_ids": [
0
],
"exclude_segment_ids": [
0
],
"data": {}
},
"steps": []
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}Get the flow step type schema
Returns the schema for flow step types, trigger events, and
audience filters. Flow steps and triggers are sourced from
config/flows.yml; filters are sourced from the audience filter
registry with lifecycle_flows added from the canonical lifecycle
catalog.
Response
Flow specification
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/flows/spec'const response = await fetch('https://api.nitrosend.com/v1/my/flows/spec', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/flows/spec')
data = response.json(){
"filters": {},
"triggers": [
{
"title": "string",
"event": "string"
}
],
"steps": [
{
"type": "string",
"title": "string",
"summary": "string",
"params": {}
}
],
"lifecycle_flows": [
{
"id": "string",
"key": "string",
"goal": "string",
"name": "string",
"description": "string",
"priority": 0,
"trigger": {
"event": "string"
},
"trigger_needs": "string",
"steps": [
{
"type": "string",
"duration": 0,
"subject": "string",
"preheader": "string",
"body": "string",
"design": {}
}
]
}
]
}List flow templates
Returns all available flow templates (static, global — not account-scoped).
Each entry includes lean card data and preview_sections from the first email step.
Response
List of flow templates
Not authenticated
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/flow_templates'const response = await fetch('https://api.nitrosend.com/v1/my/flow_templates', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/flow_templates')
data = response.json()[
{
"id": "string",
"type_label": "string",
"description": "string",
"category": "string",
"email_count": 0,
"step_count": 0,
"preview_sections": [
{}
]
}
]{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}Get a flow template
Returns a single flow template including the full trigger and steps
graph, ready to pass directly to POST /v1/my/flows.
Parameters
idstringrequiredpathFlow template slug (e.g. welcome_series)
Response
Flow template with full graph
Not authenticated
Resource not found
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/flow_templates/{id}'const response = await fetch('https://api.nitrosend.com/v1/my/flow_templates/{id}', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/flow_templates/{id}')
data = response.json(){
"id": "string",
"type_label": "string",
"description": "string",
"category": "string",
"email_count": 0,
"step_count": 0,
"preview_sections": [
{}
],
"trigger": {},
"steps": [
{}
]
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}Events
Contact event tracking
List events (paginated)
Parameters
pageinteger1querylimitinteger<= 10050queryeventstringqueryFilter by event type
contact_idintegerquerycreated_afterstring<date-time>querycreated_beforestring<date-time>queryresource_uidstringqueryresource_namestringquerytestbooleanqueryResponse
Paginated events
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/events'const response = await fetch('https://api.nitrosend.com/v1/my/events', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/events')
data = response.json()[
{
"id": 0,
"account_id": 0,
"contact_id": 0,
"user_id": 0,
"event": "string",
"amount": 0,
"data": {},
"idempotency_key": "string",
"resource_uid": "string",
"resource_name": "string",
"resource_url": "string",
"test": true,
"generated": true,
"chain_depth": 0,
"ip": "string",
"user_agent": "string",
"browser": "string",
"os": "string",
"device_type": "string",
"referrer": "string",
"utm_source": "string",
"utm_medium": "string",
"utm_term": "string",
"utm_content": "string",
"utm_campaign": "string",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}
]Track a contact event
Requires an idempotency key via the Idempotency-Key header or
idempotency_key body param. Duplicate events (same account +
event type + idempotency key) return the existing event.
Body
eventstringrequiredEvent type name (lowercase, underscores)
contact_idintegercontact_emailstring<email>Alternative to contact_id — resolves contact by email
idempotency_keystringIdempotency key (alternative to header)
amountnumber<double>resource_uidstringresource_namestringresource_urlstring<uri>testbooleanfalsedataobjectCustom event payload (max 32KB)
utm_sourcestringutm_mediumstringutm_termstringutm_contentstringutm_campaignstringParameters
Idempotency-KeystringheaderIdempotency key (alternative to body param)
Response
Duplicate event (idempotent — returns existing)
Event created
Bad request
Resource not found
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X POST 'https://api.nitrosend.com/v1/my/events' \
-H 'Content-Type: application/json' \
-d '{
"event": "string",
"contact_id": 0,
"contact_email": "user@example.com",
"idempotency_key": "string",
"amount": 0,
"resource_uid": "string",
"resource_name": "string",
"resource_url": "https://example.com",
"test": false,
"data": {},
"utm_source": "string",
"utm_medium": "string",
"utm_term": "string",
"utm_content": "string",
"utm_campaign": "string"
}'const response = await fetch('https://api.nitrosend.com/v1/my/events', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"event": "string",
"contact_id": 0,
"contact_email": "user@example.com",
"idempotency_key": "string",
"amount": 0,
"resource_uid": "string",
"resource_name": "string",
"resource_url": "https://example.com",
"test": false,
"data": {},
"utm_source": "string",
"utm_medium": "string",
"utm_term": "string",
"utm_content": "string",
"utm_campaign": "string"
}),
});
const data = await response.json();import requests
payload = {
"event": "string",
"contact_id": 0,
"contact_email": "user@example.com",
"idempotency_key": "string",
"amount": 0,
"resource_uid": "string",
"resource_name": "string",
"resource_url": "https://example.com",
"test": False,
"data": {},
"utm_source": "string",
"utm_medium": "string",
"utm_term": "string",
"utm_content": "string",
"utm_campaign": "string"
}
response = requests.post('https://api.nitrosend.com/v1/my/events', json=payload)
data = response.json(){
"event": "string",
"contact_id": 0,
"contact_email": "user@example.com",
"idempotency_key": "string",
"amount": 0,
"resource_uid": "string",
"resource_name": "string",
"resource_url": "https://example.com",
"test": false,
"data": {},
"utm_source": "string",
"utm_medium": "string",
"utm_term": "string",
"utm_content": "string",
"utm_campaign": "string"
}{
"id": 0,
"account_id": 0,
"contact_id": 0,
"user_id": 0,
"event": "string",
"amount": 0,
"data": {},
"idempotency_key": "string",
"resource_uid": "string",
"resource_name": "string",
"resource_url": "string",
"test": true,
"generated": true,
"chain_depth": 0,
"ip": "string",
"user_agent": "string",
"browser": "string",
"os": "string",
"device_type": "string",
"referrer": "string",
"utm_source": "string",
"utm_medium": "string",
"utm_term": "string",
"utm_content": "string",
"utm_campaign": "string",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}{
"id": 0,
"account_id": 0,
"contact_id": 0,
"user_id": 0,
"event": "string",
"amount": 0,
"data": {},
"idempotency_key": "string",
"resource_uid": "string",
"resource_name": "string",
"resource_url": "string",
"test": true,
"generated": true,
"chain_depth": 0,
"ip": "string",
"user_agent": "string",
"browser": "string",
"os": "string",
"device_type": "string",
"referrer": "string",
"utm_source": "string",
"utm_medium": "string",
"utm_term": "string",
"utm_content": "string",
"utm_campaign": "string",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}List event names for filter autocomplete
Returns known platform event names plus observed event names for the current brand.
Response
Event name suggestions
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/events/names'const response = await fetch('https://api.nitrosend.com/v1/my/events/names', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/events/names')
data = response.json(){
"names": [
"string"
]
}Get an event
Parameters
idintegerrequiredpathResponse
Event
Resource not found
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/events/{id}'const response = await fetch('https://api.nitrosend.com/v1/my/events/{id}', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/events/{id}')
data = response.json(){
"id": 0,
"account_id": 0,
"contact_id": 0,
"user_id": 0,
"event": "string",
"amount": 0,
"data": {},
"idempotency_key": "string",
"resource_uid": "string",
"resource_name": "string",
"resource_url": "string",
"test": true,
"generated": true,
"chain_depth": 0,
"ip": "string",
"user_agent": "string",
"browser": "string",
"os": "string",
"device_type": "string",
"referrer": "string",
"utm_source": "string",
"utm_medium": "string",
"utm_term": "string",
"utm_content": "string",
"utm_campaign": "string",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}Delete an event
Parameters
idintegerrequiredpathResponse
Deleted event
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X DELETE 'https://api.nitrosend.com/v1/my/events/{id}'const response = await fetch('https://api.nitrosend.com/v1/my/events/{id}', {
method: 'DELETE',
});
const data = await response.json();import requests
response = requests.delete('https://api.nitrosend.com/v1/my/events/{id}')
data = response.json(){
"id": 0,
"account_id": 0,
"contact_id": 0,
"user_id": 0,
"event": "string",
"amount": 0,
"data": {},
"idempotency_key": "string",
"resource_uid": "string",
"resource_name": "string",
"resource_url": "string",
"test": true,
"generated": true,
"chain_depth": 0,
"ip": "string",
"user_agent": "string",
"browser": "string",
"os": "string",
"device_type": "string",
"referrer": "string",
"utm_source": "string",
"utm_medium": "string",
"utm_term": "string",
"utm_content": "string",
"utm_campaign": "string",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}Domains
Sending domain verification
List sending domains (paginated)
Parameters
pageinteger1queryperinteger<= 10030queryResponse
Paginated domains
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/domains'const response = await fetch('https://api.nitrosend.com/v1/my/domains', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/domains')
data = response.json()[
{
"id": 0,
"brand_id": 0,
"name": "string",
"provider": "ses",
"integration_id": 0,
"status": "pending",
"dmarc_policy": "none",
"dmarc_recommended_policy": "none",
"dmarc_observed_policy": "none",
"dns_records": [
{
"record_type": "string",
"name": "string",
"value": "string",
"priority": "string",
"valid": "string"
}
],
"dns_health": {},
"dns_setup_status": "unchecked",
"verified_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z"
}
]Add a sending domain
Initiates domain verification. Returns DNS records that must be
added at your domain registrar before calling POST /verify.
Body
domainobjectrequiredResponse
Domain registered with DNS records to configure
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X POST 'https://api.nitrosend.com/v1/my/domains' \
-H 'Content-Type: application/json' \
-d '{
"domain": {
"name": "string"
}
}'const response = await fetch('https://api.nitrosend.com/v1/my/domains', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"domain": {
"name": "string"
}
}),
});
const data = await response.json();import requests
payload = {
"domain": {
"name": "string"
}
}
response = requests.post('https://api.nitrosend.com/v1/my/domains', json=payload)
data = response.json(){
"domain": {
"name": "string"
}
}{
"id": 0,
"brand_id": 0,
"name": "string",
"provider": "ses",
"integration_id": 0,
"status": "pending",
"dmarc_policy": "none",
"dmarc_recommended_policy": "none",
"dmarc_observed_policy": "none",
"dns_records": [
{
"record_type": "string",
"name": "string",
"value": "string",
"priority": "string",
"valid": "string"
}
],
"dns_health": {},
"dns_setup_status": "unchecked",
"verified_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}Get a domain with DNS records and status
Parameters
idintegerrequiredpathResponse
Domain
Resource not found
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/domains/{id}'const response = await fetch('https://api.nitrosend.com/v1/my/domains/{id}', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/domains/{id}')
data = response.json(){
"id": 0,
"brand_id": 0,
"name": "string",
"provider": "ses",
"integration_id": 0,
"status": "pending",
"dmarc_policy": "none",
"dmarc_recommended_policy": "none",
"dmarc_observed_policy": "none",
"dns_records": [
{
"record_type": "string",
"name": "string",
"value": "string",
"priority": "string",
"valid": "string"
}
],
"dns_health": {},
"dns_setup_status": "unchecked",
"verified_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}Remove a sending domain
Parameters
idintegerrequiredpathResponse
Domain deleted
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X DELETE 'https://api.nitrosend.com/v1/my/domains/{id}'const response = await fetch('https://api.nitrosend.com/v1/my/domains/{id}', {
method: 'DELETE',
});
const data = await response.json();import requests
response = requests.delete('https://api.nitrosend.com/v1/my/domains/{id}')
data = response.json()Verify domain DNS records
Checks if the required DNS records have propagated. If verified,
completes the domain_verified onboarding step and enables sending.
Parameters
idintegerrequiredpathResponse
Domain verification status
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X POST 'https://api.nitrosend.com/v1/my/domains/{id}/verify'const response = await fetch('https://api.nitrosend.com/v1/my/domains/{id}/verify', {
method: 'POST',
});
const data = await response.json();import requests
response = requests.post('https://api.nitrosend.com/v1/my/domains/{id}/verify')
data = response.json(){
"id": 0,
"brand_id": 0,
"name": "string",
"provider": "ses",
"integration_id": 0,
"status": "pending",
"dmarc_policy": "none",
"dmarc_recommended_policy": "none",
"dmarc_observed_policy": "none",
"dns_records": [
{
"record_type": "string",
"name": "string",
"value": "string",
"priority": "string",
"valid": "string"
}
],
"dns_health": {},
"dns_setup_status": "unchecked",
"verified_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z"
}Create an Entri bootstrap session for a pending domain
Returns a short-lived Entri JWT plus the DNS record payload needed to launch the Entri modal for a pending domain owned by the current brand.
Parameters
idintegerrequiredpathResponse
Entri bootstrap payload
Resource not found
Validation failed
Rate limit exceeded
Upstream service unavailable
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X POST 'https://api.nitrosend.com/v1/my/domains/{id}/entri_session'const response = await fetch('https://api.nitrosend.com/v1/my/domains/{id}/entri_session', {
method: 'POST',
});
const data = await response.json();import requests
response = requests.post('https://api.nitrosend.com/v1/my/domains/{id}/entri_session')
data = response.json(){
"domain": {
"id": 0,
"name": "string",
"status": "pending"
},
"entri": {
"application_id": "string",
"token": "string",
"prefilled_domain": "string",
"user_id": "string",
"dns_records": [
{
"type": "string",
"host": "string",
"value": "string",
"ttl": 0,
"priority": 0
}
]
}
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}Integrations
BYO provider integration management
List integrations (paginated)
Parameters
categorystringemailsmscrmquerypageinteger1queryperinteger<= 10030queryResponse
Paginated integrations
Bad request
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/integrations'const response = await fetch('https://api.nitrosend.com/v1/my/integrations', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/integrations')
data = response.json()[
{
"id": 0,
"provider": "mailgun",
"category": "email",
"active": true,
"primary": true,
"status": "pending",
"connected_at": "2024-01-15T09:30:00Z",
"last_tested_at": "2024-01-15T09:30:00Z",
"error_message": "string",
"config_summary": {},
"secret_hints": {},
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}
]{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}Create or connect an email provider integration
Body
integrationMailgunIntegrationInput | SesIntegrationInput | PostmarkIntegrationInput | ResendIntegrationInput | SendgridIntegrationInputrequiredResponse
Integration created
Bad request
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X POST 'https://api.nitrosend.com/v1/my/integrations' \
-H 'Content-Type: application/json' \
-d '{
"integration": {
"provider": "mailgun",
"api_key": "string",
"domain": "string",
"region": "string",
"active": true
}
}'const response = await fetch('https://api.nitrosend.com/v1/my/integrations', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"integration": {
"provider": "mailgun",
"api_key": "string",
"domain": "string",
"region": "string",
"active": true
}
}),
});
const data = await response.json();import requests
payload = {
"integration": {
"provider": "mailgun",
"api_key": "string",
"domain": "string",
"region": "string",
"active": True
}
}
response = requests.post('https://api.nitrosend.com/v1/my/integrations', json=payload)
data = response.json(){
"integration": {
"provider": "mailgun",
"api_key": "string",
"domain": "string",
"region": "string",
"active": true
}
}{
"id": 0,
"provider": "mailgun",
"category": "email",
"active": true,
"primary": true,
"status": "pending",
"connected_at": "2024-01-15T09:30:00Z",
"last_tested_at": "2024-01-15T09:30:00Z",
"error_message": "string",
"config_summary": {},
"secret_hints": {},
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}Get an integration
Parameters
idintegerrequiredpathResponse
Integration
Resource not found
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/integrations/{id}'const response = await fetch('https://api.nitrosend.com/v1/my/integrations/{id}', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/integrations/{id}')
data = response.json(){
"id": 0,
"provider": "mailgun",
"category": "email",
"active": true,
"primary": true,
"status": "pending",
"connected_at": "2024-01-15T09:30:00Z",
"last_tested_at": "2024-01-15T09:30:00Z",
"error_message": "string",
"config_summary": {},
"secret_hints": {},
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}Disconnect and delete an integration
Parameters
idintegerrequiredpathconfirmbooleanrequiredqueryMust be true to confirm the destructive action.
Response
Integration deleted
Bad request
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X DELETE 'https://api.nitrosend.com/v1/my/integrations/{id}'const response = await fetch('https://api.nitrosend.com/v1/my/integrations/{id}', {
method: 'DELETE',
});
const data = await response.json();import requests
response = requests.delete('https://api.nitrosend.com/v1/my/integrations/{id}')
data = response.json(){
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}Update an email provider integration
Updates credentials or operational fields for an existing email provider. The provider cannot be changed once the integration exists.
Body
integrationMailgunIntegrationInput | SesIntegrationInput | PostmarkIntegrationInput | ResendIntegrationInput | SendgridIntegrationInputrequiredParameters
idintegerrequiredpathResponse
Integration updated
Bad request
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X PATCH 'https://api.nitrosend.com/v1/my/integrations/{id}' \
-H 'Content-Type: application/json' \
-d '{
"integration": {
"provider": "mailgun",
"api_key": "string",
"domain": "string",
"region": "string",
"active": true
}
}'const response = await fetch('https://api.nitrosend.com/v1/my/integrations/{id}', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"integration": {
"provider": "mailgun",
"api_key": "string",
"domain": "string",
"region": "string",
"active": true
}
}),
});
const data = await response.json();import requests
payload = {
"integration": {
"provider": "mailgun",
"api_key": "string",
"domain": "string",
"region": "string",
"active": True
}
}
response = requests.patch('https://api.nitrosend.com/v1/my/integrations/{id}', json=payload)
data = response.json(){
"integration": {
"provider": "mailgun",
"api_key": "string",
"domain": "string",
"region": "string",
"active": true
}
}{
"id": 0,
"provider": "mailgun",
"category": "email",
"active": true,
"primary": true,
"status": "pending",
"connected_at": "2024-01-15T09:30:00Z",
"last_tested_at": "2024-01-15T09:30:00Z",
"error_message": "string",
"config_summary": {},
"secret_hints": {},
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}Test integration connectivity
Parameters
idintegerrequiredpathResponse
Tested integration
Resource not found
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X POST 'https://api.nitrosend.com/v1/my/integrations/{id}/test'const response = await fetch('https://api.nitrosend.com/v1/my/integrations/{id}/test', {
method: 'POST',
});
const data = await response.json();import requests
response = requests.post('https://api.nitrosend.com/v1/my/integrations/{id}/test')
data = response.json(){
"id": 0,
"provider": "mailgun",
"category": "email",
"active": true,
"primary": true,
"status": "pending",
"connected_at": "2024-01-15T09:30:00Z",
"last_tested_at": "2024-01-15T09:30:00Z",
"error_message": "string",
"config_summary": {},
"secret_hints": {},
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}Set an integration as the primary provider for its category
Parameters
idintegerrequiredpathResponse
Integration marked primary
Bad request
Resource not found
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X PATCH 'https://api.nitrosend.com/v1/my/integrations/{id}/primary'const response = await fetch('https://api.nitrosend.com/v1/my/integrations/{id}/primary', {
method: 'PATCH',
});
const data = await response.json();import requests
response = requests.patch('https://api.nitrosend.com/v1/my/integrations/{id}/primary')
data = response.json(){
"id": 0,
"provider": "mailgun",
"category": "email",
"active": true,
"primary": true,
"status": "pending",
"connected_at": "2024-01-15T09:30:00Z",
"last_tested_at": "2024-01-15T09:30:00Z",
"error_message": "string",
"config_summary": {},
"secret_hints": {},
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}Start Attio OAuth connect flow
Returns an Attio OAuth authorize URL for the authenticated account/brand. The response URL includes a signed state payload and the API callback URI.
Response
OAuth authorize URL
Not authenticated
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X POST 'https://api.nitrosend.com/v1/my/integrations/attio/connect'const response = await fetch('https://api.nitrosend.com/v1/my/integrations/attio/connect', {
method: 'POST',
});
const data = await response.json();import requests
response = requests.post('https://api.nitrosend.com/v1/my/integrations/attio/connect')
data = response.json(){
"authorize_url": "https://example.com"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}Start HubSpot OAuth connect flow
Returns a HubSpot OAuth authorize URL for the authenticated account/brand. The response URL includes a signed state payload and the API callback URI.
Response
OAuth authorize URL
Not authenticated
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X POST 'https://api.nitrosend.com/v1/my/integrations/hubspot/connect'const response = await fetch('https://api.nitrosend.com/v1/my/integrations/hubspot/connect', {
method: 'POST',
});
const data = await response.json();import requests
response = requests.post('https://api.nitrosend.com/v1/my/integrations/hubspot/connect')
data = response.json(){
"authorize_url": "https://example.com"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}Start Shopify OAuth connect flow
Returns a Shopify OAuth authorize URL for the authenticated account/brand.
The request accepts a myshopify.com shop domain or shop slug. The
response URL includes a signed state payload and the API callback URI.
Body
shopifyobjectrequiredResponse
OAuth authorize URL
Not authenticated
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X POST 'https://api.nitrosend.com/v1/my/integrations/shopify/connect' \
-H 'Content-Type: application/json' \
-d '{
"shopify": {
"shop": "test-shop.myshopify.com"
}
}'const response = await fetch('https://api.nitrosend.com/v1/my/integrations/shopify/connect', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"shopify": {
"shop": "test-shop.myshopify.com"
}
}),
});
const data = await response.json();import requests
payload = {
"shopify": {
"shop": "test-shop.myshopify.com"
}
}
response = requests.post('https://api.nitrosend.com/v1/my/integrations/shopify/connect', json=payload)
data = response.json(){
"shopify": {
"shop": "test-shop.myshopify.com"
}
}{
"authorize_url": "https://example.com"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}Connect customer-data Stripe integration
Connects a customer's own Stripe account using a Restricted API Key and
a webhook signing secret for /hooks/stripe_data. This is isolated from
Nitrosend billing webhooks at /hooks/stripe.
Body
stripeobjectrequiredResponse
Stripe integration connected
Not authenticated
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X POST 'https://api.nitrosend.com/v1/my/integrations/stripe/connect' \
-H 'Content-Type: application/json' \
-d '{
"stripe": {
"api_key": "string",
"signing_secret": "string"
}
}'const response = await fetch('https://api.nitrosend.com/v1/my/integrations/stripe/connect', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"stripe": {
"api_key": "string",
"signing_secret": "string"
}
}),
});
const data = await response.json();import requests
payload = {
"stripe": {
"api_key": "string",
"signing_secret": "string"
}
}
response = requests.post('https://api.nitrosend.com/v1/my/integrations/stripe/connect', json=payload)
data = response.json(){
"stripe": {
"api_key": "string",
"signing_secret": "string"
}
}{
"integration_id": 0,
"status": "string",
"provider": "stripe"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}Attio OAuth callback endpoint
Public callback endpoint used by Attio after user authorization. Verifies signed state, exchanges auth code, and finalizes Attio integration connection.
Parameters
codestringquerystatestringqueryerrorstringqueryerror_descriptionstringqueryResponse
OAuth callback processed (HTML)
Invalid callback request
OAuth exchange or webhook provisioning failure
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/integrations/attio/callback'const response = await fetch('https://api.nitrosend.com/integrations/attio/callback', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/integrations/attio/callback')
data = response.json()"string""string""string"HubSpot OAuth callback endpoint
Public callback endpoint used by HubSpot after user authorization. Verifies signed state, exchanges auth code, persists the integration, and enqueues initial sync.
Parameters
codestringquerystatestringqueryerrorstringqueryerror_descriptionstringqueryResponse
OAuth callback processed (HTML)
Invalid callback request
OAuth exchange failure
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/integrations/hubspot/callback'const response = await fetch('https://api.nitrosend.com/integrations/hubspot/callback', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/integrations/hubspot/callback')
data = response.json()"string""string""string"Shopify OAuth callback endpoint
Public callback endpoint used by Shopify after user authorization. Verifies signed state, shop domain, Shopify OAuth HMAC, exchanges the auth code, persists the integration, and enqueues initial sync.
Parameters
codestringquerystatestringqueryshopstringqueryhmacstringquerytimestampstringqueryerrorstringqueryerror_descriptionstringqueryResponse
OAuth callback processed (HTML)
Invalid callback request
OAuth exchange failure
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/integrations/shopify/callback'const response = await fetch('https://api.nitrosend.com/integrations/shopify/callback', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/integrations/shopify/callback')
data = response.json()"string""string""string"Brands
Brand context plus Brand Kit identity, theme, and per-brand configuration
List brands (paginated)
Parameters
pageinteger1queryperinteger<= 100100queryResponse
All brands for the account
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/brands'const response = await fetch('https://api.nitrosend.com/v1/my/brands', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/brands')
data = response.json()[
{
"id": 0,
"sid": "string",
"account_id": 0,
"brand_color": "string",
"text_color": "string",
"bg_color": "string",
"radius": 0,
"spacing_density": "compact",
"font_heading": "string",
"font_body": "string",
"brand_document": "string",
"style_notes": "string",
"tone": "string",
"company_description": "string",
"industry": "string",
"example_copy": [
"string"
],
"default_header": {},
"default_footer": {},
"default_theme": {},
"physical_address": "string",
"company_name": "string",
"source_url": "string",
"last_scraped_at": "2024-01-15T09:30:00Z",
"links": [
{
"url": "string",
"icon": "string",
"title": "string"
}
],
"logo": "string",
"complete": true,
"email_from_name": "string",
"email_from_email": "string",
"email_reply_to": "string",
"email_view_online": true,
"test_email_recipients": [
"user@example.com"
],
"onboarding_state": {},
"onboarding": {
"steps": {},
"progress": {
"completed": 0,
"total": 0
}
},
"domain_verified": true,
"can_send": true,
"byo_routing": {
"mismatch": true,
"provider": "string",
"bypassing_domains": [
"string"
],
"message": "string"
},
"subscribed_contacts_count": 0,
"using_sandbox": true,
"sandbox_email": "string",
"sandbox_monthly_cap": 0,
"sandbox_sends_remaining": 0,
"capabilities": {},
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}
]Create a brand
Body
namestringInternal brand name; mirrors company_name when company_name is omitted
brand_colorstringtext_colorstringbg_colorstringradiusinteger | null[0, 64]spacing_densitystring | nullcompactnormalspaciousfont_headingstringfont_bodystringheading_sizeinteger | null[12, 48]body_sizeinteger | null[12, 20]brand_documentstring | nullstyle_notesstringtonestringcompany_descriptionstringindustrystringphysical_addressstringcompany_namestringlogostringSigned blob ID or URL
email_from_namestringemail_from_emailstring<email>email_reply_tostring<email>email_view_onlinebooleantest_email_recipientsArray<string>example_copyArray<string>linksArray<object>default_headerobjectdefault_footerobjectdefault_themeobjectResponse
Brand created
Brand limit reached or validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X POST 'https://api.nitrosend.com/v1/my/brands' \
-H 'Content-Type: application/json' \
-d '{
"name": "string",
"brand_color": "string",
"text_color": "string",
"bg_color": "string",
"radius": 0,
"spacing_density": "compact",
"font_heading": "string",
"font_body": "string",
"heading_size": 12,
"body_size": 12,
"brand_document": "string",
"style_notes": "string",
"tone": "string",
"company_description": "string",
"industry": "string",
"physical_address": "string",
"company_name": "string",
"logo": "string",
"email_from_name": "string",
"email_from_email": "user@example.com",
"email_reply_to": "user@example.com",
"email_view_online": true,
"test_email_recipients": [
"user@example.com"
],
"example_copy": [
"string"
],
"links": [
{
"url": "https://example.com",
"icon": "string",
"title": "string"
}
],
"default_header": {},
"default_footer": {},
"default_theme": {}
}'const response = await fetch('https://api.nitrosend.com/v1/my/brands', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "string",
"brand_color": "string",
"text_color": "string",
"bg_color": "string",
"radius": 0,
"spacing_density": "compact",
"font_heading": "string",
"font_body": "string",
"heading_size": 12,
"body_size": 12,
"brand_document": "string",
"style_notes": "string",
"tone": "string",
"company_description": "string",
"industry": "string",
"physical_address": "string",
"company_name": "string",
"logo": "string",
"email_from_name": "string",
"email_from_email": "user@example.com",
"email_reply_to": "user@example.com",
"email_view_online": true,
"test_email_recipients": [
"user@example.com"
],
"example_copy": [
"string"
],
"links": [
{
"url": "https://example.com",
"icon": "string",
"title": "string"
}
],
"default_header": {},
"default_footer": {},
"default_theme": {}
}),
});
const data = await response.json();import requests
payload = {
"name": "string",
"brand_color": "string",
"text_color": "string",
"bg_color": "string",
"radius": 0,
"spacing_density": "compact",
"font_heading": "string",
"font_body": "string",
"heading_size": 12,
"body_size": 12,
"brand_document": "string",
"style_notes": "string",
"tone": "string",
"company_description": "string",
"industry": "string",
"physical_address": "string",
"company_name": "string",
"logo": "string",
"email_from_name": "string",
"email_from_email": "user@example.com",
"email_reply_to": "user@example.com",
"email_view_online": True,
"test_email_recipients": [
"user@example.com"
],
"example_copy": [
"string"
],
"links": [
{
"url": "https://example.com",
"icon": "string",
"title": "string"
}
],
"default_header": {},
"default_footer": {},
"default_theme": {}
}
response = requests.post('https://api.nitrosend.com/v1/my/brands', json=payload)
data = response.json(){
"name": "string",
"brand_color": "string",
"text_color": "string",
"bg_color": "string",
"radius": 0,
"spacing_density": "compact",
"font_heading": "string",
"font_body": "string",
"heading_size": 12,
"body_size": 12,
"brand_document": "string",
"style_notes": "string",
"tone": "string",
"company_description": "string",
"industry": "string",
"physical_address": "string",
"company_name": "string",
"logo": "string",
"email_from_name": "string",
"email_from_email": "user@example.com",
"email_reply_to": "user@example.com",
"email_view_online": true,
"test_email_recipients": [
"user@example.com"
],
"example_copy": [
"string"
],
"links": [
{
"url": "https://example.com",
"icon": "string",
"title": "string"
}
],
"default_header": {},
"default_footer": {},
"default_theme": {}
}{
"id": 0,
"sid": "string",
"account_id": 0,
"brand_color": "string",
"text_color": "string",
"bg_color": "string",
"radius": 0,
"spacing_density": "compact",
"font_heading": "string",
"font_body": "string",
"brand_document": "string",
"style_notes": "string",
"tone": "string",
"company_description": "string",
"industry": "string",
"example_copy": [
"string"
],
"default_header": {},
"default_footer": {},
"default_theme": {},
"physical_address": "string",
"company_name": "string",
"source_url": "string",
"last_scraped_at": "2024-01-15T09:30:00Z",
"links": [
{
"url": "string",
"icon": "string",
"title": "string"
}
],
"logo": "string",
"complete": true,
"email_from_name": "string",
"email_from_email": "string",
"email_reply_to": "string",
"email_view_online": true,
"test_email_recipients": [
"user@example.com"
],
"onboarding_state": {},
"onboarding": {
"steps": {},
"progress": {
"completed": 0,
"total": 0
}
},
"domain_verified": true,
"can_send": true,
"byo_routing": {
"mismatch": true,
"provider": "string",
"bypassing_domains": [
"string"
],
"message": "string"
},
"subscribed_contacts_count": 0,
"using_sandbox": true,
"sandbox_email": "string",
"sandbox_monthly_cap": 0,
"sandbox_sends_remaining": 0,
"capabilities": {},
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}{
"error": true,
"code": "brand_limit_reached",
"message": "string"
}Get a brand
Parameters
sidstringrequiredpathBrand secure identifier
Response
Brand
Resource not found
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/brands/{sid}'const response = await fetch('https://api.nitrosend.com/v1/my/brands/{sid}', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/brands/{sid}')
data = response.json(){
"id": 0,
"sid": "string",
"account_id": 0,
"brand_color": "string",
"text_color": "string",
"bg_color": "string",
"radius": 0,
"spacing_density": "compact",
"font_heading": "string",
"font_body": "string",
"brand_document": "string",
"style_notes": "string",
"tone": "string",
"company_description": "string",
"industry": "string",
"example_copy": [
"string"
],
"default_header": {},
"default_footer": {},
"default_theme": {},
"physical_address": "string",
"company_name": "string",
"source_url": "string",
"last_scraped_at": "2024-01-15T09:30:00Z",
"links": [
{
"url": "string",
"icon": "string",
"title": "string"
}
],
"logo": "string",
"complete": true,
"email_from_name": "string",
"email_from_email": "string",
"email_reply_to": "string",
"email_view_online": true,
"test_email_recipients": [
"user@example.com"
],
"onboarding_state": {},
"onboarding": {
"steps": {},
"progress": {
"completed": 0,
"total": 0
}
},
"domain_verified": true,
"can_send": true,
"byo_routing": {
"mismatch": true,
"provider": "string",
"bypassing_domains": [
"string"
],
"message": "string"
},
"subscribed_contacts_count": 0,
"using_sandbox": true,
"sandbox_email": "string",
"sandbox_monthly_cap": 0,
"sandbox_sends_remaining": 0,
"capabilities": {},
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}Delete a brand
Parameters
sidstringrequiredpathBrand secure identifier
forcestringtruequeryMust be true to delete a brand that has queued messages or scheduled/live campaigns.
Response
Deleted brand
Brand has active sends and requires explicit force confirmation
Cannot delete the only brand
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X DELETE 'https://api.nitrosend.com/v1/my/brands/{sid}'const response = await fetch('https://api.nitrosend.com/v1/my/brands/{sid}', {
method: 'DELETE',
});
const data = await response.json();import requests
response = requests.delete('https://api.nitrosend.com/v1/my/brands/{sid}')
data = response.json(){
"id": 0,
"sid": "string",
"account_id": 0,
"brand_color": "string",
"text_color": "string",
"bg_color": "string",
"radius": 0,
"spacing_density": "compact",
"font_heading": "string",
"font_body": "string",
"brand_document": "string",
"style_notes": "string",
"tone": "string",
"company_description": "string",
"industry": "string",
"example_copy": [
"string"
],
"default_header": {},
"default_footer": {},
"default_theme": {},
"physical_address": "string",
"company_name": "string",
"source_url": "string",
"last_scraped_at": "2024-01-15T09:30:00Z",
"links": [
{
"url": "string",
"icon": "string",
"title": "string"
}
],
"logo": "string",
"complete": true,
"email_from_name": "string",
"email_from_email": "string",
"email_reply_to": "string",
"email_view_online": true,
"test_email_recipients": [
"user@example.com"
],
"onboarding_state": {},
"onboarding": {
"steps": {},
"progress": {
"completed": 0,
"total": 0
}
},
"domain_verified": true,
"can_send": true,
"byo_routing": {
"mismatch": true,
"provider": "string",
"bypassing_domains": [
"string"
],
"message": "string"
},
"subscribed_contacts_count": 0,
"using_sandbox": true,
"sandbox_email": "string",
"sandbox_monthly_cap": 0,
"sandbox_sends_remaining": 0,
"capabilities": {},
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}{
"error": true,
"code": "brand_has_active_sends",
"active_sends": {
"queued_messages": 0,
"active_campaigns": 0
},
"deletion_safety": {
"deletion_impact": {
"contacts": 0,
"campaigns": 0,
"flows": 0,
"templates": 0,
"domains": 0,
"messages": 0
},
"active_sends": {
"queued_messages": 0,
"active_campaigns": 0
},
"can_delete": true,
"requires_force": true
}
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}Update a brand
Body
brand_colorstringtext_colorstringbg_colorstringradiusinteger | null[0, 64]spacing_densitystring | nullcompactnormalspaciousfont_headingstringfont_bodystringheading_sizeinteger | null[12, 48]body_sizeinteger | null[12, 20]brand_documentstring | nullstyle_notesstringtonestringcompany_descriptionstringindustrystringphysical_addressstringcompany_namestringlogostringSigned blob ID or URL
email_from_namestringemail_from_emailstring<email>email_reply_tostring<email>test_email_recipientsArray<string>example_copyArray<string>linksArray<object>default_headerobjectdefault_footerobjectdefault_themeobjectParameters
sidstringrequiredpathBrand secure identifier
Response
Updated brand
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X PATCH 'https://api.nitrosend.com/v1/my/brands/{sid}' \
-H 'Content-Type: application/json' \
-d '{
"brand_color": "string",
"text_color": "string",
"bg_color": "string",
"radius": 0,
"spacing_density": "compact",
"font_heading": "string",
"font_body": "string",
"heading_size": 12,
"body_size": 12,
"brand_document": "string",
"style_notes": "string",
"tone": "string",
"company_description": "string",
"industry": "string",
"physical_address": "string",
"company_name": "string",
"logo": "string",
"email_from_name": "string",
"email_from_email": "user@example.com",
"email_reply_to": "user@example.com",
"test_email_recipients": [
"user@example.com"
],
"example_copy": [
"string"
],
"links": [
{
"url": "https://example.com",
"icon": "string",
"title": "string"
}
],
"default_header": {},
"default_footer": {},
"default_theme": {}
}'const response = await fetch('https://api.nitrosend.com/v1/my/brands/{sid}', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"brand_color": "string",
"text_color": "string",
"bg_color": "string",
"radius": 0,
"spacing_density": "compact",
"font_heading": "string",
"font_body": "string",
"heading_size": 12,
"body_size": 12,
"brand_document": "string",
"style_notes": "string",
"tone": "string",
"company_description": "string",
"industry": "string",
"physical_address": "string",
"company_name": "string",
"logo": "string",
"email_from_name": "string",
"email_from_email": "user@example.com",
"email_reply_to": "user@example.com",
"test_email_recipients": [
"user@example.com"
],
"example_copy": [
"string"
],
"links": [
{
"url": "https://example.com",
"icon": "string",
"title": "string"
}
],
"default_header": {},
"default_footer": {},
"default_theme": {}
}),
});
const data = await response.json();import requests
payload = {
"brand_color": "string",
"text_color": "string",
"bg_color": "string",
"radius": 0,
"spacing_density": "compact",
"font_heading": "string",
"font_body": "string",
"heading_size": 12,
"body_size": 12,
"brand_document": "string",
"style_notes": "string",
"tone": "string",
"company_description": "string",
"industry": "string",
"physical_address": "string",
"company_name": "string",
"logo": "string",
"email_from_name": "string",
"email_from_email": "user@example.com",
"email_reply_to": "user@example.com",
"test_email_recipients": [
"user@example.com"
],
"example_copy": [
"string"
],
"links": [
{
"url": "https://example.com",
"icon": "string",
"title": "string"
}
],
"default_header": {},
"default_footer": {},
"default_theme": {}
}
response = requests.patch('https://api.nitrosend.com/v1/my/brands/{sid}', json=payload)
data = response.json(){
"brand_color": "string",
"text_color": "string",
"bg_color": "string",
"radius": 0,
"spacing_density": "compact",
"font_heading": "string",
"font_body": "string",
"heading_size": 12,
"body_size": 12,
"brand_document": "string",
"style_notes": "string",
"tone": "string",
"company_description": "string",
"industry": "string",
"physical_address": "string",
"company_name": "string",
"logo": "string",
"email_from_name": "string",
"email_from_email": "user@example.com",
"email_reply_to": "user@example.com",
"test_email_recipients": [
"user@example.com"
],
"example_copy": [
"string"
],
"links": [
{
"url": "https://example.com",
"icon": "string",
"title": "string"
}
],
"default_header": {},
"default_footer": {},
"default_theme": {}
}{
"id": 0,
"sid": "string",
"account_id": 0,
"brand_color": "string",
"text_color": "string",
"bg_color": "string",
"radius": 0,
"spacing_density": "compact",
"font_heading": "string",
"font_body": "string",
"brand_document": "string",
"style_notes": "string",
"tone": "string",
"company_description": "string",
"industry": "string",
"example_copy": [
"string"
],
"default_header": {},
"default_footer": {},
"default_theme": {},
"physical_address": "string",
"company_name": "string",
"source_url": "string",
"last_scraped_at": "2024-01-15T09:30:00Z",
"links": [
{
"url": "string",
"icon": "string",
"title": "string"
}
],
"logo": "string",
"complete": true,
"email_from_name": "string",
"email_from_email": "string",
"email_reply_to": "string",
"email_view_online": true,
"test_email_recipients": [
"user@example.com"
],
"onboarding_state": {},
"onboarding": {
"steps": {},
"progress": {
"completed": 0,
"total": 0
}
},
"domain_verified": true,
"can_send": true,
"byo_routing": {
"mismatch": true,
"provider": "string",
"bypassing_domains": [
"string"
],
"message": "string"
},
"subscribed_contacts_count": 0,
"using_sandbox": true,
"sandbox_email": "string",
"sandbox_monthly_cap": 0,
"sandbox_sends_remaining": 0,
"capabilities": {},
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}Get deletion safety for a brand
Returns authoritative deletion impact counts and active-send state for the confirmation UI.
Parameters
sidstringrequiredpathBrand secure identifier
Response
Brand deletion safety
Resource not found
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/brands/{sid}/deletion_safety'const response = await fetch('https://api.nitrosend.com/v1/my/brands/{sid}/deletion_safety', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/brands/{sid}/deletion_safety')
data = response.json(){
"deletion_impact": {
"contacts": 0,
"campaigns": 0,
"flows": 0,
"templates": 0,
"domains": 0,
"messages": 0
},
"active_sends": {
"queued_messages": 0,
"active_campaigns": 0
},
"can_delete": true,
"requires_force": true
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}Auto-detect brand from website
Enqueues a background job that scrapes the URL for brand colors,
fonts, logo, and tone. Returns 202 immediately. Poll
GET /v1/my/brands/{sid} for results.
Body
urlstring<uri>requiredParameters
sidstringrequiredpathBrand secure identifier
Response
Scrape job enqueued
Invalid URL
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X POST 'https://api.nitrosend.com/v1/my/brands/{sid}/scrape' \
-H 'Content-Type: application/json' \
-d '{
"url": "https://example.com"
}'const response = await fetch('https://api.nitrosend.com/v1/my/brands/{sid}/scrape', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"url": "https://example.com"
}),
});
const data = await response.json();import requests
payload = {
"url": "https://example.com"
}
response = requests.post('https://api.nitrosend.com/v1/my/brands/{sid}/scrape', json=payload)
data = response.json(){
"url": "https://example.com"
}{
"status": "scraping",
"url": "https://example.com"
}{
"error": "string"
}Get brand onboarding state
Parameters
sidstringrequiredpathBrand secure identifier
Response
Onboarding state for the brand
Resource not found
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/brands/{sid}/onboarding'const response = await fetch('https://api.nitrosend.com/v1/my/brands/{sid}/onboarding', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/brands/{sid}/onboarding')
data = response.json(){
"steps": {},
"progress": {
"completed": 0,
"total": 0
}
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}Complete a brand onboarding step
Body
stepstringbrand_kit_setupdomain_verifiedfirst_contactfirst_sendrequiredParameters
sidstringrequiredpathBrand secure identifier
Response
Updated onboarding state
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X POST 'https://api.nitrosend.com/v1/my/brands/{sid}/onboarding/steps' \
-H 'Content-Type: application/json' \
-d '{
"step": "brand_kit_setup"
}'const response = await fetch('https://api.nitrosend.com/v1/my/brands/{sid}/onboarding/steps', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"step": "brand_kit_setup"
}),
});
const data = await response.json();import requests
payload = {
"step": "brand_kit_setup"
}
response = requests.post('https://api.nitrosend.com/v1/my/brands/{sid}/onboarding/steps', json=payload)
data = response.json(){
"step": "brand_kit_setup"
}{
"steps": {},
"progress": {
"completed": 0,
"total": 0
}
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}Get brand setup center state
Parameters
sidstringrequiredpathBrand secure identifier
Response
Setup center state for the brand
Resource not found
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/brands/{sid}/setup_center'const response = await fetch('https://api.nitrosend.com/v1/my/brands/{sid}/setup_center', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/brands/{sid}/setup_center')
data = response.json(){
"cards": [
{
"id": "brand_kit_scan",
"complete": true,
"acknowledged": true,
"acknowledged_at": "2024-01-15T09:30:00Z"
}
],
"sections": {
"required": [
"string"
],
"recommended": [
"string"
]
},
"progress": {
"completed": 0,
"total": 0
},
"seen": true,
"dismissed": true,
"complete": true
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}Update brand setup center state
Body
Provide one of seen, dismissed, or card.
seenbooleandismissedbooleancardstringbrand_kit_scandnsplanconnect_agentimport_subscribersconnect_transactionalmetadataobjectParameters
sidstringrequiredpathBrand secure identifier
Response
Updated setup center state
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X PATCH 'https://api.nitrosend.com/v1/my/brands/{sid}/setup_center' \
-H 'Content-Type: application/json' \
-d '{
"seen": true,
"dismissed": true,
"card": "brand_kit_scan",
"metadata": {}
}'const response = await fetch('https://api.nitrosend.com/v1/my/brands/{sid}/setup_center', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"seen": true,
"dismissed": true,
"card": "brand_kit_scan",
"metadata": {}
}),
});
const data = await response.json();import requests
payload = {
"seen": True,
"dismissed": True,
"card": "brand_kit_scan",
"metadata": {}
}
response = requests.patch('https://api.nitrosend.com/v1/my/brands/{sid}/setup_center', json=payload)
data = response.json(){
"seen": true,
"dismissed": true,
"card": "brand_kit_scan",
"metadata": {}
}{
"cards": [
{
"id": "brand_kit_scan",
"complete": true,
"acknowledged": true,
"acknowledged_at": "2024-01-15T09:30:00Z"
}
],
"sections": {
"required": [
"string"
],
"recommended": [
"string"
]
},
"progress": {
"completed": 0,
"total": 0
},
"seen": true,
"dismissed": true,
"complete": true
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}SavedViews
Saved table presets (filters + sort + columns) per surface
List saved views visible to the current user
Returns all shared views in the current account plus the caller's own private views. Optionally filtered by surface.
Parameters
surfacestringcontactssendingactivityqueryFilter views by surface
pageinteger1querylimitinteger<= 10025queryResponse
Saved views
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/saved_views'const response = await fetch('https://api.nitrosend.com/v1/my/saved_views', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/saved_views')
data = response.json()[]Create a saved view
Creates a new saved view owned by the current user. Defaults to private visibility if not specified.
Body
surfacestringcontactssendingactivityrequirednamestringrequiredvisibilitystringprivatesharedprivatefiltersSegmentFilterExpressionlayoutSavedViewLayout | nullTable layout preset for contacts surface views. Only present when surface = contacts.
Response
Saved view created
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X POST 'https://api.nitrosend.com/v1/my/saved_views' \
-H 'Content-Type: application/json' \
-d '{
"surface": "contacts",
"name": "string",
"visibility": "private",
"layout": {
"columns": [
"string"
],
"sort": {
"field": "string",
"dir": "asc"
}
}
}'const response = await fetch('https://api.nitrosend.com/v1/my/saved_views', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"surface": "contacts",
"name": "string",
"visibility": "private",
"layout": {
"columns": [
"string"
],
"sort": {
"field": "string",
"dir": "asc"
}
}
}),
});
const data = await response.json();import requests
payload = {
"surface": "contacts",
"name": "string",
"visibility": "private",
"layout": {
"columns": [
"string"
],
"sort": {
"field": "string",
"dir": "asc"
}
}
}
response = requests.post('https://api.nitrosend.com/v1/my/saved_views', json=payload)
data = response.json(){
"surface": "contacts",
"name": "string",
"visibility": "private",
"layout": {
"columns": [
"string"
],
"sort": {
"field": "string",
"dir": "asc"
}
}
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}Delete a saved view
Deletes a saved view. Allowed only for the creator or the account owner. Other members receive 403.
Parameters
idintegerrequiredpathResponse
Deleted saved view
Not authorized
Resource not found
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X DELETE 'https://api.nitrosend.com/v1/my/saved_views/{id}'const response = await fetch('https://api.nitrosend.com/v1/my/saved_views/{id}', {
method: 'DELETE',
});
const data = await response.json();import requests
response = requests.delete('https://api.nitrosend.com/v1/my/saved_views/{id}')
data = response.json(){
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}Update a saved view
Updates a saved view. Allowed only for the creator or the account owner. Other members receive 403.
Body
namestringvisibilitystringprivatesharedfiltersSegmentFilterExpressionlayoutSavedViewLayout | nullTable layout preset for contacts surface views. Only present when surface = contacts.
Parameters
idintegerrequiredpathResponse
Updated saved view
Not authorized
Resource not found
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X PATCH 'https://api.nitrosend.com/v1/my/saved_views/{id}' \
-H 'Content-Type: application/json' \
-d '{
"name": "string",
"visibility": "private",
"layout": {
"columns": [
"string"
],
"sort": {
"field": "string",
"dir": "asc"
}
}
}'const response = await fetch('https://api.nitrosend.com/v1/my/saved_views/{id}', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "string",
"visibility": "private",
"layout": {
"columns": [
"string"
],
"sort": {
"field": "string",
"dir": "asc"
}
}
}),
});
const data = await response.json();import requests
payload = {
"name": "string",
"visibility": "private",
"layout": {
"columns": [
"string"
],
"sort": {
"field": "string",
"dir": "asc"
}
}
}
response = requests.patch('https://api.nitrosend.com/v1/my/saved_views/{id}', json=payload)
data = response.json(){
"name": "string",
"visibility": "private",
"layout": {
"columns": [
"string"
],
"sort": {
"field": "string",
"dir": "asc"
}
}
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}Fork a saved view into a new private view
Clones an existing view (typically a shared view) into a new private view owned by the caller. The original is not modified.
Parameters
idintegerrequiredpathResponse
Forked saved view
Resource not found
Validation failed
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X POST 'https://api.nitrosend.com/v1/my/saved_views/{id}/fork'const response = await fetch('https://api.nitrosend.com/v1/my/saved_views/{id}/fork', {
method: 'POST',
});
const data = await response.json();import requests
response = requests.post('https://api.nitrosend.com/v1/my/saved_views/{id}/fork')
data = response.json(){
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}Public
Unauthenticated public endpoints
Ingest a Shopify Web Pixel event
Browser-safe public collector for Shopify Web Pixel standard events.
Requires a dedicated wpkey_live_... collector key. Secret
nskey_live_... API keys are rejected. Pixel events are treated as
funnel telemetry; verified Shopify webhooks remain authoritative for
revenue checkout/purchase Events.
Body
event_idstringrequiredevent_namestringproduct_viewedproduct_added_to_cartproduct_removed_from_cartcheckout_startedcheckout_completedrequiredcustomer_idstringemailstring<email>phonestringpropertiesobjectResponse
Event accepted, ignored, or dropped
Not authenticated
Validation failed
Authorization
bearerAuthcurl -X POST 'https://api.nitrosend.com/v1/public/shopify/events' \
-H 'Content-Type: application/json' \
-d '{
"event_id": "string",
"event_name": "product_viewed",
"customer_id": "string",
"email": "user@example.com",
"phone": "string",
"properties": {}
}'const response = await fetch('https://api.nitrosend.com/v1/public/shopify/events', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"event_id": "string",
"event_name": "product_viewed",
"customer_id": "string",
"email": "user@example.com",
"phone": "string",
"properties": {}
}),
});
const data = await response.json();import requests
payload = {
"event_id": "string",
"event_name": "product_viewed",
"customer_id": "string",
"email": "user@example.com",
"phone": "string",
"properties": {}
}
response = requests.post('https://api.nitrosend.com/v1/public/shopify/events', json=payload)
data = response.json(){
"event_id": "string",
"event_name": "product_viewed",
"customer_id": "string",
"email": "user@example.com",
"phone": "string",
"properties": {}
}{
"ok": true,
"outcome": "captured",
"event_id": 0
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}Create or update a public contact (website forms)
Public signup endpoint for website forms. Authenticate with a wpkey_live_… public key. Returns { ok: true } whether the contact is new or already subscribed; this preserves idempotency and avoids leaking which emails are on the list.
Use the brand's public key (wpkey_live_…). Secret keys (nskey_live_…) are rejected on this endpoint.
Body
emailstring<email>requiredSubscriber email address.
list_idintegerrequiredID of a contact list owned by the brand whose public key is presented.
first_namestring | nullOptional first name written to the contact.
last_namestring | nullOptional last name written to the contact.
phonestring | nullOptional E.164 phone number written to the SMS channel if provided.
sourcestring | nullOptional free-text label, e.g. "footer-form" or "/pricing", recorded against the signup.
dataobject | nullOptional bag of custom contact data. Reserved keys are silently dropped.
Response
Contact accepted
Not authenticated
Not authorized
Resource not found
Validation failed
Rate limit exceeded
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X POST 'https://api.nitrosend.com/v1/public/contacts' \
-H 'Content-Type: application/json' \
-d '{
"email": "user@example.com",
"list_id": 0,
"first_name": "string",
"last_name": "string",
"phone": "string",
"source": "string",
"data": {}
}'const response = await fetch('https://api.nitrosend.com/v1/public/contacts', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"email": "user@example.com",
"list_id": 0,
"first_name": "string",
"last_name": "string",
"phone": "string",
"source": "string",
"data": {}
}),
});
const data = await response.json();import requests
payload = {
"email": "user@example.com",
"list_id": 0,
"first_name": "string",
"last_name": "string",
"phone": "string",
"source": "string",
"data": {}
}
response = requests.post('https://api.nitrosend.com/v1/public/contacts', json=payload)
data = response.json(){
"email": "user@example.com",
"list_id": 0,
"first_name": "string",
"last_name": "string",
"phone": "string",
"source": "string",
"data": {}
}{
"ok": true
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string",
"validation_errors": {}
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}Get available plans
Response
Active plans
curl -X GET 'https://api.nitrosend.com/v1/app'const response = await fetch('https://api.nitrosend.com/v1/app', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/app')
data = response.json(){
"plans": [
{
"id": 0,
"name": "string",
"active": true
}
],
"stripe_publishable_key": "string"
}MCP
Model Context Protocol JSON-RPC endpoint and discovery
Discover the MCP server
Returns MCP discovery metadata for clients that connect over HTTP.
Response
MCP discovery metadata
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/mcp'const response = await fetch('https://api.nitrosend.com/mcp', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/mcp')
data = response.json(){}MCP JSON-RPC endpoint
JSON-RPC endpoint for the Nitrosend MCP server. Read nitro://account,
nitro://config, or call nitro_get_status for bound account identity;
there is no per-tool account override argument.
Body
Response
JSON-RPC response
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X POST 'https://api.nitrosend.com/mcp' \
-H 'Content-Type: application/json' \
-d '{}'const response = await fetch('https://api.nitrosend.com/mcp', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({}),
});
const data = await response.json();import requests
payload = {}
response = requests.post('https://api.nitrosend.com/mcp', json=payload)
data = response.json(){}{}Chat Sessions
List persisted chat sessions
Parameters
pageinteger1querylimitinteger<= 10025queryResponse
Paginated list of chat sessions
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/chat_sessions'const response = await fetch('https://api.nitrosend.com/v1/my/chat_sessions', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/chat_sessions')
data = response.json()[
{
"id": 0,
"account_id": 0,
"brand_id": 0,
"title": "string",
"status": "active",
"started_at": "2024-01-15T09:30:00Z",
"last_message_at": "2024-01-15T09:30:00Z",
"message_count": 0,
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}
]Get a persisted chat session with ordered messages
Parameters
idintegerrequiredpathResponse
Chat session
Resource not found
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X GET 'https://api.nitrosend.com/v1/my/chat_sessions/{id}'const response = await fetch('https://api.nitrosend.com/v1/my/chat_sessions/{id}', {
method: 'GET',
});
const data = await response.json();import requests
response = requests.get('https://api.nitrosend.com/v1/my/chat_sessions/{id}')
data = response.json(){
"id": 0,
"account_id": 0,
"brand_id": 0,
"title": "string",
"status": "active",
"started_at": "2024-01-15T09:30:00Z",
"last_message_at": "2024-01-15T09:30:00Z",
"message_count": 0,
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z",
"messages": [
{
"id": 0,
"role": "user",
"content": "string",
"tool_calls": [
{}
],
"sequence": 0,
"created_at": "2024-01-15T09:30:00Z"
}
]
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}Close an active persisted chat session
Parameters
idintegerrequiredpathResponse
Closed chat session
Resource not found
Authorization
BearerAuthhttp (bearer)Authentication scheme depends on the route:
- Authenticated endpoints (
/v1/my/*) accept a server API key (nskey_live_...) or a JWT token. API key is checked first; if not found, falls back to Devise JWT authentication. - Public website-form endpoints (
/v1/public/*) require a brand public key (wpkey_live_...). Secret keys (nskey_live_...) are rejected here so they can't be smuggled into browser code.
For accounts with multiple brands, include the X-Brand-SID header to scope
requests to a specific brand. If omitted, the account's default
brand is used. JWT requests can also include X-Account-ID to select
an accessible account.
curl -X PATCH 'https://api.nitrosend.com/v1/my/chat_sessions/{id}/close'const response = await fetch('https://api.nitrosend.com/v1/my/chat_sessions/{id}/close', {
method: 'PATCH',
});
const data = await response.json();import requests
response = requests.patch('https://api.nitrosend.com/v1/my/chat_sessions/{id}/close')
data = response.json(){
"id": 0,
"account_id": 0,
"brand_id": 0,
"title": "string",
"status": "active",
"started_at": "2024-01-15T09:30:00Z",
"last_message_at": "2024-01-15T09:30:00Z",
"message_count": 0,
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}Models
TimelineEntry
objectOne normalised, whitelisted entry in a contact's unified timeline.
idstringrequiredStable composite id, e.g. "event-123".
kindstringeventactivitylifecyclerequiredtypestringrequiredEvent/activity name, e.g. checkout, opened.
titlestringrequiredHuman-readable label for the entry.
occurred_atstring<date-time>requiredmetaobjectrequiredDisplay-only extras (e.g. amount, resource_name). No internal fields.
{
"id": "string",
"kind": "event",
"type": "string",
"title": "string",
"occurred_at": "2024-01-15T09:30:00Z",
"meta": {}
}Error
objectcodeintegerrequiredmessagestringrequirederrorbooleanrequirederror_codestring | nullOptional machine-readable error reason.
{
"code": 0,
"message": "string",
"error": true,
"error_code": "string"
}User
objectidintegerfirst_namestring | nulllast_namestring | nullemailstring<email>mobilestring | nullcountry_codestring | nulltime_zonestring | nulladminbooleancreated_atstring<date-time>updated_atstring<date-time>{
"id": 0,
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"mobile": "string",
"country_code": "string",
"time_zone": "string",
"admin": true,
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}Impersonator
objectidintegeremailstring<email>namestring | null{
"id": 0,
"email": "user@example.com",
"name": "string"
}ImpersonationStatus
objectimpersonatingbooleanrequiredimpersonatorImpersonator | nullrequired{
"impersonating": true,
"impersonator": {
"id": 0,
"email": "user@example.com",
"name": "string"
}
}ImpersonationExit
objectredirect_urlstring<uri>required{
"redirect_url": "https://api.nitrosend.com/adm"
}Account
objectidintegernamestring | nullavatarstring | nullSigned blob ID
bannerstring | nullSigned blob ID
account_tierstringfreepaidtrustedsafe_mode_enabledbooleanbillingobjectbrandsArray<Brand>teamobjectcreated_atstring<date-time>updated_atstring<date-time>{
"id": 0,
"name": "string",
"avatar": "string",
"banner": "string",
"account_tier": "free",
"safe_mode_enabled": true,
"billing": {
"plan_name": "string",
"overage": {},
"resources": {
"email": {
"used": 0,
"allowance": 0,
"remaining": 0,
"overage_rate": 0
},
"sms": {
"used": 0,
"allowance": 0,
"remaining": 0,
"overage_rate": 0
},
"ai": {
"used": 0,
"allowance": 0,
"remaining": 0,
"overage_rate": 0
}
},
"brands": {
"used": 0,
"limit": 0,
"remaining": 0,
"unlimited": true,
"can_create": true
},
"lifetime": {
"email_sent": 0,
"sms_sent": 0,
"ai_used": 0
}
},
"brands": [
{
"id": 0,
"sid": "string",
"account_id": 0,
"brand_color": "string",
"text_color": "string",
"bg_color": "string",
"radius": 0,
"spacing_density": "compact",
"font_heading": "string",
"font_body": "string",
"brand_document": "string",
"style_notes": "string",
"tone": "string",
"company_description": "string",
"industry": "string",
"example_copy": [
"string"
],
"default_header": {},
"default_footer": {},
"default_theme": {},
"physical_address": "string",
"company_name": "string",
"source_url": "string",
"last_scraped_at": "2024-01-15T09:30:00Z",
"links": [
{
"url": "string",
"icon": "string",
"title": "string"
}
],
"logo": "string",
"complete": true,
"email_from_name": "string",
"email_from_email": "string",
"email_reply_to": "string",
"email_view_online": true,
"test_email_recipients": [
"user@example.com"
],
"onboarding_state": {},
"onboarding": {
"steps": {},
"progress": {
"completed": 0,
"total": 0
}
},
"domain_verified": true,
"can_send": true,
"byo_routing": {
"mismatch": true,
"provider": "string",
"bypassing_domains": [
"string"
],
"message": "string"
},
"subscribed_contacts_count": 0,
"using_sandbox": true,
"sandbox_email": "string",
"sandbox_monthly_cap": 0,
"sandbox_sends_remaining": 0,
"capabilities": {},
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}
],
"team": {
"seat_limit": 0,
"seat_count": 0,
"member_count": 0,
"invite_count": 0,
"current_role": "string",
"can_manage_team": true
},
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}AccountTeam
objectaccountAccountmembershipsArray<AccountMembership>invitesArray<AccountInvite>accessible_accountsArray<Account>{
"account": {
"id": 0,
"name": "string",
"avatar": "string",
"banner": "string",
"account_tier": "free",
"safe_mode_enabled": true,
"billing": {
"plan_name": "string",
"overage": {},
"resources": {
"email": {
"used": 0,
"allowance": 0,
"remaining": 0,
"overage_rate": 0
},
"sms": {
"used": 0,
"allowance": 0,
"remaining": 0,
"overage_rate": 0
},
"ai": {
"used": 0,
"allowance": 0,
"remaining": 0,
"overage_rate": 0
}
},
"brands": {
"used": 0,
"limit": 0,
"remaining": 0,
"unlimited": true,
"can_create": true
},
"lifetime": {
"email_sent": 0,
"sms_sent": 0,
"ai_used": 0
}
},
"brands": [
{
"id": 0,
"sid": "string",
"account_id": 0,
"brand_color": "string",
"text_color": "string",
"bg_color": "string",
"radius": 0,
"spacing_density": "compact",
"font_heading": "string",
"font_body": "string",
"brand_document": "string",
"style_notes": "string",
"tone": "string",
"company_description": "string",
"industry": "string",
"example_copy": [
"string"
],
"default_header": {},
"default_footer": {},
"default_theme": {},
"physical_address": "string",
"company_name": "string",
"source_url": "string",
"last_scraped_at": "2024-01-15T09:30:00Z",
"links": [
{
"url": "string",
"icon": "string",
"title": "string"
}
],
"logo": "string",
"complete": true,
"email_from_name": "string",
"email_from_email": "string",
"email_reply_to": "string",
"email_view_online": true,
"test_email_recipients": [
"user@example.com"
],
"onboarding_state": {},
"onboarding": {
"steps": {},
"progress": {
"completed": 0,
"total": 0
}
},
"domain_verified": true,
"can_send": true,
"byo_routing": {
"mismatch": true,
"provider": "string",
"bypassing_domains": [
"string"
],
"message": "string"
},
"subscribed_contacts_count": 0,
"using_sandbox": true,
"sandbox_email": "string",
"sandbox_monthly_cap": 0,
"sandbox_sends_remaining": 0,
"capabilities": {},
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}
],
"team": {
"seat_limit": 0,
"seat_count": 0,
"member_count": 0,
"invite_count": 0,
"current_role": "string",
"can_manage_team": true
},
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
},
"memberships": [
{
"id": 0,
"role": "member",
"user_id": 0,
"email": "user@example.com",
"name": "string",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}
],
"invites": [
{
"id": 0,
"account_id": 0,
"email": "user@example.com",
"role": "member",
"token": "string",
"status": "pending",
"accepted_at": "2024-01-15T09:30:00Z",
"revoked_at": "2024-01-15T09:30:00Z",
"expires_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}
],
"accessible_accounts": [
{
"id": 0,
"name": "string",
"avatar": "string",
"banner": "string",
"account_tier": "free",
"safe_mode_enabled": true,
"billing": {
"plan_name": "string",
"overage": {},
"resources": {
"email": {
"used": 0,
"allowance": 0,
"remaining": 0,
"overage_rate": 0
},
"sms": {
"used": 0,
"allowance": 0,
"remaining": 0,
"overage_rate": 0
},
"ai": {
"used": 0,
"allowance": 0,
"remaining": 0,
"overage_rate": 0
}
},
"brands": {
"used": 0,
"limit": 0,
"remaining": 0,
"unlimited": true,
"can_create": true
},
"lifetime": {
"email_sent": 0,
"sms_sent": 0,
"ai_used": 0
}
},
"brands": [
{
"id": 0,
"sid": "string",
"account_id": 0,
"brand_color": "string",
"text_color": "string",
"bg_color": "string",
"radius": 0,
"spacing_density": "compact",
"font_heading": "string",
"font_body": "string",
"brand_document": "string",
"style_notes": "string",
"tone": "string",
"company_description": "string",
"industry": "string",
"example_copy": [
"string"
],
"default_header": {},
"default_footer": {},
"default_theme": {},
"physical_address": "string",
"company_name": "string",
"source_url": "string",
"last_scraped_at": "2024-01-15T09:30:00Z",
"links": [
{
"url": "string",
"icon": "string",
"title": "string"
}
],
"logo": "string",
"complete": true,
"email_from_name": "string",
"email_from_email": "string",
"email_reply_to": "string",
"email_view_online": true,
"test_email_recipients": [
"user@example.com"
],
"onboarding_state": {},
"onboarding": {
"steps": {},
"progress": {
"completed": 0,
"total": 0
}
},
"domain_verified": true,
"can_send": true,
"byo_routing": {
"mismatch": true,
"provider": "string",
"bypassing_domains": [
"string"
],
"message": "string"
},
"subscribed_contacts_count": 0,
"using_sandbox": true,
"sandbox_email": "string",
"sandbox_monthly_cap": 0,
"sandbox_sends_remaining": 0,
"capabilities": {},
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}
],
"team": {
"seat_limit": 0,
"seat_count": 0,
"member_count": 0,
"invite_count": 0,
"current_role": "string",
"can_manage_team": true
},
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}
]
}AccountMembership
objectidintegerrolestringmemberadminowneruser_idintegeremailstring<email>namestring | nullcreated_atstring<date-time>updated_atstring<date-time>{
"id": 0,
"role": "member",
"user_id": 0,
"email": "user@example.com",
"name": "string",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}AccountInvite
objectidintegeraccount_idintegeremailstring<email>rolestringmemberadmintokenstringstatusstringpendingacceptedrevokedexpiredaccepted_atstring<date-time> | nullrevoked_atstring<date-time> | nullexpires_atstring<date-time> | nullcreated_atstring<date-time>updated_atstring<date-time>{
"id": 0,
"account_id": 0,
"email": "user@example.com",
"role": "member",
"token": "string",
"status": "pending",
"accepted_at": "2024-01-15T09:30:00Z",
"revoked_at": "2024-01-15T09:30:00Z",
"expires_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}Subscription
objectidintegerplan_idintegerplan_namestring | nullstatusstringpendingactiveinactivecanceledfree_tierintervalstringmonthyearweekdaycurrencystringsubtotal_centsintegertax_centsintegertotal_centsintegerbase_price_centsintegerdiscount_centsintegerPer-period Stripe discount in cents (0 when none).
next_payment_centsintegerAmount billed next period
discount_end_atstring<date-time> | nullWhen the discount stops (null for forever/once or no discount).
activatedboolean{
"id": 0,
"plan_id": 0,
"plan_name": "string",
"status": "pending",
"interval": "month",
"currency": "string",
"subtotal_cents": 0,
"tax_cents": 0,
"total_cents": 0,
"base_price_cents": 0,
"discount_cents": 0,
"next_payment_cents": 0,
"discount_end_at": "2024-01-15T09:30:00Z",
"activated": true
}SubscriptionCreateRequest
objectplan_idintegerrequiredstripe_tokenstring | nullStripe card token for paid-plan creation.
coupon_codestring | nullCustomer-entered Stripe promotion code or coupon ID.
{
"plan_id": 0,
"stripe_token": "string",
"coupon_code": "string"
}SubscriptionChangeRequest
objectplan_idintegerrequiredcoupon_codestring | nullCustomer-entered Stripe promotion code or coupon ID.
{
"plan_id": 0,
"coupon_code": "string"
}SubscriptionCouponPreviewRequest
objectplan_idintegerrequiredcoupon_codestringrequiredCustomer-entered Stripe promotion code or coupon ID.
{
"plan_id": 0,
"coupon_code": "string"
}SubscriptionCouponPreview
objectcodestringrequireddiscount_labelstringrequireddiscount_centsintegerrequiredsubtotal_centsintegerrequiredtax_centsintegerrequiredtotal_centsintegerrequiredtotal_after_discount_centsintegerrequiredcurrencystringrequired{
"code": "string",
"discount_label": "string",
"discount_cents": 0,
"subtotal_cents": 0,
"tax_cents": 0,
"total_cents": 0,
"total_after_discount_cents": 0,
"currency": "string"
}OAuthPopupAccount
objectidintegerrequirednamestringrequiredcan_managebooleanneeds_subscribebooleanrequired{
"id": 0,
"name": "string",
"can_manage": true,
"needs_subscribe": true
}OAuthPopupPlan
objectidintegerrequirednamestringrequiredslugstringrequiredbase_price_centsintegerrequiredintervalstring | null{
"id": 0,
"name": "string",
"slug": "string",
"base_price_cents": 0,
"interval": "string"
}OAuthPopupContext
objectaccountsArray<OAuthPopupAccount>requiredplansArray<OAuthPopupPlan>requiredstripe_publishable_keystring | null{
"accounts": [
{
"id": 0,
"name": "string",
"can_manage": true,
"needs_subscribe": true
}
],
"plans": [
{
"id": 0,
"name": "string",
"slug": "string",
"base_price_cents": 0,
"interval": "string"
}
],
"stripe_publishable_key": "string"
}OAuthPopupSubscribeRequest
objectplan_idintegerrequiredaccount_idinteger | nullstripe_tokenstring | null{
"plan_id": 0,
"account_id": 0,
"stripe_token": "string"
}OAuthLaunchRequest
objectproviderstringgoogle_oauth2githubrequiredauth_intentstringappagentappauth_stepstringloginsignuploginresume_urlstring<uri> | nullRequired when auth_intent=agent; must point to the frontend /oauth/connect route.
{
"provider": "google_oauth2",
"auth_intent": "app",
"auth_step": "login",
"resume_url": "https://example.com"
}OAuthLaunchResponse
objectlaunch_urlstring<uri>required{
"launch_url": "https://example.com"
}Brand
objectidintegersidstringread onlyPublic secure identifier (non-sequential)
account_idintegerbrand_colorstring | nulltext_colorstring | nullbg_colorstring | nullradiusinteger | null[0, 64]spacing_densitystring | nullcompactnormalspaciousfont_headingstring | nullfont_bodystring | nullbrand_documentstring | nullstyle_notesstring | nulltonestring | nullcompany_descriptionstring | nullindustrystring | nullexample_copyArray<string> | nulldefault_headerobject | nulldefault_footerobject | nulldefault_themeobject | nullphysical_addressstring | nullcompany_namestring | nullsource_urlstring | nulllast_scraped_atstring<date-time> | nulllinksArray<object> | nulllogostring | nullLogo URL
completebooleanTrue when brand_color and company_name are set
email_from_namestring | nullemail_from_emailstring | nullemail_reply_tostring | nullemail_view_onlinebooleanDefault-off brand setting that injects a campaign view-in-browser link when a verified tracking domain is available.
test_email_recipientsArray<string>onboarding_stateobjectJSONB — keys are step names, values are completion metadata
onboardingobjectdomain_verifiedbooleancan_sendbooleanbyo_routingobjectWarns when the brand has connected its own (BYO) email provider but verified sending domains still route through nitrosend's shared managed pool. Read-only; never blocks a send. mismatch is false (and message null) when all is well.
subscribed_contacts_countintegerCount of subscribed contacts in this brand.
using_sandboxbooleansandbox_emailstring | nullsandbox_monthly_capintegersandbox_sends_remainingintegercapabilitiesobjectcreated_atstring<date-time>updated_atstring<date-time>{
"id": 0,
"sid": "string",
"account_id": 0,
"brand_color": "string",
"text_color": "string",
"bg_color": "string",
"radius": 0,
"spacing_density": "compact",
"font_heading": "string",
"font_body": "string",
"brand_document": "string",
"style_notes": "string",
"tone": "string",
"company_description": "string",
"industry": "string",
"example_copy": [
"string"
],
"default_header": {},
"default_footer": {},
"default_theme": {},
"physical_address": "string",
"company_name": "string",
"source_url": "string",
"last_scraped_at": "2024-01-15T09:30:00Z",
"links": [
{
"url": "string",
"icon": "string",
"title": "string"
}
],
"logo": "string",
"complete": true,
"email_from_name": "string",
"email_from_email": "string",
"email_reply_to": "string",
"email_view_online": true,
"test_email_recipients": [
"user@example.com"
],
"onboarding_state": {},
"onboarding": {
"steps": {},
"progress": {
"completed": 0,
"total": 0
}
},
"domain_verified": true,
"can_send": true,
"byo_routing": {
"mismatch": true,
"provider": "string",
"bypassing_domains": [
"string"
],
"message": "string"
},
"subscribed_contacts_count": 0,
"using_sandbox": true,
"sandbox_email": "string",
"sandbox_monthly_cap": 0,
"sandbox_sends_remaining": 0,
"capabilities": {},
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}BrandDeletionSafetyImpact
objectcontactsinteger>= 0requiredcampaignsinteger>= 0requiredflowsinteger>= 0requiredtemplatesinteger>= 0requireddomainsinteger>= 0requiredmessagesinteger>= 0required{
"contacts": 0,
"campaigns": 0,
"flows": 0,
"templates": 0,
"domains": 0,
"messages": 0
}BrandDeletionSafetyActiveSends
objectqueued_messagesinteger>= 0requiredactive_campaignsinteger>= 0requiredScheduled or live campaigns.
{
"queued_messages": 0,
"active_campaigns": 0
}BrandDeletionSafety
objectdeletion_impactBrandDeletionSafetyImpactrequiredactive_sendsBrandDeletionSafetyActiveSendsrequiredcan_deletebooleanrequiredTrue when no force confirmation is required.
requires_forcebooleanrequiredTrue when active sends require force=true to delete.
{
"deletion_impact": {
"contacts": 0,
"campaigns": 0,
"flows": 0,
"templates": 0,
"domains": 0,
"messages": 0
},
"active_sends": {
"queued_messages": 0,
"active_campaigns": 0
},
"can_delete": true,
"requires_force": true
}SetupCenterPayload
objectcardsArray<SetupCenterCard>sectionsobjectprogressobjectseenbooleandismissedbooleancompleteboolean{
"cards": [
{
"id": "brand_kit_scan",
"complete": true,
"acknowledged": true,
"acknowledged_at": "2024-01-15T09:30:00Z"
}
],
"sections": {
"required": [
"string"
],
"recommended": [
"string"
]
},
"progress": {
"completed": 0,
"total": 0
},
"seen": true,
"dismissed": true,
"complete": true
}SetupCenterCard
objectidstringbrand_kit_scandnsplanconnect_agentimport_subscribersconnect_transactionalcompletebooleanacknowledgedbooleanacknowledged_atstring<date-time> | null{
"id": "brand_kit_scan",
"complete": true,
"acknowledged": true,
"acknowledged_at": "2024-01-15T09:30:00Z"
}FieldCatalog
objectidintegerrequiredkeystringrequiredDot-separated field key. Typed contact columns use the bare column name
(e.g. email, first_name). JSONB data keys are prefixed with data.
(e.g. data.plan, data.apollo.title, data.hubspot.company, data.tags).
categorystringcontactcustomenrichmentengagementtagrequiredDerived from the key namespace.
contact— typed column on the contacts tabletag—data.tagsarrayenrichment— reserved enrichment namespaces such asdata.apollo.*,data.pdl.*,data.attio.*,data.hubspot.*,data.stripe.*,data.shopify.*, and deriveddata.nitro.*custom— any otherdata.*keyengagement— future engagement traits (reserved)
field_typestringstringnumberbooleandaterequiredInferred from the first observed value; pinned and never flipped.
labelstringrequiredHuman-readable label. Defaults to a humanised version of the key.
promotedbooleanrequiredWhether this field is pinned as a default column in the contacts grid.
fill_ratestring | nullPercentage of contacts that have a non-null value for this field. Computed asynchronously; may be null if the refresh job has not run yet.
fill_rate_refreshed_atstring<date-time> | nullWhen fill_rate was last computed.
created_atstring<date-time>updated_atstring<date-time>{
"id": 0,
"key": "string",
"category": "contact",
"field_type": "string",
"label": "string",
"promoted": true,
"fill_rate": "75.0",
"fill_rate_refreshed_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}Contact
objectidintegerbrand_idinteger | nulluuidstring<uuid>first_namestring | nulllast_namestring | nullsourcestring | nullcountry_codestring | nullflag_emojistring | nullUnicode regional-indicator emoji pair derived from country_code (e.g. "🇦🇺"). Null when country_code is blank.
dataobjectCustom key-value data. The reserved key tags holds an array of
string labels used for segmentation and targeting. Reserved enrichment
namespaces such as apollo, pdl, attio, hubspot, stripe,
shopify, and derived nitro may appear when integrations or
enrichment jobs write source-scoped data.
subscribed_phonebooleansubscribed_emailbooleanemailstring<email> | nullConvenience value for the preferred email channel. Full channel detail remains in channels[].
subscribedobjectDenormalized subscription summary by channel family.
verification_statusstringverifiedsuppressedunverifiedenrichment_statusstringenrichednot_enrichedmailbox_providerstringgmailappleoutlookcorporateunknownDerived mailbox provider for the contact's primary email domain. Known consumer domains map to gmail, apple, or outlook; any other valid email domain maps to corporate; unknown means no email is present.
list_idsArray<integer>last_interacted_atstring<date-time> | nullcreated_atstring<date-time>updated_atstring<date-time>engagementobject | nullAggregated email engagement rollup for this contact. All fields are nil-safe: when no rollup row exists yet, rating is "never", counts are 0, rates and timestamps are null.
channelsArray<ContactChannel>{
"id": 0,
"brand_id": 0,
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"first_name": "string",
"last_name": "string",
"source": "string",
"country_code": "string",
"flag_emoji": "string",
"data": {
"tags": [
"vip",
"newsletter"
],
"plan": "pro"
},
"subscribed_phone": true,
"subscribed_email": true,
"email": "user@example.com",
"subscribed": {
"email": true,
"phone": true
},
"verification_status": "verified",
"enrichment_status": "enriched",
"mailbox_provider": "gmail",
"list_ids": [
0
],
"last_interacted_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z",
"engagement": {
"rating": "engaged",
"emails_sent": 0,
"unique_opens": 0,
"clicks": 0,
"open_rate": 0,
"click_rate": 0,
"last_opened_at": "2024-01-15T09:30:00Z",
"last_clicked_at": "2024-01-15T09:30:00Z"
},
"channels": [
{
"id": 0,
"contact_id": 0,
"kind": "email",
"value": "string",
"subscribed": true,
"verified": true,
"opt_in_at": "2024-01-15T09:30:00Z",
"opt_out_at": "2024-01-15T09:30:00Z",
"sent_count": 0,
"fail_count": 0,
"data": {},
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}
]
}ContactChannel
objectidintegercontact_idintegerkindstringemailphonevaluestringsubscribedbooleanverifiedbooleanopt_in_atstring<date-time> | nullopt_out_atstring<date-time> | nullsent_countintegerfail_countintegerdataobjectcreated_atstring<date-time>updated_atstring<date-time>{
"id": 0,
"contact_id": 0,
"kind": "email",
"value": "string",
"subscribed": true,
"verified": true,
"opt_in_at": "2024-01-15T09:30:00Z",
"opt_out_at": "2024-01-15T09:30:00Z",
"sent_count": 0,
"fail_count": 0,
"data": {},
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}ImageAsset
objectmedia_kindstringimagemedia_urlstring<uri>image_urlstring<uri>signed_idstringfilenamestringcontent_typestringbyte_sizeintegerwidthinteger | nullIntrinsic pixel width when detectable.
heightinteger | nullIntrinsic pixel height when detectable.
{
"media_kind": "image",
"media_url": "https://example.com",
"image_url": "https://example.com",
"signed_id": "string",
"filename": "string",
"content_type": "string",
"byte_size": 0,
"width": 0,
"height": 0
}ContactList
objectidintegeraccount_idintegerbrand_idinteger | nullnamestringcontacts_countintegersegment_idinteger | nullstalebooleanlast_populated_atstring<date-time> | nullcreated_atstring<date-time>updated_atstring<date-time>{
"id": 0,
"account_id": 0,
"brand_id": 0,
"name": "string",
"contacts_count": 0,
"segment_id": 0,
"stale": true,
"last_populated_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}ListDeleteWarning
objectcampaign_namesArray<string>flow_namesArray<string>{
"campaign_names": [
"string"
],
"flow_names": [
"string"
]
}BulkListContactsRequest
objectactionstringaddremoverequiredAdd existing contacts to the list or remove them from it.
emailsArray<string>required{
"action": "add",
"emails": [
"user@example.com"
]
}BulkListContactsResponse
objectactionstringaddremovelist_idintegeraddedintegerContacts newly added for add actions
removedintegerContacts removed for remove actions
already_in_listArray<string>not_in_listArray<string>not_foundArray<string>invalid_emailsArray<string>{
"action": "add",
"list_id": 0,
"added": 0,
"removed": 0,
"already_in_list": [
"user@example.com"
],
"not_in_list": [
"user@example.com"
],
"not_found": [
"user@example.com"
],
"invalid_emails": [
"string"
]
}DirectUploadCreateRequest
objectpurposestringimportimagemedia_assetSet to import for CSV contact imports, or image/media_asset for image media assets.
blobobjectrequired{
"purpose": "import",
"blob": {
"filename": "contacts.csv",
"byte_size": 1048576,
"checksum": "string",
"content_type": "text/csv",
"metadata": {}
}
}DirectUpload
objectsigned_idstringSubmit this value to endpoints that consume direct uploads.
filenamestringbyte_sizeintegercontent_typestring | nulldirect_uploadobject{
"signed_id": "string",
"filename": "string",
"byte_size": 0,
"content_type": "string",
"direct_upload": {
"url": "https://example.com",
"headers": {}
}
}ImportPolicy
objectmax_file_size_bytesintegermax_file_size_mbintegerauto_max_rowsintegercontact_us_max_rowsintegermax_active_importsintegercreate_rate_limit_per_minuteintegerdirect_upload_rate_limit_per_minuteinteger{
"max_file_size_bytes": 94371840,
"max_file_size_mb": 90,
"auto_max_rows": 20000,
"contact_us_max_rows": 250000,
"max_active_imports": 3,
"create_rate_limit_per_minute": 10,
"direct_upload_rate_limit_per_minute": 30
}ImportSpec
objectresourcestringcontactsparserstringdefaultuiobjectrequired_rulesobjectfieldsArray<object>guardrailsImportPolicy{
"resource": "contacts",
"parser": "default",
"ui": {},
"required_rules": {},
"fields": [
{}
],
"guardrails": {
"max_file_size_bytes": 94371840,
"max_file_size_mb": 90,
"auto_max_rows": 20000,
"contact_us_max_rows": 250000,
"max_active_imports": 3,
"create_rate_limit_per_minute": 10,
"direct_upload_rate_limit_per_minute": 30
}
}ImportGuardrail
objecttierstringautohold_sendscontact_usImport guardrail classification based on contact count.
statusstringokrequires_reviewcontact_salesClient-facing guardrail status vocabulary.
contact_us_ceilingintegerMaximum self-serve import contact count before contact-us routing.
sends_heldbooleanTrue when imported contacts are created but campaign sends remain held for review.
{
"tier": "auto",
"status": "ok",
"contact_us_ceiling": 250000,
"sends_held": true
}Import
objectidintegerresourcestringcontactsparserstringdefaultstatusstringpendingprocessingfailedcanceledcompletecontact_ustotal_rowsinteger | nullsuccess_rowsinteger | nullfailed_rowsinteger | nullprogressobjectCanonical live-progress block (the single progress representation). pct is the only percent source; a null pct means indeterminate.
import_errorsArray<Array<integer | string>>Row-level errors as [line_number, message, source].
columnsobject | nulloptionsobject | nullassigned_list_idsArray<integer>assigned_listsArray<object>guardrailImportGuardrailstarted_atstring<date-time> | nullended_atstring<date-time> | nullcreated_atstring<date-time>{
"id": 0,
"resource": "contacts",
"parser": "default",
"status": "pending",
"total_rows": 0,
"success_rows": 0,
"failed_rows": 0,
"progress": {
"status": "pending",
"pct": 0,
"stages": [
{
"key": "string",
"label": "string",
"count": 0,
"state": "done"
}
]
},
"import_errors": [
[
0
]
],
"columns": {},
"options": {},
"assigned_list_ids": [
0
],
"assigned_lists": [
{
"id": 0,
"name": "string"
}
],
"guardrail": {
"tier": "auto",
"status": "ok",
"contact_us_ceiling": 250000,
"sends_held": true
},
"started_at": "2024-01-15T09:30:00Z",
"ended_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z"
}Export
objectidintegerresourcestringcontactsformatstringcsvstatusstringpendingprocessingcompletefailedtotal_rowsinteger | nullrows_writtenintegerRows written so far; the live numerator against total_rows.
error_messagestring | nullreadybooleanTrue once the export is complete and the file is available.
download_pathstring | nullPath to download the CSV; present only when ready is true.
progressobjectLive job-progress block, updated as the export streams. status
normalizes the job lifecycle, pct is the completion percentage
(null while the row count is still unknown), and stages is the
ordered Queued to Building to Ready funnel.
started_atstring<date-time> | nullended_atstring<date-time> | nullcreated_atstring<date-time>{
"id": 0,
"resource": "contacts",
"format": "csv",
"status": "pending",
"total_rows": 0,
"rows_written": 0,
"error_message": "string",
"ready": true,
"download_path": "string",
"progress": {
"status": "pending",
"pct": 0,
"stages": [
{
"key": "string",
"label": "string",
"count": 0,
"state": "done"
}
]
},
"started_at": "2024-01-15T09:30:00Z",
"ended_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z"
}SavedView
objectidintegersurfacestringcontactssendingactivitynamestringvisibilitystringprivatesharedfiltersSegmentFilterExpressionlayoutSavedViewLayout | nullTable layout preset for contacts surface views. Only present when surface = contacts.
ownerbooleanTrue when the current user is the creator of this view
created_atstring<date-time>updated_atstring<date-time>{
"id": 0,
"surface": "contacts",
"name": "string",
"visibility": "private",
"layout": {
"columns": [
"string"
],
"sort": {
"field": "string",
"dir": "asc"
}
},
"owner": true,
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}SavedViewLayout
objectTable layout preset for contacts surface views. Only present when surface = contacts.
columnsArray<string>Ordered list of column keys to display
sortobject{
"columns": [
"string"
],
"sort": {
"field": "string",
"dir": "asc"
}
}Segment
objectidintegeraccount_idintegerbrand_idinteger | nullnamestringoriginstringusersystemWho owns this segment. user (default) — created and managed by the user;
system — curated by the platform (Champions, Loyal, At-Risk, Dormant, New,
Suppressed, Recently unsubscribed, Bounced).
System segments cannot be renamed or deleted via the API.
filtersSegmentFilterExpressioncached_countinteger | nullLast asynchronously refreshed contact count for this segment.
count_computed_atstring<date-time> | nullWhen cached_count was last refreshed.
created_atstring<date-time>updated_atstring<date-time>{
"id": 0,
"account_id": 0,
"brand_id": 0,
"name": "string",
"origin": "user",
"cached_count": 0,
"count_computed_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}SegmentFilterExpression
objectRequest-side audience filter grammar. Use a flat array for ordinary
AND filters, { "operator": "and", "children": [...] } for the legacy
expression wrapper, or { "op": "and"|"or"|"not", "conditions": [...] }
for nested boolean logic. NOT groups must contain exactly one condition.
operatorstringandrequirednotbooleanfalsefalseLegacy flat-AND wrapper does not carry NOT; use BooleanSegmentFilterGroup for NOT.
childrenArray<AttributeSegmentFilter | any | any>requiredSegment filters are validated fail-closed. Unknown filter names,
globally invalid predicates, type-incompatible predicates, bad date
values, invalid enum values, and unsupported rolling-window filters
return a 422 invalid_filter error instead of silently widening an
audience.
[
{
"name": "string",
"predicate": "string"
}
]FlatAndSegmentFilterExpression
objectoperatorstringandrequirednotbooleanfalsefalseLegacy flat-AND wrapper does not carry NOT; use BooleanSegmentFilterGroup for NOT.
childrenArray<AttributeSegmentFilter | any | any>requiredSegment filters are validated fail-closed. Unknown filter names,
globally invalid predicates, type-incompatible predicates, bad date
values, invalid enum values, and unsupported rolling-window filters
return a 422 invalid_filter error instead of silently widening an
audience.
{
"operator": "and",
"not": false,
"children": [
{
"name": "string",
"predicate": "string"
}
]
}SegmentFilterNode
objectnamestringrequiredFilter name from nitro://schema: contact_first_name, contact_last_name,
contact_phone_number, contact_email, contact_country,
contact_subscribed_phone, contact_subscribed_email,
contact_created_at, contact_last_interacted_at,
contact_source, contact_tag,
contact_engagement_rating, contact_emails_sent, contact_last_opened_at,
contact_last_clicked_at, contact_unique_opens, contact_clicks,
contact_open_rate, contact_click_rate, contact_suppressed,
contact_suppression_reason, contact_bounced, contact_complained,
contact_soft_bounce_count, contact_unsubscribed_at, contact_list.
Catalogued custom and
enrichment fields are exposed as contact_data_
predicatestringrequiredRansack predicate: eq, not_eq, cont, not_cont, start, end,
gt, lt, gteq, lteq, present, blank, true, false, in, not_in,
within_days, not_within_days. Read /v1/my/flows/spec or
nitro://schema for the predicates allowed by each filter type.
valueanyrequiredFilter value — string, number, boolean, array of strings for in/not_in predicates (e.g. ["engaged","warm"] for contact_engagement_rating in), or array of list ids for contact_list.
predicatestringperformednot_performedrequiredpredicatestringcount_at_leastcount_at_mostrequired{
"name": "string",
"predicate": "string"
}BooleanSegmentFilterGroup
objectopstringandornotrequiredconditionsArray<any>requiredNested filter nodes. NOT groups must contain exactly one condition.
{
"op": "and",
"conditions": []
}SegmentFilters
arraySegment filters are validated fail-closed. Unknown filter names,
globally invalid predicates, type-incompatible predicates, bad date
values, invalid enum values, and unsupported rolling-window filters
return a 422 invalid_filter error instead of silently widening an
audience.
[
{
"name": "string",
"predicate": "string"
}
]SegmentPreview
objectcountintegerLive count of contacts matching the supplied filters.
sampleArray<object>Bounded contact sample for quick verification.
overlapArray<object>Bounded overlap with existing segments.
{
"count": 0,
"sample": [
{
"id": 0,
"email": "string",
"name": "string"
}
],
"overlap": [
{
"segment_id": 0,
"name": "string",
"overlap_count": 0
}
]
}AttributeSegmentFilter
objectnamestringrequiredFilter name from nitro://schema: contact_first_name, contact_last_name,
contact_phone_number, contact_email, contact_country,
contact_subscribed_phone, contact_subscribed_email,
contact_created_at, contact_last_interacted_at,
contact_source, contact_tag,
contact_engagement_rating, contact_emails_sent, contact_last_opened_at,
contact_last_clicked_at, contact_unique_opens, contact_clicks,
contact_open_rate, contact_click_rate, contact_suppressed,
contact_suppression_reason, contact_bounced, contact_complained,
contact_soft_bounce_count, contact_unsubscribed_at, contact_list.
Catalogued custom and
enrichment fields are exposed as contact_data_
predicatestringrequiredRansack predicate: eq, not_eq, cont, not_cont, start, end,
gt, lt, gteq, lteq, present, blank, true, false, in, not_in,
within_days, not_within_days. Read /v1/my/flows/spec or
nitro://schema for the predicates allowed by each filter type.
valueanyrequiredFilter value — string, number, boolean, array of strings for in/not_in predicates (e.g. ["engaged","warm"] for contact_engagement_rating in), or array of list ids for contact_list.
{
"name": "string",
"predicate": "string"
}EventSegmentFilter
objectpredicatestringperformednot_performedrequiredpredicatestringcount_at_leastcount_at_mostrequired{
"predicate": "performed"
}Campaign
objectidintegeraccount_idintegerbrand_idinteger | nullstatusstringdraftactivepausedcompletedapproval_statestringchannelstringemailsmsnamestringdataobjectscheduled_atstring<date-time> | nullsent_countintegerdashboard_urlstring<uri> | nullCanonical dashboard URL with the /my route prefix.
preview_urlstring<uri> | nullSigned, expiring public preview URL for the current template version.
recipient_snapshotobject | nullLast send snapshot. Values are captured at send time and are not a live audience estimate.
last_send_recipientsinteger | nullAlias for the last dispatched recipient snapshot stored in data.recipients.
deliveryCampaignDeliverySummary | nullPresent while a campaign has a current send token; use /delivery to poll, refresh progress, and receive polling metadata.
engagementEngagementBucket & objecteditablebooleanread onlyTrue when the campaign's content/audience/template can be edited.
False for live, paused, completed, cancelled, archived, and for
scheduled campaigns within 5 minutes of their scheduled_at. When
false, PUT update accepts only name-only payloads and status
transitions (Resume / Cancel); anything else returns 422
campaign_locked. Use POST /duplicate to fork into a new draft.
created_atstring<date-time>updated_atstring<date-time>triggerFlowTriggertemplateTemplate | nulltemplatesArray<Template>{
"id": 0,
"account_id": 0,
"brand_id": 0,
"status": "draft",
"approval_state": "string",
"channel": "email",
"name": "string",
"data": {},
"scheduled_at": "2024-01-15T09:30:00Z",
"sent_count": 0,
"dashboard_url": "https://example.com",
"preview_url": "https://example.com",
"recipient_snapshot": {
"requested_recipients": 0,
"dispatched_recipients": 0,
"blocked_recipients": 0,
"requested_send_units": 0,
"dispatched_send_units": 0,
"units_per_recipient": 0,
"send_token": "string",
"started_at": "2024-01-15T09:30:00Z",
"completed_at": "2024-01-15T09:30:00Z"
},
"last_send_recipients": 0,
"delivery": {
"campaign_send_token": "string",
"status": "sending",
"recipients": 0,
"sent": 0,
"failed": 0,
"pending": 0
},
"engagement": {
"sent": 0,
"opens": 0,
"total_opens": 0,
"open_rate": 0,
"account": {
"sent": 0,
"opens": 0,
"total_opens": 0,
"open_rate": 0
}
},
"editable": true,
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z",
"trigger": {
"id": 0,
"flow_id": 0,
"event": "string",
"audience_type": "lists",
"segment_id": 0,
"contact_list_id": 0,
"contact_list_ids": [
0
],
"exclude_segment_ids": [
0
],
"exclude_contact_list_ids": [
0
],
"data": {},
"triggered_count": 0,
"last_triggered_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
},
"template": {
"id": 0,
"name": "string",
"flow_id": 0,
"action_id": 0,
"version": 0,
"subject": "string",
"body": "string",
"preheader": "string",
"from_name": "string",
"from_email": "string",
"reply_to": "string",
"design": {
"sections": [
{
"type": "header",
"props": {},
"styles": {
"background_color": "string",
"padding": "string",
"align": "left",
"font_size": 0,
"text_color": "string",
"border_radius": 0
}
}
],
"theme": {
"brand_color": "string",
"bg_color": "string",
"text_color": "string",
"font_body": "string",
"font_heading": "string",
"logo_url": "string"
}
},
"variables": {},
"generation_id": 0,
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
},
"templates": [
{
"id": 0,
"name": "string",
"flow_id": 0,
"action_id": 0,
"version": 0,
"subject": "string",
"body": "string",
"preheader": "string",
"from_name": "string",
"from_email": "string",
"reply_to": "string",
"design": {
"sections": [
{
"type": "header",
"props": {},
"styles": {
"background_color": "string",
"padding": "string",
"align": "left",
"font_size": 0,
"text_color": "string",
"border_radius": 0
}
}
],
"theme": {
"brand_color": "string",
"bg_color": "string",
"text_color": "string",
"font_body": "string",
"font_heading": "string",
"logo_url": "string"
}
},
"variables": {},
"generation_id": 0,
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}
]
}CampaignDeliverySummary
objectcampaign_send_tokenstring | nullrequiredstatusstringsendingcompletedpausedrequiredrecipientsintegerrequiredRecipient count captured for the active send.
sentintegerrequiredfailedintegerrequiredpendingintegerrequired{
"campaign_send_token": "string",
"status": "sending",
"recipients": 0,
"sent": 0,
"failed": 0,
"pending": 0
}CampaignDeliveryProgress
objectcampaign_send_tokenstring | nullrequiredstatusstringnot_startedsendingcompletedpausedrequiredrecipientsintegerrequiredRecipient count captured for the active send.
sentintegerrequiredfailedintegerrequiredpendingintegerrequiredterminalbooleanrequiredTrue when clients can stop polling.
poll_after_secondsinteger | nullrequiredSuggested polling delay for active sends.
{
"campaign_send_token": "string",
"status": "not_started",
"recipients": 0,
"sent": 0,
"failed": 0,
"pending": 0,
"terminal": true,
"poll_after_seconds": 0
}Message
objectidintegerchannelstringemailsmstostringsubjectstring | nullstatusstringqueuedsentfailedprovider_idstring | nullflow_idinteger | nullSource flow ID (null for transactional)
source_typestring | nullcampaignflowtestcampaign, flow, test, or null (transactional)
source_namestring | nullName of source campaign or flow
sent_atstring<date-time> | nullcreated_atstring<date-time>{
"id": 0,
"channel": "email",
"to": "string",
"subject": "string",
"status": "queued",
"provider_id": "string",
"flow_id": 0,
"source_type": "campaign",
"source_name": "string",
"sent_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z"
}Suppression
objectAccount suppression row with bounded source-event diagnostics.
idintegeremailstring<email>reasonstringhard_bouncesoft_bouncecomplaintmanualadminscopestringaccount_scopedactivebooleancontact_idinteger | nullsource_providerstring | nullsource_event_idstring | nullprovider_diagnosticstring | nullBounded diagnostic text extracted from the provider feedback event, when retained.
bounce_typestring | nullhardsoftbounce_subtypestring | nullcomplaint_feedback_typestring | nullevent_occurred_atstring<date-time> | nullexpires_atstring<date-time> | nullcreated_atstring<date-time>updated_atstring<date-time>{
"id": 0,
"email": "user@example.com",
"reason": "hard_bounce",
"scope": "account_scoped",
"active": true,
"contact_id": 0,
"source_provider": "string",
"source_event_id": "string",
"provider_diagnostic": "string",
"bounce_type": "hard",
"bounce_subtype": "string",
"complaint_feedback_type": "string",
"event_occurred_at": "2024-01-15T09:30:00Z",
"expires_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}ChatMessage
objectidintegerrolestringuserassistanttoolsystemcontentstringtool_callsArray<object>sequenceintegercreated_atstring<date-time>{
"id": 0,
"role": "user",
"content": "string",
"tool_calls": [
{}
],
"sequence": 0,
"created_at": "2024-01-15T09:30:00Z"
}ChatSession
objectidintegeraccount_idintegerbrand_idintegertitlestringstatusstringactiveclosedfailedstarted_atstring<date-time>last_message_atstring<date-time>message_countintegercreated_atstring<date-time>updated_atstring<date-time>{
"id": 0,
"account_id": 0,
"brand_id": 0,
"title": "string",
"status": "active",
"started_at": "2024-01-15T09:30:00Z",
"last_message_at": "2024-01-15T09:30:00Z",
"message_count": 0,
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}ChatSessionDetail
objectidintegeraccount_idintegerbrand_idintegertitlestringstatusstringactiveclosedfailedstarted_atstring<date-time>last_message_atstring<date-time>message_countintegercreated_atstring<date-time>updated_atstring<date-time>messagesArray<ChatMessage>{
"id": 0,
"account_id": 0,
"brand_id": 0,
"title": "string",
"status": "active",
"started_at": "2024-01-15T09:30:00Z",
"last_message_at": "2024-01-15T09:30:00Z",
"message_count": 0,
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z",
"messages": [
{
"id": 0,
"role": "user",
"content": "string",
"tool_calls": [
{}
],
"sequence": 0,
"created_at": "2024-01-15T09:30:00Z"
}
]
}Template
objectidintegernamestring | nullflow_idinteger | nullaction_idinteger | nullversionintegersubjectstring | nullbodystring | nullpreheaderstring | nullfrom_namestring | nullfrom_emailstring | nullreply_tostring | nulldesignEmailDesign | nullvariablesobjectgeneration_idinteger | nullcreated_atstring<date-time>updated_atstring<date-time>{
"id": 0,
"name": "string",
"flow_id": 0,
"action_id": 0,
"version": 0,
"subject": "string",
"body": "string",
"preheader": "string",
"from_name": "string",
"from_email": "string",
"reply_to": "string",
"design": {
"sections": [
{
"type": "header",
"props": {},
"styles": {
"background_color": "string",
"padding": "string",
"align": "left",
"font_size": 0,
"text_color": "string",
"border_radius": 0
}
}
],
"theme": {
"brand_color": "string",
"bg_color": "string",
"text_color": "string",
"font_body": "string",
"font_heading": "string",
"logo_url": "string"
}
},
"variables": {},
"generation_id": 0,
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}EmailStarter
objectidstringcategorystringnamestringdescriptionstringiconstringsuggested_goalsArray<string>designEmailDesignEmail template design document
preview_htmlstring | null{
"id": "string",
"category": "string",
"name": "string",
"description": "string",
"icon": "string",
"suggested_goals": [
"string"
],
"design": {
"sections": [
{
"type": "header",
"props": {},
"styles": {
"background_color": "string",
"padding": "string",
"align": "left",
"font_size": 0,
"text_color": "string",
"border_radius": 0
}
}
],
"theme": {
"brand_color": "string",
"bg_color": "string",
"text_color": "string",
"font_body": "string",
"font_heading": "string",
"logo_url": "string"
}
},
"preview_html": "string"
}TemplateSummary
objectidintegernamestring | nullversionintegersubjectstring | nullpreheaderstring | nullflow_idinteger | nullsection_countintegersection_typesArray<string>created_atstring<date-time>updated_atstring<date-time>{
"id": 0,
"name": "string",
"version": 0,
"subject": "string",
"preheader": "string",
"flow_id": 0,
"section_count": 0,
"section_types": [
"string"
],
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}Flow
objectidintegeraccount_idintegerbrand_idinteger | nullstatusstringdraftlivepausedarchivedcancelledapproval_statestringnamestringgoalstring | nulltriggerFlowTriggerOutputTrigger as returned by Flow::Format.dump
stepsArray<FlowStepOutput>sent_countintegerengagementEngagementBucket & objectcreated_atstring<date-time>updated_atstring<date-time>templatesArray<Template>{
"id": 0,
"account_id": 0,
"brand_id": 0,
"status": "draft",
"approval_state": "string",
"name": "string",
"goal": "string",
"trigger": {
"event": "string",
"segment_id": 0,
"contact_list_id": 0,
"exclude_segment_ids": [
0
],
"data": {}
},
"steps": [],
"sent_count": 0,
"engagement": {
"sent": 0,
"opens": 0,
"total_opens": 0,
"open_rate": 0,
"account": {
"sent": 0,
"opens": 0,
"total_opens": 0,
"open_rate": 0
}
},
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z",
"templates": [
{
"id": 0,
"name": "string",
"flow_id": 0,
"action_id": 0,
"version": 0,
"subject": "string",
"body": "string",
"preheader": "string",
"from_name": "string",
"from_email": "string",
"reply_to": "string",
"design": {
"sections": [
{
"type": "header",
"props": {},
"styles": {
"background_color": "string",
"padding": "string",
"align": "left",
"font_size": 0,
"text_color": "string",
"border_radius": 0
}
}
],
"theme": {
"brand_color": "string",
"bg_color": "string",
"text_color": "string",
"font_body": "string",
"font_heading": "string",
"logo_url": "string"
}
},
"variables": {},
"generation_id": 0,
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}
]
}FlowTemplate
objectLean flow template card for index listings.
idstringTemplate slug (e.g. welcome_series)
type_labelstringdescriptionstringcategorystringemail_countintegerstep_countintegerpreview_sectionsArray<object>Section objects from the first email step's design, for template previews.
{
"id": "string",
"type_label": "string",
"description": "string",
"category": "string",
"email_count": 0,
"step_count": 0,
"preview_sections": [
{}
]
}FlowTemplateDetail
objectLean flow template card for index listings.
idstringTemplate slug (e.g. welcome_series)
type_labelstringdescriptionstringcategorystringemail_countintegerstep_countintegerpreview_sectionsArray<object>Section objects from the first email step's design, for template previews.
Full flow template including the graph, ready for POST /v1/my/flows.
triggerobjectTrigger definition (pass as-is to POST /v1/my/flows trigger param)
stepsArray<object>Step definitions (pass as-is to POST /v1/my/flows steps param)
{
"id": "string",
"type_label": "string",
"description": "string",
"category": "string",
"email_count": 0,
"step_count": 0,
"preview_sections": [
{}
],
"trigger": {},
"steps": [
{}
]
}EngagementBucket
objectA (sent, opens, total_opens, open_rate) block. Used both for the resource itself
and, nested as account, for the brand-level lifetime baseline.
sentintegerrequiredTotal emails sent in this bucket.
opensintegerrequiredUnique human open events recorded in this bucket.
total_opensintegerrequiredAll human open events including repeat opens by the same recipient, so
total_opens >= opens. Falls back to opens when only unique-open data exists.
open_ratenumber<float> | nullrequiredOpens divided by sent, rounded to 4 decimal places. Null when sent is below
the meaningful threshold for this bucket — zero for resource buckets, or below
Report::Engagement::ACCOUNT_BASELINE_MIN_SENT for the account bucket.
{
"sent": 0,
"opens": 0,
"total_opens": 0,
"open_rate": 0
}Engagement
objectA (sent, opens, total_opens, open_rate) block. Used both for the resource itself
and, nested as account, for the brand-level lifetime baseline.
sentintegerrequiredTotal emails sent in this bucket.
opensintegerrequiredUnique human open events recorded in this bucket.
total_opensintegerrequiredAll human open events including repeat opens by the same recipient, so
total_opens >= opens. Falls back to opens when only unique-open data exists.
open_ratenumber<float> | nullrequiredOpens divided by sent, rounded to 4 decimal places. Null when sent is below
the meaningful threshold for this bucket — zero for resource buckets, or below
Report::Engagement::ACCOUNT_BASELINE_MIN_SENT for the account bucket.
accountEngagementBucketrequiredA (sent, opens, total_opens, open_rate) block. Used both for the resource itself
and, nested as account, for the brand-level lifetime baseline.
{
"sent": 0,
"opens": 0,
"total_opens": 0,
"open_rate": 0,
"account": {
"sent": 0,
"opens": 0,
"total_opens": 0,
"open_rate": 0
}
}FlowTrigger
objectidintegerflow_idintegereventstringaudience_typestring | nulllistssegmentall_contactsExplicit campaign audience target; null means no audience selected.
segment_idinteger | nullcontact_list_idinteger | nulldeprecatedDeprecated — use contact_list_ids
contact_list_idsArray<integer>Contact list IDs targeted by this trigger
exclude_segment_idsArray<integer>Segment IDs whose matching contacts are excluded from the recipient set
exclude_contact_list_idsArray<integer>Contact list IDs whose members are excluded from the recipient set
dataobject | nulltriggered_countintegerlast_triggered_atstring<date-time> | nullcreated_atstring<date-time>updated_atstring<date-time>{
"id": 0,
"flow_id": 0,
"event": "string",
"audience_type": "lists",
"segment_id": 0,
"contact_list_id": 0,
"contact_list_ids": [
0
],
"exclude_segment_ids": [
0
],
"exclude_contact_list_ids": [
0
],
"data": {},
"triggered_count": 0,
"last_triggered_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}FlowTriggerInput
objecteventstringBuilt-in: contact_add, keyword, message, list_add, list_remove, product_view, checkout, cart_add, cart_remove, cart_abandoned, browse_abandoned. Custom: any lowercase alphanumeric with underscores.
audience_typestring | nulllistssegmentall_contactsExplicit campaign audience target; null means no audience selected.
segment_idinteger | nullcontact_list_idinteger | nulldeprecatedDeprecated — use contact_list_ids
contact_list_idsArray<integer>Contact list IDs to target
exclude_segment_idsArray<integer>Segment IDs whose matching contacts are excluded from the recipient set; pass [] to clear
dataobject{
"event": "string",
"audience_type": "lists",
"segment_id": 0,
"contact_list_id": 0,
"contact_list_ids": [
0
],
"exclude_segment_ids": [
0
],
"data": {}
}FlowTriggerOutput
objectTrigger as returned by Flow::Format.dump
eventstringsegment_idinteger | nullcontact_list_idinteger | nullexclude_segment_idsArray<integer>Segment IDs whose matching contacts are excluded from the recipient set
dataobject | null{
"event": "string",
"segment_id": 0,
"contact_list_id": 0,
"exclude_segment_ids": [
0
],
"data": {}
}FlowStepInput
objecttypestringemailsmswaitsplitemit_eventrequiredsubjectstringEmail step: subject line
bodystringSMS body or email plain text
preheaderstringEmail step: preheader
from_namestringfrom_emailstringreply_tostringdesignEmailDesignEmail template design document
durationintegerWait step: seconds
filtersSegmentFilterExpressionyesArray<FlowStepInput>Split step: yes branch
noArray<FlowStepInput>Split step: no branch
event_namestringEmit event step: event to fire
forward_event_databooleanfalseevent_dataobjecttransactionalbooleanfalse{
"type": "email",
"subject": "string",
"body": "string",
"preheader": "string",
"from_name": "string",
"from_email": "string",
"reply_to": "string",
"design": {
"sections": [
{
"type": "header",
"props": {},
"styles": {
"background_color": "string",
"padding": "string",
"align": "left",
"font_size": 0,
"text_color": "string",
"border_radius": 0
}
}
],
"theme": {
"brand_color": "string",
"bg_color": "string",
"text_color": "string",
"font_body": "string",
"font_heading": "string",
"logo_url": "string"
}
},
"duration": 0,
"yes": [],
"no": [],
"event_name": "string",
"forward_event_data": false,
"event_data": {},
"transactional": false
}FlowStepOutput
objectStep as returned by Flow::Format.dump
typestringemailsmswaitsplitemit_eventsubjectstringbodystringpreheaderstringdurationintegerfiltersArray<object>yesArray<FlowStepOutput>noArray<FlowStepOutput>event_namestringforward_event_databoolean{
"type": "email",
"subject": "string",
"body": "string",
"preheader": "string",
"duration": 0,
"filters": [
{}
],
"yes": [],
"no": [],
"event_name": "string",
"forward_event_data": true
}Event
objectidintegeraccount_idintegercontact_idintegeruser_idintegereventstringamountnumber<double> | nulldataobjectidempotency_keystring | nullresource_uidstring | nullresource_namestring | nullresource_urlstring | nulltestbooleangeneratedbooleanchain_depthintegeripstring | nulluser_agentstring | nullbrowserstring | nullosstring | nulldevice_typestring | nullreferrerstring | nullutm_sourcestring | nullutm_mediumstring | nullutm_termstring | nullutm_contentstring | nullutm_campaignstring | nullcreated_atstring<date-time>updated_atstring<date-time>{
"id": 0,
"account_id": 0,
"contact_id": 0,
"user_id": 0,
"event": "string",
"amount": 0,
"data": {},
"idempotency_key": "string",
"resource_uid": "string",
"resource_name": "string",
"resource_url": "string",
"test": true,
"generated": true,
"chain_depth": 0,
"ip": "string",
"user_agent": "string",
"browser": "string",
"os": "string",
"device_type": "string",
"referrer": "string",
"utm_source": "string",
"utm_medium": "string",
"utm_term": "string",
"utm_content": "string",
"utm_campaign": "string",
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}Domain
objectidintegerbrand_idinteger | nullnamestringproviderstringsesintegration_idinteger | nullstatusstringpendingverifiedfaileddmarc_policystringnonequarantinerejectEffective observed DMARC policy persisted by Nitrosend; defaults to none until observed.
dmarc_recommended_policystringnonequarantinerejectNitrosend's recommended DMARC policy rung.
dmarc_observed_policystring | nullnonequarantinerejectLast live DMARC policy observed by Nitrosend.
dns_recordsArray<object> | nulldns_healthobject | nulldns_setup_statusstringuncheckedincompletereadyverifiedverified_atstring<date-time> | nullcreated_atstring<date-time>{
"id": 0,
"brand_id": 0,
"name": "string",
"provider": "ses",
"integration_id": 0,
"status": "pending",
"dmarc_policy": "none",
"dmarc_recommended_policy": "none",
"dmarc_observed_policy": "none",
"dns_records": [
{
"record_type": "string",
"name": "string",
"value": "string",
"priority": "string",
"valid": "string"
}
],
"dns_health": {},
"dns_setup_status": "unchecked",
"verified_at": "2024-01-15T09:30:00Z",
"created_at": "2024-01-15T09:30:00Z"
}EntriSessionResponse
objectdomainobjectentriobject{
"domain": {
"id": 0,
"name": "string",
"status": "pending"
},
"entri": {
"application_id": "string",
"token": "string",
"prefilled_domain": "string",
"user_id": "string",
"dns_records": [
{
"type": "string",
"host": "string",
"value": "string",
"ttl": 0,
"priority": 0
}
]
}
}EntriDnsRecord
objecttypestringhoststringvaluestringttlintegerpriorityinteger | null{
"type": "string",
"host": "string",
"value": "string",
"ttl": 0,
"priority": 0
}Integration
objectidintegerproviderstringmailgunsespostmarkresendsendgridtwilioattiohubspotcategorystringemailsmscrmactivebooleanprimarybooleanstatusstringpendingconnectederrorconnected_atstring<date-time> | nulllast_tested_atstring<date-time> | nullerror_messagestring | nullconfig_summaryobjectsecret_hintsobjectcreated_atstring<date-time>updated_atstring<date-time>{
"id": 0,
"provider": "mailgun",
"category": "email",
"active": true,
"primary": true,
"status": "pending",
"connected_at": "2024-01-15T09:30:00Z",
"last_tested_at": "2024-01-15T09:30:00Z",
"error_message": "string",
"config_summary": {},
"secret_hints": {},
"created_at": "2024-01-15T09:30:00Z",
"updated_at": "2024-01-15T09:30:00Z"
}IntegrationWriteRequest
objectintegrationMailgunIntegrationInput | SesIntegrationInput | PostmarkIntegrationInput | ResendIntegrationInput | SendgridIntegrationInputrequired{
"integration": {
"provider": "mailgun",
"api_key": "string",
"domain": "string",
"region": "string",
"active": true
}
}MailgunIntegrationInput
objectproviderstringmailgunrequiredapi_keystringrequireddomainstringrequiredMailgun sending domain
regionstring | nullOptional Mailgun region hint
activebooleantrue{
"provider": "mailgun",
"api_key": "string",
"domain": "string",
"region": "string",
"active": true
}SesIntegrationInput
objectproviderstringsesrequiredaccess_key_idstringrequiredsecret_access_keystringrequiredregionstringrequiredAWS SES region
activebooleantrue{
"provider": "ses",
"access_key_id": "string",
"secret_access_key": "string",
"region": "string",
"active": true
}PostmarkIntegrationInput
objectproviderstringpostmarkrequiredserver_tokenstringrequiredPostmark server token for sending email
account_tokenstringrequiredPostmark account token for domains API access
activebooleantrue{
"provider": "postmark",
"server_token": "string",
"account_token": "string",
"active": true
}ResendIntegrationInput
objectproviderstringresendrequiredapi_keystringrequiredactivebooleantrue{
"provider": "resend",
"api_key": "string",
"active": true
}SendgridIntegrationInput
objectproviderstringsendgridrequiredapi_keystringrequiredactivebooleantrue{
"provider": "sendgrid",
"api_key": "string",
"active": true
}EmailDesign
objectEmail template design document
sectionsArray<EmailSection>themeobjectTheme overrides merged on top of brand theme
{
"sections": [
{
"type": "header",
"props": {},
"styles": {
"background_color": "string",
"padding": "string",
"align": "left",
"font_size": 0,
"text_color": "string",
"border_radius": 0
}
}
],
"theme": {
"brand_color": "string",
"bg_color": "string",
"text_color": "string",
"font_body": "string",
"font_heading": "string",
"logo_url": "string"
}
}EmailAccessibilityLint
objectAdvisory accessibility lint result for rendered email previews
validbooleanAlways true while accessibility lint is advisory-only
warningsArray<EmailAccessibilityWarning>{
"valid": true,
"warnings": [
{
"level": "warning",
"rule": "image_alt_text",
"message": "string",
"suggested_fix": "string",
"count": 0,
"min_ratio": 0
}
]
}EmailAccessibilityWarning
objectlevelstringrulestringmessagestringsuggested_fixstringcountintegermin_rationumber<float>{
"level": "warning",
"rule": "image_alt_text",
"message": "string",
"suggested_fix": "string",
"count": 0,
"min_ratio": 0
}EmailSection
objecttypestringheaderherotextimagebuttoncolumnsproductsocialdividerspacerfooterrequiredpropsobjectSection-specific properties (see email component spec)
stylesobject{
"type": "header",
"props": {},
"styles": {
"background_color": "string",
"padding": "string",
"align": "left",
"font_size": 0,
"text_color": "string",
"border_radius": 0
}
}EmailComponentSpec
objectFull schema for email design sections. Each component has type, description, props (with types, required flags, defaults), and tips.
versionintegerdesign_guidelinesstringcomponentsArray<object>style_attributesArray<object>Standard per-section style attribute registry.
variablesArray<string>theme_attributesArray<object>Brand Kit theme attribute registry (single source of truth for the editor).
{
"version": 0,
"design_guidelines": "string",
"components": [
{
"type": "string",
"description": "string",
"tips": [
"string"
],
"props": {}
}
],
"style_attributes": [
{
"key": "string",
"label": "string",
"type": "color",
"theme_fallback": "string",
"description": "string",
"values": [
"string"
],
"target": {
"el": "section",
"attr": "string"
}
}
],
"variables": [
"string"
],
"theme_attributes": [
{
"key": "string",
"label": "string",
"type": "color",
"category": "color",
"slot": "string",
"surfaces": [
"string"
],
"min": 0,
"max": 0,
"values": [
"string"
],
"options": [
{
"value": "string",
"label": "string",
"description": "string"
}
],
"transform_table": {},
"column": true,
"value_resolver": "string",
"description": "string"
}
]
}FlowSpec
objectSchema for flow step types, trigger events, and segment filter names. Note: the raw response includes internal fields (icon, visible, inputs, outputs, alias) used by the flow editor UI — these can be ignored by API consumers.
filtersobjecttriggersArray<object>stepsArray<object>lifecycle_flowsArray<object>Canonical lifecycle flow templates for the flow picker.
{
"filters": {},
"triggers": [
{
"title": "string",
"event": "string"
}
],
"steps": [
{
"type": "string",
"title": "string",
"summary": "string",
"params": {}
}
],
"lifecycle_flows": [
{
"id": "string",
"key": "string",
"goal": "string",
"name": "string",
"description": "string",
"priority": 0,
"trigger": {
"event": "string"
},
"trigger_needs": "string",
"steps": [
{
"type": "string",
"duration": 0,
"subject": "string",
"preheader": "string",
"body": "string",
"design": {}
}
]
}
]
}