Contracts
Drift Platform API Contracts
Table of Contents
- Core Philosophy
- Runtime API (
WorkflowResource) - Definition API (
WorkflowDefinitionResource) - Node Definition API (
NodeDefinitionResource) - Widgetized Response Model
- Client Responsibilities
- Versioning Semantics
1. Core Philosophy
Note to Adopters: The philosophy described below reflects the guiding principles established by the original developers of Drift to ensure strict separation of concerns. All design decisions and contract structures in this document are influenced by this mindset. However, this does not restrict new users or contributors from experimenting with different patterns or extending the platform to suit their own architectural needs.
Drift as Action Orchestrator and Data Provider
The Drift system operates on a fundamental principle of separation of concerns between the backend (Drift) and frontend clients. Drift serves as an Action Orchestrator and Data Provider, explicitly avoiding decisions related to presentation, design, or user experience.
What Drift Provides
| Responsibility | Description |
|---|---|
| Action Orchestration | Triggers downstream actions (fetching data, processing logic) and aggregates results |
| Data Provisioning | Delivers data in a structured, uniform format (widgets) across all clients |
| Widget Structure | Defines canonical widget structure including static components and possible values |
| Script Augmentation | Provides mechanism to augment possible values with contextual instructions via Groovy |
What Drift Does NOT Control
| Limitation | Description |
|---|---|
| Design/Layout | How data is visually presented |
| Grouping/Hierarchy | How multiple widgets are organized (cards, tabs, pages) |
| Visibility | When or where specific widgets appear |
| Rendering Logic | Code that displays data on screen |
Key Principle: “Drift provides the data; you (the client) decide how to show it. Drift is not the UI controller; it is the data pipe.”
2. Runtime API (WorkflowResource)
This resource exposes runtime workflow APIs that clients call to drive workflows. It handles starting, resuming, inspecting, and terminating running workflows, returning widgetized views for user interaction.
Base Path
/v3
Required Headers
| Header | Required | Description |
|---|---|---|
X_TENANT_ID |
Yes | Tenant identifier (e.g., DEFAULT_TENANT) |
X_CLIENT_ID |
Yes | Client/channel identifier (e.g., web, mobile) |
X_USERNAME_ID |
No | User identity (defaults to X_CLIENT_ID if absent) |
2.1 Start Workflow
Endpoint: POST /v3/workflow/start
Initiates a new workflow execution.
Request Body
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class WorkflowStartRequest extends WorkflowRequest {
@NotNull private IssueDetail issueDetail; // Identification of the issue/intent
private QueueDetail queueDetail; // Optional queue routing info
@NotNull private Customer customer; // Customer context
@NotNull private Set<OrderDetail> orderDetails; // Domain-specific context (e.g., Orders)
private Map<String, Object> config; // Optional config for worker/platform
}
// Base class
public abstract class WorkflowRequest {
private String incidentId; // Populated by Drift
private String workflowId; // Populated by Drift
private String parentWorkflowId; // Populated when invoked via CHILD node
private Map<String, String> threadContext;
private Map<String, Object> params;
}
Sample Request
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"issueDetail": {
"issueId": "6332",
"issueName": "Refund"
},
"customer": {
"customerId": "CUST_12345"
},
"orderDetails": [
{
"orderId": "OD_998877"
}
],
"params": {
"channel": "WEB",
"userLocale": "en_US"
}
}
Response Body
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class WorkflowResponse implements Serializable {
private String incidentId;
private String workflowId;
private WorkflowStatus workflowStatus;
private String disposition;
private String errorMessage;
private View view; // The Widgetized Response
}
public enum WorkflowStatus {
CREATED,
RUNNING,
WAITING,
COMPLETED,
FAILED,
TERMINATED,
DELEGATED,
SCHEDULER_WAITING,
ASYNC_COMPLETE
}
Sample Response (WAITING State)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
{
"incidentId": "INC_20240414_001",
"workflowId": "WF_REFUND_INC_20240414_001",
"workflowStatus": "WAITING",
"view": {
"layoutId": "refund_options_screen",
"inputOptions": [
{
"id": "refund_method_select",
"description": "Select refund method",
"tags": { "values": ["ui.dropdown"] },
"instructions": [
{
"templateId": "select_refund_method_msg",
"templateVariables": {}
}
],
"possibleValues": [
{ "displayValue": "Original Payment Mode", "value": "SOURCE" },
{ "displayValue": "Wallet", "value": "WALLET" }
]
},
{
"id": "proceed_btn",
"tags": { "values": ["ui.button"] },
"possibleValues": [{ "value": "PROCEED" }]
}
]
}
}
2.2 Resume Workflow
Endpoint: PUT /v3/workflow/resume/{workflowId}
Continues a workflow that is in WAITING state by providing user selections.
Request Body
1
2
3
4
5
6
7
public class WorkflowResumeRequest extends WorkflowRequest {
@NotNull private ViewResponse viewResponse;
}
public class ViewResponse {
Map<String, Object> selectedOptions; // Map of Widget ID -> Selected Value
}
Sample Request
1
2
3
4
5
6
7
8
{
"viewResponse": {
"selectedOptions": {
"refund_method_select": "WALLET",
"proceed_btn": "PROCEED"
}
}
}
2.3 Terminate Workflow
Endpoint: DELETE /v3/workflow/terminate/{workflowId}
Terminates a running workflow.
2.4 Get Workflow State
Endpoint: GET /v3/workflow/{workflowId}
Retrieves the current state of a workflow (debugging/admin).
2.5 Disconnected Nodes & Utility Executions
Endpoint: POST /v3/workflow/{workflowId}/disconnected-node/execute
Disconnected nodes are nodes defined within the workflow definition but are not part of the main execution path (i.e., no other node points to them via nextNode). They are used for utility operations that do not advance the workflow state.
Use Case: A common scenario is performing repetitive validations or intermediate actions without moving the workflow forward. For example, in a bank account addition flow:
- Verify: The user might try to verify a bank account multiple times (invalid account, wrong IFSC, etc.). This verification is handled by a disconnected “verify_account” node.
- No State Change: Hitting this node executes the logic (e.g., API call to bank) and returns the result but keeps the workflow in its current state (e.g., waiting at the “Add Account” screen).
- Resume: Once verification is successful, the client calls the standard
resumeendpoint to move the workflow to the next step (e.g., “submit_account”).
Request Body
1
2
3
4
public class WorkflowUtilityRequest extends WorkflowRequest {
@NotNull private String node; // The name of the disconnected node to execute
private Map<String, Object> parameters; // Parameters specific to this execution
}
Response Body
1
2
3
4
5
6
public class WorkflowUtilityResponse implements Serializable {
private String workflowId;
private String node;
private WorkflowUtilityStatus status; // e.g., COMPLETED, FAILED
private Object response; // The output of the executed node
}
5. Widgetized Response Model
The widgetized response is how Drift expresses “what the user needs to see and choose” without dictating UI implementation.
5.1 Model Hierarchy
1
2
3
4
5
6
7
8
9
10
11
12
WorkflowResponse
└── View
├── layoutId (String)
└── inputOptions (List<Option>)
└── Option (The Widget)
├── id (String)
├── parentId (String)
├── description (String)
├── tags (Tag)
├── instructions (List<Instruction>)
├── possibleValues (List<PossibleValue>)
└── possibleDependentValues (Map<String, Option>)
5.2 Core Models
View
Container for the screen/state.
1
2
3
4
public class View {
private String layoutId; // Hint for client layout lookup
private List<Option> inputOptions; // List of widgets
}
Option (The Widget)
Represents a single interaction element (dropdown, button, text field).
1
2
3
4
5
6
7
8
public class Option {
private String id; // Unique ID (key for response)
private String parentId; // For hierarchical widgets
private Tag tags; // Rendering hints (e.g., "ui.dropdown")
private List<PossibleValue> possibleValues; // Selectable options
private Map<String, Option> possibleDependentValues; // Cascading options
private List<Instruction> instructions; // Static text content
}
PossibleValue
A selectable choice within a widget.
1
2
3
4
5
public class PossibleValue {
private String displayValue; // Text to show user
private String value; // Token to send back to Drift
private JsonNode metaData; // Extra data (images, subtitles)
}
Tag
Hints for the client renderer.
1
2
3
public class Tag {
private List<String> values; // e.g., ["ui.dropdown", "ui.required"]
}
5.3 Common Tag Vocabulary
| Tag Value | Intended UI Component |
|---|---|
ui.static_text |
Label / Text block |
ui.dropdown |
Select / Dropdown menu |
ui.button |
Action button |
ui.free_text |
Text input / Text area |
ui.date_picker |
Calendar control |
ui.complete |
Completion banner |
5.4 Hierarchical Widgets (Dependent Values)
For cascading selections (e.g., City -> Locality):
- Parent Widget: Defines
possibleValues(Cities). - Child Logic: Uses
possibleDependentValuesmap.- Key: Value of selected parent option.
- Value: Child
Optiondefinition specific to that parent selection.
6. Client Responsibilities
Drift supports both human-driven and machine-driven workflows. The responsibilities of the client differ based on the integration mode.
6.1 Integration Modes
1. User-Interactive (Human-in-the-loop)
When the workflow is intended for a human user (e.g., a Customer Support Agent), the client must implement a UI renderer. The client interprets the View response to generate the interface, allowing the user to read instructions and make selections.
2. Systematic Integration (Context-Aware Caller) When the caller is another system or service (e.g., a chatbot backend or an automated job), no UI rendering is required.
- The caller is “context-aware”—it knows which workflow it is running and what data is expected next.
- The
view/widgetssection of the response can be ignored. - The client programmatically constructs the
resumerequest based on its own internal logic.
6.2 UI Rendering (For User-Interactive Mode)
Clients must implement a renderer that:
- Reads
View.layoutIdto determine screen structure. - Iterates
inputOptions. - Maps
tags.valuesto native UI components (React component, Android View, etc.). - Displays
possibleValuesas choices.
6.3 Resume Logic
When interacting with widgets:
- Collect user input for each widget
id. - Construct
ViewResponse:1 2 3 4 5 6
{ "selectedOptions": { "widget_id_1": "selected_value_token", "widget_id_2": "entered_text" } }
- Call
PUT /v3/workflow/resume/{id}.
6.4 Template Interpolation
Instruction objects contain templateId and variables. Clients should look up localized strings from their CMS/ResourceBundle and interpolate the variables before display.