Now in early access·Start your 14-day free trial →
By Your Side
Sign inBook a demoStart free trial

Documentation

API reference

Base URL: https://api.byourside.ai. All endpoints require Authorization: Bearer bys_ak_... (your agent key). Request and response bodies are JSON.

Authentication

Every request must include an Authorization header with your agent API key. Keys are created in your account under Account - Developers.

HeaderValue
AuthorizationBearer bys_ak_YOUR_KEY

Place a call

POST /v1/agent/calls

Validates the request, runs guardrails, creates a call record with status queued, and immediately returns a callId. The call runs asynchronously. Guardrail failures return a 4xx before any call is placed.

Request body

FieldTypeRequiredDescription
tostringYesDestination number in E.164 format, e.g. +14155550123.
objectivestringYesWhat the AI should accomplish on the call. Write it as a clear goal in plain text.
contextstringNoBackground information the AI should know before the call. Not shared with the recipient.
fieldsarrayNoStructured fields to extract from the transcript. Up to 20 items. Each item: { name, type?, description? }. type is one of string (default), boolean, or number.
webhookUrlstringNoHTTPS URL to receive signed webhook events during and after the call. See Webhooks.
callerIdstringNoCaller ID override. Must be a number on your account (E.164). Defaults to the number set in your Developers dashboard.
Place a call (request)
POST /v1/agent/calls
Authorization: Bearer bys_ak_YOUR_KEY
Content-Type: application/json

{
  "to":        "+14155550123",
  "objective": "Book a table for 4 at 7 PM Friday. Confirm the time and ask for their name.",
  "context":   "We have dined here before. Our preference is a window seat.",
  "fields": [
    { "name": "booked",         "type": "boolean", "description": "Did they confirm the booking?" },
    { "name": "confirmed_time", "type": "string",  "description": "The time they confirmed"       },
    { "name": "contact_name",   "type": "string",  "description": "Name given for the reservation"}
  ],
  "webhookUrl": "https://your-server.example.com/webhooks/bys",
  "callerId":   "+12134932550"
}

Response

Place a call (response)
{
  "callId": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
  "status": "queued"
}

Structured field extraction

Pass a fields array when placing the call. After the call ends, By Your Side extracts each field from the transcript and populates the extracted object in the call record and webhook payload. Fields not found in the conversation are returned as null.

fields - request
"fields": [
  { "name": "confirmed",  "type": "boolean" },
  { "name": "amount",     "type": "number",  "description": "Price quoted in USD" },
  { "name": "next_steps", "type": "string",  "description": "What the contact said they will do next" }
]
extracted - response
"extracted": {
  "confirmed":  true,
  "amount":     249,
  "next_steps": "They will email a signed contract by end of day Thursday."
}

Get a call

GET /v1/agent/calls/{id}

Returns the current state of a call. Calls are tenant-scoped: you can only fetch calls placed by your own key.

Response fields

FieldTypeDescription
idstringThe call ID.
statusstringCurrent status. See lifecycle below.
tostringDestination number (E.164).
objectivestringThe objective you supplied.
summarystring | nullPlain-English summary of the call. Set on completed.
transcriptstring | nullFull transcript of the conversation.
extractedobject | nullExtracted field values keyed by field name.
recordingUrlstring | nullAuthenticated URL to the call recording.
startedAtstring | nullISO 8601 timestamp when the call was answered.
endedAtstring | nullISO 8601 timestamp when the call ended.
durationSecnumber | nullCall duration in seconds.
errorstring | nullError token on failed calls.
Get a call (response)
{
  "id":          "f47ac10b-58cc-4372-a567-0e02b2c3d479",
  "status":      "completed",
  "to":          "+14155550123",
  "objective":   "Book a table for 4 at 7 PM Friday.",
  "summary":     "The restaurant confirmed a table for 4 at 7 PM Friday in the name of Smith, window section.",
  "extracted": {
    "booked":         true,
    "confirmed_time": "7 PM Friday",
    "contact_name":   "Smith"
  },
  "transcript":   "...",
  "recordingUrl": "https://api.byourside.ai/v1/agent/calls/f47ac10b-58cc-4372-a567-0e02b2c3d479/recording",
  "startedAt":    "2026-06-17T14:03:12.000Z",
  "endedAt":      "2026-06-17T14:05:48.000Z",
  "durationSec":  156
}

List calls

GET /v1/agent/calls?limit=20

Returns recent calls for your account, most recent first. Each item in the array has the same shape as GET /v1/agent/calls/{id}.

Query paramTypeDefaultDescription
limitnumber20Maximum number of calls to return. Max 100.
List calls (response)
{
  "calls": [
    {
      "id":          "f47ac10b-58cc-4372-a567-0e02b2c3d479",
      "to":          "+14155550123",
      "objective":   "Book a table for 4 at 7 PM Friday.",
      "status":      "completed",
      "summary":     "Confirmed table for 4 at 7 PM Friday.",
      "startedAt":   "2026-06-17T14:03:12.000Z",
      "endedAt":     "2026-06-17T14:05:48.000Z",
      "durationSec": 156
    }
  ]
}

Status lifecycle

Statuses queued, dialing, and in_progress are non-terminal. Poll or use a webhook until you see one of the five terminal statuses.

StatusTerminalMeaning
queuedNoAccepted; call not yet dialing.
dialingNoDialing the destination.
in_progressNoCall is live; AI is speaking.
completedYesCall finished normally. Summary and extracted fields available.
no_answerYesDestination did not pick up.
voicemailYesReached voicemail.
declinedYesCall rejected by recipient.
failedYesTechnical failure. Retry if the issue is transient.

Guardrails

The following rules apply to every call. Violations are rejected at placement time with a 400 error; no call is placed or billed.

  • Allowed destinations: US, CA, GB, AU, NZ, and IL. Calls to other countries are rejected with destination_blocked.
  • Blocked number types: Premium-rate, satellite, and IRSF-listed numbers are always blocked, regardless of country.
  • Rate limit: A maximum number of calls per minute applies per API key. Excess requests return 429 rate_limited.
  • Usage cap: Outbound minutes are drawn from your plan allowance. Once the cap is reached, additional calls return 429 over_minute_cap.
  • Caller ID ownership: The callerId (or your account default) must be a number on your account. An unrecognized number returns 400 caller_id_not_owned.

Error reference

HTTP statusError tokenMeaning
400to_requiredThe to field is missing.
400objective_requiredThe objective field is missing.
400invalid_numberThe destination is not a valid E.164 number.
400destination_blockedThe destination is blocked (premium, IRSF, or unsupported country).
400caller_id_not_ownedThe callerId is not a number on your account.
400invalid_fieldsThe fields array is malformed or exceeds the 20-item limit.
400invalid_contextThe context field is the wrong type (must be a string).
400invalid_caller_idThe callerId field is the wrong type (must be a string in E.164 format).
400invalid_webhook_urlThe webhookUrl is not a valid HTTPS URL.
401unauthorizedMissing or invalid API key.
429rate_limitedToo many calls per minute. Retry after a short wait.
429over_minute_capOutbound usage limit reached for this billing period.
502placement_failedCarrier or trunk issue. Retry shortly.
503store_errorTemporary service error. Retry shortly.

Error responses have the shape { "error": "token" }.