Skip to content

Sequences API Documentation ​

The Sequences API allows external systems to trigger automated message sequences based on customer events. This API provides a secure, authenticated gateway for external integrations like e-commerce platforms, CRM systems, and custom applications to enroll customers in automated messaging sequences.

Base URL ​

https://api.talkingshops.com/v1

Authentication ​

All API requests require authentication using an API key. Include your API key in the request header:

x-tenant-api-key: your_api_key_here

API keys are tenant-specific and automatically provide access to the correct sequence data for your business account.

Rate Limiting ​

The API implements rate limiting to prevent abuse. By default, each tenant is limited to 100 requests per minute.

Service Availability ​

If the Sequences service is unavailable, the API returns 503 ServiceUnavailable.

Endpoints Overview ​

MethodEndpointDescription
POST/sequences/eventsFire an event to trigger sequence enrollments
POST/sequences/events/batchProcess multiple events in a single request (max 100)
GET/sequences/triggersList all available trigger types
POST/sequences/triggersCreate a custom trigger type
DELETE/sequences/triggers/{slug}Delete a custom trigger type
POST/sequences/enrollEnroll a customer directly by trigger type

Trigger Types ​

The system supports the following built-in trigger types:

E-commerce ​

Trigger TypeDescription
abandoned_cartCustomer adds items to cart but doesn't complete purchase
order_completedCustomer completes an order
order_deliveredOrder is delivered to customer
payment_successPayment is successfully processed
payment_failedPayment processing fails
first_purchaseCustomer's first-ever purchase
product_viewedCustomer views a product

Customer Lifecycle ​

Trigger TypeDescription
customer_inactiveCustomer has been inactive for X days
inactive_after_first_messageCustomer inactive after first bot interaction

Bookings & Appointments ​

Trigger TypeDescription
booking_completedCustomer confirms a booking
booking_cancelledCustomer cancels a booking

Lead Management ​

Trigger TypeDescription
lead_form_completedCustomer completes a lead capture form
lead_document_uploadedCustomer uploads documents

Support & Engagement ​

Trigger TypeDescription
agent_handoffCustomer is transferred to a live agent
support_requestedCustomer requests live support
message_no_replyCustomer doesn't reply within X hours

Segments ​

Trigger TypeDescription
segment_enteredCustomer enters a specific segment
segment_exitedCustomer exits a specific segment

Date-Based & Custom ​

Trigger TypeDescription
date_basedScan supported entities by date field (birthdays, anniversaries, expiry dates)
recurring_dateRecurring date trigger (birthday, subscription reminders)
custom_eventGeneric custom event from external systems

Task Management ​

Trigger TypeDescription
task_dueTask due date approaches

Fire Event ​

POST /sequences/events

Fire an event that may trigger enrollment in one or more sequences. The event type must match a sequence's trigger configuration.

Deduplication and retries

Each event reaches your sequences and your flow builder journeys. Both take an event with a given deduplicationKey only once: an event whose key was already processed is skipped, so the customer is not enrolled twice.

  • Retries must reuse the same key. Make the key once per real event, from something stable such as the order or cart ID, before the first attempt. Don't build it from the time of the request, or each retry gets a new key and enrols the customer again.
  • Without a key, we make one for the event and return it as deduplicationKey in the response. Retry with that key. If you got no response (a timeout or a dropped connection), you can't know the key, so a retry may enrol the customer twice. Send your own key whenever you might retry.

Request ​

json
{
  "eventType": "abandoned_cart",
  "customerMobile": "+919876543210",
  "customerId": "cust_12345",
  "deduplicationKey": "cart:abcd1234:1704067200000",
  "eventData": {
    "cartId": "cart_abc123",
    "items": [
      { "productId": "prod_001", "name": "Premium T-Shirt", "price": 29.99, "quantity": 2 }
    ],
    "totalAmount": 59.98,
    "currency": "USD"
  }
}

Parameters ​

