Developer API · v1 · live

One API for WhatsApp, calls, CRM & number masking.

Plug Omixo AI into any product. Send WhatsApp messages & templates, push click-to-call, mask numbers, sync contacts and raise tickets — plain REST + JSON, one API key, no SDK to install. Built for SOHO, SME and enterprise teams.

Base URL  https://api.omixo.ai/api/v1 Auth  X-API-Key: cpaas_…
✓ REST + JSON ✓ Single X-API-Key ✓ Rate-limited ✓ Every call logged ✓ Data-isolated per workspace

The Omixo AI platform, programmable

Everything your team does inside Omixo AI — WhatsApp, phone calls, your CRM, tickets and AI assistants — is available over a clean REST API so you can automate it from your website, app, ERP or backend. Authenticate with one key, call an endpoint, get JSON back. No coding framework required; if it can make an HTTPS request, it can talk to Omixo AI.

Quickstart — from zero to your first call

Three steps. You can be authenticated and making live requests in a couple of minutes.

1

Create a free account

Sign up in under a minute — no card needed. You start on the free tier with 2 concurrent calls free, so you can build and test straight away. You only buy a plan / top up the wallet when you go live.

Start free →
2

Copy your API key

Inside the panel open Settings → Developer. Copy your key (it looks like cpaas_xxxxxxxx…). This one key authenticates every request. Keep it secret; you can regenerate it any time.

Open Developer settings →
3

Make your first call

Call GET /api/v1/me with your key — a safe, read-only request that returns your account & wallet. If you get {"ok":true}, you are connected. Then send a WhatsApp message, push a call, or sync a contact — all with the same key.

Your first request — GET /api/v1/me
curl "https://api.omixo.ai/api/v1/me" \
  -H "X-API-Key: cpaas_your_api_key"
