ONP API Reference
This document describes how to integrate with the Guardline onboarding API. It covers authentication, creating onboarding sessions, tracking execution lifecycle, receiving webhook notifications, and polling for missed events.
The integration model follows a clear separation of responsibilities: Guardline verifies and decides, the integrator orchestrates. The integrator creates a session via API, embeds the experience within their application using an iframe, and receives progress and result notifications via webhook.
Overview
Seção intitulada “Overview”The integration flow involves four participants:
| Participant | Responsibility |
|---|---|
| Integrator backend | Creates sessions, receives webhooks, queries executions |
| Guardline API | Manages sessions, tokens, executions, and notifications |
| Integrator frontend | Mounts the iframe with the URL provided by the API |
| Guardline Iframe | Conducts the verification journey with the end user |
The platform supports different journey types. For kyc_minor, the journey is split into two sequential modules: the minor module (ages 14 to 17), which collects personal data, documents, and biometrics, and the legal representative module, triggered automatically via SMS or WhatsApp after the first module is completed.
All API calls follow the REST pattern over HTTPS, with JSON payloads and responses in Guardline’s standard envelope format.
Environments and Authentication
Seção intitulada “Environments and Authentication”Environments
Seção intitulada “Environments”| Environment | Base URL | API Key prefix |
|---|---|---|
| Sandbox | https://{instance}.onp.dev.guardline.com.br | gl_test_ |
| Production | https://{instance}.onp.prod.guardline.com.br | gl_live_ |
The {instance} value is provisioned during integrator setup and identifies the dedicated infrastructure. Each instance has its own isolated database, application, and storage.
Authentication
Seção intitulada “Authentication”All API calls require the X-API-Key header with the key corresponding to the environment.
X-API-Key: gl_live_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2Keys are provisioned through the Guardline admin panel. The plaintext token is displayed only at creation time. Internally, Guardline stores the SHA-256 hash of the key.
HTTP requests are rejected. HTTPS with TLS 1.2 or higher is required in all environments.
Response Format
Seção intitulada “Response Format”All responses follow the standard envelope:
Success:
{ "error": false, "data": {}}Error:
{ "error": true, "message": "error description", "code": "ERROR_CODE", "request_id": "550e8400-e29b-41d4-a716-446655440000"}The request_id field is returned in all responses and can be used for tracking in support tickets.
Available Journeys
Seção intitulada “Available Journeys”GET /api/v1/onboarding/flowsReturns the list of configured and active journeys for the integrator, with the metadata needed to create sessions correctly.
Response
Seção intitulada “Response”{ "error": false, "data": [ { "flow_type": "kyc", "name": "KYC Pessoa Física", "description": "Verificação de identidade para maiores de 18 anos.", "status": "active", "steps": [ { "id": "cpf", "name": "CPF", "order": 1 }, { "id": "personal_data", "name": "Dados pessoais", "order": 2 }, { "id": "contact", "name": "Informações de contato", "order": 3 }, { "id": "professional_data", "name": "Dados profissionais", "order": 4 }, { "id": "address", "name": "Endereço", "order": 5 }, { "id": "terms", "name": "Termos de uso", "order": 6 }, { "id": "document", "name": "Documentoscopia", "order": 7 }, { "id": "biometric", "name": "Biometria facial", "order": 8 } ], "pre_fill_schema": [ { "field": "full_name", "type": "string", "required": false, "description": "Nome completo" }, { "field": "tax_id", "type": "string", "required": false, "description": "CPF (somente dígitos ou com máscara)" }, { "field": "email", "type": "string", "required": false, "description": "Endereço de e-mail" }, { "field": "phone", "type": "string", "required": false, "description": "Telefone com código do país" }, { "field": "birth_date", "type": "string", "required": false, "description": "Data de nascimento (AAAA-MM-DD)" } ] }, { "flow_type": "kyc_minor", "name": "KYC Menor de Idade", "description": "Verificação de identidade para menores entre 14 e 17 anos, com etapa adicional do representante legal.", "status": "active", "steps": [ { "id": "cpf_birth_date", "name": "CPF e data de nascimento", "order": 1 }, { "id": "welcome", "name": "Boas-vindas", "order": 2 }, { "id": "personal_data", "name": "Dados pessoais do menor", "order": 3 }, { "id": "contact", "name": "Informações de contato", "order": 4 }, { "id": "professional_data", "name": "Dados profissionais e PEP", "order": 5 }, { "id": "address", "name": "Endereço", "order": 6 }, { "id": "terms", "name": "Termos de uso", "order": 7 }, { "id": "document", "name": "Documentoscopia do menor", "order": 8 }, { "id": "biometric", "name": "Biometria facial do menor", "order": 9 }, { "id": "rep_welcome", "name": "Boas-vindas do representante", "order": 10 }, { "id": "rep_personal_data", "name": "Dados pessoais do representante", "order": 11 }, { "id": "rep_contact", "name": "Contato do representante", "order": 12 }, { "id": "rep_professional_data", "name": "Dados profissionais do representante", "order": 13 }, { "id": "rep_address", "name": "Endereço do representante", "order": 14 }, { "id": "rep_terms", "name": "Termos de uso do representante", "order": 15 }, { "id": "rep_document", "name": "Documentoscopia do representante", "order": 16 }, { "id": "rep_biometric", "name": "Biometria facial do representante", "order": 17 }, { "id": "rep_relationship", "name": "Grau de parentesco", "order": 18 }, { "id": "rep_guardianship_doc", "name": "Comprovante de guarda legal", "order": 19 } ], "pre_fill_schema": [ { "field": "full_name", "type": "string", "required": true, "description": "Nome completo do menor" }, { "field": "tax_id", "type": "string", "required": true, "description": "CPF do menor" }, { "field": "representative.full_name", "type": "string", "required": true, "description": "Nome completo do representante legal" }, { "field": "representative.tax_id", "type": "string", "required": true, "description": "CPF do representante legal" }, { "field": "representative.phone", "type": "string", "required": true, "description": "Telefone do representante legal com código do país" } ] } ]}Steps prefixed with rep_ belong to the legal representative module and only exist in journeys involving a minor. The rep_guardianship_doc step is conditional: it is only executed when the reported relationship is not mother or father.
Creating a Session
Seção intitulada “Creating a Session”POST /api/v1/onboarding/sessionsCreates a new onboarding session and returns the credentials needed to embed the journey in the integrator’s frontend.
Request Payload
Seção intitulada “Request Payload”| Field | Type | Required | Description |
|---|---|---|---|
flow_type | string | Yes | Journey type. Possible values: kyc, kyb, kyc_minor |
reference_id | string | No | Free-form identifier for correlation with the integrator’s system |
pre_fill | object | Depends on flow | Known user data for pre-filling |
The reference_id field is returned in all responses and webhooks related to the execution. It is recommended to use a unique and stable identifier from the integrator’s system, such as the account ID or the onboarding request ID.
The pre_fill fields vary by flow_type. The complete list of accepted fields and their requirements can be found in the available journeys endpoint response (see Available Journeys).
Example Request for KYC Minor
Seção intitulada “Example Request for KYC Minor”{ "flow_type": "kyc_minor", "reference_id": "SOL-2026-00042", "pre_fill": { "full_name": "João Santos", "tax_id": "123.456.789-00", "representative": { "full_name": "Maria Santos", "tax_id": "987.654.321-00", "phone": "+5511999998888" } }}Example Request for Standard KYC
Seção intitulada “Example Request for Standard KYC”{ "flow_type": "kyc", "reference_id": "SOL-2026-00099", "pre_fill": { "full_name": "Carlos Oliveira", "tax_id": "111.222.333-44", "email": "carlos@exemplo.com" }}Success Response (201)
Seção intitulada “Success Response (201)”{ "error": false, "data": { "execution_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "customer_id": "e7f8a9b0-c1d2-3456-7890-abcdef123456", "token": "f8c2e1a4b7d9036e5c8f1a2b3d4e5f6a", "url": "https://acme.onp.prod.guardline.com.br/onboarding/link/f8c2e1a4b7d9...", "embed_url": "https://acme.onp.prod.guardline.com.br/embed/f8c2e1a4b7d9...", "expires_at": "2026-04-07T00:00:00Z", "status": "created", "reference_id": "SOL-2026-00099" }}| Field | Description |
|---|---|
execution_id | Unique execution identifier. Used for queries and webhook correlation |
customer_id | Customer record identifier |
token | Cryptographic session token (32 hexadecimal characters) |
url | Direct link to the journey, usable in browsers and messages |
embed_url | URL for iframe usage. Contains parameters optimized for embedded mode |
expires_at | Link expiration in ISO 8601 format. Default: 7 days after creation |
status | Initial execution status (created) |
reference_id | Echo of the reference_id sent in the request, when provided |
The url field is intended for direct browser access (sending via SMS, WhatsApp, email). The embed_url field is intended for iframe and webview usage. Both point to the same execution.
| HTTP | Code | Cause |
|---|---|---|
| 400 | INVALID_FLOW_TYPE | The flow_type provided does not exist or is not active for the integrator |
| 400 | MISSING_REQUIRED_FIELDS | Required pre_fill fields missing for the requested flow_type |
| 400 | INVALID_TAX_ID | The provided CPF has an invalid format |
| 401 | MISSING_API_KEY | API Key header not provided |
| 401 | INVALID_API_KEY | API Key invalid, revoked, or expired |
| 409 | ACTIVE_SESSION_EXISTS | An active session already exists for the same tax_id and flow_type |
| 429 | RATE_LIMITED | Request limit exceeded. Respect the Retry-After header |
Session Resumption and Expiration
Seção intitulada “Session Resumption and Expiration”Resumption
Seção intitulada “Resumption”Guardline fully manages journey resumption. When the user accesses the same embed_url or url again, the iframe automatically resolves to the pending step. Previously submitted data is preserved on the backend and does not need to be resent.
Resumption scenarios:
| Scenario | Behavior |
|---|---|
| User closes the iframe and reopens it | Returns to the step where they left off |
| Error during document capture | Returns directly to the document capture step |
| Connection loss during submission | Allows resubmission on the same step |
| Representative accesses the link after days | Continues where they left off, as long as the session has not expired |
The integrator does not need to implement resumption logic. The same token remains valid throughout the session’s lifetime.
Expiration
Seção intitulada “Expiration”Two expiration windows apply simultaneously. The more restrictive one takes precedence:
| Window | Duration | Starts from | Purpose |
|---|---|---|---|
| Link validity | 7 days (configurable) | Session creation | Covers delays in opening the link |
| Active session | 24 hours | First iframe access | Limits exposure of open sessions |
When a session expires, the iframe displays an informational screen and the execution transitions to the expired state. The integrator is notified via the onboarding.expired webhook and can create a new session.
Resending the Representative Link
Seção intitulada “Resending the Representative Link”In the kyc_minor flow, the link sent to the legal representative follows the same expiration policy. If the link expires before the representative completes their steps, the integrator can check the execution status via GET (see Querying an Execution) and request a link resend through the endpoint:
POST /api/v1/onboarding/executions/{execution_id}/resend-representative-linkSuccess response (200):
{ "error": false, "data": { "message": "Link reenviado com sucesso", "expires_at": "2026-04-14T00:00:00Z" }}The resend generates a new token for the representative, invalidating the previous one, and re-triggers SMS and WhatsApp to the registered phone number. Rate limited to 3 resends per execution. Returns 429 RATE_LIMITED when exceeded.
Execution Lifecycle
Seção intitulada “Execution Lifecycle”State Diagram
Seção intitulada “State Diagram”State Descriptions
Seção intitulada “State Descriptions”| State | Terminal | Description |
|---|---|---|
created | No | Session created, user has not yet accessed the iframe |
in_progress | No | User navigating through journey steps |
pending_representative | No | Minor module finished, waiting for legal representative (kyc_minor only) |
processing | No | All steps submitted, decision engine processing |
approved | Yes | Approved by the engine or by an analyst |
rejected | Yes | Rejected by the engine or by an analyst |
blocked | Yes | Journey interrupted by a security rule (CPF restriction, biometric attempt limit) |
pending_review | No | Referred for manual review. Resolution SLA: 72 hours |
expired | Yes | Session expired before completion |
cancelled | Yes | Execution cancelled by the integrator or by an administrator |
In the kyc_minor flow, the execution transitions to pending_representative after the minor completes their module. Once the representative starts, it returns to in_progress. The transition to processing occurs only after both modules are finished.
Querying an Execution
Seção intitulada “Querying an Execution”GET /api/v1/onboarding/executions/{execution_id}Returns the complete state of an execution, including data collected during the journey. This endpoint is the primary data source for the integrator. Webhooks notify state transitions; details are obtained through this query.
Standard KYC Response (200)
Seção intitulada “Standard KYC Response (200)”{ "error": false, "data": { "execution_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "flow_type": "kyc", "reference_id": "SOL-2026-00099", "status": "approved", "decision": { "result": "approved", "risk_level": "low", "decided_at": "2026-03-26T15:30:00Z", "decided_by": "engine" }, "customer": { "full_name": "Carlos Oliveira", "tax_id_masked": "111.***.**3-44", "birth_date": "1990-05-15", "nationality": "Brasileira", "email": "carlos@exemplo.com", "phone": "+5511999990000", "income": "8500.00", "is_pep": false, "has_foreign_tax_obligation": false, "address": { "zip_code": "01310-100", "street": "Avenida Paulista", "number": "1000", "complement": "Sala 302", "neighborhood": "Bela Vista", "city": "São Paulo", "state": "SP" }, "document": { "type": "cnh", "status": "verified" }, "biometric": { "status": "verified" } }, "steps_completed": 8, "steps_total": 8, "created_at": "2026-03-26T14:00:00Z", "started_at": "2026-03-26T14:05:00Z", "completed_at": "2026-03-26T14:12:00Z", "expires_at": "2026-04-02T14:00:00Z" }}KYC Minor Response (200)
Seção intitulada “KYC Minor Response (200)”The structure is identical to standard KYC, with the addition of the representative field inside customer:
{ "error": false, "data": { "execution_id": "b2c3d4e5-f6a7-8901-bcde-f12345678901", "flow_type": "kyc_minor", "reference_id": "SOL-2026-00042", "status": "approved", "decision": { "result": "approved", "risk_level": "low", "decided_at": "2026-04-01T10:45:00Z", "decided_by": "engine" }, "customer": { "full_name": "João Santos", "tax_id_masked": "123.***.**9-00", "birth_date": "2011-05-15", "nationality": "Brasileira", "email": "joao@exemplo.com", "phone": "+5511988887777", "income": "1500.00", "is_pep": false, "has_foreign_tax_obligation": false, "address": { "zip_code": "04538-132", "street": "Rua Funchal", "number": "538", "complement": null, "neighborhood": "Vila Olímpia", "city": "São Paulo", "state": "SP" }, "document": { "type": "rg", "status": "verified" }, "biometric": { "status": "verified" }, "representative": { "full_name": "Maria Santos", "tax_id_masked": "987.***.**1-00", "birth_date": "1985-03-20", "nationality": "Brasileira", "email": "maria@exemplo.com", "phone": "+5511999998888", "income": "6200.00", "is_pep": false, "has_foreign_tax_obligation": false, "relationship": "mother", "guardianship_document": null, "address": { "zip_code": "04538-132", "street": "Rua Funchal", "number": "538", "complement": null, "neighborhood": "Vila Olímpia", "city": "São Paulo", "state": "SP" }, "document": { "type": "cnh", "status": "verified" }, "biometric": { "status": "verified" } } }, "steps_completed": 19, "steps_total": 19, "created_at": "2026-03-31T09:00:00Z", "started_at": "2026-03-31T09:03:00Z", "completed_at": "2026-04-01T10:40:00Z", "expires_at": "2026-04-07T09:00:00Z" }}The representative field only exists when flow_type is kyc_minor. For standard KYC and KYB journeys, the customer structure does not include this field.
The relationship field accepts the values mother, father, and other. When the value is other, the guardianship_document field contains "uploaded" indicating that the legal guardianship document was submitted. For mother or father, the field is null.
The decision block is only populated when the execution reaches a terminal state (approved, rejected) or is under review (pending_review). In all other states, the field is null.
| HTTP | Code | Cause |
|---|---|---|
| 401 | MISSING_API_KEY | API Key header not provided |
| 401 | INVALID_API_KEY | API Key invalid, revoked, or expired |
| 404 | EXECUTION_NOT_FOUND | The execution_id does not exist or does not belong to the integrator |
Active Executions
Seção intitulada “Active Executions”GET /api/v1/onboarding/executionsReturns all in-progress executions with a valid session. Executions in a terminal state (approved, rejected, blocked, expired, cancelled) are not included in the response.
Pagination Parameters
Seção intitulada “Pagination Parameters”| Parameter | Type | Default | Description |
|---|---|---|---|
page | integer | 1 | Requested page |
per_page | integer | 50 | Items per page (maximum: 200) |
Response (200)
Seção intitulada “Response (200)”{ "error": false, "data": { "items": [ { "execution_id": "b2c3d4e5-f6a7-8901-bcde-f12345678901", "flow_type": "kyc_minor", "reference_id": "SOL-2026-00042", "status": "in_progress", "steps_completed": 9, "steps_total": 19, "created_at": "2026-03-31T09:00:00Z", "started_at": "2026-03-31T09:03:00Z", "expires_at": "2026-04-07T09:00:00Z" }, { "execution_id": "c3d4e5f6-a7b8-9012-cdef-123456789012", "flow_type": "kyc", "reference_id": "SOL-2026-00101", "status": "in_review", "steps_completed": 8, "steps_total": 8, "created_at": "2026-03-30T16:20:00Z", "started_at": "2026-03-30T16:22:00Z", "expires_at": "2026-04-06T16:20:00Z" } ], "total": 2, "page": 1, "per_page": 50, "total_pages": 1 }}Each item contains only summary fields. Complete execution data (customer, decision, representative) is obtained via the individual query endpoint (see Querying an Execution).
Webhooks
Seção intitulada “Webhooks”Webhooks are HTTP notifications sent by Guardline to the integrator’s backend when an execution changes state. Payloads are intentionally lean: they contain only the event and execution identifiers. Complete data should be obtained via the query endpoint (see Querying an Execution).
Base Events
Seção intitulada “Base Events”These events are emitted for all journey types:
| Event | Description |
|---|---|
onboarding.started | Session created via POST /sessions |
onboarding.completed | All steps submitted; decision engine processing |
onboarding.approved | Automatically approved by the engine or by an analyst |
onboarding.rejected | Automatically rejected by the engine or by an analyst |
onboarding.review | Referred for manual review |
onboarding.blocked | Journey interrupted by a security rule |
onboarding.expired | Session expired before completion |
Legal Representative Events
Seção intitulada “Legal Representative Events”These events are emitted exclusively for kyc_minor journeys, in addition to the base events:
| Event | Description |
|---|---|
representative.pending | Minor module completed. SMS and WhatsApp sent to the legal representative with the access link |
representative.started | Legal representative accessed the link and started their steps |
representative.completed | Legal representative completed all their steps |
Emission Order
Seção intitulada “Emission Order”Events follow a strict emission order within each execution. Due to retries, events may arrive out of order at the integrator’s endpoint. The event_sequence field (monotonically increasing per execution) should be used as the canonical ordering criterion, not the timestamp or delivery order.
Standard KYC
Seção intitulada “Standard KYC”Automatic approval:
onboarding.started (1) session createdonboarding.completed (2) all steps submitted, decision engine processingonboarding.approved (3) approved by engineRejection:
onboarding.started (1)onboarding.completed (2)onboarding.rejected (3) rejected by engineReferred to manual review, then resolved by analyst:
onboarding.started (1)onboarding.completed (2)onboarding.review (3) sent to analyst queueonboarding.approved (4) analyst approved (or onboarding.rejected)Blocked by security rule (CPF restriction or biometric attempt limit):
onboarding.started (1)onboarding.blocked (2) journey interruptedExpired before completion:
onboarding.started (1)onboarding.expired (2) session or link expiredKYC Minor
Seção intitulada “KYC Minor”The kyc_minor journey has two sequential modules: the minor module and the legal representative module. All webhook events reference the minor’s execution_id, which is the only identifier the integrator tracks.
Automatic approval:
onboarding.started (1) session createdrepresentative.pending (2) minor module finished, SMS/WP sent to representativerepresentative.started (3) representative accessed the linkrepresentative.completed (4) representative completed their stepsonboarding.completed (5) all steps submitted (both modules), decision engine processingonboarding.approved (6) approved by engineThe representative.pending event signals that the minor completed all their steps and the representative link was dispatched. There is no separate event for minor module completion; representative.pending serves as that signal.
Rejection after both modules complete:
onboarding.started (1)representative.pending (2)representative.started (3)representative.completed (4)onboarding.completed (5)onboarding.rejected (6) rejected by engineReferred to manual review, then resolved:
onboarding.started (1)representative.pending (2)representative.started (3)representative.completed (4)onboarding.completed (5)onboarding.review (6) sent to analyst queueonboarding.approved (7) analyst approved (or onboarding.rejected)Blocked during minor module:
onboarding.started (1)onboarding.blocked (2) CPF restricted or biometric limit exceededExpired while waiting for representative:
onboarding.started (1)representative.pending (2)onboarding.expired (3) session expired before representative completedExpired during representative module:
onboarding.started (1)representative.pending (2)representative.started (3)onboarding.expired (4) session expired during representative stepsPayload
Seção intitulada “Payload”{ "event": "onboarding.approved", "execution_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "flow_type": "kyc_minor", "reference_id": "SOL-2026-00042", "event_sequence": 6, "timestamp": "2026-04-01T10:45:00Z"}| Field | Description |
|---|---|
event | Event type |
execution_id | Execution identifier |
flow_type | Journey type |
reference_id | Integrator identifier, as sent during session creation |
event_sequence | Sequential event number within the execution, for ordering |
timestamp | Event emission timestamp in ISO 8601 format |
Headers
Seção intitulada “Headers”| Header | Description |
|---|---|
Content-Type | Always application/json |
X-Guardline-Event-ID | Stable event UUID, identical across retries. Use for deduplication |
X-Guardline-Delivery-ID | Unique UUID per delivery attempt. Changes on each retry |
X-Guardline-Attempt-Number | Sequential attempt number (1 for first delivery, 2 for first retry, etc.) |
X-Guardline-Timestamp | Unix timestamp of the signature moment (when HMAC is enabled) |
X-Guardline-Signature | HMAC-SHA256 signature in hexadecimal (when HMAC is enabled) |
Authorization | Bearer token (when OAuth is enabled) |
Webhook Authentication
Seção intitulada “Webhook Authentication”Guardline supports three authentication modes for webhook delivery. The mode is configured per webhook endpoint in the admin panel. HMAC signature is always present regardless of the selected mode, providing message integrity verification on every delivery.
| Mode | HMAC Signature | OAuth Bearer | Client Certificate |
|---|---|---|---|
| HMAC only (default) | Yes | No | No |
| OAuth 2.0 | Yes | Yes | No |
| mTLS | Yes | No | Yes |
| OAuth 2.0 + mTLS | Yes | Yes | Yes |
HMAC-SHA256 Authentication
Seção intitulada “HMAC-SHA256 Authentication”HMAC authentication uses a shared secret provisioned during integrator setup in the admin panel.
Verification process on the receiver:
- Extract the
X-Guardline-Timestampheader - Reject if the timestamp is older than 5 minutes relative to the server clock
- Concatenate timestamp and request body:
{timestamp}.{body} - Compute
HMAC-SHA256of the concatenation using the shared secret - Encode the result in hexadecimal
- Compare with the
X-Guardline-Signatureheader using constant-time comparison - Reject if there is a mismatch
Pseudocode:
import hmac, hashlib, time
def verify_webhook(body: bytes, timestamp: str, signature: str, secret: str) -> bool: if abs(time.time() - int(timestamp)) > 300: return False
message = f"{timestamp}.".encode() + body expected = hmac.new( secret.encode(), message, hashlib.sha256 ).hexdigest()
return hmac.compare_digest(expected, signature)mTLS Authentication
Seção intitulada “mTLS Authentication”Mutual TLS authentication ensures Guardline’s identity at the transport layer, without requiring application-level validation.
Setup:
- During provisioning, Guardline provides the root CA certificate (
guardline-ca.pem) - The integrator configures their webhook server to require client certificates
- The integrator adds
guardline-ca.pemto the server’s trusted CA list - On each delivery, Guardline presents a client certificate signed by the root CA
- The integrator’s server validates the certificate chain automatically at the TLS layer
The CN (Common Name) field of the client certificate contains the integrator’s instance identifier. The integrator can optionally validate this field to ensure the request comes from the correct instance.
When mTLS is enabled, the X-Guardline-Signature and X-Guardline-Timestamp headers are not sent.
OAuth 2.0 Authentication
Seção intitulada “OAuth 2.0 Authentication”OAuth authentication allows Guardline to obtain an access token before each delivery, using the Client Credentials flow (RFC 6749, section 4.4).
Setup:
- The integrator provides in the admin panel:
token_endpoint,client_id,client_secret, and optionallyscope - Before each delivery, Guardline requests a token from the provided endpoint
- The token request follows the standard format:
POST {token_endpoint}Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials&client_id={client_id}&client_secret={client_secret}&scope={scope}- Guardline includes the obtained token in the webhook authorization header:
Authorization: Bearer {access_token}- The integrator validates the token at their webhook endpoint according to their OAuth implementation
Guardline caches the token respecting the expires_in field from the token endpoint response, with a 60-second safety margin. If the webhook receiver returns 401, the cached token is invalidated and a fresh token is acquired for a single retry.
If token acquisition fails due to invalid credentials (401 or 400 from the token endpoint), the delivery is immediately marked as exhausted and is not retried. Transient token endpoint failures (500, timeout) follow the normal retry policy.
Endpoint Configuration
Seção intitulada “Endpoint Configuration”The webhook endpoint is configured in the Guardline admin panel. Requirements:
| Requirement | Detail |
|---|---|
| Protocol | HTTPS required |
| TLS version | 1.2 or higher |
| Success response | Any 2xx code (body ignored) |
| Timeout | Respond within 10 seconds |
| Idempotency | Deduplicate deliveries using X-Guardline-Event-ID |
Implementation recommendation: receive the webhook, enqueue for asynchronous processing, and respond immediately with 200. This avoids timeouts and ensures reliable delivery.
Credential Rotation
Seção intitulada “Credential Rotation”When OAuth credentials or mTLS certificates are rotated, in-flight retries for previously dispatched deliveries continue using the credentials that were active at the time of dispatch. New deliveries use the updated credentials immediately.
If failed deliveries need to be re-sent with the new credentials, a manual resend from the admin panel creates a new delivery using the latest configured credentials, preserving the original event payload. The original delivery is kept intact for audit purposes.
Retry Policy
Seção intitulada “Retry Policy”When the integrator’s endpoint returns a non-2xx code or does not respond within 10 seconds, Guardline resends the notification with exponential backoff:
| Attempt | Interval after failure |
|---|---|
| 1 | 5 seconds |
| 2 | 30 seconds |
| 3 | 2 minutes |
| 4 | 10 minutes |
| 5 | 30 minutes |
| 6 | 1 hour |
| 7 | 2 hours |
| 8 | 4 hours |
| 9 | 8 hours |
| 10 | 12 hours |
After 10 failed attempts, the delivery is marked as exhausted and an internal alert is generated. Notifications remain accessible via the polling endpoint (see Notification Polling). Manual resend is also available in the admin panel.
Notification Polling
Seção intitulada “Notification Polling”The polling endpoint is the fallback mechanism to ensure no notification is lost, regardless of webhook failures. It can also be used as the primary integration mechanism by integrators who prefer a pull model.
Querying Pending Notifications
Seção intitulada “Querying Pending Notifications”GET /api/v1/onboarding/notifications| Parameter | Type | Default | Description |
|---|---|---|---|
status | string | pending | Filter by state: pending, failed, retrying. Comma-separated for multiple values |
page | integer | 1 | Requested page |
per_page | integer | 50 | Items per page (maximum: 200) |
Response (200):
{ "error": false, "data": { "items": [ { "delivery_id": "d4e5f6a7-b8c9-0123-def0-123456789abc", "execution_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "event": "onboarding.approved", "event_sequence": 6, "status": "pending", "attempts": 3, "max_attempts": 10, "last_attempt_at": "2026-04-01T10:48:00Z", "created_at": "2026-04-01T10:45:00Z" } ], "total": 1, "page": 1, "per_page": 50, "total_pages": 1 }}Acknowledging Processing
Seção intitulada “Acknowledging Processing”POST /api/v1/onboarding/notifications/{delivery_id}/ackMarks a notification as processed. After acknowledgment, the notification no longer appears in queries with pending status. The operation is idempotent: repeated calls for the same delivery_id return success with no side effects.
Response (200):
{ "error": false, "data": { "delivery_id": "d4e5f6a7-b8c9-0123-def0-123456789abc", "status": "acknowledged" }}Complete Flow
Seção intitulada “Complete Flow”Standard KYC
Seção intitulada “Standard KYC”KYC Minor
Seção intitulada “KYC Minor”Error Reference
Seção intitulada “Error Reference”HTTP Codes
Seção intitulada “HTTP Codes”| Code | Meaning | Guidance |
|---|---|---|
| 200 | Success | Process normally |
| 201 | Resource created | Process normally |
| 400 | Invalid request | Fix the payload. Do not retry |
| 401 | Authentication failed | Check the API Key. Do not retry |
| 404 | Resource not found | Check the identifiers. Do not retry |
| 409 | Conflict | Handle according to the specific error code |
| 429 | Rate limited | Wait for the interval indicated in the Retry-After header |
| 500 | Internal error | Retry with exponential backoff (maximum 3 attempts) |
| Network timeout | Connection lost | Retry. Idempotency prevents duplications |
Domain Error Codes
Seção intitulada “Domain Error Codes”| Code | HTTP | Description |
|---|---|---|
MISSING_API_KEY | 401 | API Key header not provided |
INVALID_API_KEY | 401 | API Key invalid, revoked, or expired |
INVALID_FLOW_TYPE | 400 | The journey type provided does not exist or is not active |
MISSING_REQUIRED_FIELDS | 400 | Required pre-fill fields missing |
INVALID_TAX_ID | 400 | CPF with invalid format |
ACTIVE_SESSION_EXISTS | 409 | Active session exists for the same CPF and journey type |
EXECUTION_NOT_FOUND | 404 | Execution not found or does not belong to the integrator |
EXECUTION_TERMINATED | 409 | The execution has already reached a terminal state |
LINK_NOT_FOUND | 404 | Link token not found |
LINK_EXPIRED | 410 | Link token expired |
NOTIFICATION_NOT_FOUND | 404 | Notification not found |
RATE_LIMITED | 429 | Request limit exceeded |
Endpoint Summary
Seção intitulada “Endpoint Summary”| Method | Path | Description |
|---|---|---|
| GET | /api/v1/onboarding/flows | List available journeys |
| POST | /api/v1/onboarding/sessions | Create an onboarding session |
| GET | /api/v1/onboarding/executions/{execution_id} | Query execution with complete data |
| GET | /api/v1/onboarding/executions | List active executions |
| POST | /api/v1/onboarding/executions/{execution_id}/resend-representative-link | Resend representative link |
| GET | /api/v1/onboarding/notifications | Query pending notifications |
| POST | /api/v1/onboarding/notifications/{delivery_id}/ack | Acknowledge notification processing |