Zum Inhalt springen

Auth Webhook Contract

Dieser Inhalt ist noch nicht in deiner Sprache verfügbar.

The User Authentication extension verifies end-user identity by calling your webhook. This page documents the complete contract your webhook must implement.

  1. Your agent asks for credentials (via form or conversational flow).
  2. SynapsAI sends a POST request to your webhook with the user’s credentials and context.
  3. 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:

Channelcontext.channelCredentials containimplicitIdentity contains
WebChatCHATEmail + password (or configured fields)(empty)
WhatsAppWHATSAPPdocumentId (or configured fields)phone: "5551999999999"
InstagramINSTAGRAMEmail (or configured fields)(empty — future: instagramUserId)
POST {your-webhook-url}
Content-Type: application/json
X-Synapsai-Signature: sha256={hmac_hex}

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": {}
}
}

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"
}
}
}

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"
}
}
}

Your webhook must return one of these three responses:

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"
}
}
FieldTypeRequiredDescription
verifiedbooleanYesMust be true
userIdstringNoYour internal user ID
identityobjectNoKey-value pairs available to the agent
metadataobjectNoAdditional data (not exposed to the agent)

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"
}
}
FieldTypeRequiredDescription
challengeIdstringYesUnique ID for this challenge (you generate it)
typestringYesSELECT_OPTION or TEXT_INPUT
promptstringYesMessage shown to the user
optionsarrayFor SELECT_OPTIONList of { label, value } choices
hintstringNoAdditional guidance for the user

SELECT_OPTION — The user picks from a list (e.g., masked phone numbers):

  • Present options[].label to 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 prompt and optional hint
  • The typed value is sent back as the answer

Return when credentials are invalid.

{
"verified": false,
"error": "Invalid credentials",
"retriesLeft": 2
}
FieldTypeRequiredDescription
verifiedbooleanYesMust be false
errorstringYesError message shown to the user
retriesLeftintegerNoHow many attempts remain (informational)

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.

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 typeRecommended TTLNotes
SELECT_OPTION (masked phones)5 minutesUser is already in the conversation
TEXT_INPUT (OTP code)3–5 minutesStandard OTP expiry window

Example (Redis/DynamoDB TTL):

// Store challenge with 5-minute TTL
await 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 };
}

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}`;
}

Configure which fields are collected from users in the extension settings.

Field typeHTML input typeAvailable on WebChatAvailable on Messaging
TEXTtextYesYes
EMAILemailYesYes
PASSWORDpasswordYesNo (auto-filtered)
SECRETpasswordYesNo (auto-filtered)
PHONEtelYesYes
DOCUMENT_IDtextYesYes

You can configure different fields for WebChat and messaging channels:

  • Login Form Fields (collectFields) — Default fields used by all channels. On messaging channels, PASSWORD and SECRET types 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.