const res = await fetch("https://api.omixo.ai/api/v1/me", {
  headers: { "X-API-Key": "cpaas_your_api_key" }
});
console.log(await res.json());
$ch = curl_init("https://api.omixo.ai/api/v1/me");
curl_setopt($ch, CURLOPT_HTTPHEADER, ["X-API-Key: cpaas_your_api_key"]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
echo curl_exec($ch);
import requests
r = requests.get("https://api.omixo.ai/api/v1/me",
    headers={"X-API-Key": "cpaas_your_api_key"})
print(r.json())
Response
{
    "ok": true,
    "account": {
        "company_id": 42,
        "name": "Your Business",
        "status": "active",
        "wallet_balance": 1840.5,
        "currency": "INR"
    }
}

Authentication

Send your workspace API key in the X-API-Key header on every request. The key identifies your workspace (tenant) and every response is automatically scoped to your own data — you can never see another business's data, and they can never see yours.

Where to find your key: Log in → Settings → Developer. Copy the key (or Regenerate to roll it). One key works for every endpoint below.
Send it on every request
X-API-Key: cpaas_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
A missing / invalid key returns 401
{
    "ok": false,
    "error": "invalid_api_key",
    "message": "Invalid X-API-Key."
}

Conventions

  • REST over HTTPS — one base URL, JSON in and JSON out (UTF-8).
  • Every response has an "ok" boolean. On failure you also get "error" (a stable slug) and a human "message".
  • Phone numbers: send 10-digit Indian numbers or full E.164 (with country code). Bare 10-digit numbers are auto-prefixed with 91.
  • List endpoints are paginated / limited — pass ?limit= (most cap at 100).
  • Every call (success or failure) is logged to your Developer page for a live audit trail.

👤 Account & wallet

Read your account, wallet balance and live per-minute / per-message rates. Perfect for a first test call.

GET /api/v1/me Account summary

Your workspace name, status, KYC state, timezone and wallet balance. The recommended first call to confirm your key works.

Request
curl "https://api.omixo.ai/api/v1/me" \
  -H "X-API-Key: cpaas_your_api_key"
Response
{
    "ok": true,
    "account": {
        "company_id": 42,
        "name": "Grand Ride Motors",
        "status": "active",
        "kyc_status": "verified",
        "timezone": "Asia/Kolkata",
        "wallet_balance": 1840.5,
        "currency": "INR"
    }
}
GET /api/v1/wallet Wallet balance & rates

Live balance plus the per-minute voice / AI and per-reply WhatsApp rates that apply to your workspace.

Request
curl "https://api.omixo.ai/api/v1/wallet" \
  -H "X-API-Key: cpaas_your_api_key"
Response
{
    "ok": true,
    "wallet": {
        "balance": 1840.5,
        "currency": "INR",
        "status": "active",
        "rates": {
            "voice_per_min": 1,
            "ai_per_min": 6,
            "whatsapp_per_msg": 0.4,
            "stt_per_min": 0.3
        }
    }
}
GET /api/v1/transactions Wallet transactions

Recent wallet debits & credits. Filter with ?limit= (max 100).

Request
curl "https://api.omixo.ai/api/v1/transactions" \
  -H "X-API-Key: cpaas_your_api_key"
Response
{
    "ok": true,
    "transactions": [
        {
            "id": 90112,
            "type": "debit",
            "amount": 6,
            "reason": "AI call 00:58",
            "balance_after": 1834.5,
            "created_at": "2026-08-15 14:22:00"
        }
    ]
}

💬 WhatsApp messaging

Send any WhatsApp type from your own system — text, approved templates (+PDF), media, quick-reply buttons and list menus — and discover your templates as a ready-to-use dropdown. Replies land in your Omixo Inbox and the AI can carry the chat on.

POST /api/v1/messages/send Send a WhatsApp message

One endpoint for every send type via the "type" field. Free-form types (text/media/buttons/list/location) need the 24-hour customer-service window open (the customer messaged you in the last 24h). type=template works anytime.

FieldDescription
to required 10-digit or full-country-code number.
type required text | template | image | document | video | buttons | list | location.
text optional Message body (text/buttons/list).
template optional Approved template name (type=template).
lang optional Template language, e.g. en, hi. Default en.
variables optional Array filling {{1}}..{{n}} in order.
media_url optional Public URL for media / PDF template header.
buttons optional Up to 3 quick-reply button labels.
items optional Up to 10 list options (type=list).
Request
curl -X POST "https://api.omixo.ai/api/v1/messages/send" \
  -H "X-API-Key: cpaas_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "9565990444",
    "type": "text",
    "text": "Hello from the Omixo API! 👋"
}'
Approved template (+PDF) — works anytime
{
    "to": "9565990444",
    "type": "template",
    "template": "tally_invoice",
    "lang": "en",
    "variables": [
        "Rahul",
        "INV-101",
        "₹12,500",
        "14-07-2026"
    ],
    "media_url": "https://example.com/invoice.pdf",
    "filename": "INV-101.pdf"
}
Quick-reply buttons (max 3)
{
    "to": "9565990444",
    "type": "buttons",
    "text": "Would you like a demo?",
    "buttons": [
        "Yes",
        "No",
        "Call me"
    ]
}
List menu (max 10)
{
    "to": "9565990444",
    "type": "list",
    "text": "Our courses:",
    "list_button": "View courses",
    "items": [
        "Bank PO",
        "SSC",
        "Railway",
        "Teaching"
    ]
}
Image / document by URL
{
    "to": "9565990444",
    "type": "document",
    "media_url": "https://example.com/brochure.pdf",
    "caption": "Our brochure 📄",
    "filename": "brochure.pdf"
}
Response
{
    "ok": true,
    "message": "Text sent to 919565990444"
}
GET /api/v1/whatsapp/status Connection status

Whether a WhatsApp sender is connected and which number your messages come from.

Request
curl "https://api.omixo.ai/api/v1/whatsapp/status" \
  -H "X-API-Key: cpaas_your_api_key"
Response
{
    "ok": true,
    "connected": true,
    "from": "919044266522",
    "display_name": "Omixo AI"
}
GET /api/v1/whatsapp/window Is the 24h window open?

