עבריתLog in

API reference

Every endpoint, field, event and status.

Overview

Base URL https://api.oneli.io. Every endpoint here needs Authorization: Bearer oli_… (an API key or a connected agent’s token), except GET /v1/voices. Request bodies are JSON. Errors follow the error format. Endpoints that need a person to sign in (billing, profile, keys) are not listed.

Create a call task

POST/v1/call-tasks

FieldTypeDescription
idempotency_keystring ≤100requiredUnique per request. The same key again returns the existing task (200, created: false) and creates no call, even if the rest of the body differs.
to_numberstringrequiredAn Israeli number: mobile 05X, landline 02/03/04/08/09 or 07X. 0501234567, 050-123-4567 and +972501234567 are accepted. Invalid: 400 INVALID_NUMBER.
goalstring 1–500requiredWhat the call should achieve, in plain words.
instructionsstring ≤2000optionalHow to conduct the call: tone, details, limits.
constraintsobjectoptionalConstraints. max_price_ils (number): above it the voice agent consults you. fallback (string): what to do if the goal cannot be met.
dynamic_variablesobject<string,string>optionalopening_line: the first sentence of the call (up to 300 characters). If it does not say the caller is a digital assistant, that is added.
consult_modepolicy | manual | silentoptionalWho answers consultations. manual (default): you, via the API, webhook or the site. policy: answered at once: approve when every price mentioned is within constraints.max_price_ils, otherwise ask_user. silent: never consult; the voice agent commits to nothing (ask_user). With policy and silent the webhook is not called, and the consultation appears in events with answered_via=policy.
max_duration_sinteger 30–1800optionalMaximum call length in seconds. Default 300, max 1800. Also capped by the minutes left on your plan.
menu_dataobject<string,string>optionalData the user explicitly approved for keying into a phone menu, e.g. id_number (digits, * and # only, up to 5). Never guessed, never logged.
max_cost_minorinteger 1–100000optionalCost cap in agorot for accounts without a plan (prepaid balance). Default 300. On a plan, calls are measured in minutes.

Response: 201 with {task, created: true}, or 200 with {task, created: false} when the key was used before. Outside calling hours the task is queued and not_before shows when it will be dialed.

Errors: 400 VALIDATION · 400 INVALID_NUMBER · 403 LEGAL_ACCEPTANCE_REQUIRED · 403 CALLS_PAUSED · 403 NO_PLAN · 403 QUOTA_EXHAUSTED · 403 QUOTA_HELD · 403 DO_NOT_CALL · 429 DAILY_CALL_LIMIT · 429 NUMBER_DAILY_LIMIT

List tasks

GET/v1/call-tasks

The last 50 tasks, newest first: {tasks: [...]}. Each item has id, goal, to_number, status, outcome, created_at, not_before, attempts, duration_s, cost_minor, currency, billing, summary, status_detail. billing is plan or wallet.

Get a task

GET/v1/call-tasks/:id

Returns {task, pending_consultation}. The task has every field you sent plus status, outcome, revision (for instructions), attempts, summary, call_end (the payload of the last call.ended event) and status_detail. Call content is deleted after content_expires_at.

200 OK
{
  "task": {
    "id": "task_44be8f8d43da4748",
    "idempotency_key": "order-1234-call",
    "to_number": "972501234567",
    "goal": "לבדוק אם הזמנה 1234 מוכנה לאיסוף",
    "instructions": "",
    "constraints": { "max_price_ils": 50 },
    "dynamic_variables": {},
    "consult_mode": "manual",
    "max_duration_s": 180,
    "max_cost_minor": 300,
    "status": "completed",
    "outcome": "goal_achieved",
    "revision": 2,
    "not_before": "2026-10-22T09:14:03.120Z",
    "expires_at": "2026-10-23T09:14:03.120Z",
    "created_at": "2026-10-22T09:14:03.120Z",
    "updated_at": "2026-10-22T09:16:40.502Z",
    "content_expires_at": "2026-11-21T09:14:03.120Z",
    "attempts": 1,
    "summary": "ההזמנה מוכנה לאיסוף עד 18:00 היום.",
    "call_end": { "reason": "ended", "outcome": "goal_achieved", "duration_s": 74, "cost_minor": 0, "attempt": 1,
                  "currency": "ILS", "included_seconds": 74, "overage_seconds": 0, "summary": "…" },
    "status_detail": null
  },
  "pending_consultation": null
}

pending_consultation is null, or {id, question, options, context_summary, deadline_at} while a decision is waiting.

Errors: 404 TASK_NOT_FOUND

Events

GET/v1/call-tasks/:id/events?after=<sequence>&limit=<n>&wait=<seconds>

wait (0–25): long polling. With no new events the request waits until one arrives (in under a second) or the time runs out, so you follow a call line by line without polling every few seconds. The response also has last_user_decision: a decision the user made on the card or site, which instructions must not override. Special events: agent.unverified_claim (the voice agent stated a date, time or price the other side never said: {text, claims}) and call.end_held (the voice agent is about to end; a few seconds remain for a last instruction). In a phone menu (gradual rollout, may be off): ivr.entered, ivr.prompt, ivr.action (personal data appears only as a label like menu_data:id_number), ivr.hold, ivr.person_detected, ivr.handoff, ivr.back_to_menu, ivr.gave_up (the task ends not_achieved), ivr.unavailable, plus consultation.cancelled (the question is closed; do not answer it).

after: the last sequence number you have read (default 0). limit: up to 200, default 50. Response: {events, next_cursor, pending_consultation}. Each event: sequence, type, payload, source, occurred_at. With no new events, next_cursor equals after.

200 OK
{
  "events": [
    { "sequence": 1, "type": "task.queued", "payload": { "goal": "…" }, "source": "api", "occurred_at": "…" },
    { "sequence": 2, "type": "call.dispatching", "payload": { "attempt_id": "att_…" }, "source": "scheduler", "occurred_at": "…" },
    { "sequence": 5, "type": "transcript.final", "payload": { "speaker": "agent", "text": "שלום, אני עוזרת דיגיטלית…" }, "source": "voice", "occurred_at": "…" },
    { "sequence": 9, "type": "consultation.requested",
      "payload": { "consultation_id": "con_…", "question": "…", "options": ["approve", "decline", "ask_user"],
                   "context_summary": "…", "deadline_at": "…" }, "source": "voice", "occurred_at": "…" },
    { "sequence": 14, "type": "call.ended",
      "payload": { "reason": "ended", "outcome": "goal_achieved", "duration_s": 74, "cost_minor": 0, "attempt": 1, "summary": "…" },
      "source": "voice", "occurred_at": "…" }
  ],
  "next_cursor": 14,
  "pending_consultation": null
}

Full transcript

GET/v1/call-tasks/:id/transcript

The whole conversation in one response, in order: who spoke (agent is OneLi’s voice agent, callee the other side) and what was said, without voice-style tags. Also has status, outcome and summary. Works with an API key. After the retention period the transcript is deleted and content_deleted is true.

200 OK
{
  "task_id": "task_9380c85c2043caf3",
  "status": "completed",
  "outcome": "goal_achieved",
  "summary": "An appointment was booked for Tuesday at 10:30.",
  "content_deleted": false,
  "transcript": [
    { "speaker": "agent",  "text": "Hi, this is Daniel’s digital assistant…", "at": "2026-10-23T08:01:12Z" },
    { "speaker": "callee", "text": "Yes, how can I help?", "at": "2026-10-23T08:01:16Z" }
  ]
}

Errors: 404 TASK_NOT_FOUND

Send an instruction

POST/v1/call-tasks/:id/instructions

FieldTypeDescription
instructionstring 1–1000requiredThe instruction for the voice agent.
expected_revisionintegerrequiredThe task’s current revision. If it changed: 409 REVISION_CONFLICT.
idempotency_keystring ≤100optionalThe same key again returns the original result.
modecontextual | user_messageoptionalDefault contextual.
urgentbooleanoptionalA correction that must be said now: the voice agent stops what it is saying and says it at once. The newest instruction always overrides earlier ones.

Response: {command_id, revision, status: "pending"}. In an active call the instruction applies from the voice agent’s next turn. For a task still in the queue it is saved and added to the call’s instructions when it dials (and to any redial).

Errors: 409 REVISION_CONFLICT · 409 CALL_NOT_ACTIVE · 404 TASK_NOT_FOUND

Cancel

POST/v1/call-tasks/:id/cancel

FieldTypeDescription
reasonstringoptionalLogged. Default cancelled_by_user; it also becomes the outcome of a task cancelled while queued.

Response: {status: "cancelled"} for a queued task, or {status: "cancel_requested"} for an active call.

Errors: 409 CALL_NOT_ACTIVE · 404 TASK_NOT_FOUND

Listen live

POST/v1/call-tasks/:id/listen

Returns {url, expires_at}: a WebSocket URL for the live call, valid 60 seconds. Listen-only, both sides mixed, never recorded or stored; the other side is told when someone starts listening. Stream: PCM 16-bit LE mono 8000 Hz. Scope calls:read, up to 10 per call per minute.

Errors: 409 CALL_NOT_ACTIVE · 404 TASK_NOT_FOUND · 429 RATE_LIMITED · 503 LISTEN_NOT_CONFIGURED

Answer a consultation

POST/v1/consultations/:id/response

FieldTypeDescription
decisionapprove | decline | ask_userrequiredMust be one of the consultation’s options. ask_user is always available.
reasonstring ≤500optionalSaved in the call log. Not read out to the other side.
digitsstring [0-9*#] ≤20optionalPhone-menu questions only (menu: true), with approve, and only data the user explicitly approved. Pressed once, never stored.

Response: {status: "accepted"}; {status: "expired"} if the deadline passed; or {status: "conflict", decision} if another answer came first. The first answer wins.

Errors: 400 BAD_DECISION · 404 CONSULTATION_NOT_FOUND

Decision webhook

PUT/v1/decision-webhook

Body: {url} (up to 500 characters, public https on port 443). Response: {url, secret}. The whsec_… secret is shown once; setting it again rotates the secret.

GET/v1/decision-webhook

{webhook: {url, created_at, last_status, last_delivery_at} | null}

DELETE/v1/decision-webhook

{deleted: true} · Full guide

Errors: 400 BAD_WEBHOOK_URL

Account

GET/v1/me

{user, wallet, plan, rate_per_minute_minor, legal, terms_required}. plan has the plan code, available_seconds and period_end, or is null. Useful to check the connection and the quota before creating a task.

GET/v1/wallet

{currency, available, balance, reserved} (in agorot)

Voices

GET/v1/voices

No auth. {voices: [{id, name, gender, style, preview_url}], default_voice_id}. The voice is chosen in your profile on the site, not per task.

Event types

TypepayloadMeaning
task.queuedgoal, scheduled_for?, reason?Task created. Outside calling hours: scheduled_for and reason: "quiet_hours".
call.dispatchingattempt_idA dial attempt starts.
call.ringing-Ringing.
call.connected-The call was answered. May appear more than once.
transcript.finalspeaker (agent | callee), textA final transcript line.
consultation.requestedconsultation_id, question, options, context_summary, deadline_atThe voice agent asks for a decision.
consultation.answeredconsultation_id, decision, reason, answered_viaAn answer was accepted. answered_via: agent, webhook, web or card.
consultation.expiredconsultation_idNo answer in time. The voice agent continues without committing.
instruction.acceptedcommand_id, revision, textAn instruction was accepted.
call.endedreason, outcome, duration_s, cost_minor, attempt, summary?, currency?, included_seconds?, overage_seconds?The dial attempt ended. duration_s is the billed seconds.
task.retry_scheduledreason, attempt, max_attempts, retry_atBusy or no answer: another try is scheduled.
task.cancel_requestedreasonA hang-up was sent to an active call.
task.cancelledreasonA queued task was cancelled.
task.failedreasonThe task failed before dialing: do_not_call, quota_exhausted or insufficient_balance.
task.expiredreason, not_before, expires_atThe task was not dialed in time.
callee.do_not_call-The person called asked not to be called again.
call.reconcilingerrorThe dial result is temporarily unknown. No blind redial.

Other types may appear (for example internal quality events). Ignore types you do not recognise.

Statuses and outcomes

statusMeaning
queuedWaiting: for calling hours, a free line or a retry.
dispatchingDialing.
activeThe call is connected.
reconcilingChecking a dial whose result was lost.
completedFinal. The call took place, or every try was busy or unanswered.
failedFinal. For example a wrong number, voicemail or no minutes left.
cancelledFinal. Cancelled.
expiredFinal. Not dialed within 24 hours of not_before.
outcomeMeaning
goal_achievedThe goal was reached.
partially_achievedPart of the goal was reached.
not_achievedThe goal was not reached.
declinedThe consultation was answered decline.
needs_user_inputThe decision came back to you (ask_user or no answer).
endedThe call ended without a reported result.
busyBusy. Retried up to 3 dials in total, after 5 and 15 minutes, within calling hours and daily limits.
no_answerNo answer. Same retry policy.
voicemailReached voicemail. Not charged.
invalid_numberThe number does not exist or the network rejected it. Never retried.
do_not_callThe number is on the do-not-call list.
quota_exhaustedNo minutes left on the plan.
expiredNot dialed in time.

status_detail explains in one line what happened after an unanswered dial: {code, he, en, retry_at?}. For example busy_will_retry with the next try time, no_answer_final after the last try, or invalid_number. Otherwise it is null.