Documentation menu

Developer API

Building AI flow sequences

An AI flow is a WhatsApp chatbot: a persona, some knowledge, trigger keywords, and an optional follow-up sequence drawn as blocks on the Sequences Design canvas. This guide builds one entirely through the API.

Flow, blocks, relations

ThingWhereWhat it is
Flow/ai-flowsThe chatbot: name, system (persona, shown as System prompt), flowDesign (knowledge, shown as User's prompt), keywords, status and assignment settings.
Block/ai-flows/{id}/blocksA node on the canvas: a message to send, a question to ask, a hand-over, a stop. Has a blockType, a position, and one block per flow has orderId: 0 — the entry point.
Relation/ai-flows/{id}/relationsAn edge from one block's output handle to another block.

The complete field list for each is in the ai-flows resource reference. Writes need the ai-flows:write scope.

1. Create the flow

curl -X POST https://api2.djcsystem.com/v1/ai-flows -H "Authorization: Bearer $DJC_TOKEN" -H "Content-Type: application/json" -d '{
  "name": "Consultation booking",
  "keywords": ["consult"],
  "system": "You are Aiden, our sales consultant. Qualify the customer and secure an appointment. Never say you are an AI.",
  "flowDesign": "Business hours Mon–Fri 9am–6pm (Asia/Kuala_Lumpur). Consultations are 30 minutes via WhatsApp video or at our KL office."
}'
# → 201 { "success": true, "data": { "id": "FLOW_ID", "name": "Consultation booking", "status": "active", … } }

Keep system to the persona and rules, and put facts in flowDesign — the app shows and edits them separately.

2. Add blocks

blockTypeWhat it doesType-specific fields
sequentialSends message, waits time/timeUnit, continues.—
textNodeLike sequential, and can wait for the customer's reply.waitForReply, replyTime, replyTimeUnit
questionNodeAsks for and stores the dataFields.dataFields[], questionAskOneAtATime, no-reply and irrelevant-reply retry settings
assignLeadNodeAssigns the lead to team members.selectedMembers[], roundRobin, overrideAssignment
labelNodeApplies labels to the lead.labels[]
stopFlowNodeEnds the sequence.—
telegramNotificationNode / whatsappNotificationNodeNotifies your team.whatsappNotificationPhones[], whatsappNotificationAssignedUsers
B=https://api2.djcsystem.com/v1/ai-flows/$FLOW/blocks

# The first block: orderId 0 marks where the sequence starts
curl -X POST $B -H "Authorization: Bearer $DJC_TOKEN" -H "Content-Type: application/json" -d '{ "name": "Welcome", "blockType": "sequential", "orderId": 0,
  "position": { "x": 80, "y": 200 }, "message": "Hi {{name}}, thanks for reaching out!" }'

curl -X POST $B -H "Authorization: Bearer $DJC_TOKEN" -H "Content-Type: application/json" -d '{ "name": "Qualify", "blockType": "questionNode", "position": { "x": 460, "y": 200 },
  "message": "What budget and timeline do you have in mind?",
  "dataFields": [{ "name": "budget" }, { "name": "timeline" }], "questionAskOneAtATime": true }'

curl -X POST $B -H "Authorization: Bearer $DJC_TOKEN" -H "Content-Type: application/json" -d '{ "name": "Follow-up (1 day)", "blockType": "textNode", "position": { "x": 840, "y": 200 },
  "message": "Would Tue 11am or Thu 3pm suit you?", "time": 1, "timeUnit": "days",
  "waitForReply": true, "replyTime": 2, "replyTimeUnit": "days" }'

curl -X POST $B -H "Authorization: Bearer $DJC_TOKEN" -H "Content-Type: application/json" -d '{ "name": "Assign to sales", "blockType": "assignLeadNode", "position": { "x": 1220, "y": 200 }, "roundRobin": true }'
curl -X POST $B -H "Authorization: Bearer $DJC_TOKEN" -H "Content-Type: application/json" -d '{ "name": "No reply — stop", "blockType": "stopFlowNode", "position": { "x": 1220, "y": 520 } }'