Tells you whether a free-form text will actually be delivered to a customer. Returns send_type = "text" (open) or "template" (closed) — use it to auto-pick the send type.

FieldDescription
to required Full number with country code.
Request
curl "https://api.omixo.ai/api/v1/whatsapp/window" \
  -H "X-API-Key: cpaas_your_api_key"
Response
{
    "ok": true,
    "open": true,
    "send_type": "text",
    "expires_in_minutes": 742
}
GET /api/v1/whatsapp/templates Templates as a dropdown

Best way to build a send screen in your own panel. Each template comes decoded: label, variable_count, variables[] (position + example), preview, media_required and a copy-paste send_example — no need to parse Meta JSON.

FieldDescription
q optional Name search.
category optional MARKETING | UTILITY | AUTHENTICATION.
language optional Filter by language.
Request
curl "https://api.omixo.ai/api/v1/whatsapp/templates" \
  -H "X-API-Key: cpaas_your_api_key"
Response
{
    "ok": true,
    "templates": [
        {
            "name": "callback_confirm",
            "language": "hi",
            "category": "UTILITY",
            "label": "Callback confirm (hi)",
            "variable_count": 3,
            "preview": "Hi {{1}}, we will call you at {{2}}. — {{3}}"
        }
    ]
}
POST /api/v1/whatsapp/templates Create a template

Build a brand-new WhatsApp template from your own app — send the body text + example values and Omixo assembles the Meta component JSON and submits it for approval. Returns status=PENDING; poll GET templates until it turns APPROVED.

FieldDescription
name required Unique template name.
language required en | hi | en_US …
category optional UTILITY (default) | MARKETING.
body required Text with {{1}},{{2}}… placeholders.
examples optional Example values in {{n}} order.
Request
curl -X POST "https://api.omixo.ai/api/v1/whatsapp/templates" \
  -H "X-API-Key: cpaas_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "order_update_en",
    "language": "en",
    "category": "UTILITY",
    "body": "Hello {{1}}, your order {{2}} is ready for pickup.",
    "examples": [
        "Rahul",
        "#1042"
    ],
    "footer": "Team Omixo"
}'
Response
{
    "ok": true,
    "status": "PENDING",
    "name": "order_update_en"
}

📞 Voice calls

Originate click-to-call from your app and pull call records (CDRs) with duration, disposition and cost. Calls present your own DID as caller ID.

POST /api/v1/calls/click-to-call Push a call

Rings your agent first, then bridges to the customer, showing your DID as caller ID. Needs an active calling plan.

FieldDescription
agent required Your agent number to ring first.
destination required The customer number to bridge to.
caller_id optional A DID of yours to present (defaults to your enabled DID).
Request
curl -X POST "https://api.omixo.ai/api/v1/calls/click-to-call" \
  -H "X-API-Key: cpaas_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "agent": "9044200377",
    "destination": "9565990444",
    "caller_id": "915226523606"
}'
Response
{
    "ok": true,
    "message": "Call originated — ringing your agent first, then bridging the customer.",
    "call_id": "1723712345.678",
    "channel": "1723712345.678",
    "agent": "919044200377",
    "destination": "919565990444",
    "caller_id": "915226523606"
}
POST /api/v1/calls/hangup Hang up a live call

Cut a call you originated (click-to-call) or a masked/PIN-Connect bridge that is in progress — e.g. the customer's pre-paid balance ran out. Pass the call_id you got from click-to-call or the call_connected webhook.

FieldDescription
call_id required The call/channel id (from click-to-call or the call_connected webhook).
Request
curl -X POST "https://api.omixo.ai/api/v1/calls/hangup" \
  -H "X-API-Key: cpaas_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "call_id": "1723712345.678"
}'
Response
{
    "ok": true,
    "hungup": true,
    "call_id": "1723712345.678"
}
POST /api/v1/calls/extend Extend / shorten a live call

Change the remaining talk-time of a call in progress — pre-paid top-up mid-call, or an early cut. seconds = talk-time left FROM NOW; the auto-hangup timer resets to it. seconds:0 removes the cap (unlimited). Verified against the caller channel you own.

