REST API ומפתחות

אימות עם מפתח API, ושיחה מלאה בקוד: יצירה, מעקב, התייעצות, הנחיה וביטול.

מפתחות API

  1. נכנסים ל־oneli.io/app/connect ובכרטיס מפתחות API לוחצים ליצירת מפתח.
  2. נותנים שם (1 עד 60 תווים) ובוחרים תוקף: 90 יום (ברירת מחדל), שנה, או ללא תפוגה.
  3. המפתח, שמתחיל ב־oli_, מוצג פעם אחת בלבד. שומרים אותו במשתנה סביבה או במנהל סודות, למשל ONELI_API_KEY. אצלנו נשמר רק גיבוב שלו.
  • ברשימת המפתחות מופיעים ארבעת התווים האחרונים, מתי נוצר, מתי שימש לאחרונה ומתי יפוג. אפשר לבטל מפתח בכל רגע.
  • מפתחות נוצרים רק באתר, אחרי התחברות של אדם. אין נקודת קצה ליצירת מפתח עם מפתח.
  • מפתח שפג תוקפו או שבוטל מקבל 401 UNAUTHENTICATED. עד 20 מפתחות וסוכנים מחוברים פעילים לחשבון (429 TOO_MANY_AGENTS).

מפתח יכול לעבוד רק עם נקודות הקצה האלה. כל השאר (חיוב, פרופיל, מסלולים, מפתחות) מחזירות 403 INSUFFICIENT_SCOPE:

שיטהנתיב
GET/v1/me · /v1/wallet
GET/v1/call-tasks · /v1/call-tasks/:id · /v1/call-tasks/:id/events
POST/v1/call-tasks · /v1/call-tasks/:id/instructions · /v1/call-tasks/:id/cancel
POST/v1/consultations/:id/response
GET · PUT · DELETE/v1/decision-webhook
…הסוכנים שלכם: הגדרות, ידע, שיחות, שיחות יוצאות ווואטסאפ
מפתח API שייך לשרת בלבד. ל־API המאומת אין CORS, ולכן קריאה מדפדפן נחסמת, ומפתח בקוד צד לקוח חשוף לכל מי שפותח את העמוד. אם מפתח דלף, בטלו אותו מיד ב־/app/connect וצרו חדש.

כתובת בסיס ובקשות

Base URL
https://api.oneli.io
  • כל בקשה עם הכותרת Authorization: Bearer oli_….
  • גוף בקשה ב־JSON עם Content-Type: application/json, עד 100KB.
  • זמנים בפורמט ISO 8601 ב־UTC. מספרי טלפון חוזרים בפורמט בינלאומי בלי +, למשל 972501234567.
  • שגיאות חוזרות כ־{"error":"CODE","message":"…"}. פירוט בשגיאות ומגבלות.

הדוגמאות בהמשך משתמשות בפונקציית עזר קטנה:

# Every request: the key in the Authorization header, JSON bodies.
export ONELI_API_KEY="oli_..."
export API="https://api.oneli.io"

מחזור החיים של שיחה

יוצרים משימה, עוקבים אחרי האירועים עד שהסטטוס סופי (completed,‏ failed,‏ cancelled או expired), עונים להתייעצויות כשהן מגיעות, ואפשר לשלוח הנחיות או לבטל בכל שלב.

1. יצירת משימה

מחליפים את 05XXXXXXXX במספר אמיתי. idempotency_key חובה: אותו מפתח שוב מחזיר את אותה משימה עם created: false ולא יוצר שיחה שנייה. שדות נוספים במדריך העזר.

curl -X POST $API/v1/call-tasks \
  -H "Authorization: Bearer $ONELI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "idempotency_key": "order-1234-call",
    "to_number": "05XXXXXXXX",
    "goal": "לבדוק אם הזמנה 1234 מוכנה לאיסוף ועד מתי אפשר להגיע",
    "instructions": "לדבר בקצרה ובנימוס. אם אין תשובה ברורה, לבקש שעה לחזור.",
    "constraints": { "max_price_ils": 50 },
    "max_duration_s": 180
  }'

2. מעקב אחרי אירועים

האירועים ממוספרים ברצף. שולחים after עם ה־next_cursor האחרון ומקבלים רק את מה שחדש. קריאה כל 2–3 שניות מספיקה ונשארת הרבה מתחת למגבלת הקצב. כשהקו תפוס או שאין מענה, המשימה חוזרת ל־queued עם אירוע task.retry_scheduled, ולכן ממשיכים לעקוב עד סטטוס סופי.

# Events after the last sequence you have seen (start at 0). Repeat with after=<next_cursor>.
curl "$API/v1/call-tasks/$TASK_ID/events?after=0&limit=100" \
  -H "Authorization: Bearer $ONELI_API_KEY"

