> ## Documentation Index
> Fetch the complete documentation index at: https://docs.didit.me/llms.txt
> Use this file to discover all available pages before exploring further.

# Crear flux de treball per API: construir flux KYC

> Crea un flux de treball de Didit amb funcionalitats ordenades per API: KYC, KYB, AML i biometria. Pagament per crida, sense contractes.



Prompt de l'API per crear fluxos de treball
        Copia el prompt al porta-retalls



      
      

\<pre>

\`Create a simple Didit workflow through the Management API.

Endpoint:
POST https://verification.didit.me/v3/workflows/

Authentication:
Use the x-api-key header with my Didit API key.

Requirements:
\- Use the simple v3 API shape with features.
\- Send features in the exact order users should complete them.
\- Do not send workflow_graph, branches, actions, webhooks, or conditional logic.
\- Didit will convert the features array into a linear node-based workflow and add the final status step automatically.
\- Use uppercase feature values such as OCR, LIVENESS, FACE_MATCH, AML, QUESTIONNAIRE, EMAIL_VERIFICATION, PHONE_VERIFICATION, or PROOF_OF_ADDRESS.
\- Configure each feature with the fields from /management-api/workflows/feature-configs.
\- For an OCR feature, omit config.documents_allowed or send an empty object to allow every supported document type. Send config.documents_allowed only to restrict the allowed documents.
\- Put dependency features first. For example, put OCR before FACE_MATCH, NFC, DATABASE_VALIDATION, or user AML checks that depend on document data.
\- For a QUESTIONNAIRE feature, first create the questionnaire with POST /v3/questionnaires/ and use the returned questionnaire_id as config.questionnaire_uuid.
\- Store the workflow uuid returned by the response. Use it as workflow_id when creating sessions and as settings_uuid when updating this workflow.

Example KYC request body:
\{
"workflow_label": "Standard KYC",
"features": [
\{
  "feature": "OCR",
  "config": {
    "documents_allowed": {
      "USA": {
        "DL": {
          "enabled": 1,
          "sides": 2
        }
      }
    },
    "duplicated_user_action": "REVIEW"
  }
},
\{
  "feature": "LIVENESS",
  "config": {
    "face_liveness_method": "PASSIVE"
  }
},
\{
  "feature": "FACE_MATCH"
}
]
}

Example questionnaire workflow body:
\{
"workflow_label": "Source of Funds",
"features": [
\{
  "feature": "QUESTIONNAIRE",
  "config": {
    "questionnaire_uuid": "11111111-2222-3333-4444-555555555555",
    "review_questionnaire_manually": true
  }
}
]
}

Build the API call, handle validation errors, and return the workflow uuid from the response.`

\</pre>



      
      

Enganxa a