FieldDescription
call_id required The call/channel id (from the call_connected webhook or click-to-call).
seconds required New talk-time remaining from now, in seconds (0 = no limit).
Request
curl -X POST "https://api.omixo.ai/api/v1/calls/extend" \
  -H "X-API-Key: cpaas_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "call_id": "1723712345.678",
    "seconds": 600
}'
Response
{
    "ok": true,
    "call_id": "1723712345.678",
    "seconds_left": 600,
    "unlimited": false
}
GET /api/v1/calls/records Call records (CDRs)

Recent call log — direction, duration, disposition and cost. Each row carries a cdr_id and recording reference.

FieldDescription
limit optional Rows to return (default 50).
Request
curl "https://api.omixo.ai/api/v1/calls/records" \
  -H "X-API-Key: cpaas_your_api_key"
Response
{
    "ok": true,
    "count": 1,
    "records": [
        {
            "cdr_id": 270,
            "direction": "outbound",
            "from": "915226523606",
            "to": "919565990444",
            "duration": 58,
            "disposition": "ANSWERED",
            "cost": 6,
            "started_at": "2026-08-15 14:21:02"
        }
    ]
}

🔐 PIN Connect — number masking

Create masked-call sessions where two people talk without seeing each other's number — QR "call the owner", ride-hailing rider↔driver, delivery, classifieds. The caller dials your PIN-Connect DID, enters a PIN, and is bridged to the owner with your DID as caller ID. Numbers stay private; a webhook fires on connect and completion. For pre-paid talk-time products (astrologer / consult / helpline where the caller buys minutes), set max_call_seconds so the bridge auto-hangs up when the balance runs out — or cut it yourself any time with /api/v1/calls/hangup.

Where you'd use it
🔮 Astrologer / consultPre-paid minutes, auto-cut when the balance ends
🚕 Ride-hailingRider and driver talk, numbers hidden both sides
📦 DeliveryAgent and customer for one drop, PIN dies after
🏷️ ClassifiedsCall the seller without leaking any number
🩺 TelehealthDoctor and patient, private and recorded
🛟 Support callbackA public line that protects your staff DIDs
How it works — end to end
1

Create a session

POST /masked-sessions with the owner_number (plus optional max_call_seconds and webhook_url). You get back a PIN.

2

Share the PIN

Show the caller: dial your PIN-Connect DID and enter the PIN. You can embed it in a QR code or a button.

3

Caller enters the PIN

They call your DID and key in the PIN. Omixo validates it, guarded by a brute-force lock and a per-caller cooldown.

4

Bridged privately

Omixo rings the owner and connects both legs. Your DID is the caller ID; the real numbers never show.

5

call_connected fires

Your webhook receives the live call_id. Start your billing timer and keep the call_id for live control.

6

Control and close

Extend on top-up or cut instantly with /calls/extend and /calls/hangup. call_completed fires at the end with duration and a signed recording_url.

🛡️Numbers never leakNeither party ever sees the other real number, only your DID. Recordings are private and served through short-lived signed links that expire.
⚠️PINs are one-time by defaultmax_uses defaults to 1 (a single call). Set N for N calls, or 0 for unlimited until expiry. A brute-force lock plus per-caller cooldown block PIN guessing automatically.
ℹ️Pre-paid talk-time: bill precisely, cap as a safety netmax_call_seconds is a safety auto-cut. Because the timer starts as the bridge is set up, it can include a few seconds of ring time, so treat it as a backstop. For exact billing, start your own timer from the call_connected webhook and end the call with /calls/hangup.
💡Top up without dropping the callWhen a customer buys more minutes mid-call, POST /calls/extend with the new seconds and the auto-cut moves out live. Send seconds 0 to remove the cap entirely.
🛡️Only your calls, only youhangup and extend confirm the call belongs to your workspace before acting, so a call_id from another account returns 404. There is no cross-tenant control.
ℹ️Live control needs the call_idThe call_id for a live inbound call arrives in the call_connected webhook. Save it against your session so you can extend or hang up while the call is still in progress.
POST /api/v1/masked-sessions Create a session

