Skip to main content

Base URL

https://hub.knotie-ai.pro

Endpoint

MethodPathAuthPurpose
POST/api/outbound-callPer-number webhook tokenExternal systems (GHL, n8n, Zapier, Facebook lead bridge)

Authentication

Pass the per-number outbound webhook token via one of these headers:
Authorization: Bearer <token>
or
X-API-Key: <token>
Generate the token in the Partner Portal under the phone number’s Outbound Settings. Tokens are:
  • Scoped to a single phone number — the from_number in the request must match the number the token belongs to.
  • Shown once at generation time; only a secure hash is stored.
  • Revocable at any time from the portal.
Brute-force protection: after 10 failed auth attempts from the same IP within 5 minutes, that IP is blocked for 15 minutes.

Request body

Standard format

{
  "from_number": "+14155551234",
  "to_number": "+19876543210",
  "dynamic_variables": {
    "lead_name": "Sarah",
    "outreach_topic": "Q3 renewal",
    "company": "Acme Corp"
  },
  "metadata": {
    "campaign_id": "camp_abc123",
    "external_id": "crm_lead_789"
  }
}
FieldTypeRequiredDescription
from_numberstringYesE.164 caller number. Must match a phone number registered in Knotie and assigned to a Knova agent.
to_numberstringYesE.164 number to call.
dynamic_variablesobjectNoKey-value pairs injected into the agent’s prompt and greeting as {{key}} placeholders.
metadataobjectNoArbitrary metadata stored with the call record. Not passed to the agent.
Phone numbers are auto-normalised to E.164 — a leading + is added if missing and non-digit characters are stripped.

GHL native format (auto-detected)

GoHighLevel workflows send a flat customData envelope. The integration gateway detects this automatically — no configuration needed.
{
  "contact_id": "abc123",
  "first_name": "Sarah",
  "last_name": "Jones",
  "customData": {
    "from_number": "+14155551234",
    "to_number": "+19876543210",
    "dynamicdata_lead_name": "Sarah Jones",
    "dynamicdata_outreach_topic": "Q3 renewal",
    "metadata_campaign_id": "camp_abc123"
  }
}
Normalisation rules:
GHL fieldMaps to
customData.from_numberfrom_number
customData.to_numberto_number
customData.dynamicdata_<name>dynamic_variables.<name>
customData.metadata_<name>metadata.<name>
Other top-level GHL fieldsIgnored
A body is treated as GHL format when it has no top-level from_number but has a customData.from_number.

Dynamic variables

Any key in dynamic_variables (or GHL dynamicdata_<name>) becomes a {{key}} substitution in the agent’s system prompt and greeting message. Example: Agent system prompt:
You are calling {{lead_name}} about {{outreach_topic}}.
Request:
{
  "dynamic_variables": {
    "lead_name": "Sarah",
    "outreach_topic": "Q3 renewal"
  }
}
Agent receives:
You are calling Sarah about Q3 renewal.
Keys not present in dynamic_variables are left as {{key}} — no error is thrown, but the agent will speak the literal placeholder.

Rate limiting

LimitValue
Calls per minute per phone number60
Auth failures before IP block10 in 5 minutes
IP block duration15 minutes
Rate limit headers are included on every response:
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
When the limit is exceeded:
HTTP 429
Retry-After: 60

Response

Success (200 OK)

{
  "success": true,
  "call_id": "550e8400-e29b-41d4-a716-446655440000",
  "provider": "knova",
  "agent_id": "agt_abc123",
  "from_number": "+14155551234",
  "to_number": "+19876543210",
  "provider_response": {
    "room_name": "knova-out-agt_abc123-550e8400",
    "trunk_mode": "byo"
  }
}
trunk_mode is either "byo" (partner’s own Twilio/Telnyx trunk) or "shared" (Knotie’s shared trunk).

Error

{
  "success": false,
  "error": "Human-readable description",
  "error_code": "ERROR_CODE"
}

Error codes

error_codeHTTPMeaning
VALIDATION_ERROR400Missing or invalid fields — a details array is included
UNAUTHORIZED401Missing, invalid, or inactive token; or token doesn’t match the from_number
INSUFFICIENT_CREDITS402Partner or customer does not have enough credits
NO_AGENT_MAPPING404No active Knova agent assigned to the from_number, or outbound is disabled
NO_OUTBOUND_TRUNK422The calling route for this number isn’t provisioned yet
DISPATCH_FAILED422The call could not be started — retry
CALL_REJECTED422The person you called declined or was busy
CALL_NO_ANSWER422No answer, or the line was temporarily unavailable
SIP_TRUNK_FAILURE422The telephony carrier returned an error
RATE_LIMITED429Per-number rate exceeded, or IP blocked after repeated auth failures
The call-related failures (NO_OUTBOUND_TRUNK, DISPATCH_FAILED, CALL_REJECTED, CALL_NO_ANSWER, SIP_TRUNK_FAILURE) all return HTTP 422 with a JSON body — rather than a 5xx status — so your integration always receives a machine-readable error you can act on.

Full example — curl

curl -X POST https://hub.knotie-ai.pro/api/outbound-call \
  -H "Authorization: Bearer owt_xxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "from_number": "+14155551234",
    "to_number": "+19876543210",
    "dynamic_variables": {
      "lead_name": "Sarah",
      "outreach_topic": "your Q3 renewal"
    },
    "metadata": {
      "source": "ghl_workflow"
    }
  }'
Expected response:
{
  "success": true,
  "call_id": "550e8400-e29b-41d4-a716-446655440000",
  "provider": "knova",
  "agent_id": "agt_abc123",
  "from_number": "+14155551234",
  "to_number": "+19876543210",
  "provider_response": {
    "room_name": "knova-out-agt_abc123-550e8400",
    "trunk_mode": "byo"
  }
}

Compatibility note

The Knova response envelope is intentionally identical to the Retell outbound response shape. If you already handle Retell outbound call responses in your integration, you do not need to update your response-handling code when switching a number to a Knova agent.