MENU navbar-image

Introduction

This documentation aims to provide all the information you need to work with our API.

Authenticating requests

To authenticate requests, include an Authorization header with the value "Bearer {YOUR_API_KEY}".

All authenticated endpoints are marked with a requires authentication badge in the documentation below.

You can retrieve your token by visiting your Team's dashboard and clicking Generate API token.

CMS

Returns a list of all sites belonging to the authenticated team.

Get sites for the current team (API endpoint)

requires authentication

Example request:
curl --request GET \
    --get "http://localhost/api/sites" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost/api/sites"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/sites'
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$response = $client->get(
    'http://localhost/api/sites',
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

using System.Net.Http.Headers;

var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "{YOUR_API_KEY}");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

var request = new HttpRequestMessage
{
    Method = HttpMethod.Get,
    RequestUri = new Uri("http://localhost/api/sites"),
};
using (var response = await client.SendAsync(request))
{
    //response.EnsureSuccessStatusCode();
    var body = await response.Content.ReadAsStringAsync();
    Console.WriteLine(body);
}

Example response (200):


[
    {
        "id": 1,
        "name": "Main Website"
    },
    {
        "id": 2,
        "name": "Landing Pages"
    }
]
 

Request      

GET api/sites

Headers

Authorization      

Example: Bearer {YOUR_API_KEY}

Content-Type      

Example: application/json

Accept      

Example: application/json

Contact Fields

APIs for managing contact fields.

Contact fields define the data structure for your contacts. Each team has its own set of fields that determine what information can be stored on contacts.

Field Types

Type Description Example Value
text Plain text string "John Doe"
email Email address (validated) "john@example.com"
phone Phone number (normalized to E.164) "+14155552671"
number Numeric value 42 or 3.14
date Date value "2024-01-15"
datetime Date and time "2024-01-15T10:30:00Z"
boolean True/false value true or false
url Web URL "https://example.com"
pick_list Selection from predefined options "option_a"
related Reference to another contact Contact ID

Field Tags (Merge Tags)

Each field has a unique tag identifier (also called a merge tag) that you use when:

Tags should be lowercase, use underscores for spaces, and be descriptive (e.g., first_name, company_name, membership_level).

Contact Types

Fields are scoped to a contact type:

Integration Fields

Some fields may be created by third-party integrations (like ChamberMaster or Mailchimp). These fields have an integration_id set and cannot be modified or deleted through the API.

List all contact fields

requires authentication

Get all contact fields for your team. Use the contact_type query parameter to filter by person or organization fields.

Example request:
curl --request GET \
    --get "http://localhost/api/v1/contact-fields?contact_type=person" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost/api/v1/contact-fields"
);

const params = {
    "contact_type": "person",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/contact-fields'
params = {
  'contact_type': 'person',
}
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()
$client = new \GuzzleHttp\Client();
$response = $client->get(
    'http://localhost/api/v1/contact-fields',
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'contact_type' => 'person',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

using System.Net.Http.Headers;

var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "{YOUR_API_KEY}");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

var request = new HttpRequestMessage
{
    Method = HttpMethod.Get,
    RequestUri = new Uri("http://localhost/api/v1/contact-fields?contact_type=person"),
};
using (var response = await client.SendAsync(request))
{
    //response.EnsureSuccessStatusCode();
    var body = await response.Content.ReadAsStringAsync();
    Console.WriteLine(body);
}

Example response (200):


[
    {
        "id": 1,
        "name": "First Name",
        "tag": "first_name",
        "type": "text",
        "contact_type": "person",
        "max_length": 255,
        "integration_id": null
    },
    {
        "id": 2,
        "name": "Email",
        "tag": "email",
        "type": "email",
        "contact_type": "person",
        "max_length": 255,
        "integration_id": null
    }
]
 

Request      

GET api/v1/contact-fields

Headers

Authorization      

Example: Bearer {YOUR_API_KEY}

Content-Type      

Example: application/json

Accept      

Example: application/json

Query Parameters

contact_type   string  optional  

Filter by contact type. Must be person or organization. Example: person

Get available field types

requires authentication

Returns a list of all available contact field types with their display names.

Example request:
curl --request GET \
    --get "http://localhost/api/v1/contact-fields/types" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost/api/v1/contact-fields/types"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/contact-fields/types'
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$response = $client->get(
    'http://localhost/api/v1/contact-fields/types',
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

using System.Net.Http.Headers;

var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "{YOUR_API_KEY}");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

var request = new HttpRequestMessage
{
    Method = HttpMethod.Get,
    RequestUri = new Uri("http://localhost/api/v1/contact-fields/types"),
};
using (var response = await client.SendAsync(request))
{
    //response.EnsureSuccessStatusCode();
    var body = await response.Content.ReadAsStringAsync();
    Console.WriteLine(body);
}

Example response (200):


[
    {
        "value": "text",
        "name": "Text"
    },
    {
        "value": "email",
        "name": "Email"
    },
    {
        "value": "phone",
        "name": "Phone"
    },
    {
        "value": "number",
        "name": "Number"
    },
    {
        "value": "date",
        "name": "Date"
    },
    {
        "value": "datetime",
        "name": "Datetime"
    },
    {
        "value": "boolean",
        "name": "True / False"
    },
    {
        "value": "url",
        "name": "URL"
    },
    {
        "value": "pick_list",
        "name": "Pick List"
    },
    {
        "value": "related",
        "name": "Related Contact/Organization"
    }
]
 

Request      

GET api/v1/contact-fields/types

Headers

Authorization      

Example: Bearer {YOUR_API_KEY}

Content-Type      

Example: application/json

Accept      

Example: application/json

Create a contact field

requires authentication

Create a new contact field for your team.

Example request:
curl --request POST \
    "http://localhost/api/v1/contact-fields" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"name\": \"Membership Level\",
    \"tag\": \"membership_level\",
    \"type\": \"pick_list\",
    \"contact_type\": \"person\",
    \"max_length\": 100,
    \"options\": [
        \"gold\",
        \"silver\",
        \"bronze\"
    ],
    \"allow_multiple\": false
}"
const url = new URL(
    "http://localhost/api/v1/contact-fields"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "name": "Membership Level",
    "tag": "membership_level",
    "type": "pick_list",
    "contact_type": "person",
    "max_length": 100,
    "options": [
        "gold",
        "silver",
        "bronze"
    ],
    "allow_multiple": false
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/contact-fields'
payload = {
    "name": "Membership Level",
    "tag": "membership_level",
    "type": "pick_list",
    "contact_type": "person",
    "max_length": 100,
    "options": [
        "gold",
        "silver",
        "bronze"
    ],
    "allow_multiple": false
}
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, json=payload)
response.json()
$client = new \GuzzleHttp\Client();
$response = $client->post(
    'http://localhost/api/v1/contact-fields',
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'name' => 'Membership Level',
            'tag' => 'membership_level',
            'type' => 'pick_list',
            'contact_type' => 'person',
            'max_length' => 100,
            'options' => [
                'gold',
                'silver',
                'bronze',
            ],
            'allow_multiple' => false,
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

using System.Net.Http.Headers;

var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "{YOUR_API_KEY}");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

var data = new MultipartFormDataContent();
data.Add(new StringContent("Membership Level"), "name");
data.Add(new StringContent("membership_level"), "tag");
data.Add(new StringContent("pick_list"), "type");
data.Add(new StringContent("person"), "contact_type");
data.Add(new StringContent("100"), "max_length");
data.Add(new StringContent("gold"), "options[]");
data.Add(new StringContent(""), "allow_multiple");

var request = new HttpRequestMessage
{
    Method = HttpMethod.Post,
    RequestUri = new Uri("http://localhost/api/v1/contact-fields"),
    Content = data
};
using (var response = await client.SendAsync(request))
{
    //response.EnsureSuccessStatusCode();
    var body = await response.Content.ReadAsStringAsync();
    Console.WriteLine(body);
}

Example response (201):


{
    "id": 10,
    "name": "Membership Level",
    "tag": "membership_level",
    "type": "pick_list",
    "contact_type": "person",
    "max_length": null,
    "options": [
        "gold",
        "silver",
        "bronze"
    ],
    "allow_multiple": false,
    "integration_id": null
}
 

Example response (422):


{
    "message": "The tag has already been taken."
}
 