Returns a PIN. max_uses controls one-time vs multi-call; two_way lets either party call the other; per-caller cooldown + brute-force guard are built in. Set max_call_seconds for a pre-paid talk-time cap — the bridged call auto-hangs up at that many seconds (both legs), no polling needed. Top up or cut talk-time mid-call with /api/v1/calls/extend.

FieldDescription
owner_number required Who the caller reaches.
💡 Why & when: The person the caller wants to reach, such as the astrologer or the driver. Their number stays hidden; the caller only ever dials your DID.
pin optional Omit for a random 4-digit PIN.
💡 Why & when: Let Omixo generate a random PIN unless you need a fixed one, for example a PIN printed on a card. Random is safer.
ttl_minutes optional Lifetime (default 30).
💡 Why & when: Auto-expires the PIN so an old session cannot be reused. Match it to how long the caller has to dial in.
max_uses optional 1 = one-time (default), N = N calls, 0 = unlimited till expiry.
💡 Why & when: Decides whether the PIN dies after the first call (a marketplace enquiry) or keeps working for a set number or until expiry (a support line).
two_way optional true = owner can also call caller_bind back.
💡 Why & when: Turn on only when the owner also needs to call the customer back on the same masked link, for example a driver calling a rider.
caller_bind optional Lock the session to one caller.
💡 Why & when: Locks the PIN to one phone number so nobody who overhears the PIN can use it. Recommended for one-to-one pairings.
max_call_seconds optional Hard cap per bridged call — the call auto-hangs up at this many seconds (pre-paid / talk-time cap). Omit for no cap.
💡 Why & when: Your pre-paid safety cap. If a caller has 15 paid minutes, set 900 so the bridge can never run over even if your own timer fails.
webhook_url optional POSTed call_connected + call_completed (with signed recording_url).
💡 Why & when: Where Omixo tells your app that the call connected and ended. This is how you start and stop billing and fetch the recording. Set it whenever you bill or log calls.
Request
curl -X POST "https://api.omixo.ai/api/v1/masked-sessions" \
  -H "X-API-Key: cpaas_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "owner_number": "919044266522",
    "ttl_minutes": 30,
    "max_uses": 1,
    "two_way": false,
    "caller_bind": "919999888877",
    "max_call_seconds": 900,
    "purpose": "Astrologer consult — 15 min pack",
    "webhook_url": "https://your-app.com/hooks/omixo"
}'
Response
{
    "ok": true,
    "session": {
        "id": 842,
        "pin": "4821",
        "status": "active",
        "owner_number": "919044266522",
        "max_uses": 1,
        "max_call_seconds": 900,
        "expires_at": "2026-08-15 18:30:00"
    }
}
GET /api/v1/masked-sessions List sessions

Your PIN sessions (active by default). Filter with ?status=active|used|revoked|expired|all, ?pin=, ?limit=.

Request
curl "https://api.omixo.ai/api/v1/masked-sessions" \
  -H "X-API-Key: cpaas_your_api_key"
Response
{
    "ok": true,
    "sessions": [
        {
            "id": 842,
            "pin": "4821",
            "status": "active",
            "owner_number": "919044266522",
            "uses": 0
        }
    ]
}
DELETE /api/v1/masked-sessions/{id} Revoke a session

Kill a session early so its PIN can no longer connect. Replace {id} with the session id.

Request
curl -X DELETE "https://api.omixo.ai/api/v1/masked-sessions/{id}" \
  -H "X-API-Key: cpaas_your_api_key"
Response
{
    "ok": true,
    "revoked": true
}
End-to-end demo — a pre-paid consult

Create a capped, webhook-wired session, then control the live call from your webhook handler.

const BASE = "https://api.omixo.ai", KEY = "cpaas_your_api_key";