ParameterTypeRequiredDescription
eventTypestringYesTrigger type slug (e.g., abandoned_cart, order_completed)
customerMobilestringYesWhatsApp phone number with country code in E.164 format (e.g., +919876543210)
customerIdstringNoYour internal customer ID
deduplicationKeystringNo (recommended)Your stable ID for this event. An event whose key was already processed is skipped. Reuse the same key on every retry
eventDataobjectNoArbitrary data passed to message templates

Response (200 OK) ​

json
{
  "success": true,
  "enrollments": [
    {
      "sequenceId": "seq_cart_recovery_001",
      "sequenceName": "Cart Recovery",
      "enrollmentId": "enr_abc123def456",
      "firstStepAt": "2024-01-01T10:00:00.000Z"
    }
  ],
  "skipped": [],
  "errors": []
}

Response Fields ​

FieldTypeDescription
successbooleanWhether the event was processed
enrollmentsarrayList of successful enrollments
enrollments[].sequenceIdstringID of the sequence the customer was enrolled in
enrollments[].sequenceNamestringName of the sequence
enrollments[].enrollmentIdstringUnique enrollment ID
enrollments[].firstStepAtstringISO 8601 timestamp when the first message will be sent
skippedarraySequences that were skipped (e.g., customer already enrolled)
errorsarrayAny errors encountered during enrollment
deduplicationKeystringThe event's key: the one you sent, or the one we made when you sent none. Reuse it if you retry

Batch Events ​

POST /sequences/events/batch

Process multiple events in a single request. Each event is processed independently. Maximum 100 events per request.

Batch Processing

Events are processed sequentially — batch size should be chosen based on your timeout requirements. For high-throughput scenarios, consider processing events in parallel from your client.

Request ​

json
{
  "events": [
    {
      "eventType": "abandoned_cart",
      "customerMobile": "+919876543210",
      "deduplicationKey": "cart:abcd1234:1704067200000",
      "eventData": { "cartId": "cart_001", "totalAmount": 59.98 }
    },
    {
      "eventType": "order_completed",
      "customerMobile": "+14155552671",
      "customerId": "cust_67890",
      "eventData": { "orderId": "order_xyz789", "totalAmount": 149.99 }
    }
  ]
}

Parameters ​

ParameterTypeRequiredDescription
eventsarrayYesArray of event objects (1–100 items)
events[].eventTypestringYesTrigger type slug
events[].customerMobilestringYesE.164 phone number
events[].customerIdstringNoInternal customer ID
events[].deduplicationKeystringNo (recommended)Your stable ID for this event. Reuse the same key on every retry. See Deduplication and retries
events[].eventDataobjectNoEvent-specific data

Response (200 OK) ​

json
{
  "success": true,
  "processed": 2,
  "enrolled": 2,
  "skipped": 0,
  "errors": [],
  "results": [
    {
      "eventType": "abandoned_cart",
      "customerMobile": "+919876543210",
      "status": "enrolled",
      "enrollments": [
        {
          "sequenceId": "seq_cart_recovery_001",
          "sequenceName": "Cart Recovery",
          "enrollmentId": "enr_abc123def456"
        }
      ]
    },
    {
      "eventType": "order_completed",
      "customerMobile": "+14155552671",
      "status": "enrolled",
      "enrollments": [
        {
          "sequenceId": "seq_thank_you_001",
          "sequenceName": "Thank You",
          "enrollmentId": "enr_def456ghi789"
        }
      ]
    }
  ],
  "deduplicationKeys": ["cart:abcd1234:1704067200000", "ts-6f1c2d4e-8a3b-4c5d-9e7f-0a1b2c3d4e5f"]
}

deduplicationKeys lists each event's key in request order: the one you sent, or the one we made when you sent none. If you retry the batch, send these keys.


List Triggers ​

GET /sequences/triggers

Get all trigger types available for your tenant, including built-in system triggers and any custom triggers you've created.

Response (200 OK) ​