position is in canvas pixels. Blocks are about 330 px wide, so x = 80 + n × 380 lays a row out neatly; put branches on a second row around y + 320.

Poll, catalog and template nodes

Poll nodes, Meta catalog nodes and WhatsApp Business template nodes need setup that only the app can do, so the API does not create them. Everything else on the palette is available.

3. Connect them — handles

A relation leaves a block through one of its output handles, the coloured dots on the canvas. Each block type has its own set, and the API only accepts asourceHandleId that exists on the source block's type — otherwise the canvas could not draw the edge.

Source blockTypeOutputs (sourceHandleId)Default
sequential, telegramNotificationNode, whatsappNotificationNodeSEQUENTIAL — after the message or notificationSEQUENTIAL
questionNodeSEQUENTIAL — after all data is collected · NO_REPLY — no-reply follow-up · IRRELEVANT — irrelevant retries exhaustedSEQUENTIAL
textNodeSEQUENCE — immediately after sending · REPLIED — path after reply · NO_REPLY — path after timeoutREPLIED
assignLeadNode, labelNode, stopFlowNodenone — these end a branch—
R=https://api2.djcsystem.com/v1/ai-flows/$FLOW/relations

curl -X POST $R -H "Authorization: Bearer $DJC_TOKEN" -H "Content-Type: application/json" -d '{ "sourceNodeId": "$WELCOME", "targetNodeId": "$QUALIFY" }'                              # SEQUENTIAL (default)
curl -X POST $R -H "Authorization: Bearer $DJC_TOKEN" -H "Content-Type: application/json" -d '{ "sourceNodeId": "$QUALIFY", "targetNodeId": "$NUDGE" }'                                # SEQUENTIAL = data collected
curl -X POST $R -H "Authorization: Bearer $DJC_TOKEN" -H "Content-Type: application/json" -d '{ "sourceNodeId": "$NUDGE",   "targetNodeId": "$ASSIGN", "sourceHandleId": "REPLIED" }'
curl -X POST $R -H "Authorization: Bearer $DJC_TOKEN" -H "Content-Type: application/json" -d '{ "sourceNodeId": "$NUDGE",   "targetNodeId": "$STOP",   "sourceHandleId": "NO_REPLY" }'

Omit sourceHandleId to use the default. A wrong handle is rejected and the response tells you what is allowed:

HTTP/1.1 400 Bad Request
{
  "success": false,
  "error": "\"textNode\" blocks have no \"SEQUENTIAL\" output.",
  "code": "BAD_REQUEST",
  "details": {
    "sourceBlockType": "textNode",
    "allowedHandles": { "SEQUENCE": "immediately after sending", "REPLIED": "path after reply", "NO_REPLY": "path after timeout (no reply)" },
    "default": "REPLIED"
  }
}

Worked example

The calls above produce this on the canvas:

Welcome FIRST ──SEQUENTIAL──▶ Qualify ──SEQUENTIAL──▶ Follow-up (1 day)
├─REPLIED──▶ Assign to sales
└─NO_REPLY─▶ No reply — stop

Rules the API enforces

  • One entry point. Exactly one block per flow may have orderId: 0. A second one returns 409 with the existing block's id.
  • Handles must exist on the source block's type, and terminal blocks cannot be a source (400).
  • No duplicates, no self-loops. The same source, target and handle twice is 409; a block connecting to itself is 400.
  • blockType is fixed after creation. Delete and recreate to change it.
  • Deleting a block also deletes its relations and removes it from the other blocks' outgoing lists, so the canvas never shows dangling edges.

Editing an existing sequence

  1. GET /ai-flows/{id}/blocks?sort=orderId:asc and GET /ai-flows/{id}/relations to see what is there.
  2. Change copy or timings with PATCH /ai-flows/{id}/blocks/{blockId}.
  3. Re-route by deleting a relation and creating another; relations have no update.
  4. Refresh the Sequences Design page in the app to see the result. Changes made in the app and through the API are the same records.