Skip to content

Flows

View as Markdown

Start your flow-builder automations for a customer.

Flows are the conversations you build in the flow builder: questions, buttons, waits, conditions, hand-overs to your team. The API starts them from your systems and tells you how they end, so an event in your store or CRM can open a real conversation.

How it works: Flows & automationsMake a flow startable · Start a flow for a customer · Follow a run · WhatsApp Flows (forms)

Make a flow startable#

In the flow builder, give the flow the API / webhook trigger and publish it. GET /flows?startable_via_api=true then lists it with startable_via_api: true. A draft, or a flow with another trigger (a keyword, a new conversation…), answers flow_not_triggerable.

Start a flow for a customer#

POST /flows/{id}/runs:

JSON
{
  "to": "+966501234567",
  "variables": { "order_id": "10482", "delivery_date": "الخميس" },
  "reference": "order-10482"
}
  • variables become the run's starting variables: the flow reads them as {{order_id}}, next to what it already knows about the contact (name, custom fields).
  • reference is your own id. It comes back on the run and in every flow.run.* event.
  • The flow's first message follows WhatsApp's rules: outside the 24-hour window it must be an approved template, so start flows meant for cold contacts with a template step.

The run starts at once; the answer shows where it stands (often waiting_input, waiting for the customer's reply).

Follow a run#

GET /flow_runs/{id} shows the run's state and the variables it has collected so far: answers, button choices, values from your systems. GET /flows/{id}/runs lists a flow's runs, by state or customer.

EventWhen
flow.run.startedA run began (from the API, a trigger or the inbox)
flow.run.handed_offThe flow passed the customer to your team
flow.run.completedThe run reached its end; variables holds everything it collected
flow.run.expiredThe flow stopped waiting for a customer who did not answer in time

A typical integration: start a delivery-feedback flow from your order system, and on flow.run.completed save the rating from variables against the order found by reference.

WhatsApp Flows (forms)#

WhatsApp Flows are forms that open inside the chat: a booking, a sign-up, a survey. Each submission arrives as a flow.response event with the customer's answers, and GET /flow_responses lists them, by form (whatsapp_flow_id) or date.

Endpoints

List WhatsApp Flow form responses

gethttps://api.saei.automize.sa/v1/flow_responses
  • Scope: flows:read
  • Live keys only

Answers customers submitted in WhatsApp Flows (the forms that open inside the chat), newest first. Each new one also arrives as a flow.response event.

Query parameters

  • limitintegeroptional

    How many objects to return, 1 to 100.

  • cursorstringoptional

    The next_cursor from the previous page.

  • whatsapp_flow_idstringoptional

    Only responses to this WhatsApp Flow (Meta's flow id).

  • sincestringoptional
Response fields200
  • object"list"required
  • dataarray<FlowResponse>required
    Child fields (10)
    • idstringrequired
    • object"flow_response"required
    • whatsapp_flow_idstring | nulloptional
    • flow_namestring | nulloptional
    • customerobjectoptional
      Child fields (2)
      • contact_idstring | nulloptional
      • addressstring | nulloptional
    • campaign_idstring | nulloptional
    • template_idstring | nulloptional
    • answersobjectrequired

      The form's fields and what the customer entered, by the field names set in the WhatsApp Flow.

    • file_countintegeroptional
    • submitted_atstring | nulloptional
  • has_morebooleanrequired
  • next_cursorstring | nullrequired
Errors this can return3
Try it
curl -X GET https://api.saei.automize.sa/v1/flow_responses \
  -H "Authorization: Bearer $API_KEY"
Response

A page of responses.

{
  "object": "list",
  "data": [
    {
      "id": "fres_77",
      "object": "flow_response",
      "whatsapp_flow_id": "string",
      "flow_name": "string",
      "customer": {
        "contact_id": "string",
        "address": "string"
      },
      "campaign_id": "string",
      "template_id": "string",
      "answers": {},
      "file_count": 0,
      "submitted_at": "2026-10-01T09:30:00Z"
    }
  ],
  "has_more": false,
  "next_cursor": "string"
}

Get a flow run

gethttps://api.saei.automize.sa/v1/flow_runs/{id}
  • Scope: flows:read
  • Live keys only

Where one customer is in a flow, and the variables the flow has collected so far (answers, choices, values from your systems).

Path parameters

  • idstringrequired

    The object's id.

Response fields200
  • idstringrequired
  • object"flow_run"required
  • flow_idstringrequired
  • customerobjectoptional
    Child fields (2)
    • contact_idstring | nulloptional
    • addressstring | nulloptional
  • channelstringoptional
  • statestringrequired

    waiting_input waits for the customer; paused waits for a delay step; handed_off passed to your team; expired gave up waiting.

    One ofactivewaiting_inputpausedhanded_offcompletedexpired

  • current_stepstring | nulloptional
  • referencestring | nulloptional
  • variablesobjectoptional
  • started_atstring | nulloptional
  • completed_atstring | nulloptional
  • updated_atstring | nulloptional
Errors this can return3
Try it
curl -X GET https://api.saei.automize.sa/v1/flow_runs/id_123 \
  -H "Authorization: Bearer $API_KEY"
Response

The run.

{
  "id": "run_9021",
  "object": "flow_run",
  "flow_id": "string",
  "customer": {
    "contact_id": "string",
    "address": "string"
  },
  "channel": "string",
  "state": "active",
  "current_step": "string",
  "reference": "string",
  "variables": {},
  "started_at": "2026-10-01T09:30:00Z",
  "completed_at": "2026-10-01T09:30:00Z",
  "updated_at": "2026-10-01T09:30:00Z"
}

List flows

gethttps://api.saei.automize.sa/v1/flows
  • Scope: flows:read
  • Works in test mode

The automation flows built in the flow builder. startable_via_api marks the published flows with an "API / webhook" trigger, which POST /v1/flows/{id}/runs can start for a customer.

Query parameters

  • limitintegeroptional

    How many objects to return, 1 to 100.

  • cursorstringoptional

    The next_cursor from the previous page.

  • statusstringoptional

    One ofdraftpublishedarchived

  • startable_via_apibooleanoptional

    true for only the flows you can start through the API.

Response fields200
  • object"list"required
  • dataarray<Flow>required
    Child fields (11)
    • idstringrequired
    • object"flow"required
    • namestringrequired
    • descriptionstring | nulloptional
    • statusstringrequired

      One ofdraftpublishedarchived

    • triggerstring | nulloptional

      What starts the flow, e.g. webhook, keyword, inbound-message, contact-added.

    • startable_via_apibooleanrequired
    • number_idstring | nulloptional
    • published_atstring | nulloptional
    • created_atstring | nulloptional
    • updated_atstring | nulloptional
  • has_morebooleanrequired
  • next_cursorstring | nullrequired
Errors this can return2
Try it
curl -X GET https://api.saei.automize.sa/v1/flows \
  -H "Authorization: Bearer $API_KEY"
Response

A page of flows.

{
  "object": "list",
  "data": [
    {
      "id": "flow_18",
      "object": "flow",
      "name": "string",
      "description": "string",
      "status": "draft",
      "trigger": "string",
      "startable_via_api": false,
      "number_id": "string",
      "published_at": "2026-10-01T09:30:00Z",
      "created_at": "2026-10-01T09:30:00Z",
      "updated_at": "2026-10-01T09:30:00Z"
    }
  ],
  "has_more": false,
  "next_cursor": "string"
}

Get a flow

gethttps://api.saei.automize.sa/v1/flows/{id}
  • Scope: flows:read
  • Works in test mode

Path parameters

  • idstringrequired

    The object's id.

Response fields200
  • idstringrequired
  • object"flow"required
  • namestringrequired
  • descriptionstring | nulloptional
  • statusstringrequired

    One ofdraftpublishedarchived

  • triggerstring | nulloptional

    What starts the flow, e.g. webhook, keyword, inbound-message, contact-added.

  • startable_via_apibooleanrequired
  • number_idstring | nulloptional
  • published_atstring | nulloptional
  • created_atstring | nulloptional
  • updated_atstring | nulloptional
Errors this can return2
Try it
curl -X GET https://api.saei.automize.sa/v1/flows/flow_18 \
  -H "Authorization: Bearer $API_KEY"
Response

The flow.

{
  "id": "flow_18",
  "object": "flow",
  "name": "متابعة بعد الشراء",
  "description": "يسأل العميل عن تجربته بعد 3 أيام من التسليم",
  "status": "published",
  "trigger": "webhook",
  "startable_via_api": true,
  "number_id": "num_3",
  "published_at": "2026-09-01T08:00:00Z",
  "created_at": "2026-08-28T12:00:00Z",
  "updated_at": "2026-09-01T08:00:00Z"
}

List a flow's runs

gethttps://api.saei.automize.sa/v1/flows/{id}/runs
  • Scope: flows:read
  • Live keys only

Path parameters

  • idstringrequired

    The object's id.

Query parameters

  • limitintegeroptional

    How many objects to return, 1 to 100.

  • cursorstringoptional

    The next_cursor from the previous page.

  • statestringoptional

    One ofactivewaiting_inputpausedhanded_offcompletedexpired

  • tostringoptional

    Only this customer's runs (phone, any format).

Response fields200
  • object"list"required
  • dataarray<FlowRun>required
    Child fields (12)
    • idstringrequired
    • object"flow_run"required
    • flow_idstringrequired
    • customerobjectoptional
      Child fields (2)
      • contact_idstring | nulloptional
      • addressstring | nulloptional
    • channelstringoptional
    • statestringrequired

      waiting_input waits for the customer; paused waits for a delay step; handed_off passed to your team; expired gave up waiting.

      One ofactivewaiting_inputpausedhanded_offcompletedexpired

    • current_stepstring | nulloptional
    • referencestring | nulloptional
    • variablesobjectoptional
    • started_atstring | nulloptional
    • completed_atstring | nulloptional
    • updated_atstring | nulloptional
  • has_morebooleanrequired
  • next_cursorstring | nullrequired
Errors this can return4
Try it
curl -X GET https://api.saei.automize.sa/v1/flows/flow_18/runs \
  -H "Authorization: Bearer $API_KEY"
Response

A page of runs.

{
  "object": "list",
  "data": [
    {
      "id": "run_9021",
      "object": "flow_run",
      "flow_id": "string",
      "customer": {
        "contact_id": "string",
        "address": "string"
      },
      "channel": "string",
      "state": "active",
      "current_step": "string",
      "reference": "string",
      "variables": {},
      "started_at": "2026-10-01T09:30:00Z",
      "completed_at": "2026-10-01T09:30:00Z",
      "updated_at": "2026-10-01T09:30:00Z"
    }
  ],
  "has_more": false,
  "next_cursor": "string"
}

Start a flow for a customer

posthttps://api.saei.automize.sa/v1/flows/{id}/runs
  • Scope: flows:trigger
  • Live keys only
  • Accepts Idempotency-Key

Runs the flow for one customer now, exactly as its "API / webhook" trigger would: the same steps, messages, waits and hand-offs. variables become the run's starting variables (the flow reads them as {{name}}), next to what it already knows about the contact. The customer comes from to only: contact_id, contact_phone, phone, phone_number, customer and keys starting with _ are reserved and refused. reference is your own id, returned on the run and in every flow.run.* event.

The flow must be published with the "API / webhook" trigger (startable_via_api: true). Its first message follows WhatsApp's rules: outside the 24-hour window that means an approved template.

Path parameters

  • idstringrequired

    The object's id.

Headers

  • Idempotency-Keystringoptional

    Any unique string (a UUID is ideal). Retrying with the same key and body returns the first response instead of acting twice. Remembered for 24 hours.

Request body

  • tostringrequired

    The customer's phone, in any format.

  • variablesobjectoptional
  • referencestringoptional
Response fields201
  • idstringrequired
  • object"flow_run"required
  • flow_idstringrequired
  • customerobjectoptional
    Child fields (2)
    • contact_idstring | nulloptional
    • addressstring | nulloptional
  • channelstringoptional
  • statestringrequired

    waiting_input waits for the customer; paused waits for a delay step; handed_off passed to your team; expired gave up waiting.

    One ofactivewaiting_inputpausedhanded_offcompletedexpired

  • current_stepstring | nulloptional
  • referencestring | nulloptional
  • variablesobjectoptional
  • started_atstring | nulloptional
  • completed_atstring | nulloptional
  • updated_atstring | nulloptional
Errors this can return6
Try it
curl -X POST https://api.saei.automize.sa/v1/flows/flow_18/runs \
  -H "Authorization: Bearer $API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "to": "+966501234567",
  "variables": {
    "order_id": "10482",
    "delivery_date": "الخميس"
  },
  "reference": "order-10482"
}'
Response

The run, already under way.

{
  "id": "run_9021",
  "object": "flow_run",
  "flow_id": "flow_18",
  "customer": {
    "contact_id": "ct_1052",
    "address": "+966501234567"
  },
  "channel": "whatsapp",
  "state": "waiting_input",
  "current_step": "node_ask_rating",
  "reference": "order-10482",
  "variables": {
    "order_id": "10482",
    "delivery_date": "الخميس",
    "first_name": "سارة",
    "reference": "order-10482"
  },
  "started_at": "2026-10-01T10:00:00Z",
  "completed_at": null,
  "updated_at": "2026-10-01T10:00:01Z"
}