Auth Webhook Contract
Este conteúdo não está disponível em sua língua ainda.
The User Authentication extension verifies end-user identity by calling your webhook. This page documents the complete contract your webhook must implement.
How it works
Section titled “How it works”- Your agent asks for credentials (via form or conversational flow).
- SynapsAI sends a POST request to your webhook with the user’s credentials and context.
- Your webhook verifies the credentials and returns a result: verified, challenge, or failure.
One endpoint handles all channels. Use the context.channel field to differentiate:
| Channel | context.channel | Credentials contain | implicitIdentity contains |
|---|---|---|---|
| WebChat | CHAT | Email + password (or configured fields) | (empty) |
WHATSAPP | documentId (or configured fields) | phone: "5551999999999" | |
INSTAGRAM | Email (or configured fields) | (empty — future: instagramUserId) |
Request format
Section titled “Request format”POST {your-webhook-url}Content-Type: application/jsonX-Synapsai-Signature: sha256={hmac_hex}Standard verification request
Section titled “Standard verification request”Sent when a user submits credentials for the first time.
{ "credentials": { "email": "user@example.com", "password": "s3cret" }, "context": { "accountId": "your-tenant-id", "agentKey": "your-agent-key", "chatId": "conversation-id", "channel": "CHAT", "contactId": "contact-uuid", "implicitIdentity": {} }}WhatsApp verification request
Section titled “WhatsApp verification request”On WhatsApp, implicitIdentity includes the user’s phone number automatically.
{ "credentials": { "documentId": "11144477735" }, "context": { "accountId": "your-tenant-id", "agentKey": "your-agent-key", "chatId": "conversation-id", "channel": "WHATSAPP", "contactId": "contact-uuid", "implicitIdentity": { "phone": "5551999999999" } }}Challenge answer request
Section titled “Challenge answer request”Sent when the user responds to a challenge (multi-step verification).
{ "challengeResponse": { "challengeId": "ch_abc123", "answer": "+5551981975115" }, "context": { "accountId": "your-tenant-id", "agentKey": "your-agent-key", "chatId": "conversation-id", "channel": "WHATSAPP", "contactId": "contact-uuid", "implicitIdentity": { "phone": "5551999999999" } }}Response format
Section titled “Response format”Your webhook must return one of these three responses:
1. Success (verified)
Section titled “1. Success (verified)”The user is authenticated. userId is your internal identifier for the user. identity fields are available to the AI agent for personalization.
{ "verified": true, "userId": "usr_123", "identity": { "name": "David Petro", "email": "david@example.com" }, "metadata": { "plan": "premium" }}| Field | Type | Required | Description |
|---|---|---|---|
verified | boolean | Yes | Must be true |
userId | string | No | Your internal user ID |
identity | object | No | Key-value pairs available to the agent |
metadata | object | No | Additional data (not exposed to the agent) |
2. Challenge (multi-step verification)
Section titled “2. Challenge (multi-step verification)”Return a challenge when you need additional verification — for example, confirming a phone number.
{ "verified": false, "challenge": { "challengeId": "ch_abc123", "type": "SELECT_OPTION", "prompt": "Confirm one of your registered phones:", "options": [ { "label": "555198xxxxx96", "value": "+5551981975196" }, { "label": "051998xxxxx17", "value": "+5519981975117" } ], "hint": "Type the full number with area code" }}| Field | Type | Required | Description |
|---|---|---|---|
challengeId | string | Yes | Unique ID for this challenge (you generate it) |
type | string | Yes | SELECT_OPTION or TEXT_INPUT |
prompt | string | Yes | Message shown to the user |
options | array | For SELECT_OPTION | List of { label, value } choices |
hint | string | No | Additional guidance for the user |
Challenge types
Section titled “Challenge types”SELECT_OPTION — The user picks from a list (e.g., masked phone numbers):
- Present
options[].labelto the user - The user’s choice is sent back as the
answer - Use masked labels for security (e.g.,
555198xxxxx96)
TEXT_INPUT — The user types a free-text answer (e.g., OTP code):
- Show the
promptand optionalhint - The typed value is sent back as the
answer
3. Failure
Section titled “3. Failure”Return when credentials are invalid.
{ "verified": false, "error": "Invalid credentials", "retriesLeft": 2}| Field | Type | Required | Description |
|---|---|---|---|
verified | boolean | Yes | Must be false |
error | string | Yes | Error message shown to the user |
retriesLeft | integer | No | How many attempts remain (informational) |
4. Challenge expired
Section titled “4. Challenge expired”When a challengeResponse references an expired challenge:
{ "verified": false, "error": "Challenge expired", "retriesLeft": 0}SynapsAI clears the pending challenge and tells the user to start verification again.
Challenge TTL and expiry
Section titled “Challenge TTL and expiry”Your webhook is responsible for managing challenge expiry. When you create a challenge, store it with a TTL (recommended: 5 minutes). When SynapsAI sends a challengeResponse with an expired challengeId, return a failure response with retriesLeft: 0.
| Challenge type | Recommended TTL | Notes |
|---|---|---|
SELECT_OPTION (masked phones) | 5 minutes | User is already in the conversation |
TEXT_INPUT (OTP code) | 3–5 minutes | Standard OTP expiry window |
Example (Redis/DynamoDB TTL):
// Store challenge with 5-minute TTLawait cache.set(challengeId, challengeData, { EX: 300 });
// On challenge response:const challenge = await cache.get(challengeResponse.challengeId);if (!challenge) { return { verified: false, error: "Challenge expired", retriesLeft: 0 };}HMAC-SHA256 signature verification
Section titled “HMAC-SHA256 signature verification”If you configured a Webhook Secret in the extension settings, SynapsAI signs every request with HMAC-SHA256:
X-Synapsai-Signature: sha256=<hex_digest>Verify the signature in your webhook:
const crypto = require('crypto');
function verifySignature(body, signature, secret) { const expected = crypto .createHmac('sha256', secret) .update(JSON.stringify(body)) .digest('hex'); return signature === `sha256=${expected}`;}Field types reference
Section titled “Field types reference”Configure which fields are collected from users in the extension settings.
| Field type | HTML input type | Available on WebChat | Available on Messaging |
|---|---|---|---|
TEXT | text | Yes | Yes |
EMAIL | Yes | Yes | |
PASSWORD | password | Yes | No (auto-filtered) |
SECRET | password | Yes | No (auto-filtered) |
PHONE | tel | Yes | Yes |
DOCUMENT_ID | text | Yes | Yes |
Channel-specific field configuration
Section titled “Channel-specific field configuration”You can configure different fields for WebChat and messaging channels:
- Login Form Fields (
collectFields) — Default fields used by all channels. On messaging channels,PASSWORDandSECRETtypes are automatically filtered. - Messaging Fields (
messagingFields) — Override for WhatsApp and Instagram. Only safe types allowed (TEXT,EMAIL,PHONE,DOCUMENT_ID).
If no messagingFields are configured, the login form fields are used with PASSWORD/SECRET types removed automatically.
Next steps
Section titled “Next steps”- Node.js webhook starter — Copy-paste Lambda template
- Python webhook starter — Copy-paste Lambda template