Build with Rafiki.
Add voice conversations, speech generation, and transcription to your application. This guide takes you from your first request to a production integration.
Base URL
https://api.rafiki.nileagi.comStart here
Get started in three steps.
API products
Choose what you want to build.
Talk
POST/v1/talk/
Send speech and receive a transcript, a reply, and reply audio.
Speak
POST/v1/speech/synthesize/
Turn text into a WAV file in the selected voice.
Listen
POST/v1/speech/transcribe/
Turn an audio recording into a transcript.
Voices
GET/v1/voices/
List the preset voices and ready clones available to you.
Ready to connect your application?
Create a scoped key, then keep it in a server-side environment variable.
Get started
Introduction
Version 1
Use Rafiki to add voice conversations, speech generation, and transcription to your product. Every route starts with /v1 and ends with a trailing slash. Send JSON as UTF-8. To receive audio as a file, set Accept: audio/wav. JSON responses provide an audio_url instead of embedding audio data. Include request_id when contacting support.
Response
GET https://api.rafiki.nileagi.com/v1/health/
{
"status": "ok",
"service": "rafiki-api"
}Get started
Quickstart
About 5 minutes
Create an API key and make your first request. The example below generates a WAV file you can play immediately.
- 1Create an account, then open API keys in Studio.
- 2Create a test key with the scopes your integration needs. Copy the secret when it appears; Rafiki will not show it again.
- 3Store the key in an environment variable on your server. Never include it in browser or mobile application code.
- 4Run the example to generate a Kiswahili WAV file.
- 5Use GET /v1/usage/ in Studio to review usage.
curl -o habari.wav https://api.rafiki.nileagi.com/v1/speech/synthesize/ \ -H "Authorization: Bearer $RAFIKI_API_KEY" \ -H "Content-Type: application/json" \ -H "Accept: audio/wav" \ -H "Idempotency-Key: $(uuidgen)" \ -d '{"text":"Habari","language":"sw"}'
Get started
Authentication
Bearer
Server integrations use an API key that starts with rk_test_ or rk_live_. Send it as a Bearer token over HTTPS and keep it outside browser and mobile application code. Test and live labels help you separate development from production; both use the same API host. Copy a key when it is created or rotated because the full value is shown only once.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| Authorization | header | string | Required | Bearer rk_test_… or Bearer rk_live_… for server integrations. Signed-in Studio requests use a short-lived access token. |
Request
Authorization: Bearer rk_test_…
Response
401 unauthorized — missing, unknown, or revoked credential 403 forbidden — the credential lacks the required scope
Get started
Errors
All routes
Errors use one consistent JSON shape. The HTTP status and error.code describe the same failure. Retry temporary 429, 502, and 503 responses with exponential backoff. Fix the request or credentials before retrying 400, 401, or 403.
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_request | A field is missing, or the language and voice do not match. |
| 401 | unauthorized | The key is missing, unknown, or revoked. |
| 403 | forbidden | The key is valid, but it does not include the required scope. |
| 404 | not_found | That session, voice, project, or key does not exist. |
| 429 | rate_limited | Too many requests in a short window. |
| 429 | quota_exceeded | This period’s allowance for that product is used up. |
| 502 | service_unavailable | The service could not complete the request. Try again shortly. |
| 503 | service_unavailable | The service is temporarily unavailable. |
Response
{
"error": {
"code": "invalid_request",
"message": "That voice does not match the requested language.",
"request_id": "req_…"
}
}Get started
Idempotency
Optional header
Talk, Speak, Listen, and voice cloning accept Idempotency-Key. Repeating a request with the same key and account returns the original result without recording usage twice. Use a new key when the request body changes.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| Idempotency-Key | header | string | Optional | Up to 128 letters, numbers, periods, underscores, colons, or hyphens. A UUID is a good choice. |
Request
Idempotency-Key: 6f1c2a40-1c4e-4d3a-9b2e-0c5a9e2f7d11
Response
The second call returns the first response body and status.
Get started
Limits
Plan and quota
Account usage periods begin at 00:00 UTC on the first day of each month. Your plan controls the available allowance. Exceeding it returns 429 quota_exceeded; sending a short burst of requests may return 429 rate_limited. Speak accepts up to 5,000 characters per request, audio uploads up to 25 MB, and speed and pitch values from 0.5 to 2. Check /v1/usage/ for the limits currently applied to your account.
Response
{ "plan": "free", "meters": { "tts_chars": { "used": 6, "limit": 50000, "credits": 6 } } }Get started
Languages
Language codes
Each call names one language. Kiswahili uses its own recognizer and voice. Sukuma Listen is live, and Sukuma Speak is paused. Rafiki does not substitute another language. A mismatch is 400 invalid_request.
| Code | Language | Available in |
|---|---|---|
| sw | Kiswahili | Talk, Speak, Listen |
| suk | Sukuma | Listen. Speak is paused. |
Speech
Synthesize speech
/v1/speech/synthesize/API key · Speak scope
Turn text into speech. Set Accept: audio/wav to receive the audio file directly, or Accept: application/json to receive metadata and an audio_url. Usage is measured in synthesized characters.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| text | body | string | Required | Text to synthesize. Empty text is rejected. Maximum 5000 characters. |
| language | body | string | Optional | sw. Sukuma synthesis is paused. If voice_id is set, the language comes from that voice. |
| voice_id | body | uuid | Optional | A Rafiki voice or a ready clone. It must use the same language. |
| speed | body | number | Optional | From 0.5 to 2. Default 1. |
| pitch | body | number | Optional | From 0.5 to 2. Default 1. |
| profile | body | string | Optional | quality or edge. |
Request
{ "text": "Habari", "language": "sw", "speed": 1, "pitch": 1 }Response
{
"id": "…",
"request_id": "…",
"audio_url": "/v1/speech/renders/…/audio/",
"mime_type": "audio/wav",
"char_count": 6,
"has_audio": true
}Speech
Transcribe audio
/v1/speech/transcribe/API key · Listen scope
Transcribe a Kiswahili or Sukuma recording. Upload a file as multipart/form-data, or send base64 audio in JSON. Usage is measured in audio seconds. duration_seconds is null when the source does not provide a duration.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| file | body | file | Required | Audio file. Omit when you send JSON audio. |
| language | body | string | Required | sw for Kiswahili, or suk for Sukuma. |
| audio | body | string | Optional | Base64 audio when file is omitted. |
| mime_type | body | string | Optional | Required with JSON audio. Example: audio/wav. |
| profile | body | string | Optional | quality or edge. |
Request
multipart/form-data file=<audio> language=sw
Response
{
"text": "Habari",
"language": "sw",
"duration_seconds": 1.2,
"request_id": "req_…"
}Speech
Speech projects
/v1/speech/projects/Sign-in required
Store a script and render it later. GET lists projects. GET or PATCH /v1/speech/projects/{id}/ reads or edits one. POST /v1/speech/projects/{id}/synthesize/ renders the saved script. GET /v1/speech/renders/ and GET /v1/speech/transcripts/ return history.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| title | body | string | Required | Name shown in Studio. |
| script | body | string | Required | The script to store and synthesize. |
| language | body | string | Required | sw or suk. |
| voice | body | uuid | Optional | Voice used when the project is rendered. |
| settings | body | object | Optional | Optional speed and pitch. |
Request
{ "title": "Greeting", "script": "Habari", "language": "sw", "settings": { "speed": 1 } }Response
{ "id": "…", "title": "Greeting", "language": "sw", "renders": [] }Talk
Create a turn
/v1/talk/API key · Talk scope
Send a spoken message and receive its transcript, a written reply, and an audio_url for the spoken reply. Set Accept: audio/wav to receive only the reply audio. Pass session_id to continue a conversation, or omit it to start one. Uploads larger than 25 MB are rejected. Streaming is not currently available.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| file | body | file | Optional | Recording. Use this or JSON audio. |
| audio | body | string | Optional | Base64 recording when file is omitted. |
| mime_type | body | string | Optional | Mime type for JSON audio. |
| language | body | string | Optional | sw. Talk rejects other codes. |
| session_id | body | uuid | Optional | Existing session. A new one is created when omitted. |
| voice_id | body | uuid | Optional | Reply voice. Must match language. |
| profile | body | string | Optional | quality or edge. |
Request
{ "language": "sw", "mime_type": "audio/wav", "audio": "<base64>" }Response
{
"session_id": "…",
"conversation_id": "raf_tk_…",
"source": "api",
"transcript": "…",
"reply": "…",
"audio_url": "/v1/talk/turns/…/audio/",
"mime_type": "audio/wav",
"has_audio": true,
"turn_id": "…"
}Talk
Sessions
/v1/talk/sessions/{id}/Sign-in required to list · Talk scope to read one
List recent conversations with GET /v1/talk/sessions/. A session response includes its turns without embedding audio bytes. POST /v1/talk/sessions/{id}/reset/ clears the conversation context while preserving its transcript. Download a spoken reply from GET /v1/talk/turns/{id}/audio/.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| id | path | uuid | Required | Session id returned by Talk. |
Response
{ "session_id": "…", "reset": true }Voices
List voices
/v1/voices/API key · Voices scope
List the voices available to your request. Use the language query to filter the result. GET /v1/voices/{id}/ returns one voice. Signed-in users also see their own cloned voices.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| language | query | string | Optional | sw or suk. |
| id | path | uuid | Optional | Used on GET /v1/voices/{id}/. |
Response
[{
"id": "…",
"name": "Rafiki Kiswahili",
"language": "sw",
"kind": "preset",
"status": "ready"
}]Voices
Clone a voice
/v1/voices/clone/Sign-in required · Voices scope
Clone a voice only with the speaker’s informed consent. First request the consent script, then submit it unchanged with consent_accepted set to true and at least one recording. GET /v1/voices/clone/{job_id}/ returns the latest status.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| name | body | string | Required | Display name. |
| language | body | string | Required | sw or suk. |
| samples | body | file[] | Required | Recordings of the consenting speaker. |
| consent_accepted | body | boolean | Required | Must be true. |
| consent_text | body | string | Required | Exact text from GET /v1/voices/consent-script/. |
Request
GET /v1/voices/consent-script/
{ "script": "…" }Response
{ "id": "…", "status": "queued", "consent_accepted": true }Developers
API keys
/v1/developers/keys/Sign-in required
Create a test or live API key with any combination of tts, stt, talk, and voices scopes. Copy the secret from the creation response because it is shown only once. GET lists key metadata and prefixes. Rotate a key with POST /v1/developers/keys/{id}/secret/, or revoke it immediately with POST /v1/developers/keys/{id}/revoke/.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| name | body | string | Required | Label for this key. |
| env | body | string | Required | test or live. |
| scopes | body | string[] | Required | tts, stt, talk, voices. |
Request
{ "name": "Production server", "env": "live", "scopes": ["tts", "stt", "talk", "voices"] }Response
{ "prefix": "rk_live_ab12", "secret": "rk_live_…", "scopes": ["tts", "stt", "talk", "voices"] }Developers
Usage
/v1/usage/Sign-in required
Review the current plan, usage period, credits, and product meters. events contains the most recent metered requests. This endpoint reports consumption and allowances, not prices.
Response
{
"plan": "free",
"period_start": "2026-10-01T00:00:00Z",
"meters": { "talk_turns": { "used": 1, "limit": 500, "credits": 100 } },
"events": []
}