# The task itself: status, outcome, summary, revision
curl $API/v1/call-tasks/$TASK_ID -H "Authorization: Bearer $ONELI_API_KEY"

3. מענה להתייעצות

כשהסוכנת צריכה החלטה, pending_consultation מתמלא (וגם מגיע אירוע consultation.requested). יש רק כמה שניות עד deadline_at, ולכן עונים מהר. התשובה הראשונה קובעת. ask_user תמיד אפשרי: הסוכנת לא מתחייבת וההחלטה חוזרת אליכם. לתשובה אוטומטית בלי polling, ראו Webhook להחלטות.

curl -X POST $API/v1/consultations/con_3d48e1a72832d769/response \
  -H "Authorization: Bearer $ONELI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "decision": "approve", "reason": "בתוך התקציב" }'

# → { "status": "accepted" }  (or "expired" / "conflict" with the decision that won)

4. הנחיה בזמן שיחה

בשיחה פעילה ההנחיה מגיעה לסוכנת ומשפיעה מהתור הבא שלה. expected_revision מונע התנגשות בין שני שולחים: אם המשימה השתנתה בינתיים מתקבל 409 REVISION_CONFLICT. הנחיה למשימה שעדיין בתור נרשמת ומעלה את הגרסה, אבל לא מועברת לשיחה; כדי לשנות שיחה שעוד לא התחילה, מבטלים ויוצרים משימה חדשה.

# expected_revision = task.revision from GET /v1/call-tasks/:id
curl -X POST $API/v1/call-tasks/$TASK_ID/instructions \
  -H "Authorization: Bearer $ONELI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "instruction": "לשאול גם אם אפשר לאסוף מחר אחרי 18:00",
    "expected_revision": 1,
    "idempotency_key": "order-1234-instr-1"
  }'

# → { "command_id": "cmd_…", "revision": 2, "status": "pending" }

5. ביטול

משימה בתור מתבטלת מיד. בשיחה פעילה נשלחת בקשת ניתוק, והסטטוס הסופי מגיע באירועים. ביטול של משימה שכבר הסתיימה מחזיר 409 CALL_NOT_ACTIVE. ביטול לא כפוף למגבלת הקצב.

curl -X POST $API/v1/call-tasks/$TASK_ID/cancel \
  -H "Authorization: Bearer $ONELI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "reason": "user_changed_plans" }'

# queued → { "status": "cancelled" }   during the call → { "status": "cancel_requested" }

הסוכנים שלכם ב־API

כל מה שעוזר הצ׳אט באתר עושה עם הסוכנים שלכם זמין גם במפתח API ובשרת ה־MCP: לבנות ולערוך סוכן, מאגר הידע, לקרוא את השיחות שלו, להפעיל שיחה יוצאת ולנהל את הוואטסאפ שלו. כך אפשר לבנות על OneLi מוצר משלכם: CRM, מערכת לידים או סוכן AI שמפעיל את הסוכן הקולי שלכם. כל נתיב דורש הרשאה (scope); מפתחות וחיבורים חדשים מקבלים את כולן.

שיטהנתיבהרשאהמה זה עושה
GET/v1/voice-agents · /v1/voice-agents/:idagents:readהסוכנים, וכל ההגדרות של סוכן אחד ומה חסר כדי להפעיל.
GET/v1/voice-agent-templates · /v1/voice-agent-voices · /v1/voice-agent-appsagents:readתבניות, כלים, שפות ומודלים; קולות; האפליקציות שחיברתם.
POST/v1/voice-agentsagents:writeסוכן חדש מתבנית (template ו־name).
PUT/v1/voice-agents/:idagents:writeשומר שם ו־config מלא (קוראים קודם ושולחים את כולו).
POST/v1/voice-agents/:id/deploy · /pause · /playgroundagents:writeמפעיל, משהה, או שיחת בדיקה בטקסט.
DELETE/v1/voice-agents/:idagents:deleteמוחק סוכן: המספר משתחרר והתשלום החודשי שלו מבוטל.
GET · POST/v1/voice-agents/:id/kb · /kb/searchagents:readמאגר הידע: רשימה וחיפוש כמו בשיחה.
POST · PUT · DELETE/v1/voice-agents/:id/kb · /kb/:itemagents:writeהוספה (טקסט, קישור או התנגדות), עדכון והסרה.
GET/v1/voice-agents/:id/calls · /calls/:task_idcalls:readהשיחות של הסוכן, ושיחה אחת עם התמלול והערות המפקח.
POST · GET/v1/voice-agents/:id/outbound-calls · /outbound-calls/:callcalls:createcalls:readהסוכן מתקשר למישהו עכשיו (to, variables, Idempotency-Key), וסטטוס השיחה.
GET/v1/voice-agents/:id/whatsapp · /threads · /threads/:tid/messages · /templates · /automationswhatsapp:readמצב הוואטסאפ של הסוכן, הצ׳אטים וההודעות, התבניות והחוקים.
POST/v1/voice-agents/:id/whatsapp/send · /threads/:tid/messageswhatsapp:sendשליחה מהמספר של הסוכן: to ו־text, או to עם template_id ו־params.
POST · PATCH · DELETE/v1/voice-agents/:id/whatsapp/templates · /automations · /whatsappwhatsapp:writeתבניות, חוקים ומענה אוטומטי.

