Custom HTTP Tools & Webhooks
Build reliable mid-call REST integrations (`http_api`), store API keys in the Credentials Vault, use `body_template` & double-brace `{{param}}` substitution, test requests with header masking, and configure Post-Call Webhooks.
Custom HTTP Tools & Webhooks
When your agent needs live data during a conversation—booking a slot in Google Calendar, looking up an order in Shopify, or creating a lead in HubSpot/Zoho—you attach Custom HTTP Tools (http_api) to your Agent nodes. For guaranteed post-call CRM syncing, you add a Post-Call Webhook (webhook) node to the canvas.
Step 1: Store Secrets in the Credentials Vault
Never paste API tokens or Basic Auth passwords directly into raw tool headers. Store them once per organization in the Credentials Vault (/api/v1/credentials) and reference them by credential_uuid. (Full CRUD: GET/POST /api/v1/credentials/ and GET/PUT/DELETE /api/v1/credentials/{credential_uuid}; duplicate org name returns 409.)
Supported Credential Types
credential_type | Required credential_data Keys | Outbound Header Injected |
|---|---|---|
none | {} (must be empty) | None |
api_key | header_name, api_key | {header_name: api_key} (defaults header name to X-API-Key at runtime) |
bearer_token | token | Authorization: Bearer <token> |
basic_auth | username, password | Authorization: Basic <base64> |
custom_header | header_name, header_value | {header_name: header_value} (defaults header name to X-Custom at runtime) |
oauth2_client_credentials | client_id, client_secret, token_url (optional: scope, audience) | Authorization: Bearer <cached_token> |
Security & OAuth2 SSRF / Caching Behavior
- Write-only API boundary: Reading or listing credentials never returns
credential_data—secrets cannot be read back through the API once saved. - OAuth2 SSRF & caching:
oauth2_client_credentialsrequires anhttps://token_urlwith SSRF protection blocking private/loopback/internal hosts (10stoken fetch timeout, requiring200,token_type: bearer,access_token). Tokens cache in Redis with a 60-second pre-expiry buffer (short tokens withexpires_in <= 60bypass caching) and auto-invalidate on credential update/delete. - 401 auto-retry behavior: Pre-call fetch, Post-Call Webhook deliveries, dynamic transfer resolvers, and remote MCP sessions automatically invalidate the cached OAuth2 token and retry once on HTTP
401. Mid-callhttp_apitool calls (and tool test runs) do NOT auto-retry on401—they return the status directly.
Interactive Credentials API
AuthorizationBearer <token>Authenticated builder/user JWT or API key for dashboard-scoped management endpoints.
Credential metadata list
curl -X GET 'https://api.talkar.in/api/v1/credentials/'AuthorizationBearer <token>Authenticated builder/user JWT or API key for dashboard-scoped management endpoints.
application/json- body
name*stringdescription?stringcredential_type*string"none""api_key""bearer_token""basic_auth""oauth2_client_credentials""custom_header"credential_data*Created credential metadata
curl -X POST 'https://api.talkar.in/api/v1/credentials/' \ -H 'Content-Type: application/json' \ -d '{ "name": "string", "credential_type": "none", "credential_data": {}}'Step 2: Configure Tools (http_api & All 6 Categories)
Organizations manage typed tools via /api/v1/tools across 6 categories: http_api, end_call (endCallReason: true injects a required reason parameter for the LLM), transfer_call, calculator, wait, and mcp.
Core http_api Configuration Fields
method:GET,POST,PUT,PATCH, orDELETEurl: Destination endpoint. Supports double-brace path placeholders like`https://api.example.com/orders/{{order_id}}`(single{order_id}is sent literally!).credential_uuid: Reference to your stored Vault credentialheaders: Static custom headers (Vault credential headers overwrite any colliding keys inheaders)timeout_ms: Request timeout in milliseconds (>= 1, default5000ms)customMessage&customMessageType: Optional spoken filler (textor pre-recordedaudioviacustomMessageRecordingId) played while waiting on slow APIs.
Parameter Modes: parameters vs preset_parameters
- LLM Parameters (
parameters): Exposed in the LLM function schema. Each parameter defines aname(regex^[a-zA-Z0-9_\-]+$, no spaces/dots),type(string,number,boolean,object, orarray— noteintegeris NOT valid),description, andrequiredflag. - Preset Parameters (
preset_parameters): Hidden from the LLM and configured with avalue_templatesupporting`{{initial_context.*}}`,`{{gathered_context.*}}`, and flat initial context keys, coerced to declared types. At live runtime,preset_parameterstake precedence over LLMparametersif both share a name. - Reserved Names: Names cannot collide with reserved system prefixes (
initial_context,gathered_context,current_time*,current_weekday*).
How Parameters Map to the Outbound Request
- Path substitution (
`{{param}}`in URL): Matches`{{param}}`inurl, URL-encodes the value, and strips consumed path params from query params / default JSON bodies on live execution (while keeping them available forbody_templateinterpolation). GET&DELETErequests: Remaining parameters become URL query parameters (object/arrayvalues JSON-stringified);body_templateis disallowed.POST,PUT,PATCHrequests:- Without
body_template: remaining parameters serialize as a flat JSON object. - With
body_template(must be a JSON objectdict, max depth20, max size64 KB/65,536bytes): interpolates`{{param}}`placeholders anywhere in the nested structure ({"properties": {"email": "{{email}}", "qty": "{{qty}}"}}). Using`"{{qty}}"`as the entire string value preserves native JSON types (number/boolean/object/array), whereas`"Ref-{{id}}"`coerces to a string. Undeclared placeholders or duplicate rendered keys are rejected on save.
- Without
Step 3: Test & Debug Live With POST /api/v1/tools/{tool_uuid}/test
Run the tool test endpoint before putting an agent on a live phone line. It accepts { "llm_params": {...}, "preset_params": {...} } and returns:
- Rendered
request_method,request_url,request_params,request_body, andconsumed_path_params(note: in test previews,request_paramsretains consumed path params and givesllm_paramsprecedence, whereas live calls strip path params and preferpreset_parameters) - Masked
request_headers(Vault credentials show only the last 4 characters) - Round-trip
duration_ms, HTTPstatus_code, and Diagnostic Error Hints on>= 400(400–5xx)
AuthorizationBearer <token>Authenticated builder/user JWT or API key for dashboard-scoped management endpoints.
tool_uuid*stringapplication/json- body
llm_params?preset_params?ToolTestResponse with rendered request & live upstream response
curl -X POST 'https://api.talkar.in/api/v1/tools/string/test' \ -H 'Content-Type: application/json' \ -d '{}'Mid-Call Tool vs. Post-Call Webhook Node: When to Use Which
| Need | Use http_api Tool on Agent Node | Use Post-Call Webhook Node (webhook) |
|---|---|---|
| Agent needs the HTTP response to answer the caller | Yes — response JSON feeds back to the LLM to speak mid-call | No — Webhook Nodes are disconnected (0 edges) and execute asynchronously after the call ends |
Must fire deterministically after every finished call (with extracted_data, QA tags, recording & transcript URLs) | Risky — LLM chooses when to call mid-call tools | Yes — fires reliably after QA & Post-Call Intelligence finish (30s timeout, up to 5 attempts with 30s–600s backoff; dead-letters permanent 4xx) |
| Custom static secret headers allowed? | Yes (overridden by Vault credential if key collides) | Static custom_headers with secret keywords (authorization, auth, token, secret, password, passwd, cookie, credential, api-key, apikey, api_key, access-key) are stripped except X-Idempotency-Key — use credential_uuid |
For multi-step CRM workflows, keep mid-call http_api responses small and flat—strip huge arrays, nested metadata, and HTML fields in https://n8n.talkar.in before returning JSON to the LLM.
Copy-Paste Sample Payloads
1. Post-Call Webhook payload_template
At webhook delivery time, only call_disposition is auto-injected if your template omits it ("" if unset). Any extracted variables, QA outputs, or media download URLs you want in n8n.talkar.in or your CRM must be mapped explicitly in payload_template:
{
"run_id": "{{workflow_run_id}}",
"run_name": "{{workflow_run_name}}",
"call_time": "{{call_time}}",
"phone_number": "{{initial_context.called_number | fallback:unknown}}",
"duration_seconds": "{{cost_info.call_duration_seconds}}",
"call_disposition": "{{gathered_context.call_disposition | default}}",
"lead_name": "{{initial_context.customer_name | default}}",
"intent": "{{extracted_data.intent | default}}",
"live_vars_json": "{{gathered_context.extracted_variables}}",
"post_call_json": "{{extracted_data}}",
"qa_tags_json": "{{annotations.tags}}",
"recording_url": "{{recording_url}}",
"transcript_url": "{{transcript_url}}"
}Webhook render-context & stringification quirks
- Every placeholder renders to a string in webhooks: Unlike mid-call
http_apibody_template, webhookpayload_templateserializes placeholders via string substitution—numbers become strings (e.g."142"or""), anddict/listobjects such as{{gathered_context.extracted_variables}},{{extracted_data}}, and{{annotations.tags}}serialize to JSON-encoded strings (json.dumps, soJSON.parse()inn8n.talkar.in, or reference leaf fields directly like{{extracted_data.intent}}). - Use
| default(not empty| fallback:) for blank defaults:| fallback:}}with nothing after:does not match the template regex and outputs the literal{{...}}token. Use{{var | default}}or plain{{var}}to resolve missing values to"". cost_infoholds usage metrics:{{cost_info.call_duration_seconds}}readsusage_infoinside webhook templates.extracted_datavs.gathered_context.extracted_variables: Inside webhook templates,{{extracted_data}}is the Post-Call Intelligence (post_call_schema) output, while node-level live extractions sit in{{gathered_context.extracted_variables}}(and top-level{{gathered_context.<key>}}).GET/DELETEwebhooks: No JSON body or query string is attached automatically forGETorDELETEwebhook nodes; usePOST,PUT, orPATCHto sendpayload_template.
2. Dynamic transfer_call Resolver Request & Response
When a transfer_call tool uses destination_source: "dynamic", Talkar always sends an HTTP POST request (timeout_ms 500–5000, default 3000) with a flat JSON body combining LLM-provided parameters and server-side preset_parameters (presets overwrite same-named LLM keys; no extra run metadata is sent unless added as a preset):
{
"department": "billing",
"account_id": "acct_123"
}Return HTTP 2xx with transfer_context.destination (required non-empty phone number or SIP target) and optional transfer_context.custom_message (overrides static tool pre-transfer message when non-empty):
{
"transfer_context": {
"destination": "+14155550123",
"custom_message": "Connecting you with our billing specialist now."
}
}Pre-Call Data Fetch & Dynamic Variables
Load CRM records into `initial_context` before the first greeting using Pre-Call Fetch, Campaign CSV columns, or Trigger API payloads.
Knowledge Bases & RAG Search
Upload PDFs, DOCX, TXT, or Markdown documents via presigned S3 upload, understand the 5 MB processing limit, choose between `chunked` and `full_document` retrieval, and test semantic search.