Request      

POST api/v1/contact-fields

Headers

Authorization      

Example: Bearer {YOUR_API_KEY}

Content-Type      

Example: application/json

Accept      

Example: application/json

Body Parameters

name   string   

The display name for the field. Example: Membership Level

tag   string   

The merge tag identifier (lowercase, underscores, unique per team). Example: membership_level

type   string   

The field type. Must be one of: text, email, phone, number, date, datetime, boolean, url, pick_list, related. Example: pick_list

contact_type   string   

The contact type this field belongs to. Must be person or organization. Example: person

max_length   integer  optional  

The maximum length for text fields. Default: 255. Example: 100

options   string[]  optional  

An array of options for pick_list fields.

allow_multiple   boolean  optional  

Whether multiple values can be selected (for pick_list). Default: false. Example: false

Get a contact field

requires authentication

Retrieve details for a specific contact field.

Example request:
curl --request GET \
    --get "http://localhost/api/v1/contact-fields/1" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost/api/v1/contact-fields/1"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/contact-fields/1'
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$response = $client->get(
    'http://localhost/api/v1/contact-fields/1',
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

using System.Net.Http.Headers;

var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "{YOUR_API_KEY}");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

var request = new HttpRequestMessage
{
    Method = HttpMethod.Get,
    RequestUri = new Uri("http://localhost/api/v1/contact-fields/1"),
};
using (var response = await client.SendAsync(request))
{
    //response.EnsureSuccessStatusCode();
    var body = await response.Content.ReadAsStringAsync();
    Console.WriteLine(body);
}

Example response (200):


{
    "id": 1,
    "name": "First Name",
    "tag": "first_name",
    "type": "text",
    "contact_type": "person",
    "max_length": 255,
    "options": null,
    "allow_multiple": false,
    "integration_id": null
}
 

Example response (403):


{
    "message": "This action is unauthorized."
}
 

Example response (404):


{
    "message": "No query results for model [ContactField]"
}
 

Request      

GET api/v1/contact-fields/{id}

Headers

Authorization      

Example: Bearer {YOUR_API_KEY}

Content-Type      

Example: application/json

Accept      

Example: application/json

URL Parameters

id   integer   

The ID of the contact field. Example: 1

contact_field   integer   

The contact field ID. Example: 1

Update a contact field

requires authentication

Update an existing contact field. Integration fields cannot be updated.

Example request:
curl --request PUT \
    "http://localhost/api/v1/contact-fields/1" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"name\": \"Full Name\",
    \"tag\": \"full_name\",
    \"type\": \"text\",
    \"max_length\": 150,
    \"options\": [
        \"premium\",
        \"standard\",
        \"basic\"
    ],
    \"allow_multiple\": true
}"
const url = new URL(
    "http://localhost/api/v1/contact-fields/1"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "name": "Full Name",
    "tag": "full_name",
    "type": "text",
    "max_length": 150,
    "options": [
        "premium",
        "standard",
        "basic"
    ],
    "allow_multiple": true
};