json
{
  "triggers": [
    {
      "slug": "abandoned_cart",
      "name": "Cart Created",
      "description": "Triggered when customer creates/abandons a cart",
      "category": "e-commerce",
      "isBuiltIn": true,
      "isScheduled": false
    },
    {
      "slug": "recurring_date",
      "name": "Date Trigger",
      "description": "Birthday, anniversary, subscription expiry, or any custom date field",
      "category": "date-based",
      "isBuiltIn": true,
      "isScheduled": true
    },
    {
      "slug": "my_custom_trigger",
      "name": "My Custom Trigger",
      "description": "Custom event for my integration",
      "category": "custom",
      "isBuiltIn": false,
      "isScheduled": false,
      "eventDataSchema": {}
    }
  ],
  "dateTriggerEntities": [
    {
      "entityType": "customer",
      "knownDateFields": ["created_at", "custom_fields.birthday", "custom_fields.subscription_end_date"],
      "supportsCustomDateFields": true
    },
    {
      "entityType": "booking",
      "knownDateFields": ["booking_date", "booking_end_date"],
      "supportsCustomDateFields": true
    },
    {
      "entityType": "order",
      "knownDateFields": ["order_date", "delivery_date"],
      "supportsCustomDateFields": false
    },
    {
      "entityType": "task",
      "knownDateFields": ["due_date"],
      "supportsCustomDateFields": true
    }
  ]
}

dateTriggerEntities

The dateTriggerEntities array is required by the ssp-ui dashboard for configuring date-based triggers. If you're building an integration that creates sequences programmatically, use entityType: "customer" with knownDateFields to determine which date fields are available.


Create Trigger ​

POST /sequences/triggers

Register a custom trigger type for your tenant. Custom triggers allow you to define event types specific to your business that can then be used to create sequences in the dashboard.

Trigger Slug Rules

The slug must be unique across your tenant and cannot conflict with built-in trigger slugs. It must follow the pattern: starts with a lowercase letter, followed by lowercase letters, numbers, or underscores (e.g., high_value_purchase, app_installed).

Request ​

json
{
  "slug": "high_value_purchase",
  "name": "High Value Purchase",
  "description": "Triggered when customer completes a purchase over $500",
  "eventDataSchema": {
    "type": "object",
    "properties": {
      "orderId": { "type": "string" },
      "totalAmount": { "type": "number" },
      "currency": { "type": "string" }
    },
    "required": ["orderId", "totalAmount"]
  }
}

Parameters ​

ParameterTypeRequiredDescription
slugstringYesUnique identifier (lowercase, ^[a-z][a-z0-9_]*$, 2–50 chars)
namestringYesHuman-readable name (min 2 chars)
descriptionstringNoDescription of when this trigger fires
eventDataSchemaobjectNoJSON Schema for validating event data

Response (201 Created) ​

json
{
  "slug": "high_value_purchase",
  "name": "High Value Purchase",
  "description": "Triggered when customer completes a purchase over $500",
  "category": "custom",
  "isBuiltIn": false,
  "isScheduled": false,
  "eventDataSchema": {
    "type": "object",
    "properties": {
      "orderId": { "type": "string" },
      "totalAmount": { "type": "number" }
    }
  }
}

Delete Trigger ​

DELETE /sequences/triggers/{slug}

Remove a custom trigger type. Built-in triggers cannot be deleted.

Cannot Delete In-Use Triggers

You cannot delete a trigger that is currently used by any active sequences. Pause or archive those sequences first.

Response (200 OK) ​

json
{
  "success": true,
  "message": "Trigger deleted successfully"
}

Error Response (400 Bad Request) ​

json
{
  "error": "Cannot delete trigger \"high_value_purchase\" - used by 2 active sequence(s)"
}

Enroll Customer ​

POST /sequences/enroll

Enroll a customer directly in all sequences matching a given trigger type. This is equivalent to firing an event via POST /sequences/events but uses a simpler request format that specifies the trigger type explicitly rather than inferring it from the event.

Request ​

json
{
  "customerMobile": "+919876543210",
  "triggerType": "abandoned_cart",
  "customerId": "cust_12345",
  "orderId": "order_abc123",
  "eventData": {
    "cartId": "cart_xyz789",
    "totalAmount": 129.99
  }
}

