Core concepts
Workflows
Reusable validation circuits: models, steps, clients, and transactions. Each company is isolated.
Clients
A client is the counterparty the circuit is launched for — not a contacts-book entry. Required fields on create: name (last name), firstname, cni_number, phone, email (unique per company), motif_demande.
POST /api/clients/create always inserts. POST /api/clients/ensure is idempotent on email: existing → 200 { created: false, client: { id } }; new → 201 { created: true, client: { id } }. Company admins can bulk-import up to 1000 rows on POST /api/clients/import (existing emails are skipped).
Models and steps
POST /api/workflows/models/create—name,descriptionoptional,signature_leveloptional (simpleoradvanced)POST /api/workflows/models/{model}/steps/create—name,type(unidirectionnelorconditionnel),users[],roles[]optional,actions[]optional, for example[{ "libelle": "Signer", "action": "sign" }]POST .../steps/configs/create— saves the graph and finalizes the model. Unidirectional steps neednext_step_id. Conditional steps needyes_next_step_idandno_next_step_id
Too many finalized models → 403 MODEL_LIMIT_REACHED with limit / used. Changing signature_level on a completed model is company-admin only. After a workflow is launched, client_id / model_id cannot change (409 WORKFLOW_STRUCTURE_LOCKED).
Running a workflow
- POST /api/workflows/create — multipart: name, model_id, optional client_id / description, and files[] (PDFs, max 10 MB each)
- An actor calls
GET /api/workflows/transactions/{transaction}/take(403 STEP_NOT_CANDIDATE if they are not assigned) - Then POST /api/workflows/transactions/step/process
{
"transaction_id": 44,
"actions": [{ "action": "validate" }],
"condition": "yes"
}actions is an array (not a single action string). It may be sent as a JSON string on multipart. Status moves pending → in_progress → completed / cancelled.
Other outcomes: .../process/cancelled (motif_refus), .../return and .../return-to-initiator (motif_retour), then POST /api/workflows/{workflow}/relaunch with new files[].
Step actions
| Action | Payload |
|---|---|
validate | Approve the step. No data required. |
sign | Also send JSON strings signers_data and signature_params (zones per file_id). Optional signature_appearance PNG data-URL. signature_level is frozen on the instance. |
stamp | Place via data.documents[].pages[].elements (type: stamp). Image comes from the user’s stored stamp or multipart imgStamp. |
qr_code | QR content is the document URL (the element value is ignored). |
text / date / initials | elements[].type plus value, position, size |
{
"documents": [
{
"file_id": 123,
"pages": [
{
"page": 1,
"elements": [
{
"type": "text",
"value": "Approved",
"position": { "x": 10, "y": 20 },
"size": { "width": 100, "height": 20 }
}
]
}
]
}
]
}LDAP
Company admins configure the directory on PUT /api/companies/{company}/ldap/save (ldap_host, ldap_base_dn, bind credentials, ldap_role_mode = default or ad_groups). Bind password is never returned. Map AD groups with PUT .../ldap/role-mappings.
- Import creates or updates users from AD and never disables missing accounts.
202— poll.../import/latest - Sync updates existing LDAP users and disables those gone from AD (it never deletes rows). Poll
.../sync/latest
Job status: pending → processing → completed / failed, plus stats and error. Targeted variants accept emails[] (import, 1–100) or user_ids[] (sync, 1–100).