fetch(url, {
    method: "PUT",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/contact-fields/1'
payload = {
    "name": "Full Name",
    "tag": "full_name",
    "type": "text",
    "max_length": 150,
    "options": [
        "premium",
        "standard",
        "basic"
    ],
    "allow_multiple": true
}
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('PUT', url, headers=headers, json=payload)
response.json()
$client = new \GuzzleHttp\Client();
$response = $client->put(
    'http://localhost/api/v1/contact-fields/1',
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'name' => 'Full Name',
            'tag' => 'full_name',
            'type' => 'text',
            'max_length' => 150,
            'options' => [
                'premium',
                'standard',
                'basic',
            ],
            'allow_multiple' => true,
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

using System.Net.Http.Headers;

var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "{YOUR_API_KEY}");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

var data = new MultipartFormDataContent();
data.Add(new StringContent("Full Name"), "name");
data.Add(new StringContent("full_name"), "tag");
data.Add(new StringContent("text"), "type");
data.Add(new StringContent("150"), "max_length");
data.Add(new StringContent("premium"), "options[]");
data.Add(new StringContent("1"), "allow_multiple");

var request = new HttpRequestMessage
{
    Method = HttpMethod.Post,
    RequestUri = new Uri("http://localhost/api/v1/contact-fields/1"),
    Content = data
};
using (var response = await client.SendAsync(request))
{
    //response.EnsureSuccessStatusCode();
    var body = await response.Content.ReadAsStringAsync();
    Console.WriteLine(body);
}

Example response (200):


{
    "id": 1,
    "name": "Full Name",
    "tag": "full_name",
    "type": "text",
    "contact_type": "person",
    "max_length": 150,
    "options": null,
    "allow_multiple": false,
    "integration_id": null
}
 

Example response (403):


{
    "message": "This field is managed by an integration and cannot be modified."
}
 

Example response (422):


{
    "message": "The tag has already been taken."
}
 

Request      

PUT api/v1/contact-fields/{id}

Headers

Authorization      

Example: Bearer {YOUR_API_KEY}

Content-Type      

Example: application/json

Accept      

Example: application/json

URL Parameters

id   integer   

The ID of the contact field. Example: 1

contact_field   integer   

The contact field ID. Example: 1

Body Parameters

name   string  optional  

The display name for the field. Example: Full Name

tag   string  optional  

The merge tag identifier (lowercase, underscores, unique per team). Example: full_name

type   string  optional  

The field type. Must be one of: text, email, phone, number, date, datetime, boolean, url, pick_list, related. Example: text

max_length   integer  optional  

The maximum length for text fields. Example: 150

options   string[]  optional  

An array of options for pick_list fields.

allow_multiple   boolean  optional  

Whether multiple values can be selected (for pick_list). Example: true

Delete a contact field

requires authentication

Delete a contact field. Integration fields cannot be deleted.

Warning: Deleting a field will remove the field definition, but existing contact data stored in that field will remain in the database (orphaned). Consider exporting contact data before deleting fields.

Example request:
curl --request DELETE \
    "http://localhost/api/v1/contact-fields/1" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost/api/v1/contact-fields/1"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/contact-fields/1'
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('DELETE', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$response = $client->delete(
    'http://localhost/api/v1/contact-fields/1',
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

using System.Net.Http.Headers;

var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "{YOUR_API_KEY}");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

var data = new MultipartFormDataContent();

var request = new HttpRequestMessage
{
    Method = HttpMethod.Post,
    RequestUri = new Uri("http://localhost/api/v1/contact-fields/1"),
    Content = data
};
using (var response = await client.SendAsync(request))
{
    //response.EnsureSuccessStatusCode();
    var body = await response.Content.ReadAsStringAsync();
    Console.WriteLine(body);
}

Example response (200):


{
    "message": "Contact field deleted successfully."
}
 

Example response (403):


{
    "message": "This field is managed by an integration and cannot be deleted."
}
 

Request      

DELETE api/v1/contact-fields/{id}

Headers

Authorization      

Example: Bearer {YOUR_API_KEY}

Content-Type      

Example: application/json

Accept      

Example: application/json

URL Parameters

id   integer   

The ID of the contact field. Example: 1

contact_field   integer   

The contact field ID. Example: 1

Contact management

APIs for managing contacts.

Understanding Contact Fields

Contacts in SallyJo use a flexible, team-specific field system. Each team can define their own custom fields (like "first_name", "company", "membership_level", etc.) to store contact data.

How Contact Fields Work

Example Workflow

  1. First, fetch your team's contact fields using GET /api/v1/contact-fields
  2. Use the field tag values as keys when creating/updating contacts
  3. The field type tells you what data format to use (e.g., email fields expect valid email addresses)

Note: The bodyParam examples below use default team fields (first_name, last_name, email, phone, address). Your team may have different or additional custom fields. Always check GET /api/v1/contact-fields for your actual fields.

Get contact list

requires authentication

This endpoint allows you to get a full list of contacts for a team

Example request:
curl --request GET \
    --get "http://localhost/api/v1/contacts" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost/api/v1/contacts"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/contacts'
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$response = $client->get(
    'http://localhost/api/v1/contacts',
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

using System.Net.Http.Headers;

var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "{YOUR_API_KEY}");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

var request = new HttpRequestMessage
{
    Method = HttpMethod.Get,
    RequestUri = new Uri("http://localhost/api/v1/contacts"),
};
using (var response = await client.SendAsync(request))
{
    //response.EnsureSuccessStatusCode();
    var body = await response.Content.ReadAsStringAsync();
    Console.WriteLine(body);
}

Example response (401):

Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
 

{
    "message": "Unauthenticated."
}
 

Request      

GET api/v1/contacts

Headers

Authorization      

Example: Bearer {YOUR_API_KEY}

Content-Type      

Example: application/json

Accept      

Example: application/json

requires authentication

This endpoint allows you to search for a contact using any custom field values returns 0+ records

Example request:
curl --request GET \
    --get "http://localhost/api/v1/contacts/search?order_by=last_name&page=1&per_page=15" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost/api/v1/contacts/search"
);

const params = {
    "order_by": "last_name",
    "page": "1",
    "per_page": "15",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/contacts/search'
params = {
  'order_by': 'last_name',
  'page': '1',
  'per_page': '15',
}
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()
$client = new \GuzzleHttp\Client();
$response = $client->get(
    'http://localhost/api/v1/contacts/search',
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'order_by' => 'last_name',
            'page' => '1',
            'per_page' => '15',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

using System.Net.Http.Headers;

var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "{YOUR_API_KEY}");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

var request = new HttpRequestMessage
{
    Method = HttpMethod.Get,
    RequestUri = new Uri("http://localhost/api/v1/contacts/search?order_by=last_name&page=1&per_page=15"),
};
using (var response = await client.SendAsync(request))
{
    //response.EnsureSuccessStatusCode();
    var body = await response.Content.ReadAsStringAsync();
    Console.WriteLine(body);
}

Example response (401):

Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
 

{
    "message": "Unauthenticated."
}
 

Create a new contact

requires authentication

This endpoint allows you to create a new contact. Contact fields are team-specific and use the field's "tag" (merge tag identifier) as the key.

Example request:
curl --request POST \
    "http://localhost/api/v1/contacts/create" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"type\": \"person\",
    \"first_name\": \"John\",
    \"last_name\": \"Doe\",
    \"email\": \"john@example.com\",
    \"phone\": \"+14155552671\",
    \"birthday\": \"1990-05-15\",
    \"address\": \"123 Main Street\",
    \"city\": \"San Francisco\",
    \"state\": \"CA\",
    \"zipcode\": \"94102\",
    \"tags\": [
        \"customer\",
        \"vip\"
    ]
}"
const url = new URL(
    "http://localhost/api/v1/contacts/create"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "type": "person",
    "first_name": "John",
    "last_name": "Doe",
    "email": "john@example.com",
    "phone": "+14155552671",
    "birthday": "1990-05-15",
    "address": "123 Main Street",
    "city": "San Francisco",
    "state": "CA",
    "zipcode": "94102",
    "tags": [
        "customer",
        "vip"
    ]
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/contacts/create'
payload = {
    "type": "person",
    "first_name": "John",
    "last_name": "Doe",
    "email": "john@example.com",
    "phone": "+14155552671",
    "birthday": "1990-05-15",
    "address": "123 Main Street",
    "city": "San Francisco",
    "state": "CA",
    "zipcode": "94102",
    "tags": [
        "customer",
        "vip"
    ]
}
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, json=payload)
response.json()
$client = new \GuzzleHttp\Client();
$response = $client->post(
    'http://localhost/api/v1/contacts/create',
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'type' => 'person',
            'first_name' => 'John',
            'last_name' => 'Doe',
            'email' => 'john@example.com',
            'phone' => '+14155552671',
            'birthday' => '1990-05-15',
            'address' => '123 Main Street',
            'city' => 'San Francisco',
            'state' => 'CA',
            'zipcode' => '94102',
            'tags' => [
                'customer',
                'vip',
            ],
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

using System.Net.Http.Headers;

var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "{YOUR_API_KEY}");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

var data = new MultipartFormDataContent();
data.Add(new StringContent("person"), "type");
data.Add(new StringContent("John"), "first_name");
data.Add(new StringContent("Doe"), "last_name");
data.Add(new StringContent("john@example.com"), "email");
data.Add(new StringContent("+14155552671"), "phone");
data.Add(new StringContent("1990-05-15"), "birthday");
data.Add(new StringContent("123 Main Street"), "address");
data.Add(new StringContent("San Francisco"), "city");
data.Add(new StringContent("CA"), "state");
data.Add(new StringContent("94102"), "zipcode");
data.Add(new StringContent("customer"), "tags[]");

var request = new HttpRequestMessage
{
    Method = HttpMethod.Post,
    RequestUri = new Uri("http://localhost/api/v1/contacts/create"),
    Content = data
};
using (var response = await client.SendAsync(request))
{
    //response.EnsureSuccessStatusCode();
    var body = await response.Content.ReadAsStringAsync();
    Console.WriteLine(body);
}

Example response (200):


{
    "id": 1,
    "team_id": 1,
    "type": "person",
    "attributes": {
        "1": "John",
        "2": "Doe",
        "3": "john@example.com"
    },
    "tags": [
        {
            "id": 1,
            "slug": "customer"
        }
    ]
}
 

Example response (403):


{
    "message": "This action is unauthorized."
}
 

Example response (422):


{
    "message": "Tags not found: [found:1][passed:2][missing:invalid-tag]"
}
 

Request      

POST api/v1/contacts/create

Headers

Authorization      

Example: Bearer {YOUR_API_KEY}

Content-Type      

Example: application/json

Accept      

Example: application/json

Body Parameters

type   string   

The contact type. Must be either "person" or "organization". Example: person

first_name   string  optional  

The contact's first name. Example: John

last_name   string  optional  

The contact's last name. Example: Doe

email   string  optional  

The contact's email address. Must be a valid email format. Example: john@example.com

phone   string  optional  

The contact's phone number. Will be normalized to E.164 format. Example: +14155552671

birthday   string  optional  

The contact's birthday (date format). Example: 1990-05-15

address   string  optional  

The contact's street address. Example: 123 Main Street

city   string  optional  

The contact's city. Example: San Francisco

state   string  optional  

The contact's state. Example: CA

zipcode   string  optional  

The contact's zip/postal code. Example: 94102

tags   string[]  optional  

An array of tag slugs to assign to the contact. All tags must exist in your team's tag collection.

Get a contact by id

requires authentication

This endpoint allows you to get a single contact by their ID

magic here that i did not expect the call from ContactTest::test_api_get_contact passes a $contact model (which is really passing an ID???) by the time we get here, the $contact param is an object we got from the db??

Example request:
curl --request GET \
    --get "http://localhost/api/v1/contacts/1" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost/api/v1/contacts/1"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/contacts/1'
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$response = $client->get(
    'http://localhost/api/v1/contacts/1',
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

using System.Net.Http.Headers;

var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "{YOUR_API_KEY}");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

var request = new HttpRequestMessage
{
    Method = HttpMethod.Get,
    RequestUri = new Uri("http://localhost/api/v1/contacts/1"),
};
using (var response = await client.SendAsync(request))
{
    //response.EnsureSuccessStatusCode();
    var body = await response.Content.ReadAsStringAsync();
    Console.WriteLine(body);
}

Example response (401):

Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
 

{
    "message": "Unauthenticated."
}
 

Request      

GET api/v1/contacts/{contact_id}

Headers

Authorization      

Example: Bearer {YOUR_API_KEY}

Content-Type      

Example: application/json

Accept      

Example: application/json

URL Parameters

contact_id   integer   

The ID of the contact. Example: 1

Update an existing contact

requires authentication

This endpoint allows you to update an existing contact. Contact fields are team-specific and use the field's "tag" (merge tag identifier) as the key.

Example request:
curl --request PUT \
    "http://localhost/api/v1/contacts/1/update" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"first_name\": \"Jane\",
    \"last_name\": \"Smith\",
    \"email\": \"jane@example.com\",
    \"phone\": \"+14155552672\",
    \"birthday\": \"1985-08-22\",
    \"address\": \"456 Oak Avenue\",
    \"city\": \"Los Angeles\",
    \"state\": \"CA\",
    \"zipcode\": \"90210\",
    \"tags\": [
        \"customer\",
        \"newsletter\"
    ]
}"
const url = new URL(
    "http://localhost/api/v1/contacts/1/update"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "first_name": "Jane",
    "last_name": "Smith",
    "email": "jane@example.com",
    "phone": "+14155552672",
    "birthday": "1985-08-22",
    "address": "456 Oak Avenue",
    "city": "Los Angeles",
    "state": "CA",
    "zipcode": "90210",
    "tags": [
        "customer",
        "newsletter"
    ]
};