Fes servir aquest endpoint per crear fluxos de treball a través de l'API sense haver de construir tu mateix els nodes del graf. Envia un array `features` en l'ordre en què els usuaris han de completar les comprovacions. Didit el converteix internament en un flux de treball basat en nodes i afegeix automàticament el pas final d'estat.Aquest endpoint `POST /v3/workflows/` només crea fluxos de treball **simples i lineals**, amb una llista plana `features`. Per a **enrutament condicional, ramificacions, Document AI i nodes de rebuig o de decisió**, fes servir el [format de graf de nodes](#branques-i-fluxos-de-treball-basats-en-nodes-graf) que es documenta a continuació (és el que alimenta el constructor visual de la consola i les eines de flux de treball del [MCP de Didit](https://docs.didit.me/ca/integration/mcp/overview.md)).Consulta [Configuració de les funcionalitats del flux de treball](https://docs.didit.me/ca/management-api/workflows/feature-configs.md) per a cada camp `config` que accepta cada funcionalitat.## Flux de treball de KYC bàsic```json theme={null}
{
  "workflow_label": "Standard KYC",
  "features": [
    {
      "feature": "OCR",
      "config": {
        "documents_allowed": {
          "USA": {
            "DL": {
              "enabled": 1,
              "sides": 2
            }
          }
        },
        "duplicated_user_action": "REVIEW"
      }
    },
    {
      "feature": "LIVENESS",
      "config": {
        "face_liveness_method": "PASSIVE"
      }
    },
    {
      "feature": "FACE_MATCH"
    }
  ]
}
```## Flux de treball de qüestionariPrimer crea el qüestionari amb `POST /v3/questionnaires/`. Després fes servir el `questionnaire_id` retornat com a `questionnaire_uuid`.```json theme={null}
{
  "workflow_label": "Source of Funds",
  "features": [
    {
      "feature": "QUESTIONNAIRE",
      "config": {
        "questionnaire_uuid": "11111111-2222-3333-4444-555555555555",
        "review_questionnaire_manually": true
      }
    }
  ]
}
```L'ordre de les funcionalitats importa. Per exemple, posa `OCR` abans de `FACE_MATCH`, `NFC`, `DATABASE_VALIDATION` o de les comprovacions AML de l'usuari que depenen de les dades del document.## Referència de configuració de les funcionalitatsCada element de `features[]` té aquesta estructura:```json theme={null}
{
  "feature": "OCR",
  "label": "ID Verification",
  "config": {}
}
```L'objecte `config` exacte depèn de la funcionalitat. Revisa la llista completa de camps, els valors per defecte, la configuració obligatòria, els intervals de valors i els exemples a [Configuració de les funcionalitats del flux de treball](https://docs.didit.me/ca/management-api/workflows/feature-configs.md).Per a `OCR`, omet `config.documents_allowed`, envia `null` o envia `{}` per permetre tots els tipus de document compatibles. Inclou-lo només si vols restringir el flux de treball a països o tipus de document concrets. Per a `QUESTIONNAIRE`, `config.questionnaire_uuid` és obligatori.## Configuració opcional del flux de treballPots incloure qualsevol d'aquests camps de nivell superior en crear un flux de treball per controlar el comportament de la sessió. Tots són opcionals i, si s'ommeten, es fan servir els valors per defecte del flux de treball.| Camp | Tipus | Descripció |
| - | - | - |
| `is_white_label_enabled` | booleà | Activa la personalització en marca blanca per a les sessions creades amb aquest flux de treball. Per defecte `false`. |
| `is_desktop_allowed` | booleà | Permet que el flux de verificació s'executi en navegadors d'escriptori. Per defecte `false`. |
| `max_retry_attempts` | enter (0–10) | Nombre màxim de reintents permesos després d'una verificació rebutjada. `0` bloqueja l'usuari després del primer rebuig. Per defecte `3`. |
| `retry_window_days` | enter (1–365) o `null` | Finestra mòbil en dies usada per comptar els reintents (`null` = límit total sense restricció temporal). Per defecte `7`. |
| `session_expiration_time` | enter (3600–2419200) | Segons abans que caduqui una sessió no finalitzada. Mínim 1 hora, màxim 4 setmanes. Per defecte `604800` (7 dies). |
| `response_attributes` | objecte o `null` | Limita els camps retornats per a cada funcionalitat, per exemple `{"id_verifications": ["full_name", "document_number"], "face_matches": null}`. Si és `null` o falta la clau, es retornen tots els camps. Una llista buida retorna només `status`, `warnings`, `node_id`, `is_nfc_skipped` i `skip_reason`, i la resta de camps es retornen com a `null`. |```json theme={null}
{
  "workflow_label": "Standard KYC",
  "is_white_label_enabled": true,
  "is_desktop_allowed": true,
  "max_retry_attempts": 5,
  "retry_window_days": 14,
  "session_expiration_time": 86400,
  "features": [
    { "feature": "OCR" },
    { "feature": "LIVENESS" },
    { "feature": "FACE_MATCH" }
  ]
}
```## Branques i fluxos de treball basats en nodes (graf)Una llista lineal `features` no pot expressar "si X, aleshores Y". Per a la **branca condicional** (rebutjar segons un estat, encaminar segons un camp extret o condicionar un pas a una coincidència), un pas de sol·licitud de **Document AI** o els nodes terminals de **rebuig/decisió**, els fluxos de Didit fan servir un **graf de nodes**, la mateixa estructura que produeix el constructor visual de la consola.> [!NOTE]
>
> La manera més senzilla de crear un flux de treball de graf és el **[MCP de Didit](https://docs.didit.me/ca/integration/mcp/overview.md)**: demana a un agent en llenguatge natural ("després de la verificació d'identitat, si la professió és ≈ 'Software Engineer', afegeix un pas de comprovant de fons") i ell construirà, validarà i desarà el graf per tu. L'estructura que hi ha a continuació és la que produeixen aquestes eines (i la consola).### Estructura del grafUn graf és `{ start_node, nodes }`. `nodes` és un mapa d'id de node a node. Les arestes són implícites: cada node apunta cap endavant mitjançant `next` (incondicional) i/o `branches[].goto` (condicional).| Tipus de node | Estructura |
| - | - |
| `feature` | `{ "node_type": "feature", "feature": "OCR", "config": {…}, "next": "<id>", "branches": [] }` |
| `branch` | `{ "node_type": "branch", "branches": [ { "id", "logic": "and"\|"or", "rules": [<rule>], "goto": "<id>" } ], "next": "<fallback id>" }` |
| `status` (terminal) | `{ "node_type": "status", "session_status": "Approved"\|"Declined"\|"In Review"\|"Determine" }` |
| `action` | `{ "node_type": "action", "actions": [ { "type": "add_tag"\|"add_review"\|… } ], "next": "<id>" }` |
| `webhook` | `{ "node_type": "webhook", "config": { "url", "method" }, "branches": [], "next": "<id>" }` |`start_node` ha de ser un node de tipus feature. Les branques s'avaluen en ordre, **guanya la primera que coincideixi**; un `rules: []` buit és la branca general "else" (manté-la al final). `session_status: "Determine"` decideix automàticament a partir dels resultats combinats de les funcionalitats.> [!WARNING]
>
> **Tots els nodes de branca han de tenir una branca else explícita**: una branca amb `rules: []` que encamini les sessions que no coincideixin amb cap de les condicions. No confiïs en el `next` del node de branca com a alternativa: un `next` per si sol es mostra com una aresta ambigua al constructor i és fàcil d'ometre. Quan envies un node de branca amb `next` i sense branca else, l'API **converteix aquest `next` en una branca else explícita** per a tu (així, `{ …, "branches": [<conditions>], "next": "liveness" }` es desa com a `branches: [<conditions>, { "id": "else", "rules": [], "goto": "liveness" }]`). Crea tu la branca else per ser explícit; la conversió és una xarxa de seguretat, no un substitut.### Regles de branca i operadorsCada regla compara un **camp** amb un **valor** mitjançant un **operador**:```json theme={null}
{ "field": "kyc.extra_fields.profession", "operator": "fuzzy_match", "value": "Software Engineer", "score": 80 }
```- **Camps:** nomenen un resultat de funcionalitat (`kyc.status`, `aml.status`, `document_ai.status`, `face_match.score`, …) o un valor extret (`kyc.full_name`, `kyc.age`, `kyc.nationality`, `kyc.extra_fields.profession`, un camp de Document AI `document_ai.<key>`, `expected_details.*`). Una branca només pot llegir un camp la funcionalitat del qual s'hagi executat en tots els camins que hi arriben.
- **Operadors:** `equals`, `not_equals`, `greater_than(_or_equals)`, `less_than(_or_equals)`, `contains`, `not_contains`, `in`, `not_in`, `is_empty`, `is_not_empty`, `regex` i **`fuzzy_match`** (només per a camps de text; requereix un `score` de 0 a 100, un llindar de similitud, per exemple, professió amb una similitud ≥ 80 % amb "Software Engineer").### Branca segons per què no s'ha executat NFCDesprés d'un node `NFC`, fes servir `nfc.skip_reason` amb `equals` o `in` per encaminar les sessions segons el motiu pel qual no s'ha llegit el xip. El camp té aquests set valors estables:- `USER_SKIPPED`
- `DOCUMENT_WITHOUT_CHIP`
- `CHIP_CERTIFICATE_UNAVAILABLE`
- `DEVICE_WITHOUT_NFC`
- `INTEGRATION_WITHOUT_NFC_ACCESS`
- `MRZ_KEY_UNAVAILABLE`
- `JPKI_UNAVAILABLE`Consulta [Motius d'omissió de NFC](https://docs.didit.me/ca/core-technology/nfc-verification/warnings-nfc-verification.md#motius-d’omissió) per saber què significa cada valor. Quan NFC es completa correctament, `nfc.skip_reason` és `null`, de manera que ni una regla `equals` ni una `in` per a un motiu d'omissió coincideixen.El camp també es resol per als nodes NFC **omesos per una porta de control**. Això inclou els casos en què no existeix cap informe ni advertència de NFC, i els casos en què `allow_nfc_skip` és `false` però la porta del document o del dispositiu impedeix que NFC s'executi. Per tant, pots encaminar aquestes sessions sense dependre d'una entrada de `nfc_verifications[]`.> [!NOTE]
>
> Les sessions desades abans que la capacitat NFC passés a tenir tres estats poden tenir `has_device_nfc_support: false`. Una sessió web antiga pot, per tant, resoldre's com a `DEVICE_WITHOUT_NFC` en lloc de `INTEGRATION_WITHOUT_NFC_ACCESS`.Aquest graf fa servir `equals` per a una omissió per part de l'usuari, `in` per a omissions per porta de control o per capacitat, i una branca else explícita per a NFC correcte. La branca va després del node `NFC`, i tots els destins apunten cap endavant, a nodes terminals:```json theme={null}
{
  "start_node": "ocr",
  "nodes": {
    "ocr": {
      "node_type": "feature",
      "feature": "OCR",
      "next": "nfc"
    },
    "nfc": {
      "node_type": "feature",
      "feature": "NFC",
      "config": { "allow_nfc_skip": false },
      "next": "route_nfc"
    },
    "route_nfc": {
      "node_type": "branch",
      "branches": [
        {
          "id": "user_skipped",
          "logic": "and",
          "rules": [
            { "field": "nfc.skip_reason", "operator": "equals", "value": "USER_SKIPPED" }
          ],
          "goto": "manual_review"
        },
        {
          "id": "nfc_unavailable",
          "logic": "and",
          "rules": [
            {
              "field": "nfc.skip_reason",
              "operator": "in",
              "value": [
                "DOCUMENT_WITHOUT_CHIP",
                "CHIP_CERTIFICATE_UNAVAILABLE",
                "DEVICE_WITHOUT_NFC",
                "INTEGRATION_WITHOUT_NFC_ACCESS",
                "MRZ_KEY_UNAVAILABLE",
                "JPKI_UNAVAILABLE"
              ]
            }
          ],
          "goto": "manual_review"
        },
        {
          "id": "else",
          "logic": "and",
          "rules": [],
          "goto": "approved"
        }
      ]
    },
    "manual_review": { "node_type": "status", "session_status": "In Review" },
    "approved": { "node_type": "status", "session_status": "Approved" }
  }
}
```Per expressar "NFC no s'ha realitzat per cap motiu conegut", fes servir `in` amb **els set** valors. Mantén una branca else explícita per a NFC correcte (`nfc.skip_reason: null`) i per a qualsevol valor futur que el teu graf encara no reconegui.### Document AI (per exemple, comprovant de fons)Un node de funcionalitat `DOCUMENT_AI` sol·licita un o diversos documents i extreu camps amb nom:```json theme={null}
{
  "node_type": "feature",
  "feature": "DOCUMENT_AI",
  "label": "Proof of Funds",
  "config": {
    "document_ai_documents": [
      {
        "document_key": "proof_of_funds",
        "title": "Proof of Funds",
        "description": "Upload a recent bank statement.",
        "fields": [
          {
            "key": "account_holder",
            "name": "Account holder",
            "instruction": "The full name of the account holder as printed on the statement.",
            "type": "text",
            "required": true,
            "is_full_name": true
          },
          {
            "key": "closing_balance",
            "name": "Closing balance",
            "instruction": "The closing balance amount.",
            "type": "number",
            "required": true
          }
        ]
      }
    ],
    "document_ai_missing_required_fields_action": "REVIEW",
    "document_ai_name_mismatch_action": "REVIEW"
  },
  "next": "final_decision"
}
```Cada camp configurat es converteix en un valor `document_ai.<key>` que es pot utilitzar en una branca, i el resultat del pas és `document_ai.status`.Estableix `"is_full_name": true` al camp que conté el nom complet del titular del document. El seu valor extret es compara amb el nom complet de la identitat verificada (el nom obtingut per OCR o en la verificació d'identitat, o les dades esperades de la sessió), i `document_ai_name_mismatch_action` decideix què passa en cas de discrepància per sota de `document_ai_name_match_score_threshold`. La marca és **opcional**: un document pot no marcar cap camp, però **com a màxim un camp per document** pot activar-la. Consulta [Configuracions de funcionalitats del flux de treball → Document AI](https://docs.didit.me/ca/management-api/workflows/feature-configs.md#document-ai) per veure tots els camps de configuració de Document AI.### Endpoints i cicle de vida de l'esborranyL'edició del graf es fa per aplicació i utilitza els endpoints de la consola i de gestió (Bearer d'usuari + `read:workflows`/`write:workflows`). Un graf només es pot editar en una versió **esborrany**, així que el cicle de vida és **crear esborrany → definir graf → publicar**:| Mètode | Ruta | Finalitat |
| - | - | - |
| `GET` | `…/verification-settings/{settings_uuid}/workflow-graph/` | Graf actual + `status`/`is_editable` |
| `POST` | `…/application/{app}/workflow-graph/validate/` (body `{ "graph": … }`) | Validació en sec |
| `GET` | `…/application/{app}/workflow-graph/field-definitions/` | Camps que es poden ramificar + operadors vàlids |
| `POST` | `…/verification-settings/{settings_uuid}/create-draft/` | Esborrany editable a partir d'una versió publicada |
| `PUT` | `…/verification-settings/{settings_uuid}/workflow-graph/` (body `{ "graph": … }`) | Desa el graf |
| `PATCH` | `…/verification-settings/{settings_uuid}/` (body `{ "status": "published" }`) | Publica l'esborrany |#### Advertències de validacióL'endpoint de validació respon amb `{ "is_valid": true, "graph": …, "warnings": [] }`. Una advertència és **orientativa**: el graf és vàlid, es desa i es publica amb advertències. Cada entrada indica el node de branca i el braç al qual fa referència, perquè el creador del flux pugui assenyalar la condició exacta:```json theme={null}
{
  "type": "branch_outcome_contradiction",
  "node_id": "after_ocr",
  "branch_id": "b1",
  "severity": "warning",
  "message": "Branch 1 only matches sessions where ID Verification Status is Approved or In Review, but every path from it ends in the session outcome \"Declined\". Check the condition or the outcome.",
  "params": { "branchNumber": 1, "field": "ID Verification Status", "allowed": "Approved or In Review", "outcome": "Declined" }
}
```| `type` | Què significa |
| - | - |
| `branch_outcome_contradiction` | La condició del braç i el resultat al qual arriba qualsevol camí des d'aquest braç es contradiuen entre si; per exemple, `kyc.status NOT EQUALS Declined` encaminat a un resultat `Declined`. El resultat pot trobar-se diversos passos més avall del camí. |
| `branch_condition_unreachable` | El braç no pot coincidir mai, perquè tots els camins que arriben a aquesta branca ja limiten aquest camp d'estat a valors que la condició exclou. |
| `else_branch_unreachable` | El braç else no s'executa mai: els altres braços ja cobreixen tots els valors que pot tenir el camp en aquest punt. |Un graf no vàlid respon amb `400` i amb `errors` **i** una llista de `warnings` tan completa com sigui possible. Només `errors` bloquegen un desament.### Exemple pràctic: dirigeix els enginyers de programari cap al comprovant de fons> Després de la verificació d'identitat: si ha estat **rebutjada**, rebutja la sessió; si la **professió del titular ≈ "Software Engineer"** (≥80% de similitud), sol·licita un document de **comprovant de fons**; després pren una decisió final.```json theme={null}
{
  "start_node": "ocr_1",
  "nodes": {
    "ocr_1": { "node_type": "feature", "feature": "OCR", "label": "ID Verification", "next": "after_ocr" },
    "after_ocr": {
      "node_type": "branch",
      "label": "Route after ID verification",
      "branches": [
        { "id": "declined", "logic": "or", "rules": [ { "field": "kyc.status", "operator": "equals", "value": "Declined" } ], "goto": "decline" },
        { "id": "software_engineer", "logic": "and", "rules": [ { "field": "kyc.extra_fields.profession", "operator": "fuzzy_match", "value": "Software Engineer", "score": 80 } ], "goto": "proof_of_funds" },
        { "id": "else", "logic": "and", "rules": [], "goto": "final_decision" }
      ]
    },
    "proof_of_funds": {
      "node_type": "feature",
      "feature": "DOCUMENT_AI",
      "label": "Proof of Funds",
      "config": {
        "document_ai_documents": [
          { "document_key": "proof_of_funds", "title": "Proof of Funds", "description": "Upload a recent bank statement.",
            "fields": [
              { "key": "account_holder", "name": "Account holder", "type": "text", "required": true },
              { "key": "closing_balance", "name": "Closing balance", "type": "number", "required": true }
            ] }
        ],
        "document_ai_missing_required_fields_action": "REVIEW"
      },
      "next": "final_decision"
    },
    "final_decision": { "node_type": "status", "session_status": "Determine", "label": "Final decision" },
    "decline": { "node_type": "status", "session_status": "Declined", "label": "Declined" }
  }
}
```El node final usa `session_status: "Determine"`, que **decideix automàticament** (aprovar / rebutjar / en revisió) a partir de les funcionalitats que s'hagin executat realment a la sessió. Així, tant el camí del comprovant de fons com el camí else es resolen correctament sense cap branca que llegeixi `document_ai.status` (que no existeix en el camí que omet Document AI). Recorda: una branca només pot llegir un camp la funcionalitat del qual s'hagi executat en *tots* els camins que hi arriben.Envia'l com a `{ "graph": <above> }` a l'endpoint `…/workflow-graph/` (valida-ho primer). Per crear un flux **nou** des de zero, usa `didit_workflow_set_graph` del MCP; per modificar un flux **existent**, usa `didit_workflow_edit_graph` (operacions petites, conserva els nodes existents i les llistes de permesos). Consulta [Didit MCP](https://docs.didit.me/ca/integration/mcp/tools.md).


## OpenAPI

````yaml ca/openapi-25.json POST /v3/workflows/
openapi: 3.0.0
info:
  version: 3.0.0
  title: Didit Verification API
  description: API de verificació d'identitat. Autentica't amb la capçalera x-api-key.
servers:
  - url: https://verification.didit.me
security: []
tags: []
paths:
  /v3/workflows/:
    post:
      tags:
        - Workflows
      summary: Crea un flux de treball
      description: >-
        Crea un flux de treball simple. Envia `features` en ordre d'execució
        (s'apliquen regles d'ordenació); el valor per defecte és `published` v1.
        El cos NOMÉS accepta els camps llistats a `SimpleWorkflowRequest`;
        qualsevol altra clau (incloent-hi `workflow_type`) es rebutja amb un
        400. No és idempotent: cada crida crea un nou flux de treball. Màxim de
        50 fluxos de treball per aplicació.
      operationId: create_workflow
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SimpleWorkflowRequest'
            examples:
              Simple KYC:
                summary: >-
                  Flux de treball lineal de verificació d'identitat, prova de
                  vida i coincidència facial
                value:
                  workflow_label: Standard KYC
                  features:
                    - feature: OCR
                      config:
                        duplicated_user_action: review
                    - feature: LIVENESS
                      config:
                        face_liveness_method: passive
                    - feature: FACE_MATCH
                      config:
                        face_match_score_decline_threshold: 40
                        face_match_score_review_threshold: 60
              KYC + AML:
                summary: Executa el cribratge AML després de la verificació d'identitat
                value:
                  workflow_label: KYC with AML
                  features:
                    - feature: OCR
                    - feature: AML
                      config:
                        aml_score_review_threshold: 70
                        aml_score_approve_threshold: 30
              Questionnaire workflow:
                summary: Executa un qüestionari creat amb POST /v3/questionnaires/
                value:
                  workflow_label: Source of Funds
                  features:
                    - feature: QUESTIONNAIRE
                      config:
                        questionnaire_uuid: 11111111-2222-3333-4444-555555555555
                        review_questionnaire_manually: true
      responses:
        '201':
          description: >-
            Flux de treball creat. El cos de la resposta és la configuració
            COMPLETA del flux de treball (la mateixa serialització sense
            processar de `VerificationSettings` que retorna `GET
            /v3/workflows/{settings_uuid}/`, ~190 camps: cada commutador de
            funcionalitat, llindar, acció i el `workflow_graph` generat), no
            l'element de llista compacte. Guarda l'`uuid` (també exposat com a
            `workflow_id`) per poder fer-hi referència en futures crides de
            creació de sessions. Nota: `features` és una cadena unida per `" +
            "` i els preus són números JSON.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkflowDetail'
              examples:
                Created (abbreviated):
                  summary: Camps clau de l'objecte de configuració complet
                  value:
                    uuid: c3d4e5f6-7890-12cd-ef34-333333333333
                    workflow_id: c3d4e5f6-7890-12cd-ef34-333333333333
                    workflow_label: Standard KYC
                    workflow_type: null
                    is_default: false
                    is_archived: false
                    total_price: 0.15
                    min_price: 0.15
                    max_price: 0.15
                    features: OCR + LIVENESS + FACE_MATCH
                    is_simple_workflow: false
                    is_editable: false
                    workflow_url: https://verify.didit.me/u/w9TkPOx8RWG3UAz5ZRQGVQ
                    workflow_graph:
                      start_node: ocr
                      nodes: ... one node per feature plus a final status node ...
                    max_retry_attempts: 3
                    retry_window_days: 7
                    session_expiration_time: 604800
                    version: 1
                    status: published
                    published_at: '2026-05-17T10:30:00Z'
                    created_at: '2026-05-17T10:30:00Z'
                    updated_at: '2026-05-17T10:30:00Z'
        '400':
          description: >-
            Error de validació. Causes habituals: una clau de nivell superior
            fora de la llista blanca admesa (p. ex., `workflow_type`), un valor
            de `feature` desconegut, una funcionalitat col·locada abans de la
            seva dependència (p. ex., `FACE_MATCH` abans d'`OCR`), una
            funcionalitat passiva (`AML`, `IP_ANALYSIS`, `DATABASE_VALIDATION`,
            `KYB_KEY_PEOPLE`) utilitzada com a primer pas, una funcionalitat
            `QUESTIONNAIRE` el `config.questionnaire_uuid` de la qual no
            existeix per a aquesta aplicació, una funcionalitat `SIGNATURE` que
            es publicaria sense cap document per signar, una funcionalitat
            `SIGNATURE` amb `signature_level: "aes"` quan Advanced (AES) no està
            disponible (`aes_not_available`, consulta `signature_availability`
            al flux de treball) o un llindar fora de rang. El cos és un objecte
            d'error de validació de DRF; les claus són noms de camps i els
            valors són arrays de missatges llegibles per humans.
          content:
            application/json:
              examples:
                Advanced (AES) not available:
                  value:
                    features:
                      signature_level:
                        - >-
                          Node 'signature': Advanced (AES) is not available yet
                          (aes_not_available).
                Signature step with no document:
                  value:
                    features:
                      non_field_errors:
                        - >-
                          Node 'signature': Add a document to sign, or let each
                          session bring its own.
                Missing feature:
                  value:
                    features:
                      - At least one feature is required.
                Unknown top-level field:
                  value:
                    workflow_type:
                      - >-
                        The v3 workflow API only accepts `workflow_label`,
                        `is_default`, `status`, `features`,
                        `is_white_label_enabled`, `is_desktop_allowed`,
                        `max_retry_attempts`, `retry_window_days`,
                        `session_expiration_time`, `face_liveness_max_attempts`,
                        `face_match_max_attempts`.
                Unknown feature:
                  value:
                    features:
                      - >-
                        Invalid feature 'FOO'. Allowed values: AGE_ESTIMATION,
                        AML, DATABASE_VALIDATION, EMAIL_VERIFICATION,
                        FACE_MATCH, IP_ANALYSIS, KYB_DOCUMENTS, KYB_KEY_PEOPLE,
                        KYB_REGISTRY, LIVENESS, NFC, OCR, PHONE_VERIFICATION,
                        PROOF_OF_ADDRESS, QUESTIONNAIRE.
                Ordering:
                  value:
                    features:
                      - 'Feature ''FACE_MATCH'' must appear after one of: OCR.'
                Questionnaire not found:
                  value:
                    features: >-
                      Questionnaire '11111111-2222-3333-4444-555555555555' was
                      not found for this application. Create the questionnaire
                      first, then use its questionnaire_id.
        '403':
          description: >-
            Falta la clau d'API, està mal formada, ha caducat o està restringida
            a una aplicació diferent. Actualitza-la mitjançant l'[Auth
            API](/ca/auth-api/get-credentials) i torna-ho a provar.
          content:
            application/json:
              examples:
                Invalid token:
                  value:
                    detail: You do not have permission to perform this action.
        '415':
          description: >-
            Tipus de mitjà no admès. Defineix `Content-Type: application/json` i
            envia un cos JSON.
        '429':
          description: >-
            S'ha superat el límit de freqüència. Reintenta amb un retrocés
            exponencial.
        '500':
          description: >-
            Error inesperat del servidor en crear el flux de treball. Es pot
            reintentar amb seguretat.
      security:
        - ApiKeyAuth: []
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X POST 'https://verification.didit.me/v3/workflows/' \
              -H 'x-api-key: YOUR_API_KEY' \
              -H 'Content-Type: application/json' \
              -d '{
                "workflow_label": "Standard KYC",
                "features": [
                  {"feature": "OCR"},
                  {"feature": "LIVENESS", "config": {"face_liveness_method": "passive"}},
                  {"feature": "FACE_MATCH", "config": {"face_match_score_decline_threshold": 40, "face_match_score_review_threshold": 60}}
                ]
              }'
        - lang: python
          label: Python
          source: |-
            from didit import Didit

            # Reads DIDIT_API_KEY.
            client = Didit()

            result = client.workflows.create(
                workflow_label="Standard KYC",
                features=[{
                    "feature": "OCR",
                    "config": {"duplicated_user_action": "review"},
                }, {
                    "feature": "LIVENESS",
                    "config": {"face_liveness_method": "passive"},
                }, {
                    "feature": "FACE_MATCH",
                    "config": {"face_match_score_decline_threshold": 40, "face_match_score_review_threshold": 60},
                }],
            )
            print(result)
        - lang: javascript
          label: Node.js
          source: |-
            import Didit from "@didit-protocol/sdk-node";

            // Reads DIDIT_API_KEY.
            const didit = new Didit();

            const result = await didit.workflows.create({
              workflow_label: "Standard KYC",
              features: [{
                feature: "OCR",
                config: { duplicated_user_action: "review" },
              }, {
                feature: "LIVENESS",
                config: { face_liveness_method: "passive" },
              }, {
                feature: "FACE_MATCH",
                config: { face_match_score_decline_threshold: 40, face_match_score_review_threshold: 60 },
              }],
            });
            console.log(result);
        - lang: go
          label: Go
          source: "ctx := context.Background()\n// Reads DIDIT_API_KEY.\nclient := didit.NewClient()\n\nresult, err := client.Workflows.Create(ctx, didit.SimpleWorkflowRequest{\n\tWorkflowLabel: didit.String(\"Standard KYC\"),\n\tFeatures: []didit.SimpleWorkflowFeature{{\n\t\tFeature: \"OCR\",\n\t\tConfig:  didit.Some(map[string]any{\"duplicated_user_action\": \"review\"}),\n\t}, {\n\t\tFeature: \"LIVENESS\",\n\t\tConfig:  didit.Some(map[string]any{\"face_liveness_method\": \"passive\"}),\n\t}, {\n\t\tFeature: \"FACE_MATCH\",\n\t\tConfig:  didit.Some(map[string]any{\"face_match_score_decline_threshold\": 40, \"face_match_score_review_threshold\": 60}),\n\t}},\n})\nif err != nil {\n\tlog.Fatal(err)\n}\nfmt.Printf(\"%+v\\n\", result)"
        - lang: java
          label: Java
          source: >-
            import java.util.List;

            import java.util.Map;

            import me.didit.Didit;

            import me.didit.types.SimpleWorkflowFeature;

            import me.didit.types.SimpleWorkflowRequest;


            // Reads DIDIT_API_KEY.

            Didit client = new Didit();


            var result =
            client.workflows().create(SimpleWorkflowRequest.builder()
                    .workflowLabel("Standard KYC")
                    .features(List.of(
                            SimpleWorkflowFeature.builder()
                                    .feature(SimpleWorkflowFeature.Feature.of("OCR"))
                                    .config(Map.of("duplicated_user_action", "review"))
                                    .build(),
                            SimpleWorkflowFeature.builder()
                                    .feature(SimpleWorkflowFeature.Feature.of("LIVENESS"))
                                    .config(Map.of("face_liveness_method", "passive"))
                                    .build(),
                            SimpleWorkflowFeature.builder()
                                    .feature(SimpleWorkflowFeature.Feature.of("FACE_MATCH"))
                                    .config(Map.of("face_match_score_decline_threshold", 40, "face_match_score_review_threshold", 60))
                                    .build()))
                    .build());
            System.out.println(result);
        - lang: php
          label: PHP
          source: |-
            <?php

            require 'vendor/autoload.php';

            use Didit\DiditClient;

            // Reads DIDIT_API_KEY.
            $didit = new DiditClient();

            $result = $didit->workflows->create([
                'workflow_label' => 'Standard KYC',
                'features' => [[
                    'feature' => 'OCR',
                    'config' => ['duplicated_user_action' => 'review'],
                ], [
                    'feature' => 'LIVENESS',
                    'config' => ['face_liveness_method' => 'passive'],
                ], [
                    'feature' => 'FACE_MATCH',
                    'config' => ['face_match_score_decline_threshold' => 40, 'face_match_score_review_threshold' => 60],
                ]],
            ]);
            print_r($result->toArray());
        - lang: ruby
          label: Ruby
          source: |-
            require "didit"

            # Reads DIDIT_API_KEY.
            didit = Didit::Client.new

            result = didit.workflows.create(
              workflow_label: "Standard KYC",
              features: [{
                feature: "OCR",
                config: { duplicated_user_action: "review" },
              }, {
                feature: "LIVENESS",
                config: { face_liveness_method: "passive" },
              }, {
                feature: "FACE_MATCH",
                config: { face_match_score_decline_threshold: 40, face_match_score_review_threshold: 60 },
              }]
            )
            puts result.to_h
        - lang: csharp
          label: .NET
          source: >-
            using System;

            using System.Collections.Generic;

            using System.Text.Json;

            using Didit;


            // Reads DIDIT_API_KEY.

            using var client = new DiditClient();


            var result = await client.Workflows.CreateAsync(new
            SimpleWorkflowRequest

            {
                WorkflowLabel = "Standard KYC",
                Features = new SimpleWorkflowFeature[]
                {
                    new()
                    {
                        Feature = "OCR",
                        Config = new Dictionary<string, object> { ["duplicated_user_action"] = "review" },
                    },
                    new()
                    {
                        Feature = "LIVENESS",
                        Config = new Dictionary<string, object> { ["face_liveness_method"] = "passive" },
                    },
                    new()
                    {
                        Feature = "FACE_MATCH",
                        Config = new Dictionary<string, object> { ["face_match_score_decline_threshold"] = 40, ["face_match_score_review_threshold"] = 60 },
                    },
                },
            });

            Console.WriteLine(JsonSerializer.Serialize(result));
