Flow, blocks, relations
| Thing | Where | What it is |
|---|---|---|
| Flow | /ai-flows | The chatbot: name, system (persona, shown as System prompt), flowDesign (knowledge, shown as User's prompt), keywords, status and assignment settings. |
| Block | /ai-flows/{id}/blocks | A 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}/relations | An 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
blockType | What it does | Type-specific fields |
|---|---|---|
sequential | Sends message, waits time/timeUnit, continues. | — |
textNode | Like sequential, and can wait for the customer's reply. | waitForReply, replyTime, replyTimeUnit |
questionNode | Asks for and stores the dataFields. | dataFields[], questionAskOneAtATime, no-reply and irrelevant-reply retry settings |
assignLeadNode | Assigns the lead to team members. | selectedMembers[], roundRobin, overrideAssignment |
labelNode | Applies labels to the lead. | labels[] |
stopFlowNode | Ends the sequence. | — |
telegramNotificationNode / whatsappNotificationNode | Notifies 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 blockType | Outputs (sourceHandleId) | Default |
|---|---|---|
sequential, telegramNotificationNode, whatsappNotificationNode | SEQUENTIAL — after the message or notification | SEQUENTIAL |
questionNode | SEQUENTIAL — after all data is collected · NO_REPLY — no-reply follow-up · IRRELEVANT — irrelevant retries exhausted | SEQUENTIAL |
textNode | SEQUENCE — immediately after sending · REPLIED — path after reply · NO_REPLY — path after timeout | REPLIED |
assignLeadNode, labelNode, stopFlowNode | none — 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:
Rules the API enforces
- One entry point. Exactly one block per flow may have
orderId: 0. A second one returns409with 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 is400. blockTypeis 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
GET /ai-flows/{id}/blocks?sort=orderId:ascandGET /ai-flows/{id}/relationsto see what is there.- Change copy or timings with
PATCH /ai-flows/{id}/blocks/{blockId}. - Re-route by deleting a relation and creating another; relations have no update.
- 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.