Partner — provision companies
For platform partners who resell Salesnix to their own customers. With a partner key you create and fund a company (a tenant) entirely over the API — no dashboard. Each company is billed separately; usage rolls up to the company, never the individual caller.
POST/api/partner/companiesPartner key
Create a company
Provisions a company in one call: its voice agent, its CRM credentials (so the assistant can reach that company's retailers, products and history), and its prepaid billing account. Returns a companyId you use for every later call.
| Field | Type | Required | Description |
|---|
name | string | required | Display name of the company, e.g. "Rasna" |
companyId | string | — | Optional explicit slug; otherwise derived from the name and namespaced to you |
integration | object | required | The company's external-CRM login: { provider, baseUrl, auth }. auth holds the provider's credentials (for mSELL: email + password). |
Request
curl -X POST https://be.salesnix.com/api/partner/companies \
-H "Authorization: Bearer $PARTNER_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Rasna",
"integration": {
"provider": "msell",
"baseUrl": "http://demo.msell.in/public/api",
"auth": { "email": "12345@rasna", "password": "••••••" }
}
}'
Response
{
"companyId": "msell-rasna",
"name": "Rasna",
"status": "active",
"partnerId": "msell",
"integration": {
"provider": "msell",
"baseUrl": "http://demo.msell.in/public/api"
}
}
GET/api/partner/companiesPartner key
List your companies
Every company you've provisioned, newest name first. You only ever see your own — a partner key can never touch another partner's tenants.
Request
curl -H "Authorization: Bearer $PARTNER_KEY" \
https://be.salesnix.com/api/partner/companies
Response
[
{ "companyId": "msell-rasna", "name": "Rasna", "status": "active", "partnerId": "msell" }
]
PATCH/api/partner/companies/{companyId}Partner key
Update a company
Change a company's display name or rotate its CRM credentials. Send only the fields you want to change.
Request
curl -X PATCH https://be.salesnix.com/api/partner/companies/msell-rasna \
-H "Authorization: Bearer $PARTNER_KEY" \
-H "Content-Type: application/json" \
-d '{ "integration": { "auth": { "email": "12345@rasna", "password": "new-secret" } } }'
Response
{ "companyId": "msell-rasna", "name": "Rasna", "status": "active",
"integration": { "provider": "msell", "baseUrl": "http://demo.msell.in/public/api" } }
POST/api/partner/companies/{companyId}/creditsPartner key
Top up a company
Add prepaid credits to a company's balance (1 credit = ₹1). You fund each company; all of that company's call usage draws down its own balance.
| Field | Type | Required | Description |
|---|
amount | number | required | Amount in INR to credit, e.g. 5000 |
Request
curl -X POST https://be.salesnix.com/api/partner/companies/msell-rasna/credits \
-H "Authorization: Bearer $PARTNER_KEY" \
-H "Content-Type: application/json" \
-d '{ "amount": 5000 }'
Response
{ "clientId": "msell-rasna", "added": 5000, "balance": 5000, "gateway": "partner" }
GET/api/partner/companies/{companyId}/usagePartner key
Company balance & usage
The company's current prepaid balance and its recent ledger (top-ups and per-call charges) — build per-company statements from this.
Request
curl -H "Authorization: Bearer $PARTNER_KEY" \
https://be.salesnix.com/api/partner/companies/msell-rasna/usage
Response
{
"companyId": "msell-rasna",
"balance": 4830.5,
"lowBalance": 100,
"currency": "credit",
"ledger": [
{ "delta": 5000, "kind": "recharge", "reason": "recharge via partner by msell", "balanceAfter": 5000 },
{ "delta": -169.5, "kind": "call", "reason": "138s @ 4/min", "balanceAfter": 4830.5 }
]
}
Partner — wallet & allocation
Fund one shared partner wallet, then push credits down to each company. Company calls always bill from that company's own balance; the wallet is just your funding pool. Auto-refill tops a company up from the wallet when it runs low.
GET/api/partner/walletPartner key
Wallet balance & ledger
Your shared wallet's current balance and its recent movements (recharges in, allocations out).
Request
curl -H "Authorization: Bearer $PARTNER_KEY" https://be.salesnix.com/api/partner/wallet
Response
{
"partnerId": "msell",
"balance": 42000,
"lowBalance": 1000,
"currency": "credit",
"ledger": [
{ "delta": 50000, "kind": "recharge", "reason": "recharge via razorpay", "balanceAfter": 50000 },
{ "delta": -8000, "kind": "allocation", "reason": "allocate to msell-rasna", "balanceAfter": 42000 }
]
}
POST/api/partner/wallet/rechargePartner key
Recharge the wallet
Start a wallet top-up (min ₹1,000). When Razorpay is enabled you get an order to pay (GST + gateway fee added on top; the wallet is credited the base amount), then confirm it via /wallet/recharge/verify. Without a gateway it returns a manual intent an admin confirms.
| Field | Type | Required | Description |
|---|
amountInr | number | required | Credits to add to the wallet (1 credit = ₹1), min 1000 |
Request
curl -X POST https://be.salesnix.com/api/partner/wallet/recharge \
-H "Authorization: Bearer $PARTNER_KEY" \
-H "Content-Type: application/json" \
-d '{ "amountInr": 50000 }'
Response
{
"paymentId": 812, "amountInr": 50000, "credits": 50000,
"gateway": "razorpay", "status": "pending",
"razorpayOrderId": "order_Nx…", "razorpayKeyId": "rzp_live_…"
}
POST/api/partner/companies/{companyId}/allocatePartner key
Allocate wallet → company
Atomically move credits from your wallet into a company's balance. Refuses if the wallet is underfunded.
| Field | Type | Required | Description |
|---|
amount | number | required | Credits to move from the wallet to this company |
Request
curl -X POST https://be.salesnix.com/api/partner/companies/msell-rasna/allocate \
-H "Authorization: Bearer $PARTNER_KEY" \
-H "Content-Type: application/json" \
-d '{ "amount": 8000 }'
Response
{ "companyId": "msell-rasna", "companyBalance": 8000, "wallet": 42000 }
POST/api/partner/companies/{companyId}/auto-refillPartner key
Set company auto-refill
When this company's balance dips below its low-balance threshold, pull this many credits from your wallet automatically. Set 0 to turn it off.
| Field | Type | Required | Description |
|---|
amount | number | required | Auto-refill amount in credits (0 disables) |
Request
curl -X POST https://be.salesnix.com/api/partner/companies/msell-rasna/auto-refill \
-H "Authorization: Bearer $PARTNER_KEY" \
-H "Content-Type: application/json" \
-d '{ "amount": 2000 }'
Response
{ "companyId": "msell-rasna", "autoRefill": 2000 }
Partner — agents & tools
Build and manage each company's voice agent (persona, greeting, and which tools it can call) programmatically — the same thing the partner dashboard does. The tool catalog is scoped per company, so it sees its own CRM tools but never another client's.
GET/api/partner/companies/{companyId}/agent-optionsPartner key
Agent options (voices, tools, defaults)
Everything to build the create-agent form in ONE call: the voices (friendly name + gender), the tools the agent may use, and the defaults. The voice id IS the friendly name — show it and pass it straight back on create.
Request
curl -H "Authorization: Bearer $PARTNER_KEY" \
https://be.salesnix.com/api/partner/companies/msell-rasna/agent-options
Response
{
"voices": [
{ "id": "Priya", "label": "Priya", "gender": "female" },
{ "id": "Rohan", "label": "Rohan", "gender": "male" }
],
"tools": [
{ "name": "identify_customer", "label": "Identify caller", "group": "Retail CRM", "kind": "crm" },
{ "name": "get_purchase_history", "label": "Purchase history", "group": "Retail CRM", "kind": "crm" },
{ "name": "search_products", "label": "Search products", "group": "Retail CRM", "kind": "crm" },
{ "name": "connect_to_support", "label": "Connect to support", "group": "Retail CRM", "kind": "crm" }
],
"defaults": { "voice": "Priya" }
}
GET/api/partner/companies/{companyId}/toolsPartner key
Tool list
Just the tools this company's agent may be granted (CRM tools if it has an integration). For voices + defaults use /agent-options.
Request
curl -H "Authorization: Bearer $PARTNER_KEY" \
https://be.salesnix.com/api/partner/companies/msell-rasna/tools
Response
{
"tools": [
{ "name": "identify_customer", "label": "Identify caller", "group": "Retail CRM", "kind": "crm" },
{ "name": "get_purchase_history", "label": "Purchase history", "group": "Retail CRM", "kind": "crm" },
{ "name": "search_products", "label": "Search products", "group": "Retail CRM", "kind": "crm" },
{ "name": "connect_to_support", "label": "Connect to support", "group": "Retail CRM", "kind": "crm" }
]
}
GET/api/partner/companies/{companyId}/agentsPartner key
List a company's agents
The voice agents belonging to this company (not shared/global demo agents).
Request
curl -H "Authorization: Bearer $PARTNER_KEY" \
https://be.salesnix.com/api/partner/companies/msell-rasna/agents
Response
[
{ "id": 42, "name": "mSELL Voice Assistant", "voice": "Rohan",
"tools": ["identify_customer","get_purchase_history","search_products","connect_to_support"] }
]
POST/api/partner/companies/{companyId}/agentsPartner key
Create an agent
Create a voice agent for a company: its name, voice, greeting, system prompt, and the tools it may call. (PUT …/agents/{agentId} updates it, DELETE removes it.)
| Field | Type | Required | Description |
|---|
name | string | required | Agent name |
voice | string | — | Voice name from /agent-options (e.g. Priya, Rohan) |
greeting | string | — | Opening line |
prompt | string | — | System prompt |
tools | string[] | — | Tool names from the company's catalog |
Request
curl -X POST https://be.salesnix.com/api/partner/companies/msell-rasna/agents \
-H "Authorization: Bearer $PARTNER_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "mSELL Voice Assistant", "voice": "Rohan",
"greeting": "Namaste! …",
"prompt": "You are the mSELL voice assistant …",
"tools": ["identify_customer","get_purchase_history","search_products","connect_to_support"]
}'
Response
{ "id": 42, "name": "mSELL Voice Assistant", "voice": "Rohan", "tools": ["…"] }
POST/api/partner/companies/{companyId}/callsPartner key
Place a call
Trigger a live outbound call for a company from your own system. Bills the company; caller-ID is the company's number. Returns a callId immediately; the call runs async — read it back from GET /api/partner/calls/{callId}. Sandbox: with an sk_test_ key this returns { callId, status, sandbox: true } and does NOT dial or bill — safe for testing.
| Field | Type | Required | Description |
|---|
phone | string | required | Destination number to call (the retailer) |
contactName | string | — | Name for the call log |
agentId | number | — | Which agent runs it (else the number's assigned agent) |
didId | number | — | Which of the company's numbers to call from (else its default) |
Request
curl -X POST https://be.salesnix.com/api/partner/companies/msell-rasna/calls \
-H "Authorization: Bearer $PARTNER_KEY" \
-H "Content-Type: application/json" \
-d '{ "phone": "9958001967", "contactName": "Ravi", "agentId": 42 }'
Response
{ "callId": 2207, "status": "answered" }
POST/api/partner/companies/{companyId}/tools/{toolName}/testPartner key
Test a tool
Fire one CRM tool directly (no live call) to confirm it's wired for a company. Pass the same args the agent would — e.g. identify: {"phone":"…"}, products: {"query":"…","retailerId":"…"}.
Request
curl -X POST https://be.salesnix.com/api/partner/companies/msell-rasna/tools/search_products/test \
-H "Authorization: Bearer $PARTNER_KEY" \
-H "Content-Type: application/json" \
-d '{ "args": { "query": "mango", "retailerId": "20100701222328" } }'
Response
{ "tool": "search_products", "ok": true,
"result": { "count": 5, "products": [
{ "name": "Jumpin Tetra - Mango 9.50Rs", "code": "JUM_125ML_MGO_9.50RS", "rate": "7.60" }
] } }
POST/api/partner/companies/{companyId}/custom-toolsPartner key
Create your own tool
Define a custom webhook tool. When the agent calls it we POST { …args, phone, callId, companyId } to your url (your secret as Authorization: Bearer, if set) and hand the JSON back to the agent. Then add its name to an agent's tools to enable it. https only; localhost/private IPs are rejected.
| Field | Type | Required | Description |
|---|
name | string | required | snake_case, e.g. place_order |
description | string | required | When the agent should call it |
url | string | required | Your https webhook URL |
secret | string | — | Optional — sent as Bearer to your URL |
properties | object | — | JSON-schema of the args the agent passes |
required | string[] | — | Which properties are required |
Request
curl -X POST https://be.salesnix.com/api/partner/companies/msell-rasna/custom-tools \
-H "Authorization: Bearer $PARTNER_KEY" -H "Content-Type: application/json" \
-d '{
"name": "place_order",
"description": "Place an order once the retailer confirms items and quantities",
"url": "https://your-system.com/api/tools/place-order",
"secret": "s3cr3t",
"properties": { "items": { "type": "array" } },
"required": ["items"]
}'
Response
{ "name": "place_order", "url": "https://your-system.com/api/tools/place-order", "hasSecret": true }
GET/api/partner/companies/{companyId}/custom-toolsPartner key
List / update / delete custom tools
GET lists your custom tools (secrets hidden). PUT …/custom-tools/{name} updates (blank url keeps the stored one; omit secret to keep it). DELETE …/custom-tools/{name} removes it. Test any tool with POST …/tools/{name}/test.
Request
curl -H "Authorization: Bearer $PARTNER_KEY" \
https://be.salesnix.com/api/partner/companies/msell-rasna/custom-tools
Response
[ { "name": "place_order", "url": "https://…", "hasSecret": true, "properties": { "items": { "type": "array" } } } ]
Partner — call webhook, logs & keys
Have every finished call pushed to your system (webhook), read call activity across your companies, confirm your identity, and mint API keys for server-to-server use.
PUT/api/partner/webhookPartner key
Configure your call webhook
Where we POST every finished call across ALL your companies. Pass url="" to disable. Send `secret` only to change it — we return it as an Authorization: Bearer header on each delivery so you can verify it's us. Configurable here or in your dashboard (API keys page).
| Field | Type | Required | Description |
|---|
url | string | required | Your receiver URL (empty disables) |
secret | string | — | Optional — sent as Bearer on every delivery |
Request
curl -X PUT https://be.salesnix.com/api/partner/webhook \
-H "Authorization: Bearer $PARTNER_KEY" \
-H "Content-Type: application/json" \
-d '{ "url": "https://your-system.com/api/salesnix/calls", "secret": "s3cr3t" }'
Response
{ "url": "https://your-system.com/api/salesnix/calls", "hasSecret": true }
GET/api/partner/webhookPartner key
Read your webhook config
Your configured webhook URL and whether a secret is set (the secret is never returned).
Request
curl -H "Authorization: Bearer $PARTNER_KEY" https://be.salesnix.com/api/partner/webhook
Response
{ "url": "https://your-system.com/api/salesnix/calls", "hasSecret": true }
POST{your webhook URL}Partner key
What we POST when a call ends
On every finished call we POST this to your webhook URL (with your secret as Authorization: Bearer, if set). `clientId` is the companyId, so you know which company the call belongs to.
Response
{
"event": "call.completed",
"callId": 2207, "clientId": "msell-rasna",
"direction": "outbound", "phone": "9958001967", "contactName": "Ravi",
"status": "completed", "outcomeKey": "interested",
"durationSecs": 84, "cost": 5.6,
"summary": "Retailer engaged about products; no order yet.",
"recordingUrl": "https://…", "startedAt": "2026-08-14T…"
}
GET/api/partner/callsPartner key
Calls across your companies
Every call across your companies (or filter to one with ?company_id=), newest first — for a log table or CSV export. Includes per-call cost.
| Field | Type | Required | Description |
|---|
company_id | string | — | Optional — restrict to one company |
limit | number | — | Max rows (default 500, max 2000) |
Request
curl -H "Authorization: Bearer $PARTNER_KEY" \
"https://be.salesnix.com/api/partner/calls?limit=100"
Response
[
{
"id": 90210, "companyId": "msell-rasna", "companyName": "Rasna",
"contactName": "Gupta Stores", "phone": "+9199…", "direction": "inbound",
"status": "completed", "outcomeKey": "answered",
"startedAt": "2026-07-11T11:04:00+05:30", "durationSecs": 138, "cost": 9.2,
"sentiment": 70, "hasRecording": true
}
]
GET/api/partner/calls/{callId}Partner key
One call by its callId
Full detail for a call (the callId returned by POST …/calls): status, outcome, duration, cost, sentiment, a playable (presigned) recording link, summary, and the turn-by-turn transcript.
Request
curl -H "Authorization: Bearer $PARTNER_KEY" \
https://be.salesnix.com/api/partner/calls/2207
Response
{
"callId": 2207, "companyId": "msell-rasna", "status": "completed",
"outcomeKey": "interested", "durationSecs": 84, "cost": 5.6, "sentiment": 70,
"summary": "…", "recordingUrl": "https://…(presigned)…",
"transcript": [ { "role": "ai", "text": "Namaste…", "atSecs": 6 } ]
}
GET/api/partner/mePartner key
Who am I
Confirms your partner identity behind the key or login. Call this first to verify credentials.
Request
curl -H "Authorization: Bearer $PARTNER_KEY" https://be.salesnix.com/api/partner/me
Response
{ "partnerId": "msell", "name": "mSELL", "kind": "apikey" }
POST/api/partner/keysPartner key
Mint an API key
Create a partner API key for server-to-server use — same permissions as your dashboard login. The plaintext key is returned ONCE. (GET lists your keys; DELETE …/keys/{keyId} revokes one instantly.)
| Field | Type | Required | Description |
|---|
name | string | — | A label, e.g. "Production" |
env | string | — | "live" or "test" (default live) |
Request
curl -X POST https://be.salesnix.com/api/partner/keys \
-H "Authorization: Bearer $PARTNER_KEY" \
-H "Content-Type: application/json" \
-d '{ "name": "Production", "env": "live" }'
Response
{
"id": "…", "partnerId": "msell", "name": "Production", "env": "live",
"keyPrefix": "sk_live_ab12", "scopes": ["companies:write","companies:read"],
"key": "sk_live_ab12…copy-this-now"
}