components:
  schemas:
    SimpleWorkflowRequest:
      type: object
      description: >-
        Crea un flux de treball lineal simple. L'API converteix internament
        aquesta llista de funcionalitats en un graf de flux basat en nodes.
        Llista blanca de camps ESTRICTA: qualsevol clau no indicada aquí
        (incloent-hi `workflow_type`) es rebutja amb un 400.
      required:
        - features
      properties:
        workflow_label:
          type: string
          maxLength: 50
          default: ID Verification
          description: >-
            Nom visible per al flux de treball (màxim 50 caràcters). El valor
            per defecte és `"ID Verification"` quan s'omet — defineix-lo sempre
            perquè els fluxos de treball es puguin distingir.
          example: Standard KYC
        is_default:
          type: boolean
          description: >-
            Estableix aquest flux de treball com a predeterminat per a les noves
            sessions.
        status:
          type: string
          enum:
            - draft
            - published
          description: >-
            Omet aquest camp per crear un flux de treball publicat a punt per a
            sessions. Utilitza `draft` només quan vulguis desar sense publicar.
        features:
          type: array
          minItems: 1
          description: >-
            Funcionalitats de verificació en ordre d'execució. L'API enllaça
            cada element amb el següent i afegeix un node d'estat final
            automàticament.
          items:
            $ref: '#/components/schemas/SimpleWorkflowFeature'
        is_white_label_enabled:
          type: boolean
          description: >-
            Habilita la personalització de marca blanca per a les sessions
            creades amb aquest flux de treball.
          default: false
        is_desktop_allowed:
          type: boolean
          description: >-
            Permet que el flux de verificació s'executi en navegadors
            d'escriptori.
          default: false
        max_retry_attempts:
          type: integer
          minimum: 0
          maximum: 10
          default: 3
          description: >-
            Nombre màxim d'intents de reintent permesos després d'una
            verificació rebutjada. `0` bloqueja l'usuari després del primer
            rebuig.
        retry_window_days:
          type: integer
          minimum: 1
          maximum: 365
          nullable: true
          default: 7
          description: >-
            Finestra mòbil en dies utilitzada per comptar els reintents. `null`
            aplica un límit per a tot l'historial.
        face_liveness_max_attempts:
          type: integer
          minimum: 1
          maximum: 3
          default: 3
          description: >-
            Nombre màxim d'enviaments de prova de vida per sessió. Per defecte
            3: un intent inicial més dos reintents. Aquest valor també es copia
            als nodes generats del flux de treball de prova de vida i estimació
            d'edat tret que la configuració a nivell de funcionalitat el
            sobreescrigui.
        face_match_max_attempts:
          type: integer
          minimum: 1
          maximum: 3
          default: 3
          description: >-
            Nombre màxim d'enviaments de coincidència facial per sessió. Per
            defecte 3: un intent inicial més dos reintents. Aquest valor també
            es copia als nodes generats del flux de treball de coincidència
            facial tret que la configuració a nivell de funcionalitat el
            sobreescrigui.
        session_expiration_time:
          type: integer
          minimum: 3600
          maximum: 2419200
          default: 604800
          description: >-
            Segons abans que caduqui una sessió no finalitzada. Mínim 1 hora
            (3600), màxim 4 setmanes (2419200).
    WorkflowDetail:
      type: object
      description: >-
        Els camps següents estan tipats; l'objecte també conté la resta de
        columnes de la configuració del flux de treball (commutadors de
        funcionalitats, llindars, accions d'advertència, documents permesos,
        callbacks) com a propietats addicionals. Els camps que no s'apliquen al
        `workflow_type` són `null`.
      properties:
        uuid:
          type: string
          format: uuid
          description: >-
            Identificador per versió (`settings_uuid`). Cada versió d'un flux de
            treball té el seu propi identificador.
        workflow_id:
          type: string
          format: uuid
          description: >-
            Identificador estable compartit per totes les versions del flux de
            treball. Les sessions creades amb aquest identificador utilitzen
            l'última versió publicada.
        workflow_label:
          type: string
          description: Nom visible del flux de treball.
        workflow_type:
          type: string
          nullable: true
          enum:
            - kyc
            - kyb
            - adaptive_age_verification
            - biometric_authentication
            - address_verification
            - questionnaire_verification
            - email_verification
            - phone_verification
            - null
          description: >-
            Plantilla de flux de treball. `null` per a fluxos de treball basats
            en grafs creats sense plantilla.
        is_default:
          type: boolean
          description: Si aquest és el flux de treball per defecte de l'aplicació.
        is_archived:
          type: boolean
          description: Els fluxos de treball arxivats no poden iniciar noves sessions.
        version:
          type: integer
          description: Número de versió dins del flux de treball.
        status:
          type: string
          enum:
            - draft
            - published
          description: >-
            Les versions en esborrany són editables; les versions publicades són
            immutables i s'utilitzen per a noves sessions.
        published_at:
          type: string
          format: date-time
          nullable: true
          description: Quan es va publicar aquesta versió. `null` per a esborranys.
        is_simple_workflow:
          type: boolean
          description: >-
            `true` quan el flux de treball no té cap `workflow_graph`
            personalitzat.
        is_editable:
          type: boolean
          description: '`true` només per a versions `draft`.'
        workflow_url:
          type: string
          format: uri
          description: URL pública que inicia una sessió amb aquest flux de treball.
        workflow_graph:
          type: object
          nullable: true
          additionalProperties: true
          description: >-
            Estructura del graf del flux de treball (nodes i arestes). `null`
            per a fluxos de treball simples.
        features:
          type: string
          description: >-
            Funcionalitats habilitades unides amb `" + "`, per exemple `"OCR +
            LIVENESS"`.
        total_price:
          type: number
          nullable: true
          description: >-
            Preu per sessió; per als fluxos de treball amb graf, el camí més
            car.
        min_price:
          type: number
          nullable: true
          description: Preu del camí més econòmic a través del flux de treball.
        max_price:
          type: number
          nullable: true
          description: Preu del camí més car a través del flux de treball.
        special_add_on_prices:
          type: object
          nullable: true
          additionalProperties: true
          description: >-
            Preus de complements específics de l'organització, o `null` si no
            n'hi ha cap de definit.
        max_retry_attempts:
          type: integer
          description: Reintents permesos després d'una verificació rebutjada.
        retry_window_days:
          type: integer
          nullable: true
          description: Dies durant els quals es permeten els reintents.
        session_expiration_time:
          type: integer
          description: Segons abans que caduqui una sessió no finalitzada.
        questionnaire:
          type: object
          nullable: true
          additionalProperties: true
          description: El qüestionari adjunt al flux de treball, o `null`.
        kyb_role_settings:
          type: array
          items:
            type: object
            additionalProperties: true
          description: Configuració de verificació per rol per a persones clau de KYB.
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
        signature_availability:
          type: object
          description: >-
            Quins nivells de signatura electrònica poden signar ara mateix.
            Comprova-ho abans d'establir `signature_level`. Es retorna en fluxos
            de treball `kyc`, `kyb` i de graf.
          properties:
            simple:
              type: boolean
              description: El pla Simple sempre està disponible.
            aes:
              type: boolean
              description: >-
                Indica si es pot signar amb signatura avançada (AES) en aquest
                moment. Mentre sigui `false`, desar un nou pas amb
                `signature_level: "aes"` es rebutjarà amb `aes_not_available`.
            qes:
              type: boolean
              description: >-
                Indica si es pot signar amb signatura qualificada (QES) en
                aquest moment. És `false` fins que es connecti un proveïdor
                qualificat.
        is_bank_verification_enabled:
          type: boolean
          description: >-
            Indica si un flux de treball senzill de KYC o KYB executa la
            verificació bancària. S'executa després dels passos de contacte (i
            la verificació d'ubicació) i abans de la validació en bases de
            dades, l'anàlisi AML i l'anàlisi d'IP. La verificació bancària
            encara no està disponible de manera general: activar-la es rebutjarà
            allà on no estigui habilitada.
        bank_verification_config:
          type: object
          additionalProperties: true
          description: >-
            Configuració de verificació bancària d'un flux de treball simple,
            amb les mateixes claus que accepta un node `BANK_VERIFICATION` (per
            exemple `bank_countries` i `bank_method_order`). Les claus
            desconegudes es descarten. Cada clau és opcional i una clau absent
            manté el seu valor per defecte, de manera que `{}` indica tots els
            valors per defecte. Consulta [Configuració de verificació
            bancària](/ca/management-api/workflows/feature-configs#verificació-bancària).
          example: {}
        is_geolocation_enabled:
          type: boolean
          description: >-
            Indica si un flux de treball senzill de KYC executa la verificació
            d'ubicació. S'executa després dels passos de contacte i abans de la
            verificació bancària i la validació en bases de dades. Els fluxos de
            treball d'empreses (KYB) no la poden executar.
        geolocation_config:
          type: object
          additionalProperties: true
          description: >-
            Configuració de verificació d'ubicació d'un flux de treball simple,
            amb les mateixes claus que accepta un node `GEOLOCATION` (per
            exemple, `is_geolocation_geofencing_enabled` i
            `geolocation_max_attempts`). S'ometen les claus desconegudes. Totes
            les claus són opcionals i una clau absent manté el seu valor per
            defecte, de manera que `{}` implica tots els valors per defecte.
          example: {}
      additionalProperties: true
    SimpleWorkflowFeature:
      type: object
      required:
        - feature
      properties:
        feature:
          type: string
          description: >-
            Funcionalitat a executar. Utilitza els valors en majúscules que es
            mostren aquí.
          enum:
            - OCR
            - NFC
            - LIVENESS
            - FACE_MATCH
            - PROOF_OF_ADDRESS
            - QUESTIONNAIRE
            - DOCUMENT_AI
            - PHONE_VERIFICATION
            - EMAIL_VERIFICATION
            - DATABASE_VALIDATION
            - AML
            - IP_ANALYSIS
            - AGE_ESTIMATION
            - KYB_REGISTRY
            - KYB_DOCUMENTS
            - KYB_KEY_PEOPLE
            - SIGNATURE
        config:
          type: object
          description: >-
            Configuració específica de la funcionalitat. Per a `QUESTIONNAIRE`,
            inclou `questionnaire_uuid` amb el `questionnaire_id` retornat per
            l'endpoint de creació de qüestionaris. Per a `SIGNATURE`, un flux de
            treball que passi a producció necessita un document per signar:
            defineix `signature_documents_source` com a `session` o `both`
            perquè cada sessió pugui aportar el seu propi, o envia `status:
            "draft"` i afegeix els documents abans de publicar.
            `signature_level: "aes"` es rebutja amb `aes_not_available` mentre
            `signature_availability.aes` sigui `false` al flux de treball. Per a
            `OCR`, `methods` selecciona quins mètodes de Verificació d'identitat
            pot utilitzar cada país (captura de documents, consulta sense
            document en una font governamental o una altra font oficial, i
            carteres d'identitat digital); omet-lo i, per a tots els països,
            només s'utilitzarà la captura de documents. Per a `SIGNATURE`,
            consulta [Configuració de signatura
            electrònica](/ca/management-api/workflows/feature-configs#e-signature):
            de moment `signature_level` accepta `simple` (el valor per defecte,
            sense necessitat de verificació d'identitat, correu electrònic o
            telèfon) i `aes`, i els documents del flux de treball i els seus
            camps es gestionen a la consola, de manera que a través de l'API
            s'envien documents i camps per sessió amb
            `signature_documents_source: "session"`.
          additionalProperties: true
        label:
          type: string
          description: Etiqueta interna opcional per a aquest node del flux de treball.
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: x-api-key
      description: >-
        La clau d'API de la teva aplicació, des de Developers -> API keys a la
        Business Console. La clau primària té accés complet. Una clau amb nom
        pot tenir l'abast limitat: cap, lectura o escriptura per recurs,
        limitada a determinats fluxos de treball o a sessions aprovades, a una
        llista d'adreces IP i a una data de caducitat. 401 significa que la clau
        és incorrecta, revocada o caducada; 403 significa que no s'ha enviat cap
        clau, que la clau no té accés a aquest recurs o acció, o que la
        sol·licitud prové d'una adreça fora de la seva llista d'IP; 404 en una
        ruta de sessió significa que la sessió està fora dels fluxos de treball
        o estats de la clau. Una clau sense accés a fitxers multimèdia rep els
        URL d'imatge, vídeo i PDF com a null, i una clau sense permís
        d'escriptura de sessions rep els enllaços de sessió i els tokens com a
        null. Consulta https://docs.didit.me/console/api-keys.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.