// 1) Create a masked session for a 15-minute pre-paid consult
const r = await fetch(BASE + "/api/v1/masked-sessions", {
  method: "POST",
  headers: { "X-API-Key": KEY, "Content-Type": "application/json" },
  body: JSON.stringify({
    owner_number: "919044266522",   // the astrologer (stays hidden)
    caller_bind: "919999888877",    // lock the PIN to this customer
    max_call_seconds: 900,          // safety cap = 15 minutes
    webhook_url: "https://your-app.com/hooks/omixo"
  })
});
const { session } = await r.json();
// Tell the customer: dial your PIN-Connect DID and enter PIN <session.pin>

// 2) In your webhook handler (Express):
app.post("/hooks/omixo", (req, res) => {
  const e = req.body;
  if (e.event === "call_connected") { saveCallId(e.session_id, e.call_id); startTimer(e.session_id); }
  if (e.event === "call_completed") { chargeCustomer(e.session_id, e.duration); archive(e.recording_url); }
  res.sendStatus(200);
});

// 3) Customer tops up mid-call -> push the cap out live
await fetch(BASE + "/api/v1/calls/extend", {
  method: "POST",
  headers: { "X-API-Key": KEY, "Content-Type": "application/json" },
  body: JSON.stringify({ call_id: callId, seconds: 600 })  // 10 more minutes
});

// 4) Balance ends -> cut the call instantly
await fetch(BASE + "/api/v1/calls/hangup", {
  method: "POST",
  headers: { "X-API-Key": KEY, "Content-Type": "application/json" },
  body: JSON.stringify({ call_id: callId })
});
Webhook guide — real-time call events

Set webhook_url on the session and Omixo calls your app in real time over HTTPS POST with a JSON body. Two events fire.

event: call_connectedPIN accepted — Omixo is bridging the two legs now.
Payload your endpoint receives
{
    "event": "call_connected",
    "call_id": "1723712345.678",
    "session_id": 842,
    "pin": "4821",
    "caller": "919999888877",
    "bridged_to": "919044266522",
    "use": 1,
    "at": "2026-08-15T18:22:04+05:30"
}
FieldWhat it's for
call_idThe live channel id. Pass it to /calls/extend or /calls/hangup to control this call while it is still in progress.
session_idThe masked session this call belongs to.
caller / bridged_toThe two connected parties, for your own records.
useWhich use of the PIN this is (1 for the first call).
atConnect time — a useful billing start marker.
event: call_completedThe call has ended (either side hung up, or a cap fired).
Payload your endpoint receives
{
    "event": "call_completed",
    "session_id": 842,
    "caller": "919999888877",
    "owner_number": "919044266522",
    "duration": 372,
    "disposition": "ANSWERED",
    "recording_url": "https://api.omixo.ai/rec/842-signed",
    "cdr_id": 90231,
    "at": "2026-08-15T18:28:16+05:30"
}
FieldWhat it's for
durationTalk-time in seconds — bill on this exact number.
dispositionANSWERED, NO ANSWER, BUSY, and so on.
recording_urlA signed link to the recording that expires in 7 days. Download it promptly.
cdr_idThe call record id, for your reconciliation.

📇 CRM contacts

Push leads from your website/app straight into the Omixo CRM, keep them in sync, and read them back. Contacts are matched (upserted) by phone; tags and attributes merge.

GET /api/v1/contacts List contacts

Paginated CRM contacts. Filter with ?q= (name/phone) or ?status=. ?limit= caps at 100.

Request
curl "https://api.omixo.ai/api/v1/contacts" \
  -H "X-API-Key: cpaas_your_api_key"
Response
{
    "ok": true,
    "contacts": [
        {
            "id": 5501,
            "name": "Rahul Sharma",
            "phone": "919565990444",
            "status": "new",
            "tags": [
                "website-lead"
            ]
        }
    ],
    "total": 128,
    "current_page": 1,
    "per_page": 30
}
POST /api/v1/contacts Create / upsert a contact

Add or update a contact (matched by phone). Great for capturing website leads.

