Documentation Index Fetch the complete documentation index at: https://docs.layercode.com/llms.txt
Use this file to discover all available pages before exploring further.
When you create a new conversation and authorize a client session you can set custom metadata and custom headers on the session webhook configuration (either on the agent itself or per-session via a config override).
Add them to your agent’s session_webhook config, or send a one-off override in the config field when calling POST /v1/agents/web/authorize_session (see REST API docs ). Both fields must be plain JSON objects. For agent.webhook plugin requests, set custom_headers / custom_metadata in the plugin options to have them included on every agent webhook call.
curl -X POST https://api.layercode.com/v1/agents/web/authorize_session \
-H "Authorization: Bearer $LAYERCODE_API_KEY " \
-H "Content-Type: application/json" \
-d '{
"agent_id": "dvv052qk",
"config": {
"type": "voice",
"clients": {
"browser": {
"enabled": true
}
},
"plugins": [
{ "use": "stt.deepgram", "options": { "model_id": "flux" } },
{ "use": "turn_manager", "options": { "mode": "automatic" } },
{ "use": "agent.llm", "options": { "provider": "google", "model_id": "gemini-2.5-flash-lite" } },
{ "use": "tts.rime", "options": { "model_id": "mistv2", "voice_id": "courtney" } }
],
"session_webhook": {
"url": "https://example.com/session-webhook",
"events": ["session.start", "session.end", "session.update"],
"custom_metadata": { "tenant_id": "t_42", "crm_contact_id": "abc-123" },
"custom_headers": { "x-tenant-id": "t_42" }
}
}
}'
Next.js app/api/authorize/route.ts
export const dynamic = "force-dynamic" ;
import { NextResponse } from "next/server" ;
export const POST = async ( request : Request ) => {
// Here you could do any user authorization checks you need for your app
const endpoint = "https://api.layercode.com/v1/agents/web/authorize_session" ;
const apiKey = process . env . LAYERCODE_API_KEY ;
if ( ! apiKey ) {
throw new Error ( "LAYERCODE_API_KEY is not set." );
}
const requestBody = await request . json ();
if ( ! requestBody || ! requestBody . agent_id ) {
throw new Error ( "Missing agent_id in request body." );
}
requestBody . config = {
type: "voice" ,
clients: {
browser: {
enabled: true
}
},
plugins: [
{ use: "stt.deepgram" , options: { model_id: "flux" } },
{ use: "turn_manager" , options: { mode: "automatic" } },
{ use: "agent.llm" , options: { provider: "google" , model_id: "gemini-2.5-flash-lite" } },
{ use: "tts.rime" , options: { model_id: "mistv2" , voice_id: "courtney" } }
],
session_webhook: {
url: "https://example.com/session-webhook" ,
events: [ "session.start" , "session.end" , "session.update" ],
custom_metadata: {
tenant_id: "t_42" ,
crm_contact_id: "abc-123"
},
custom_headers: {
"x-tenant-id" : "t_42" ,
"x-layercode-flow" : "concierge"
}
}
}
try {
const response = await fetch ( endpoint , {
method: "POST" ,
headers: {
"Content-Type" : "application/json" ,
Authorization: `Bearer ${ apiKey } ` ,
},
body: JSON . stringify ( requestBody ),
});
if ( ! response . ok ) {
const text = await response . text ();
throw new Error ( text || response . statusText );
}
return NextResponse . json ( await response . json ());
} catch ( error : any ) {
console . log ( "Layercode authorize session response error:" , error . message );
return NextResponse . json ({ error: error . message }, { status: 500 });
}
};
See all 61 lines
Every webhook invocation now includes the metadata you provided:
{
"type" : "message" ,
"session_id" : "a0ad4pv43sdakgh99lxeik8x" ,
"conversation_id" : "ary4c07o15n5l43iu7dkhukt" ,
"custom_metadata" : {
"tenant_id" : "t_42" ,
"crm_contact_id" : "abc-123"
},
// ...
}
Layercode prepends two headers to every webhook call: Content-Type: application/json and layercode-signature. Your custom headers are then appended.
export async function POST ( request : Request ) {
const xTenantId = request . headers . get ( 'x-tenant-id' );
// ...
const payload = await request . json ();
// ...
}