Parameters ​

ParameterTypeRequiredDescription
customerMobilestringYesE.164 phone number
triggerTypestringYesTrigger type slug to match sequences against
customerIdstringNoInternal customer ID
orderIdstringNoAssociated order ID
eventDataobjectNoData passed to message templates

Response (200 OK) ​

json
{
  "success": true,
  "enrollments": [
    {
      "sequenceId": "seq_cart_recovery_001",
      "sequenceName": "Cart Recovery",
      "enrollmentId": "enr_abc123def456"
    }
  ]
}

Response (400 Bad Request — Opted Out) ​

json
{
  "success": false,
  "error": "Customer has opted out of marketing messages"
}

Error Codes ​

HTTP StatusError CodeDescription
400ValidationErrorInvalid request body or parameters
401UnauthorizedMissing or invalid API key
404NotFoundTrigger not found
400EnrollmentErrorCannot enroll customer (e.g., opted out)
503ServiceUnavailableUtility service not configured

Integration Examples ​

E-commerce: Abandoned Cart Recovery ​

javascript
// After a user abandons their cart
async function onCartAbandoned(cartData) {
  const response = await fetch('https://api.talkingshops.com/v1/sequences/events', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'x-tenant-api-key': process.env.TALKINGSHOPS_API_KEY
    },
    body: JSON.stringify({
      eventType: 'abandoned_cart',
      customerMobile: cartData.mobile,
      customerId: cartData.customerId,
      // Stable across retries: the same abandoned cart always gives the same key.
      deduplicationKey: `cart:${cartData.cartId}:${cartData.updatedAt}`,
      eventData: {
        cartId: cartData.cartId,
        items: cartData.items,
        totalAmount: cartData.total,
        currency: cartData.currency,
        checkoutUrl: cartData.checkoutUrl
      }
    })
  });

  const result = await response.json();
  console.log(`Enrolled in ${result.enrollments?.length ?? 0} sequences`);
}

E-commerce: Order Completion ​

javascript
async function onOrderCompleted(orderData) {
  const response = await fetch('https://api.talkingshops.com/v1/sequences/events', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'x-tenant-api-key': process.env.TALKINGSHOPS_API_KEY
    },
    body: JSON.stringify({
      eventType: 'order_completed',
      customerMobile: orderData.mobile,
      customerId: orderData.customerId,
      deduplicationKey: `order:${orderData.orderId}`,
      eventData: {
        orderId: orderData.orderId,
        items: orderData.items,
        totalAmount: orderData.total,
        currency: orderData.currency
      }
    })
  });

  return response.json();
}

CRM: Lead Form Submission ​

javascript
async function onLeadFormSubmitted(leadData) {
  const response = await fetch('https://api.talkingshops.com/v1/sequences/enroll', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'x-tenant-api-key': process.env.TALKINGSHOPS_API_KEY
    },
    body: JSON.stringify({
      customerMobile: leadData.mobile,
      triggerType: 'lead_form_completed',
      customerId: leadData.customerId,
      eventData: {
        formId: leadData.formId,
        source: leadData.source,
        interests: leadData.interests
      }
    })
  });

  return response.json();
}

Custom Integration: Custom Event ​

javascript
// If you have a custom trigger "high_value_purchase" created via the dashboard
async function onHighValuePurchase(purchaseData) {
  const response = await fetch('https://api.talkingshops.com/v1/sequences/events', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'x-tenant-api-key': process.env.TALKINGSHOPS_API_KEY
    },
    body: JSON.stringify({
      eventType: 'high_value_purchase',
      customerMobile: purchaseData.mobile,
      customerId: purchaseData.customerId,
      deduplicationKey: `purchase:${purchaseData.orderId}`,
      eventData: {
        orderId: purchaseData.orderId,
        totalAmount: purchaseData.total,
        currency: purchaseData.currency,
        items: purchaseData.items
      }
    })
  });

  return response.json();
}

Talking Shops product guides and API reference