FieldDescription
phone required Contact phone (the match key).
name optional Full name.
email optional Email address.
service_required optional What they want.
tags optional Array of tags (merged).
attrs optional Custom key/value object (merged).
Request
curl -X POST "https://api.omixo.ai/api/v1/contacts" \
  -H "X-API-Key: cpaas_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "9565990444",
    "name": "Rahul Sharma",
    "email": "rahul@example.com",
    "tags": [
        "website-lead"
    ],
    "attrs": {
        "city": "Lucknow"
    }
}'
Response
{
    "ok": true,
    "contact": {
        "id": 5501,
        "name": "Rahul Sharma",
        "phone": "919565990444",
        "status": "new"
    }
}
PUT /api/v1/contacts/{id} Update a contact

Update a contact by id — status, service, tags, attrs. Replace {id}.

Request
curl -X PUT "https://api.omixo.ai/api/v1/contacts/{id}" \
  -H "X-API-Key: cpaas_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "qualified",
    "attrs": {
        "budget": "50k"
    }
}'
Response
{
    "ok": true,
    "contact": {
        "id": 5501,
        "status": "qualified"
    }
}

🎫 Tickets & action items

Raise action items from your own system and resolve them — callbacks, complaints, tasks. They appear in the Omixo Action Center for your team.

GET /api/v1/tickets List tickets

Your action items. Filter ?status=open|acknowledged|resolved or ?level=.

Request
curl "https://api.omixo.ai/api/v1/tickets" \
  -H "X-API-Key: cpaas_your_api_key"
Response
{
    "ok": true,
    "tickets": [
        {
            "id": 3310,
            "subject": "Callback requested",
            "level": "important",
            "status": "open"
        }
    ],
    "total": 4
}
POST /api/v1/tickets Create a ticket

Raise a ticket / action item from your app.

FieldDescription
subject required Short title.
level optional normal | important | emergency.
phone optional Related contact number.
details optional Free text.
Request
curl -X POST "https://api.omixo.ai/api/v1/tickets" \
  -H "X-API-Key: cpaas_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "subject": "Callback requested",
    "level": "important",
    "phone": "9565990444",
    "details": "Wants a demo tomorrow 4 PM"
}'
Response
{
    "ok": true,
    "ticket": {
        "id": 3311,
        "subject": "Callback requested",
        "level": "important",
        "status": "open"
    }
}
PUT /api/v1/tickets/{id} Update / resolve a ticket

Acknowledge or resolve a ticket. Replace {id}.

Request
curl -X PUT "https://api.omixo.ai/api/v1/tickets/{id}" \
  -H "X-API-Key: cpaas_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "resolved",
    "resolution": "Demo scheduled"
}'
Response
{
    "ok": true,
    "ticket": {
        "id": 3311,
        "status": "resolved"
    }
}

🤖 AI assistants

List the AI assistants configured on your workspace — the brains that answer your calls, WhatsApp and widget.

GET /api/v1/assistants List assistants

Your AI assistants with name, languages and status.

Request
curl "https://api.omixo.ai/api/v1/assistants" \
  -H "X-API-Key: cpaas_your_api_key"
Response
{
    "ok": true,
    "assistants": [
        {
            "id": 7,
            "name": "Maya — Sales",
            "languages": [
                "hi",
                "en"
            ],
            "status": "active"
        }
    ]
}

🧾 Tally ERP bridge

Send a formatted Tally ERP / Prime voucher (invoice, receipt, statement, reminder) to a customer over WhatsApp with the PDF attached. Needs the Tally add-on active.

POST /api/v1/tally/send Send a voucher

Delivers a mapped template with the voucher PDF. Works from Tally TDL or any ERP.

FieldDescription
phone required Customer number.
type required invoice | receipt | statement | reminder | payment | order.
party_name optional Ledger / party name.
amount optional Voucher amount.
items optional Line items array.
Request
curl -X POST "https://api.omixo.ai/api/v1/tally/send" \
  -H "X-API-Key: cpaas_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "9565990444",
    "type": "invoice",
    "party_name": "Ashish Saxena",
    "number": "INV-101",
    "date": "07-07-2026",
    "amount": 12500,
    "due_date": "14-07-2026",
    "items": [
        {
            "name": "Course fee",
            "qty": 1,
            "amount": 12500
        }
    ]
}'
Response
{
    "ok": true,
    "message": "Voucher sent to 919565990444"
}

