Phone calls
GET/v1/calls/quote
Quote a destination and check the call purpose for that country
Parameters
| Name | Type | Description |
|---|---|---|
to required | query · string | |
purpose | query · "transactional" | "scheduling" | "support" | "marketing" | |
consent | query · "existing_customer" | "prior_express" | "written" | |
from | query · string |
Response 200
| Name | Type | Description |
|---|---|---|
to required | string | Masked number |
country required | string | |
kind required | string | |
allowed required | boolean | |
minute_factor required | number | |
reason required | string | |
purpose required | object | null | |
purpose.purpose required | "transactional" | "scheduling" | "support" | "marketing" | |
purpose.allowed required | boolean | |
purpose.code required | string | |
purpose.message required | string | null | |
purpose.requires required | string[] | |
purpose.legal_reviewed required | boolean | |
simulator required | string | null |
Example
curl "https://api.kanutus.com/v1/calls/quote?to=string" \
-H "Authorization: Bearer $KANUTUS_API_KEY"const res = await fetch("https://api.kanutus.com/v1/calls/quote", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.KANUTUS_API_KEY}`,
},
});
console.log(res.status, await res.json());import os, uuid, requests
r = requests.request(
"GET",
"https://api.kanutus.com/v1/calls/quote",
headers={"Authorization": f"Bearer {os.environ['KANUTUS_API_KEY']}"},
)
print(r.status_code, r.json())Try it
Runs from your browser against the real API. Use a kt_test_ key: nothing is charged. The key stays in this tab only.
GET /v1/calls/quoteResponses by status
200 Destination, minute factor and whether this purpose is allowed there
{
"to": "string",
"country": "string",
"kind": "string",
"allowed": true,
"minute_factor": 0,
"reason": "string",
"purpose": {
"purpose": "transactional",
"allowed": true,
"code": "string",
"message": "string",
"requires": [
"string"
],
"legal_reviewed": true
},
"simulator": "string"
}400 Invalid request
{
"type": "https://docs.kanutus.com/errors",
"title": "<code>",
"status": 400,
"code": "<code>",
"message": "…",
"request_id": "req_…"
}401 Missing, invalid, expired or revoked credential
{
"type": "https://docs.kanutus.com/errors",
"title": "<code>",
"status": 401,
"code": "<code>",
"message": "…",
"request_id": "req_…"
}403 Missing permission, blocked or not allowed
{
"type": "https://docs.kanutus.com/errors",
"title": "<code>",
"status": 403,
"code": "<code>",
"message": "…",
"request_id": "req_…"
}429 Rate limit exceeded (see RateLimit-* and Retry-After headers)
{
"type": "https://docs.kanutus.com/errors",
"title": "<code>",
"status": 429,
"code": "<code>",
"message": "…",
"request_id": "req_…"
}POST/v1/calls
Place a translated call as an AI agent (always announces it is an AI) Soon
Live mode answers 501 coming soon. Try it now with a kt_test_ key (simulator).
Parameters
| Name | Type | Description |
|---|---|---|
idempotency-key required | header · string | Unique key per create request; retries with the same key return the same result. |
Request body
| Name | Type | Description |
|---|---|---|
to required | string | length 4–32 |
from | string | Caller ID (one of the organization's numbers) · length 0–32 |
purpose required | "transactional" | "scheduling" | "support" | "marketing" | |
consent | object | |
consent.kind required | "existing_customer" | "prior_express" | "written" | |
consent.ref | string | Your reference to the consent record · length 0–200 |
agent_lang | string | default "en" |
remote_lang | string | |
voice_id | string | length 0–100 |
Response 201
| Name | Type | Description |
|---|---|---|
id required | string | |
to required | string | |
country required | string | |
purpose required | "transactional" | "scheduling" | "support" | "marketing" | |
status required | "queued" | "ringing" | "answered" | "completed" | "busy" | "voicemail" | "no_answer" | "failed" | "blocked" | |
ai_disclosure required | true | |
billed_seconds required | integer | |
created_at required | string | |
answered_at | string | null | |
ended_at | string | null | |
end_reason | string | null | agent_hangup, remote_hangup, max_duration, busy, voicemail, no_answer… |
livemode required | boolean |
Example
curl -X POST "https://api.kanutus.com/v1/calls" \
-H "Authorization: Bearer $KANUTUS_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"to":"+1 555 0100","from":"string","purpose":"transactional","consent":{"kind":"existing_customer","ref":"string"},"agent_lang":"en","remote_lang":"string","voice_id":"string"}'const res = await fetch("https://api.kanutus.com/v1/calls", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.KANUTUS_API_KEY}`,
"Idempotency-Key": crypto.randomUUID(),
"Content-Type": "application/json",
},
body: JSON.stringify({"to":"+1 555 0100","from":"string","purpose":"transactional","consent":{"kind":"existing_customer","ref":"string"},"agent_lang":"en","remote_lang":"string","voice_id":"string"}),
});
console.log(res.status, await res.json());import os, uuid, requests
r = requests.request(
"POST",
"https://api.kanutus.com/v1/calls",
headers={"Authorization": f"Bearer {os.environ['KANUTUS_API_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={"to":"+1 555 0100","from":"string","purpose":"transactional","consent":{"kind":"existing_customer","ref":"string"},"agent_lang":"en","remote_lang":"string","voice_id":"string"},
)
print(r.status_code, r.json())Try it
Runs from your browser against the real API. Use a kt_test_ key: nothing is charged. The key stays in this tab only.
POST /v1/callsResponses by status
201 Call created
{
"id": "string",
"to": "string",
"country": "string",
"purpose": "transactional",
"status": "queued",
"ai_disclosure": true,
"billed_seconds": 0,
"created_at": "string",
"answered_at": "string",
"ended_at": "string",
"end_reason": "string",
"livemode": true
}400 Invalid request
{
"type": "https://docs.kanutus.com/errors",
"title": "<code>",
"status": 400,
"code": "<code>",
"message": "…",
"request_id": "req_…"
}401 Missing, invalid, expired or revoked credential
{
"type": "https://docs.kanutus.com/errors",
"title": "<code>",
"status": 401,
"code": "<code>",
"message": "…",
"request_id": "req_…"
}402 Spend limit of this credential reached
{
"type": "https://docs.kanutus.com/errors",
"title": "<code>",
"status": 402,
"code": "<code>",
"message": "…",
"request_id": "req_…"
}403 Missing permission, blocked or not allowed
{
"type": "https://docs.kanutus.com/errors",
"title": "<code>",
"status": 403,
"code": "<code>",
"message": "…",
"request_id": "req_…"
}409 Conflict (idempotency or state)
{
"type": "https://docs.kanutus.com/errors",
"title": "<code>",
"status": 409,
"code": "<code>",
"message": "…",
"request_id": "req_…"
}429 Rate limit exceeded (see RateLimit-* and Retry-After headers)
{
"type": "https://docs.kanutus.com/errors",
"title": "<code>",
"status": 429,
"code": "<code>",
"message": "…",
"request_id": "req_…"
}501 Not available yet in live mode (use a kt_test_ key)
{
"type": "https://docs.kanutus.com/errors",
"title": "<code>",
"status": 501,
"code": "<code>",
"message": "…",
"request_id": "req_…"
}GET/v1/calls
Calls placed by this credential
Response 200
| Name | Type | Description |
|---|---|---|
data required | object[] | |
data[].id required | string | |
data[].to required | string | |
data[].country required | string | |
data[].purpose required | "transactional" | "scheduling" | "support" | "marketing" | |
data[].status required | "queued" | "ringing" | "answered" | "completed" | "busy" | "voicemail" | "no_answer" | "failed" | "blocked" | |
data[].ai_disclosure required | true | |
data[].billed_seconds required | integer | |
data[].created_at required | string | |
data[].answered_at | string | null | |
data[].ended_at | string | null | |
data[].end_reason | string | null | agent_hangup, remote_hangup, max_duration, busy, voicemail, no_answer… |
data[].livemode required | boolean |
Example
curl "https://api.kanutus.com/v1/calls" \
-H "Authorization: Bearer $KANUTUS_API_KEY"const res = await fetch("https://api.kanutus.com/v1/calls", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.KANUTUS_API_KEY}`,
},
});
console.log(res.status, await res.json());import os, uuid, requests
r = requests.request(
"GET",
"https://api.kanutus.com/v1/calls",
headers={"Authorization": f"Bearer {os.environ['KANUTUS_API_KEY']}"},
)
print(r.status_code, r.json())Try it
Runs from your browser against the real API. Use a kt_test_ key: nothing is charged. The key stays in this tab only.
GET /v1/callsResponses by status
200 Calls, newest first
{
"data": [
{
"id": "string",
"to": "string",
"country": "string",
"purpose": "transactional",
"status": "queued",
"ai_disclosure": true,
"billed_seconds": 0,
"created_at": "string",
"answered_at": "string",
"ended_at": "string",
"end_reason": "string",
"livemode": true
}
]
}400 Invalid request
{
"type": "https://docs.kanutus.com/errors",
"title": "<code>",
"status": 400,
"code": "<code>",
"message": "…",
"request_id": "req_…"
}401 Missing, invalid, expired or revoked credential
{
"type": "https://docs.kanutus.com/errors",
"title": "<code>",
"status": 401,
"code": "<code>",
"message": "…",
"request_id": "req_…"
}403 Missing permission, blocked or not allowed
{
"type": "https://docs.kanutus.com/errors",
"title": "<code>",
"status": 403,
"code": "<code>",
"message": "…",
"request_id": "req_…"
}429 Rate limit exceeded (see RateLimit-* and Retry-After headers)
{
"type": "https://docs.kanutus.com/errors",
"title": "<code>",
"status": 429,
"code": "<code>",
"message": "…",
"request_id": "req_…"
}GET/v1/calls/{id}
Get a call
Parameters
| Name | Type | Description |
|---|---|---|
id required | path · string |
Response 200
| Name | Type | Description |
|---|---|---|
id required | string | |
to required | string | |
country required | string | |
purpose required | "transactional" | "scheduling" | "support" | "marketing" | |
status required | "queued" | "ringing" | "answered" | "completed" | "busy" | "voicemail" | "no_answer" | "failed" | "blocked" | |
ai_disclosure required | true | |
billed_seconds required | integer | |
created_at required | string | |
answered_at | string | null | |
ended_at | string | null | |
end_reason | string | null | agent_hangup, remote_hangup, max_duration, busy, voicemail, no_answer… |
livemode required | boolean |
Example
curl "https://api.kanutus.com/v1/calls/call_7Hn2Qd9Wk4Lp6Rt1Xb8Mc3Zf" \
-H "Authorization: Bearer $KANUTUS_API_KEY"const res = await fetch("https://api.kanutus.com/v1/calls/call_7Hn2Qd9Wk4Lp6Rt1Xb8Mc3Zf", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.KANUTUS_API_KEY}`,
},
});
console.log(res.status, await res.json());import os, uuid, requests
r = requests.request(
"GET",
"https://api.kanutus.com/v1/calls/call_7Hn2Qd9Wk4Lp6Rt1Xb8Mc3Zf",
headers={"Authorization": f"Bearer {os.environ['KANUTUS_API_KEY']}"},
)
print(r.status_code, r.json())Try it
Runs from your browser against the real API. Use a kt_test_ key: nothing is charged. The key stays in this tab only.
GET /v1/calls/{id}Responses by status
200 Call
{
"id": "string",
"to": "string",
"country": "string",
"purpose": "transactional",
"status": "queued",
"ai_disclosure": true,
"billed_seconds": 0,
"created_at": "string",
"answered_at": "string",
"ended_at": "string",
"end_reason": "string",
"livemode": true
}400 Invalid request
{
"type": "https://docs.kanutus.com/errors",
"title": "<code>",
"status": 400,
"code": "<code>",
"message": "…",
"request_id": "req_…"
}401 Missing, invalid, expired or revoked credential
{
"type": "https://docs.kanutus.com/errors",
"title": "<code>",
"status": 401,
"code": "<code>",
"message": "…",
"request_id": "req_…"
}403 Missing permission, blocked or not allowed
{
"type": "https://docs.kanutus.com/errors",
"title": "<code>",
"status": 403,
"code": "<code>",
"message": "…",
"request_id": "req_…"
}404 Not found
{
"type": "https://docs.kanutus.com/errors",
"title": "<code>",
"status": 404,
"code": "<code>",
"message": "…",
"request_id": "req_…"
}429 Rate limit exceeded (see RateLimit-* and Retry-After headers)
{
"type": "https://docs.kanutus.com/errors",
"title": "<code>",
"status": 429,
"code": "<code>",
"message": "…",
"request_id": "req_…"
}POST/v1/calls/{id}/hangup
Hang up (idempotent: an ended call is returned as is) Soon
Live mode answers 501 coming soon. Try it now with a kt_test_ key (simulator).
Parameters
| Name | Type | Description |
|---|---|---|
id required | path · string |
Response 200
| Name | Type | Description |
|---|---|---|
id required | string | |
to required | string | |
country required | string | |
purpose required | "transactional" | "scheduling" | "support" | "marketing" | |
status required | "queued" | "ringing" | "answered" | "completed" | "busy" | "voicemail" | "no_answer" | "failed" | "blocked" | |
ai_disclosure required | true | |
billed_seconds required | integer | |
created_at required | string | |
answered_at | string | null | |
ended_at | string | null | |
end_reason | string | null | agent_hangup, remote_hangup, max_duration, busy, voicemail, no_answer… |
livemode required | boolean |
Example
curl -X POST "https://api.kanutus.com/v1/calls/call_7Hn2Qd9Wk4Lp6Rt1Xb8Mc3Zf/hangup" \
-H "Authorization: Bearer $KANUTUS_API_KEY"const res = await fetch("https://api.kanutus.com/v1/calls/call_7Hn2Qd9Wk4Lp6Rt1Xb8Mc3Zf/hangup", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.KANUTUS_API_KEY}`,
},
});
console.log(res.status, await res.json());import os, uuid, requests
r = requests.request(
"POST",
"https://api.kanutus.com/v1/calls/call_7Hn2Qd9Wk4Lp6Rt1Xb8Mc3Zf/hangup",
headers={"Authorization": f"Bearer {os.environ['KANUTUS_API_KEY']}"},
)
print(r.status_code, r.json())Try it
Runs from your browser against the real API. Use a kt_test_ key: nothing is charged. The key stays in this tab only.
POST /v1/calls/{id}/hangupResponses by status
200 The call, ended
{
"id": "string",
"to": "string",
"country": "string",
"purpose": "transactional",
"status": "queued",
"ai_disclosure": true,
"billed_seconds": 0,
"created_at": "string",
"answered_at": "string",
"ended_at": "string",
"end_reason": "string",
"livemode": true
}400 Invalid request
{
"type": "https://docs.kanutus.com/errors",
"title": "<code>",
"status": 400,
"code": "<code>",
"message": "…",
"request_id": "req_…"
}401 Missing, invalid, expired or revoked credential
{
"type": "https://docs.kanutus.com/errors",
"title": "<code>",
"status": 401,
"code": "<code>",
"message": "…",
"request_id": "req_…"
}403 Missing permission, blocked or not allowed
{
"type": "https://docs.kanutus.com/errors",
"title": "<code>",
"status": 403,
"code": "<code>",
"message": "…",
"request_id": "req_…"
}404 Not found
{
"type": "https://docs.kanutus.com/errors",
"title": "<code>",
"status": 404,
"code": "<code>",
"message": "…",
"request_id": "req_…"
}409 Conflict (idempotency or state)
{
"type": "https://docs.kanutus.com/errors",
"title": "<code>",
"status": 409,
"code": "<code>",
"message": "…",
"request_id": "req_…"
}429 Rate limit exceeded (see RateLimit-* and Retry-After headers)
{
"type": "https://docs.kanutus.com/errors",
"title": "<code>",
"status": 429,
"code": "<code>",
"message": "…",
"request_id": "req_…"
}POST/v1/calls/{id}/dtmf
Press phone keys (DTMF) for menus like "press 2 for sales": 0-9, * and #, up to 32 Soon
Live mode answers 501 coming soon. Try it now with a kt_test_ key (simulator).
Parameters
| Name | Type | Description |
|---|---|---|
id required | path · string |
Request body
| Name | Type | Description |
|---|---|---|
digits required | string | 0-9, * and #; spaces and dashes are ignored · length 1–64 |
Response 200
| Name | Type | Description |
|---|---|---|
id required | string | |
sent required | string | |
status required | "queued" | "ringing" | "answered" | "completed" | "busy" | "voicemail" | "no_answer" | "failed" | "blocked" | |
livemode required | boolean |
Example
curl -X POST "https://api.kanutus.com/v1/calls/call_7Hn2Qd9Wk4Lp6Rt1Xb8Mc3Zf/dtmf" \
-H "Authorization: Bearer $KANUTUS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"digits":"2#"}'const res = await fetch("https://api.kanutus.com/v1/calls/call_7Hn2Qd9Wk4Lp6Rt1Xb8Mc3Zf/dtmf", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.KANUTUS_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"digits":"2#"}),
});
console.log(res.status, await res.json());import os, uuid, requests
r = requests.request(
"POST",
"https://api.kanutus.com/v1/calls/call_7Hn2Qd9Wk4Lp6Rt1Xb8Mc3Zf/dtmf",
headers={"Authorization": f"Bearer {os.environ['KANUTUS_API_KEY']}"},
json={"digits":"2#"},
)
print(r.status_code, r.json())Try it
Runs from your browser against the real API. Use a kt_test_ key: nothing is charged. The key stays in this tab only.
POST /v1/calls/{id}/dtmfResponses by status
200 Keys sent
{
"id": "string",
"sent": "string",
"status": "queued",
"livemode": true
}400 Invalid request
{
"type": "https://docs.kanutus.com/errors",
"title": "<code>",
"status": 400,
"code": "<code>",
"message": "…",
"request_id": "req_…"
}401 Missing, invalid, expired or revoked credential
{
"type": "https://docs.kanutus.com/errors",
"title": "<code>",
"status": 401,
"code": "<code>",
"message": "…",
"request_id": "req_…"
}403 Missing permission, blocked or not allowed
{
"type": "https://docs.kanutus.com/errors",
"title": "<code>",
"status": 403,
"code": "<code>",
"message": "…",
"request_id": "req_…"
}404 Not found
{
"type": "https://docs.kanutus.com/errors",
"title": "<code>",
"status": 404,
"code": "<code>",
"message": "…",
"request_id": "req_…"
}409 Conflict (idempotency or state)
{
"type": "https://docs.kanutus.com/errors",
"title": "<code>",
"status": 409,
"code": "<code>",
"message": "…",
"request_id": "req_…"
}429 Rate limit exceeded (see RateLimit-* and Retry-After headers)
{
"type": "https://docs.kanutus.com/errors",
"title": "<code>",
"status": 429,
"code": "<code>",
"message": "…",
"request_id": "req_…"
}