הסוכן מתקשר לליד

הסוכן צריך להיות פעיל. השדות ב־variables ממלאים את ה־{{משתנים}} בהנחיות שלו. אותו Idempotency-Key לא יחייג פעמיים. השיחה המלאה מופיעה בלשונית ״שיחות״ של הסוכן וב־GET …/calls.

curl
curl -X POST https://api.oneli.io/v1/voice-agents/va_…/outbound-calls \
  -H "Authorization: Bearer $ONELI_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: lead-42" \
  -d '{"to":"0521234567","variables":{"name":"Dana","interest":"kitchen renovation"}}'

וואטסאפ מהמספר של הסוכן

טקסט חופשי עובר רק בתוך 24 שעות מההודעה האחרונה של אותו אדם; מחוץ לחלון שולחים template_id של תבנית מאושרת עם params. שליחה מה־API משהה את המענה האוטומטי של הסוכן באותו צ׳אט, כמו תשובה שנכתבה באתר.

curl
curl -X POST https://api.oneli.io/v1/voice-agents/va_…/whatsapp/send \
  -H "Authorization: Bearer $ONELI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"to":"0521234567","text":"Thanks for the call! Here are the details you asked for: …"}'
נשארים באתר בלבד: לקיחת מספר טלפון, תשלומים, אנשי הקשר של הסוכן, הקלטות, חיבור מספר וואטסאפ או אפליקציה (שנעשים בדפדפן), ובדיקה קולית. ל־MCP, אותם דברים ככלים.

מתכונים לחיבור

הדרך הקצרה לתת לסוכן שלכם לחייג: לעטוף את POST /v1/call-tasks ואת GET /v1/call-tasks/:id בשני כלים. זה עובד עם function calling של OpenAI, עם כלים של LangChain ועם כל מסגרת שמקבלת JSON Schema. מסגרות שתומכות ב־MCP יכולות להתחבר ישירות לשרת ה־MCP עם מפתח ה־API, בלי לכתוב כלים.

JavaScript (framework-neutral)
// Two tools for your agent. Map them to your framework's tool format.
export const tools = [
  {
    name: "place_phone_call",
    description: "Phone an Israeli number in Hebrew through OneLi to reach a goal. Returns a task_id.",
    parameters: {
      type: "object",
      properties: {
        to_number: { type: "string", description: "Israeli number, e.g. 03-1234567 or 050-1234567" },
        goal: { type: "string", description: "What the call should achieve (max 500 characters)" },
        instructions: { type: "string", description: "How to conduct the call (optional)" },
        max_price_ils: { type: "number", description: "Above this price the voice agent consults you" },
      },
      required: ["to_number", "goal"],
    },
  },
  {
    name: "get_call_result",
    description: "Status, outcome and summary of a OneLi call task.",
    parameters: { type: "object", properties: { task_id: { type: "string" } }, required: ["task_id"] },
  },
];

export async function runTool(name, args) {
  if (name === "place_phone_call") {
    const { task } = await oneli("POST", "/v1/call-tasks", {
      idempotency_key: crypto.randomUUID(),
      to_number: args.to_number,
      goal: args.goal,
      instructions: args.instructions,
      ...(args.max_price_ils != null ? { constraints: { max_price_ils: args.max_price_ils } } : {}),
    });
    return { task_id: task.id, status: task.status };
  }
  if (name === "get_call_result") {
    const { task, pending_consultation } = await oneli("GET", `/v1/call-tasks/${args.task_id}`);
    return { status: task.status, outcome: task.outcome, summary: task.summary, pending_consultation };
  }
}

ב־n8n,‏ Make ו־Zapier: צומת או מודול HTTP Request עם ההגדרות האלה, ואחריו המתנה וקריאת התוצאה:

HTTP Request
Method:  POST
URL:     https://api.oneli.io/v1/call-tasks
Headers: Authorization: Bearer oli_...        (store it as a credential)
         Content-Type: application/json
Body:    {
           "idempotency_key": "lead-{{ id }}",
           "to_number": "{{ phone }}",
           "goal": "לאשר את פרטי הפנייה ואת מועד הפגישה"
         }

מדריכים מלאים לכל מסגרת: