curl -X POST https://app.demeterrr.com/api/v1/sequences/880e8400-e29b-41d4-a716-446655440000/execute \
-H "X-API-Key: dem_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"contacts": [
{
"email": "customer1@example.com",
"firstName": "Alice",
"lastName": "Johnson",
"phone": "+15551234567"
},
{
"email": "customer2@example.com",
"firstName": "Bob",
"lastName": "Williams",
"phone": "+15559876543"
}
],
"locationId": "660e8400-e29b-41d4-a716-446655440000",
"employeeId": "770e8400-e29b-41d4-a716-446655440000"
}'
// When customer completes purchase
async function triggerPostPurchaseSurvey(order) {
const response = await fetch(
'https://app.demeterrr.com/api/v1/sequences/880e8400-e29b-41d4-a716-446655440000/execute',
{
method: 'POST',
headers: {
'X-API-Key': 'dem_your_key_here',
'Content-Type': 'application/json'
},
body: JSON.stringify({
contacts: [{
email: order.customerEmail,
firstName: order.customerFirstName,
lastName: order.customerLastName,
phone: order.customerPhone
}],
locationId: order.storeLocationId
})
}
);
const result = await response.json();
console.log(`Survey queued for ${result.data.contactsProcessed} contact(s)`);
}
import requests
# Execute for multiple customers
contacts = [
{'email': 'alice@example.com', 'firstName': 'Alice', 'phone': '+15551234567'},
{'email': 'bob@example.com', 'firstName': 'Bob', 'phone': '+15559876543'},
# ... up to 100 contacts
]
response = requests.post(
'https://app.demeterrr.com/api/v1/sequences/880e8400-e29b-41d4-a716-446655440000/execute',
headers={
'X-API-Key': 'dem_your_key_here',
'Content-Type': 'application/json'
},
json={
'contacts': contacts,
'locationId': '660e8400-e29b-41d4-a716-446655440000'
}
)
result = response.json()['data']
print(f"Processed: {result['contactsProcessed']}, Queued: {result['sendingsCreated']}")
{
"data": {
"sequenceId": "880e8400-e29b-41d4-a716-446655440000",
"sequenceName": "Post-Purchase Satisfaction Survey",
"contactsProcessed": 2,
"sendingsCreated": 2,
"results": [
{
"email": "customer1@example.com",
"contactId": "990e8400-e29b-41d4-a716-446655440000",
"status": "queued"
},
{
"email": "customer2@example.com",
"contactId": "aa0e8400-e29b-41d4-a716-446655440000",
"status": "queued"
}
]
}
}
{
"error": {
"code": "SEQUENCE_INACTIVE",
"message": "Sequence is not active"
}
}
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid request data",
"details": {
"contacts": ["At least one contact is required"],
"contacts.0.email": ["Invalid email address"]
}
}
}
Sequences
Execute Sequence
Trigger a sequence for one or more contacts (KEY ENDPOINT)
POST
/
api
/
v1
/
sequences
/
:id
/
execute
curl -X POST https://app.demeterrr.com/api/v1/sequences/880e8400-e29b-41d4-a716-446655440000/execute \
-H "X-API-Key: dem_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"contacts": [
{
"email": "customer1@example.com",
"firstName": "Alice",
"lastName": "Johnson",
"phone": "+15551234567"
},
{
"email": "customer2@example.com",
"firstName": "Bob",
"lastName": "Williams",
"phone": "+15559876543"
}
],
"locationId": "660e8400-e29b-41d4-a716-446655440000",
"employeeId": "770e8400-e29b-41d4-a716-446655440000"
}'
// When customer completes purchase
async function triggerPostPurchaseSurvey(order) {
const response = await fetch(
'https://app.demeterrr.com/api/v1/sequences/880e8400-e29b-41d4-a716-446655440000/execute',
{
method: 'POST',
headers: {
'X-API-Key': 'dem_your_key_here',
'Content-Type': 'application/json'
},
body: JSON.stringify({
contacts: [{
email: order.customerEmail,
firstName: order.customerFirstName,
lastName: order.customerLastName,
phone: order.customerPhone
}],
locationId: order.storeLocationId
})
}
);
const result = await response.json();
console.log(`Survey queued for ${result.data.contactsProcessed} contact(s)`);
}
import requests
# Execute for multiple customers
contacts = [
{'email': 'alice@example.com', 'firstName': 'Alice', 'phone': '+15551234567'},
{'email': 'bob@example.com', 'firstName': 'Bob', 'phone': '+15559876543'},
# ... up to 100 contacts
]
response = requests.post(
'https://app.demeterrr.com/api/v1/sequences/880e8400-e29b-41d4-a716-446655440000/execute',
headers={
'X-API-Key': 'dem_your_key_here',
'Content-Type': 'application/json'
},
json={
'contacts': contacts,
'locationId': '660e8400-e29b-41d4-a716-446655440000'
}
)
result = response.json()['data']
print(f"Processed: {result['contactsProcessed']}, Queued: {result['sendingsCreated']}")
{
"data": {
"sequenceId": "880e8400-e29b-41d4-a716-446655440000",
"sequenceName": "Post-Purchase Satisfaction Survey",
"contactsProcessed": 2,
"sendingsCreated": 2,
"results": [
{
"email": "customer1@example.com",
"contactId": "990e8400-e29b-41d4-a716-446655440000",
"status": "queued"
},
{
"email": "customer2@example.com",
"contactId": "aa0e8400-e29b-41d4-a716-446655440000",
"status": "queued"
}
]
}
}
{
"error": {
"code": "SEQUENCE_INACTIVE",
"message": "Sequence is not active"
}
}
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid request data",
"details": {
"contacts": ["At least one contact is required"],
"contacts.0.email": ["Invalid email address"]
}
}
}
Most Important Endpoint: This is the primary integration point for triggering automated customer workflows.
Authentication
Requiressequences:execute scope.
Path Parameters
string
required
Sequence UUID
Request Body
array
required
string
Location UUID to associate with all contacts
string
Employee UUID to associate with all contacts (for attribution)
How It Works
- Contact Creation/Update: Contacts are created if they don’t exist, or updated if they do (matched by email)
- Sequence Validation: Sequence must be
activestatus - Sending Creation: Creates a
sendingrecord for each contact - Background Execution: Triggers Inngest background job to execute the sequence steps
- Immediate Response: Returns immediately without waiting for execution to complete
Use this endpoint to trigger surveys after purchase, onboarding sequences for new customers, or review requests after service completion.
curl -X POST https://app.demeterrr.com/api/v1/sequences/880e8400-e29b-41d4-a716-446655440000/execute \
-H "X-API-Key: dem_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"contacts": [
{
"email": "customer1@example.com",
"firstName": "Alice",
"lastName": "Johnson",
"phone": "+15551234567"
},
{
"email": "customer2@example.com",
"firstName": "Bob",
"lastName": "Williams",
"phone": "+15559876543"
}
],
"locationId": "660e8400-e29b-41d4-a716-446655440000",
"employeeId": "770e8400-e29b-41d4-a716-446655440000"
}'
// When customer completes purchase
async function triggerPostPurchaseSurvey(order) {
const response = await fetch(
'https://app.demeterrr.com/api/v1/sequences/880e8400-e29b-41d4-a716-446655440000/execute',
{
method: 'POST',
headers: {
'X-API-Key': 'dem_your_key_here',
'Content-Type': 'application/json'
},
body: JSON.stringify({
contacts: [{
email: order.customerEmail,
firstName: order.customerFirstName,
lastName: order.customerLastName,
phone: order.customerPhone
}],
locationId: order.storeLocationId
})
}
);
const result = await response.json();
console.log(`Survey queued for ${result.data.contactsProcessed} contact(s)`);
}
import requests
# Execute for multiple customers
contacts = [
{'email': 'alice@example.com', 'firstName': 'Alice', 'phone': '+15551234567'},
{'email': 'bob@example.com', 'firstName': 'Bob', 'phone': '+15559876543'},
# ... up to 100 contacts
]
response = requests.post(
'https://app.demeterrr.com/api/v1/sequences/880e8400-e29b-41d4-a716-446655440000/execute',
headers={
'X-API-Key': 'dem_your_key_here',
'Content-Type': 'application/json'
},
json={
'contacts': contacts,
'locationId': '660e8400-e29b-41d4-a716-446655440000'
}
)
result = response.json()['data']
print(f"Processed: {result['contactsProcessed']}, Queued: {result['sendingsCreated']}")
{
"data": {
"sequenceId": "880e8400-e29b-41d4-a716-446655440000",
"sequenceName": "Post-Purchase Satisfaction Survey",
"contactsProcessed": 2,
"sendingsCreated": 2,
"results": [
{
"email": "customer1@example.com",
"contactId": "990e8400-e29b-41d4-a716-446655440000",
"status": "queued"
},
{
"email": "customer2@example.com",
"contactId": "aa0e8400-e29b-41d4-a716-446655440000",
"status": "queued"
}
]
}
}
{
"error": {
"code": "SEQUENCE_INACTIVE",
"message": "Sequence is not active"
}
}
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid request data",
"details": {
"contacts": ["At least one contact is required"],
"contacts.0.email": ["Invalid email address"]
}
}
}
Use Cases
Post-Purchase Surveys
Post-Purchase Surveys
Trigger CSAT or NPS surveys automatically after customers complete a purchase.
executeSequence(satisfactionSequenceId, {
contacts: [{ email: customer.email, firstName: customer.name }]
});
Service Appointment Follow-up
Service Appointment Follow-up
Send review requests after service appointments (dental, salon, etc.).
executeSequence(reviewSequenceId, {
contacts: [{ email: appointment.customerEmail }],
employeeId: appointment.providerId
});
Onboarding Sequences
Onboarding Sequences
Welcome new customers with a multi-step onboarding sequence.
executeSequence(onboardingSequenceId, {
contacts: newSignups.map(user => ({
email: user.email,
firstName: user.firstName
}))
});
Bulk Campaign
Bulk Campaign
Execute marketing campaigns for up to 100 contacts at once.
// Process in batches of 100
for (let i = 0; i < allContacts.length; i += 100) {
const batch = allContacts.slice(i, i + 100);
await executeSequence(campaignId, { contacts: batch });
}
⌘I