fetch(url, {
    method: "PUT",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/contacts/1/update'
payload = {
    "first_name": "Jane",
    "last_name": "Smith",
    "email": "jane@example.com",
    "phone": "+14155552672",
    "birthday": "1985-08-22",
    "address": "456 Oak Avenue",
    "city": "Los Angeles",
    "state": "CA",
    "zipcode": "90210",
    "tags": [
        "customer",
        "newsletter"
    ]
}
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('PUT', url, headers=headers, json=payload)
response.json()
$client = new \GuzzleHttp\Client();
$response = $client->put(
    'http://localhost/api/v1/contacts/1/update',
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'first_name' => 'Jane',
            'last_name' => 'Smith',
            'email' => 'jane@example.com',
            'phone' => '+14155552672',
            'birthday' => '1985-08-22',
            'address' => '456 Oak Avenue',
            'city' => 'Los Angeles',
            'state' => 'CA',
            'zipcode' => '90210',
            'tags' => [
                'customer',
                'newsletter',
            ],
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

using System.Net.Http.Headers;

var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "{YOUR_API_KEY}");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

var data = new MultipartFormDataContent();
data.Add(new StringContent("Jane"), "first_name");
data.Add(new StringContent("Smith"), "last_name");
data.Add(new StringContent("jane@example.com"), "email");
data.Add(new StringContent("+14155552672"), "phone");
data.Add(new StringContent("1985-08-22"), "birthday");
data.Add(new StringContent("456 Oak Avenue"), "address");
data.Add(new StringContent("Los Angeles"), "city");
data.Add(new StringContent("CA"), "state");
data.Add(new StringContent("90210"), "zipcode");
data.Add(new StringContent("customer"), "tags[]");

var request = new HttpRequestMessage
{
    Method = HttpMethod.Post,
    RequestUri = new Uri("http://localhost/api/v1/contacts/1/update"),
    Content = data
};
using (var response = await client.SendAsync(request))
{
    //response.EnsureSuccessStatusCode();
    var body = await response.Content.ReadAsStringAsync();
    Console.WriteLine(body);
}

Example response (200):


{
    "id": 1,
    "team_id": 1,
    "type": "person",
    "attributes": {
        "1": "Jane",
        "2": "Smith",
        "3": "jane@example.com"
    },
    "tags": [
        {
            "id": 1,
            "slug": "customer"
        }
    ]
}
 

Example response (403):


{
    "message": "This action is unauthorized."
}
 

Example response (422):


{
    "message": "Tags not found: [found:1][passed:2][missing:invalid-tag]"
}
 

Example response (422):


{
    "message": "Field with tag 'unknown_field' not found"
}
 

Request      

PUT api/v1/contacts/{id}/update

Headers

Authorization      

Example: Bearer {YOUR_API_KEY}

Content-Type      

Example: application/json

Accept      

Example: application/json

URL Parameters

id   integer   

The ID of the contact. Example: 1

contact   integer   

The contact ID. Example: 1

Body Parameters

first_name   string  optional  

The contact's first name. Example: Jane

last_name   string  optional  

The contact's last name. Example: Smith

email   string  optional  

The contact's email address. Must be a valid email format. Example: jane@example.com

phone   string  optional  

The contact's phone number. Will be normalized to E.164 format. Example: +14155552672

birthday   string  optional  

The contact's birthday (date format). Example: 1985-08-22

address   string  optional  

The contact's street address. Example: 456 Oak Avenue

city   string  optional  

The contact's city. Example: Los Angeles

state   string  optional  

The contact's state. Example: CA

zipcode   string  optional  

The contact's zip/postal code. Example: 90210

tags   string[]  optional  

An array of tag slugs to assign to the contact. Pass null or empty array to remove all tags. All tags must exist in your team's tag collection.

Delete a contact

requires authentication

This endpoint allows you to delete a contact

Example request:
curl --request DELETE \
    "http://localhost/api/v1/contacts/1" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost/api/v1/contacts/1"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/contacts/1'
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('DELETE', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$response = $client->delete(
    'http://localhost/api/v1/contacts/1',
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

using System.Net.Http.Headers;

var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "{YOUR_API_KEY}");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

var data = new MultipartFormDataContent();

var request = new HttpRequestMessage
{
    Method = HttpMethod.Post,
    RequestUri = new Uri("http://localhost/api/v1/contacts/1"),
    Content = data
};
using (var response = await client.SendAsync(request))
{
    //response.EnsureSuccessStatusCode();
    var body = await response.Content.ReadAsStringAsync();
    Console.WriteLine(body);
}

Request      

DELETE api/v1/contacts/{contact_id}

Headers

Authorization      

Example: Bearer {YOUR_API_KEY}

Content-Type      

Example: application/json

Accept      

Example: application/json

URL Parameters

contact_id   integer   

The ID of the contact. Example: 1

Email List management

APIs for managing email lists and subscriptions.

Get list subscribers

requires authentication

Get all subscriptions for an email list, with optional filtering.

Example request:
curl --request GET \
    --get "http://localhost/api/v1/lists/1/subscribers?limit=8&order_by=last_name&page=6&email=subscriber%40example.com&status=active" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost/api/v1/lists/1/subscribers"
);

const params = {
    "limit": "8",
    "order_by": "last_name",
    "page": "6",
    "email": "subscriber@example.com",
    "status": "active",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/lists/1/subscribers'
params = {
  'limit': '8',
  'order_by': 'last_name',
  'page': '6',
  'email': 'subscriber@example.com',
  'status': 'active',
}
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()
$client = new \GuzzleHttp\Client();
$response = $client->get(
    'http://localhost/api/v1/lists/1/subscribers',
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'limit' => '8',
            'order_by' => 'last_name',
            'page' => '6',
            'email' => 'subscriber@example.com',
            'status' => 'active',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

using System.Net.Http.Headers;

var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "{YOUR_API_KEY}");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

var request = new HttpRequestMessage
{
    Method = HttpMethod.Get,
    RequestUri = new Uri("http://localhost/api/v1/lists/1/subscribers?limit=8&order_by=last_name&page=6&email=subscriber%40example.com&status=active"),
};
using (var response = await client.SendAsync(request))
{
    //response.EnsureSuccessStatusCode();
    var body = await response.Content.ReadAsStringAsync();
    Console.WriteLine(body);
}

Example response (200):


[
    {
        "id": 1,
        "email_address_id": 5,
        "email_list_id": 1,
        "contact_id": 123,
        "status": "active",
        "address": {
            "id": 5,
            "email": "subscriber@example.com"
        }
    }
]
 

Request      

GET api/v1/lists/{list_id}/subscribers

Headers

Authorization      

Example: Bearer {YOUR_API_KEY}

Content-Type      

Example: application/json

Accept      

Example: application/json

URL Parameters

list_id   integer   

The ID of the list. Example: 1

list   integer   

The email list ID. Example: 1

Query Parameters

limit   integer  optional  

Limit number of records in the search. Example: 8

order_by   string  optional  

Field tag to order the results by. Example: last_name

page   integer  optional  

Page to return results for. Example: 6

email   string  optional  

Filter by exact email address. Example: subscriber@example.com

status   string  optional  

Filter by subscription status (active, unsubscribed, bounced, complained). Example: active

Create a new Subscription

requires authentication

This endpoint allows you to create a new subscription to an email list.

Example request:
curl --request POST \
    "http://localhost/api/v1/lists/1/subscribers?email=ibrahim26%40example.com&contact_id=19&limit=12&order_by=last_name&page=8" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"email\": \"subscriber@example.com\",
    \"contact_id\": 123
}"
const url = new URL(
    "http://localhost/api/v1/lists/1/subscribers"
);

const params = {
    "email": "ibrahim26@example.com",
    "contact_id": "19",
    "limit": "12",
    "order_by": "last_name",
    "page": "8",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "email": "subscriber@example.com",
    "contact_id": 123
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/lists/1/subscribers'
payload = {
    "email": "subscriber@example.com",
    "contact_id": 123
}
params = {
  'email': 'ibrahim26@example.com',
  'contact_id': '19',
  'limit': '12',
  'order_by': 'last_name',
  'page': '8',
}
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, json=payload, params=params)
response.json()
$client = new \GuzzleHttp\Client();
$response = $client->post(
    'http://localhost/api/v1/lists/1/subscribers',
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'email' => 'ibrahim26@example.com',
            'contact_id' => '19',
            'limit' => '12',
            'order_by' => 'last_name',
            'page' => '8',
        ],
        'json' => [
            'email' => 'subscriber@example.com',
            'contact_id' => 123,
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

using System.Net.Http.Headers;

var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "{YOUR_API_KEY}");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

var data = new MultipartFormDataContent();
data.Add(new StringContent("subscriber@example.com"), "email");
data.Add(new StringContent("123"), "contact_id");

var request = new HttpRequestMessage
{
    Method = HttpMethod.Post,
    RequestUri = new Uri("http://localhost/api/v1/lists/1/subscribers?email=ibrahim26%40example.com&contact_id=19&limit=12&order_by=last_name&page=8"),
    Content = data
};
using (var response = await client.SendAsync(request))
{
    //response.EnsureSuccessStatusCode();
    var body = await response.Content.ReadAsStringAsync();
    Console.WriteLine(body);
}

Example response (200):


{
    "id": 1,
    "email_address_id": 5,
    "email_list_id": 1,
    "contact_id": 123,
    "status": "active"
}
 

Example response (400):


{
    "message": "Failed to process the email address.",
    "error": "Invalid email format"
}
 

Request      

POST api/v1/lists/{list_id}/subscribers

Headers

Authorization      

Example: Bearer {YOUR_API_KEY}

Content-Type      

Example: application/json

Accept      

Example: application/json

URL Parameters

list_id   integer   

The ID of the list. Example: 1

list   integer   

The email list ID. Example: 1

Query Parameters

email   string   

Must be a valid email address. Example: ibrahim26@example.com

contact_id   integer  optional  

Example: 19

limit   integer  optional  

Limit number of records in the search. Example: 12

order_by   string  optional  

Field tag to order the results by. Example: last_name

page   integer  optional  

Page to return results for. Example: 8

Body Parameters

email   string   

The email address to subscribe. Example: subscriber@example.com

contact_id   integer  optional  

Optional contact ID to link the subscription to. Example: 123

Update a subscription

requires authentication

Update the status or contact association of an existing subscription.

Example request:
curl --request PUT \
    "http://localhost/api/v1/subscriptions/1/update" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"contact_id\": 123,
    \"status\": \"active\"
}"
const url = new URL(
    "http://localhost/api/v1/subscriptions/1/update"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "contact_id": 123,
    "status": "active"
};

fetch(url, {
    method: "PUT",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/subscriptions/1/update'
payload = {
    "contact_id": 123,
    "status": "active"
}
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('PUT', url, headers=headers, json=payload)
response.json()
$client = new \GuzzleHttp\Client();
$response = $client->put(
    'http://localhost/api/v1/subscriptions/1/update',
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'contact_id' => 123,
            'status' => 'active',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

using System.Net.Http.Headers;

var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "{YOUR_API_KEY}");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

var data = new MultipartFormDataContent();
data.Add(new StringContent("123"), "contact_id");
data.Add(new StringContent("active"), "status");

var request = new HttpRequestMessage
{
    Method = HttpMethod.Post,
    RequestUri = new Uri("http://localhost/api/v1/subscriptions/1/update"),
    Content = data
};
using (var response = await client.SendAsync(request))
{
    //response.EnsureSuccessStatusCode();
    var body = await response.Content.ReadAsStringAsync();
    Console.WriteLine(body);
}

Example response (200):


{
    "id": 1,
    "email_address_id": 5,
    "email_list_id": 1,
    "contact_id": 123,
    "status": "active"
}
 

Request      

PUT api/v1/subscriptions/{id}/update

Headers

Authorization      

Example: Bearer {YOUR_API_KEY}

Content-Type      

Example: application/json

Accept      

Example: application/json

URL Parameters

id   integer   

The ID of the subscription. Example: 1

subscription   integer   

The subscription ID. Example: 1

Body Parameters

contact_id   integer  optional  

The contact ID to associate with this subscription. Example: 123

status   string  optional  

The subscription status (active, unsubscribed, bounced, complained). Example: active

Email management

APIs for managing emails

Send an email

requires authentication

This endpoint allows you to send an email via HTTP

Example request:
curl --request POST \
    "http://localhost/api/v1/email/send" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: multipart/form-data" \
    --header "Accept: application/json" \
    --form "to=candace.kuhn@example.net"\
    --form "from=qmurazik@example.net"\
    --form "subject=vel"\
    --form "merge_data=["pariatur","dolores"]"\
    --form "cc[]=weston62@example.com"\
    --form "bcc[]=vbradtke@example.org"\
    --form "attachments[]=@/tmp/phpuqropf85so0j8LteJyu" 
const url = new URL(
    "http://localhost/api/v1/email/send"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "multipart/form-data",
    "Accept": "application/json",
};

const body = new FormData();
body.append('to', 'candace.kuhn@example.net');
body.append('from', 'qmurazik@example.net');
body.append('subject', 'vel');
body.append('merge_data', '["pariatur","dolores"]');
body.append('cc[]', 'weston62@example.com');
body.append('bcc[]', 'vbradtke@example.org');
body.append('attachments[]', document.querySelector('input[name="attachments[]"]').files[0]);

fetch(url, {
    method: "POST",
    headers,
    body,
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/email/send'
files = {
  'to': (None, 'candace.kuhn@example.net'),
  'from': (None, 'qmurazik@example.net'),
  'subject': (None, 'vel'),
  'merge_data': (None, '["pariatur","dolores"]'),
  'cc[]': (None, 'weston62@example.com'),
  'bcc[]': (None, 'vbradtke@example.org'),
  'attachments[]': open('/tmp/phpuqropf85so0j8LteJyu', 'rb')}
payload = {
    "to": "candace.kuhn@example.net",
    "from": "qmurazik@example.net",
    "subject": "vel",
    "merge_data": "[\"pariatur\",\"dolores\"]",
    "cc": [
        "weston62@example.com"
    ],
    "bcc": [
        "vbradtke@example.org"
    ]
}
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'multipart/form-data',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, files=files)
response.json()
$client = new \GuzzleHttp\Client();
$response = $client->post(
    'http://localhost/api/v1/email/send',
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_KEY}',
            'Content-Type' => 'multipart/form-data',
            'Accept' => 'application/json',
        ],
        'multipart' => [
            [
                'name' => 'to',
                'contents' => 'candace.kuhn@example.net'
            ],
            [
                'name' => 'from',
                'contents' => 'qmurazik@example.net'
            ],
            [
                'name' => 'subject',
                'contents' => 'vel'
            ],
            [
                'name' => 'merge_data',
                'contents' => '["pariatur","dolores"]'
            ],
            [
                'name' => 'cc[]',
                'contents' => 'weston62@example.com'
            ],
            [
                'name' => 'bcc[]',
                'contents' => 'vbradtke@example.org'
            ],
            [
                'name' => 'attachments[]',
                'contents' => fopen('/tmp/phpuqropf85so0j8LteJyu', 'r')
            ],
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

using System.Net.Http.Headers;

var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "{YOUR_API_KEY}");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

var data = new MultipartFormDataContent();
data.Add(new StringContent("candace.kuhn@example.net"), "to");
data.Add(new StringContent("qmurazik@example.net"), "from");
data.Add(new StringContent("vel"), "subject");
data.Add(new StringContent("["pariatur","dolores"]"), "merge_data");
data.Add(new StringContent("weston62@example.com"), "cc[]");
data.Add(new StringContent("vbradtke@example.org"), "bcc[]");

var file = new ByteArrayContent(System.IO.File.ReadAllBytes("/tmp/phpuqropf85so0j8LteJyu"));
data.Add(file, "attachments[]", "test.png");

var request = new HttpRequestMessage
{
    Method = HttpMethod.Post,
    RequestUri = new Uri("http://localhost/api/v1/email/send"),
    Content = data
};
using (var response = await client.SendAsync(request))
{
    //response.EnsureSuccessStatusCode();
    var body = await response.Content.ReadAsStringAsync();
    Console.WriteLine(body);
}

Request      

POST api/v1/email/send

Headers

Authorization      

Example: Bearer {YOUR_API_KEY}

Content-Type      

Example: multipart/form-data

Accept      

Example: application/json

Body Parameters

to   string   

Must be a valid email address. Example: candace.kuhn@example.net

from   string   

Must be a valid email address. Example: qmurazik@example.net

subject   string   

Example: vel

html   string  optional  
plaintext   string  optional  
message_id   string  optional  
campaign   string  optional  
merge_data   string  optional  

Must be a valid JSON string. Example: ["pariatur","dolores"]

cc   string[]  optional  

Must be a valid email address.

bcc   string[]  optional  

Must be a valid email address.

attachments   file[]  optional  

Must be a file.

Link management

APIs for managing emails

requires authentication

This endpoint allows you to create a new short link

Example request:
curl --request POST \
    "http://localhost/api/v1/links/create" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"destination_url\": \"https:\\/\\/brekke.com\\/quae-sit-repudiandae-placeat-ut-laboriosam.html\"
}"
const url = new URL(
    "http://localhost/api/v1/links/create"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "destination_url": "https:\/\/brekke.com\/quae-sit-repudiandae-placeat-ut-laboriosam.html"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/links/create'
payload = {
    "destination_url": "https:\/\/brekke.com\/quae-sit-repudiandae-placeat-ut-laboriosam.html"
}
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, json=payload)
response.json()
$client = new \GuzzleHttp\Client();
$response = $client->post(
    'http://localhost/api/v1/links/create',
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'destination_url' => 'https://brekke.com/quae-sit-repudiandae-placeat-ut-laboriosam.html',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

using System.Net.Http.Headers;

var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "{YOUR_API_KEY}");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

var data = new MultipartFormDataContent();
data.Add(new StringContent("https://brekke.com/quae-sit-repudiandae-placeat-ut-laboriosam.html"), "destination_url");

var request = new HttpRequestMessage
{
    Method = HttpMethod.Post,
    RequestUri = new Uri("http://localhost/api/v1/links/create"),
    Content = data
};
using (var response = await client.SendAsync(request))
{
    //response.EnsureSuccessStatusCode();
    var body = await response.Content.ReadAsStringAsync();
    Console.WriteLine(body);
}

Push Notifications

APIs for push notification subscriptions

Subscribe to push notifications (single list)

This endpoint allows a browser to subscribe to push notifications for a specific list. The endpoint is public and does not require authentication.

Example request:
curl --request POST \
    "http://localhost/api/v1/push/subscribe" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"list_slug\": \"my-notifications\",
    \"endpoint\": \"https:\\/\\/fcm.googleapis.com\\/fcm\\/send\\/...\",
    \"p256dh\": \"BNVAPKu...\",
    \"auth\": \"abc123...\",
    \"expiration_time\": 13,
    \"domain\": \"example.com\",
    \"browser\": \"Chrome\",
    \"platform\": \"Win32\",
    \"categories\": [
        \"s\"
    ]
}"
const url = new URL(
    "http://localhost/api/v1/push/subscribe"
);

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "list_slug": "my-notifications",
    "endpoint": "https:\/\/fcm.googleapis.com\/fcm\/send\/...",
    "p256dh": "BNVAPKu...",
    "auth": "abc123...",
    "expiration_time": 13,
    "domain": "example.com",
    "browser": "Chrome",
    "platform": "Win32",
    "categories": [
        "s"
    ]
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/push/subscribe'
payload = {
    "list_slug": "my-notifications",
    "endpoint": "https:\/\/fcm.googleapis.com\/fcm\/send\/...",
    "p256dh": "BNVAPKu...",
    "auth": "abc123...",
    "expiration_time": 13,
    "domain": "example.com",
    "browser": "Chrome",
    "platform": "Win32",
    "categories": [
        "s"
    ]
}
headers = {
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, json=payload)
response.json()
$client = new \GuzzleHttp\Client();
$response = $client->post(
    'http://localhost/api/v1/push/subscribe',
    [
        'headers' => [
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'list_slug' => 'my-notifications',
            'endpoint' => 'https://fcm.googleapis.com/fcm/send/...',
            'p256dh' => 'BNVAPKu...',
            'auth' => 'abc123...',
            'expiration_time' => 13,
            'domain' => 'example.com',
            'browser' => 'Chrome',
            'platform' => 'Win32',
            'categories' => [
                's',
            ],
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

using System.Net.Http.Headers;

var client = new HttpClient();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

var data = new MultipartFormDataContent();
data.Add(new StringContent("my-notifications"), "list_slug");
data.Add(new StringContent("https://fcm.googleapis.com/fcm/send/..."), "endpoint");
data.Add(new StringContent("BNVAPKu..."), "p256dh");
data.Add(new StringContent("abc123..."), "auth");
data.Add(new StringContent("13"), "expiration_time");
data.Add(new StringContent("example.com"), "domain");
data.Add(new StringContent("Chrome"), "browser");
data.Add(new StringContent("Win32"), "platform");
data.Add(new StringContent("s"), "categories[]");

var request = new HttpRequestMessage
{
    Method = HttpMethod.Post,
    RequestUri = new Uri("http://localhost/api/v1/push/subscribe"),
    Content = data
};
using (var response = await client.SendAsync(request))
{
    //response.EnsureSuccessStatusCode();
    var body = await response.Content.ReadAsStringAsync();
    Console.WriteLine(body);
}

Example response (201):


{
    "success": true,
    "subscription_id": "123",
    "message": "Successfully subscribed to push notifications"
}
 

Example response (422):


{
    "message": "The given data was invalid.",
    "errors": {
        "list_slug": [
            "The specified push notification list does not exist."
        ]
    }
}
 

Example response (429):


{
    "message": "Too many subscription attempts. Please try again later."
}
 

Request      

POST api/v1/push/subscribe

Headers

Content-Type      

Example: application/json

Accept      

Example: application/json

Body Parameters

list_slug   string   

The slug of the push notification list. Example: my-notifications

endpoint   string   

The push subscription endpoint URL. Example: https://fcm.googleapis.com/fcm/send/...

p256dh   string   

The p256dh encryption key. Example: BNVAPKu...

auth   string   

The auth secret. Example: abc123...

expiration_time   integer  optional  

Example: 13

domain   string  optional  

The domain where the subscription was created. Example: example.com

browser   string  optional  

The browser name. Example: Chrome

platform   string  optional  

The platform/OS. Example: Win32

categories   string[]  optional  

Must not be greater than 100 characters.

Batch subscribe to push notifications (multiple lists)

Subscribe a browser to multiple push notification lists at once. Each list requires its own push subscription (different VAPID key = different endpoint). Used by prompts that target multiple lists.

Example request:
curl --request POST \
    "http://localhost/api/v1/push/batch-subscribe" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"prompt_id\": \"550e8400-e29b-41d4-a716-446655440000\",
    \"subscriptions\": [
        \"praesentium\"
    ],
    \"domain\": \"example.com\",
    \"browser\": \"Chrome\",
    \"platform\": \"Win32\"
}"
const url = new URL(
    "http://localhost/api/v1/push/batch-subscribe"
);

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "prompt_id": "550e8400-e29b-41d4-a716-446655440000",
    "subscriptions": [
        "praesentium"
    ],
    "domain": "example.com",
    "browser": "Chrome",
    "platform": "Win32"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/push/batch-subscribe'
payload = {
    "prompt_id": "550e8400-e29b-41d4-a716-446655440000",
    "subscriptions": [
        "praesentium"
    ],
    "domain": "example.com",
    "browser": "Chrome",
    "platform": "Win32"
}
headers = {
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, json=payload)
response.json()
$client = new \GuzzleHttp\Client();
$response = $client->post(
    'http://localhost/api/v1/push/batch-subscribe',
    [
        'headers' => [
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'prompt_id' => '550e8400-e29b-41d4-a716-446655440000',
            'subscriptions' => [
                'praesentium',
            ],
            'domain' => 'example.com',
            'browser' => 'Chrome',
            'platform' => 'Win32',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

using System.Net.Http.Headers;

var client = new HttpClient();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

var data = new MultipartFormDataContent();
data.Add(new StringContent("550e8400-e29b-41d4-a716-446655440000"), "prompt_id");
data.Add(new StringContent("praesentium"), "subscriptions[]");
data.Add(new StringContent("example.com"), "domain");
data.Add(new StringContent("Chrome"), "browser");
data.Add(new StringContent("Win32"), "platform");

var request = new HttpRequestMessage
{
    Method = HttpMethod.Post,
    RequestUri = new Uri("http://localhost/api/v1/push/batch-subscribe"),
    Content = data
};
using (var response = await client.SendAsync(request))
{
    //response.EnsureSuccessStatusCode();
    var body = await response.Content.ReadAsStringAsync();
    Console.WriteLine(body);
}

Example response (201):


{
    "success": true,
    "results": [
        {
            "list_slug": "news",
            "subscription_id": "1",
            "status": "created"
        },
        {
            "list_slug": "deals",
            "subscription_id": "2",
            "status": "created"
        }
    ]
}
 

Example response (422):


{
    "message": "The given data was invalid."
}
 

Request      

POST api/v1/push/batch-subscribe

Headers

Content-Type      

Example: application/json

Accept      

Example: application/json

Body Parameters

prompt_id   string  optional  

The UUID of the prompt that initiated the subscription. Example: 550e8400-e29b-41d4-a716-446655440000

subscriptions   string[]   

Array of subscription objects.

list_slug   string   

The slug of the push notification list. Example: my-notifications

endpoint   string   

The push subscription endpoint URL. Example: https://fcm.googleapis.com/fcm/send/...

p256dh   string   

The p256dh encryption key. Example: BNVAPKu...

auth   string   

The auth secret. Example: abc123...

categories   string[]  optional  

Must not be greater than 100 characters.

domain   string  optional  

The domain where the subscriptions were created. Example: example.com

browser   string  optional  

The browser name. Example: Chrome

platform   string  optional  

The platform/OS. Example: Win32

Get prompt configuration

Returns the prompt configuration, theme, tracking URLs, and list VAPID keys. Used by the embed script on external sites to render the prompt UI.

Example request:
curl --request GET \
    --get "http://localhost/api/v1/push/prompt/totam" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost/api/v1/push/prompt/totam"
);

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/push/prompt/totam'
headers = {
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$response = $client->get(
    'http://localhost/api/v1/push/prompt/totam',
    [
        'headers' => [
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

using System.Net.Http.Headers;

var client = new HttpClient();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

var request = new HttpRequestMessage
{
    Method = HttpMethod.Get,
    RequestUri = new Uri("http://localhost/api/v1/push/prompt/totam"),
};
using (var response = await client.SendAsync(request))
{
    //response.EnsureSuccessStatusCode();
    var body = await response.Content.ReadAsStringAsync();
    Console.WriteLine(body);
}

Example response (200):


{
    "uuid": "550e8400...",
    "type": "slide",
    "position": "bottom_center",
    "lists": [
        {
            "listId": 1,
            "slug": "news",
            "publicKey": "BN..."
        }
    ],
    "tracking": {
        "impression": "https://..."
    }
}
 

Example response (404):


{
    "message": "Prompt not found or disabled."
}
 

Request      

GET api/v1/push/prompt/{prompt_uuid_id}

Headers

Content-Type      

Example: application/json

Accept      

Example: application/json

URL Parameters

prompt_uuid_id   string   

The ID of the prompt uuid. Example: totam

prompt   string   

The UUID of the prompt. Example: 550e8400-e29b-41d4-a716-446655440000

SMS List management

APIs for managing SMS lists and subscriptions

Get SMS list subscribers

requires authentication

Returns a paginated list of subscribers for the specified SMS list.

Example request:
curl --request GET \
    --get "http://localhost/api/v1/sms/lists/1/subscribers?phone_number=%2B1555&status=active&per_page=15" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost/api/v1/sms/lists/1/subscribers"
);

const params = {
    "phone_number": "+1555",
    "status": "active",
    "per_page": "15",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/sms/lists/1/subscribers'
params = {
  'phone_number': '+1555',
  'status': 'active',
  'per_page': '15',
}
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()
$client = new \GuzzleHttp\Client();
$response = $client->get(
    'http://localhost/api/v1/sms/lists/1/subscribers',
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'phone_number' => '+1555',
            'status' => 'active',
            'per_page' => '15',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

using System.Net.Http.Headers;

var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "{YOUR_API_KEY}");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

var request = new HttpRequestMessage
{
    Method = HttpMethod.Get,
    RequestUri = new Uri("http://localhost/api/v1/sms/lists/1/subscribers?phone_number=%2B1555&status=active&per_page=15"),
};
using (var response = await client.SendAsync(request))
{
    //response.EnsureSuccessStatusCode();
    var body = await response.Content.ReadAsStringAsync();
    Console.WriteLine(body);
}

Example response (200):


{
    "data": [],
    "current_page": 1,
    "total": 0
}
 

Request      

GET api/v1/sms/lists/{list_id}/subscribers

Headers

Authorization      

Example: Bearer {YOUR_API_KEY}

Content-Type      

Example: application/json

Accept      

Example: application/json

URL Parameters

list_id   integer   

The ID of the list. Example: 1

list   integer   

The SMS list ID. Example: 1

Query Parameters

phone_number   string  optional  

Filter subscribers by phone number (partial match). Example: +1555

status   string  optional  

Filter by subscription status. Example: active

per_page   integer  optional  

Number of results per page. Example: 15

Create SMS list subscription

requires authentication

Add a phone number to an SMS list. Automatically cleans and validates the phone number.

Example request:
curl --request POST \
    "http://localhost/api/v1/sms/lists/1/subscribers" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"phone_number\": \"+15551234567\",
    \"contact_id\": 42,
    \"assume_country_code\": 1
}"
const url = new URL(
    "http://localhost/api/v1/sms/lists/1/subscribers"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "phone_number": "+15551234567",
    "contact_id": 42,
    "assume_country_code": 1
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/sms/lists/1/subscribers'
payload = {
    "phone_number": "+15551234567",
    "contact_id": 42,
    "assume_country_code": 1
}
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, json=payload)
response.json()
$client = new \GuzzleHttp\Client();
$response = $client->post(
    'http://localhost/api/v1/sms/lists/1/subscribers',
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'phone_number' => '+15551234567',
            'contact_id' => 42,
            'assume_country_code' => 1,
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

using System.Net.Http.Headers;

var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "{YOUR_API_KEY}");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

var data = new MultipartFormDataContent();
data.Add(new StringContent("+15551234567"), "phone_number");
data.Add(new StringContent("42"), "contact_id");
data.Add(new StringContent("1"), "assume_country_code");

var request = new HttpRequestMessage
{
    Method = HttpMethod.Post,
    RequestUri = new Uri("http://localhost/api/v1/sms/lists/1/subscribers"),
    Content = data
};
using (var response = await client.SendAsync(request))
{
    //response.EnsureSuccessStatusCode();
    var body = await response.Content.ReadAsStringAsync();
    Console.WriteLine(body);
}

Example response (201):


{
    "id": 1,
    "phone_number": "+15551234567",
    "status": "active"
}
 

Example response (422):


{
    "message": "Validation failed",
    "errors": {
        "phone_number": [
            "Invalid phone number"
        ]
    }
}
 

Request      

POST api/v1/sms/lists/{list_id}/subscribers

Headers

Authorization      

Example: Bearer {YOUR_API_KEY}

Content-Type      

Example: application/json

Accept      

Example: application/json

URL Parameters

list_id   integer   

The ID of the list. Example: 1

list   integer   

The SMS list ID. Example: 1

Body Parameters

phone_number   string   

The phone number to subscribe. Example: +15551234567

contact_id   integer  optional  

The contact ID to associate with the subscription. Example: 42

assume_country_code   integer  optional  

Country code to assume if not provided. Defaults to 1 (US). Example: 1

SMS management

APIs for managing text messages

Send an SMS/MMS message

requires authentication

Send a text message or multimedia message via Twilio. Include media_urls to send as MMS.

Example request:
curl --request POST \
    "http://localhost/api/v1/sms/send" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"to\": \"+15551234567\",
    \"from\": \"+15559876543\",
    \"message\": \"Hello from our team!\",
    \"media_urls\": [
        \"https:\\/\\/example.com\\/image.jpg\"
    ]
}"
const url = new URL(
    "http://localhost/api/v1/sms/send"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "to": "+15551234567",
    "from": "+15559876543",
    "message": "Hello from our team!",
    "media_urls": [
        "https:\/\/example.com\/image.jpg"
    ]
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/sms/send'
payload = {
    "to": "+15551234567",
    "from": "+15559876543",
    "message": "Hello from our team!",
    "media_urls": [
        "https:\/\/example.com\/image.jpg"
    ]
}
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, json=payload)
response.json()
$client = new \GuzzleHttp\Client();
$response = $client->post(
    'http://localhost/api/v1/sms/send',
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'to' => '+15551234567',
            'from' => '+15559876543',
            'message' => 'Hello from our team!',
            'media_urls' => [
                'https://example.com/image.jpg',
            ],
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

using System.Net.Http.Headers;

var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "{YOUR_API_KEY}");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

var data = new MultipartFormDataContent();
data.Add(new StringContent("+15551234567"), "to");
data.Add(new StringContent("+15559876543"), "from");
data.Add(new StringContent("Hello from our team!"), "message");
data.Add(new StringContent("https://example.com/image.jpg"), "media_urls[]");

var request = new HttpRequestMessage
{
    Method = HttpMethod.Post,
    RequestUri = new Uri("http://localhost/api/v1/sms/send"),
    Content = data
};
using (var response = await client.SendAsync(request))
{
    //response.EnsureSuccessStatusCode();
    var body = await response.Content.ReadAsStringAsync();
    Console.WriteLine(body);
}

Example response (200):


{
    "success": true
}
 

Example response (422):


{
    "message": "The to field is required.",
    "errors": {
        "to": [
            "The to field is required."
        ]
    }
}
 

Request      

POST api/v1/sms/send

Headers

Authorization      

Example: Bearer {YOUR_API_KEY}

Content-Type      

Example: application/json

Accept      

Example: application/json

Body Parameters

to   string   

The recipient phone number in E.164 format. Example: +15551234567

from   string   

The sender phone number. Must be a verified Twilio number for the team. Example: +15559876543

message   string   

The message body text. Example: Hello from our team!

media_urls   string[]  optional  

An array of public image URLs for MMS. Max 10 items. Supported formats: JPEG, PNG, GIF. Max 5MB per image.

Team management

APIs for managing teams

GET api/v1/team

requires authentication

Example request:
curl --request GET \
    --get "http://localhost/api/v1/team" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost/api/v1/team"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/team'
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$response = $client->get(
    'http://localhost/api/v1/team',
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

using System.Net.Http.Headers;

var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "{YOUR_API_KEY}");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

var request = new HttpRequestMessage
{
    Method = HttpMethod.Get,
    RequestUri = new Uri("http://localhost/api/v1/team"),
};
using (var response = await client.SendAsync(request))
{
    //response.EnsureSuccessStatusCode();
    var body = await response.Content.ReadAsStringAsync();
    Console.WriteLine(body);
}

Example response (401):

Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
 

{
    "message": "Unauthenticated."
}
 

Request      

GET api/v1/team

Headers

Authorization      

Example: Bearer {YOUR_API_KEY}

Content-Type      

Example: application/json

Accept      

Example: application/json

Verified Identities

APIs for retrieving verified sender identities.

Before sending emails or SMS messages through the API, you need verified sender identities. These endpoints allow you to retrieve your team's verified email addresses and phone numbers.

Email Verification

Email addresses are verified through AWS SES. When you add a new email address, a verification email is sent to that address. Once verified, you can use it as the "from" address when sending emails.

Phone Verification

Phone numbers are verified through Twilio. These are typically purchased or ported numbers that have been registered with your Twilio account and linked to your team.

Using Verified Identities

List all verified identities

requires authentication

Get all verified identities (emails, phones, and domains) for this team. Useful for getting a complete overview of available sender identities.

Example request:
curl --request GET \
    --get "http://localhost/api/v1/verified-identities?type=email" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost/api/v1/verified-identities"
);

const params = {
    "type": "email",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/verified-identities'
params = {
  'type': 'email',
}
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()
$client = new \GuzzleHttp\Client();
$response = $client->get(
    'http://localhost/api/v1/verified-identities',
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'type' => 'email',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

using System.Net.Http.Headers;

var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "{YOUR_API_KEY}");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

var request = new HttpRequestMessage
{
    Method = HttpMethod.Get,
    RequestUri = new Uri("http://localhost/api/v1/verified-identities?type=email"),
};
using (var response = await client.SendAsync(request))
{
    //response.EnsureSuccessStatusCode();
    var body = await response.Content.ReadAsStringAsync();
    Console.WriteLine(body);
}

Example response (200):


{
    "emails": [
        {
            "id": 1,
            "email": "hello@example.com",
            "verified_at": "2024-01-15T10:30:00Z"
        }
    ],
    "phones": [
        {
            "id": 1,
            "phone_number": "+14155552671",
            "type": "twilio",
            "verified_at": "2024-01-15T10:30:00Z"
        }
    ],
    "domains": [
        {
            "id": 1,
            "domain": "example.com",
            "verified_at": "2024-01-10T09:00:00Z"
        }
    ]
}
 

Request      

GET api/v1/verified-identities

Headers

Authorization      

Example: Bearer {YOUR_API_KEY}

Content-Type      

Example: application/json

Accept      

Example: application/json

Query Parameters

type   string  optional  

Filter by identity type. Must be email, phone, or domain. Example: email

List verified email addresses

requires authentication

Get all verified email addresses that can be used as sender addresses for this team. Only returns emails that have completed verification.

Example request:
curl --request GET \
    --get "http://localhost/api/v1/verified-identities/emails" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost/api/v1/verified-identities/emails"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/verified-identities/emails'
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$response = $client->get(
    'http://localhost/api/v1/verified-identities/emails',
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

using System.Net.Http.Headers;

var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "{YOUR_API_KEY}");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

var request = new HttpRequestMessage
{
    Method = HttpMethod.Get,
    RequestUri = new Uri("http://localhost/api/v1/verified-identities/emails"),
};
using (var response = await client.SendAsync(request))
{
    //response.EnsureSuccessStatusCode();
    var body = await response.Content.ReadAsStringAsync();
    Console.WriteLine(body);
}

Example response (200):


[
    {
        "id": 1,
        "email": "hello@example.com",
        "verified_at": "2024-01-15T10:30:00Z"
    },
    {
        "id": 2,
        "email": "support@example.com",
        "verified_at": "2024-01-20T14:45:00Z"
    }
]
 

Request      

GET api/v1/verified-identities/emails

Headers

Authorization      

Example: Bearer {YOUR_API_KEY}

Content-Type      

Example: application/json

Accept      

Example: application/json

List verified phone numbers

requires authentication

Get all verified phone numbers that can be used as sender numbers for SMS messages. Phone numbers are in E.164 format (e.g., +14155552671).

Example request:
curl --request GET \
    --get "http://localhost/api/v1/verified-identities/phones" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost/api/v1/verified-identities/phones"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/verified-identities/phones'
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$response = $client->get(
    'http://localhost/api/v1/verified-identities/phones',
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

using System.Net.Http.Headers;

var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "{YOUR_API_KEY}");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

var request = new HttpRequestMessage
{
    Method = HttpMethod.Get,
    RequestUri = new Uri("http://localhost/api/v1/verified-identities/phones"),
};
using (var response = await client.SendAsync(request))
{
    //response.EnsureSuccessStatusCode();
    var body = await response.Content.ReadAsStringAsync();
    Console.WriteLine(body);
}

Example response (200):


[
    {
        "id": 1,
        "phone_number": "+14155552671",
        "type": "twilio",
        "verified_at": "2024-01-15T10:30:00Z"
    },
    {
        "id": 2,
        "phone_number": "+14155552672",
        "type": "twilio",
        "verified_at": "2024-01-20T14:45:00Z"
    }
]
 

Request      

GET api/v1/verified-identities/phones

Headers

Authorization      

Example: Bearer {YOUR_API_KEY}

Content-Type      

Example: application/json

Accept      

Example: application/json