Errors

Failures return an HTTP status plus a JSON body with a stable error slug and a human message.

StatuserrorWhen it happens
401invalid_api_keyThe X-API-Key header is missing or does not match a workspace.
402no_planThe action needs an active plan (e.g. a calling plan for click-to-call). Buy one in Billing.
403spam_blockedThe target number is marked Spam in your CRM — all outbound to it is blocked until you restore the lead.
422whatsapp_not_connectedNo WhatsApp sender is connected. Connect a number in Setup → WhatsApp.
422validationA required field is missing or malformed — the message says which.
422send_failedA free-form WhatsApp type was sent outside the 24-hour window. Use type=template instead.
429rate_limitedYou exceeded the per-minute rate limit — slow down and retry.

Rate limits

  • Tenant self-service API (contacts, tickets, wallet, me, assistants, WhatsApp discovery): 120 requests/minute.
  • Message send, call, Tally, masked-session create: 60 requests/minute.
  • Read endpoints for records/masked-session list: 120 requests/minute.

Exceeding a limit returns 429 — back off and retry.

Webhooks

Omixo AI can call your app back in real time.

PIN Connect call events
Pass a webhook_url when you create a masked session. Omixo POSTs event=call_connected when the masked call bridges, and event=call_completed when it ends — the completed event carries a signed, expiring recording_url and the call duration.
CRM Events Webhook (calls + WhatsApp → your CRM)
Set ONE endpoint + get a signing secret in panel → Developer → CRM Events Webhook. Omixo POSTs a JSON body for every subscribed event: call.completed / call.missed (with direction, from, to, the original called number "did", agent, duration, billsec, disposition, is_ai, a signed 7-day recording_url, and the linked contact incl. your external_id) and whatsapp.inbound / whatsapp.outbound / whatsapp.status (delivery/read receipts). Each request carries X-Omixo-Event and X-Omixo-Signature: sha256=HMAC_SHA256(rawBody, secret) — verify it. Deliveries are logged (panel → Developer) so support can trace any issue. Use "Send test event" to try it against your endpoint.
Partner Relay (become the brain)
Point your workspace's WhatsApp + widget inbound at your own app (panel → Developer → Partner Relay). Omixo forwards every inbound message to your URL; your app replies by calling POST /api/v1/whatsapp/send. Omixo never double-replies.

Start building free

2 concurrent calls free. Pay-as-you-go when you go live. Your API key is waiting in Settings → Developer.

Create a free account → See pricing

Developer FAQ

The questions SOHO, SME and enterprise teams ask before they build.

How do I get an Omixo AI API key?
Create a free account, then open Settings → Developer in your panel and copy the key (it looks like cpaas_…). The same key authenticates every endpoint. You can regenerate it any time. No sales call needed to start.
How do I enable Omixo services / do I have to buy first?
No. You start free with 2 concurrent calls free, so you can integrate and test immediately. You only buy a plan or top up your wallet when you go live — pricing is pay-as-you-go. The API itself is included; you pay for usage (AI minutes, WhatsApp replies, numbers).
What can the API do?
Send WhatsApp messages and templates, push click-to-call and pull call records, mask numbers with PIN Connect, sync CRM contacts, raise and resolve tickets, read your wallet and rates, and list your AI assistants — all REST + JSON with a single X-API-Key.
How do I authenticate?
Send your workspace key in the X-API-Key header on every request over HTTPS. Responses are automatically scoped to your own workspace data.
Which languages / SDKs are supported?
Any language that can make an HTTPS request — the docs show cURL, Node.js, PHP and Python. There is no SDK to install; it is plain REST.
Is my data isolated from other businesses?
Yes. The API key resolves to your workspace and every query is tenant-scoped, so you only ever see your own contacts, calls and messages.
What is the base URL?
All endpoints live under https://api.omixo.ai/api/v1/. See the Authentication section for the exact host, which is always shown live from your account.