Workflows
Flows are e-services the persona runs in conversation. Design them on a canvas in the console; Servly asks for each input, validates it and hands the result to your systems.
Node types
Step- One screen of the service: an introduction spoken by the persona, then ordered inputs. Inputs can be grouped into a short form.
Condition- Routes to different steps based on earlier answers, using and/or rule groups with operators such as equals, not equals, contains, greater than, less than and is empty.
API call- Calls your system with the answers collected so far and maps the response into variables.
End- Completes the service.
Prompts and labels can be written in Arabic, English or both; a flow's language is ar, en or bilingual. A flow is a draft until you activate it. When you generate media, the persona's intro, prompt and confirmation clips are rendered in its own voice.
Inputs
Each input has an internal field name, a label, an optional placeholder and the prompt the persona speaks to ask for it. Input types:
textnumberemailphonedatechoicecomponentotp
Validation rules
Attach any number of rules to an input. Each rule can carry its own error message in Arabic and English, so people hear exactly what to fix. There are 34 rule types:
General
required | Must have a value |
email | Valid email address |
phone | Valid phone number |
min_length | At least N characters |
max_length | At most N characters |
min_value | Number of at least N |
max_value | Number of at most N |
pattern | Matches a regular expression |
equals | Equals a value |
not_equals | Doesn't equal a value |
contains | Contains text |
not_contains | Doesn't contain text |
starts_with | Starts with text |
ends_with | Ends with text |
numeric | A number |
integer | A whole number |
alpha | Letters only |
alphanumeric | Letters and numbers only |
url | Valid URL |
Dates (DD/MM/YYYY)
past_date | A date in the past |
future_date | A date in the future, for example an expiry |
min_age | At least N years old |
National IDs
emirates_id | UAE Emirates ID, 15 digits (784-YYYY-NNNNNNN-C) |
saudi_id | Saudi national ID or Iqama, 10 digits starting with 1 or 2 |
qatar_id | Qatar ID (QID), 11 digits |
bahrain_cpr | Bahrain CPR, 9 digits |
oman_id | Oman civil ID, 8 digits |
kuwait_id | Kuwait civil ID, 12 digits |
Phone numbers
uae_phone | UAE (+971) |
saudi_phone | Saudi Arabia (+966) |
qatar_phone | Qatar (+974) |
bahrain_phone | Bahrain (+973) |
oman_phone | Oman (+968) |
kuwait_phone | Kuwait (+965) |
One-time passcodes
An otp input verifies that the person controls a phone number or email address. Codes are 6 digits, expire after 5 minutes, allow 5 attempts and work once. Sends are limited to 5 per identifier and 100 per tenant in any 10 minutes; over the limit, the API returns 429 with a Retry-After header.
curl -X POST "https://avatar-api.syntiva.tech/otp/send" \
-H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
-d '{"identifier": "+971501234567"}'
curl -X POST "https://avatar-api.syntiva.tech/otp/verify" \
-H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
-d '{"identifier": "+971501234567", "code": "482913"}'API call nodes
methodstringGET,POST,PUT,PATCHorDELETE.urlstring- The endpoint to call.
headerskey/value[]- Values can use template variables such as
{{step_1.field_name}}. body, body_typestring- A templated body sent as
json,formortext. response_mappingsobject[]- JSON paths in the response saved as variables for later steps.
variable_namestring- Results are available as
apiCall_{variable_name}. continue_on_errorboolean- Keep going if the call fails, instead of stopping the flow.
timeout_msnumber- Optional timeout in milliseconds.
Webhooks
When a submission completes or is abandoned, Servly POSTs it to the submission's webhook URL. Set the URL when you create a submission with POST /flows/{id}/submissions. It must use HTTPS and can't point at private or internal network addresses.
{
"event": "flow.completed",
"flow_id": "flw_7c2e…",
"flow_name": "Renew trade licence",
"submission_id": "sub_91ab…",
"session_id": "4f0d…",
"completed_at": "2026-10-04T10:42:17.000Z",
"data": {
"step_1": { "licence_number": "CN-1234567" },
"step_2": { "emirates_id": "784-1990-1234567-1", "mobile": "+971501234567" }
}
}X-Webhook-Eventheaderflow.completedorflow.abandoned.X-Submission-IDheader- The submission's ID.
dataobject- Collected answers, keyed by step and then by field name.
Retriespolicy- Up to 3 retries with backoff; each attempt times out after 30 seconds. The response is stored on the submission.
How the persona runs a flow
- It matches the request to a flow by name and trigger keywords, with Arabic spelling normalized.
- It offers the service and waits for a yes. A bare “no” never cancels a service in progress.
- It asks for each input, validates the answer, and asks again with the error message if it doesn't pass.
- If someone asks a side question, it answers and then repeats the current step's prompt.
- On completion it sends the webhook; if the person stops, the submission is recorded as abandoned.
Analytics
Every flow, step, input, validation failure, retry and API call is tracked. In the console you get an overview, a per-step funnel (entries, completions, average time), per-input statistics, peak hours and trends, and you can export the data as CSV or JSON.