API v1Stable

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.com

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.

  1. 1Create an account, then open API keys in Studio.
  2. 2Create a test key with the scopes your integration needs. Copy the secret when it appears; Rafiki will not show it again.
  3. 3Store the key in an environment variable on your server. Never include it in browser or mobile application code.
  4. 4Run the example to generate a Kiswahili WAV file.
  5. 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.

ParameterInTypeRequiredDescription
AuthorizationheaderstringRequiredBearer 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.

StatusCodeMeaning
400invalid_requestA field is missing, or the language and voice do not match.
401unauthorizedThe key is missing, unknown, or revoked.
403forbiddenThe key is valid, but it does not include the required scope.
404not_foundThat session, voice, project, or key does not exist.
429rate_limitedToo many requests in a short window.
429quota_exceededThis period’s allowance for that product is used up.
502service_unavailableThe service could not complete the request. Try again shortly.
503service_unavailableThe 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.

ParameterInTypeRequiredDescription
Idempotency-KeyheaderstringOptionalUp 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.

CodeLanguageAvailable in
swKiswahiliTalk, Speak, Listen
sukSukumaListen. Speak is paused.

Speech

POST

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.

ParameterInTypeRequiredDescription
textbodystringRequiredText to synthesize. Empty text is rejected. Maximum 5000 characters.
languagebodystringOptionalsw. Sukuma synthesis is paused. If voice_id is set, the language comes from that voice.
voice_idbodyuuidOptionalA Rafiki voice or a ready clone. It must use the same language.
speedbodynumberOptionalFrom 0.5 to 2. Default 1.
pitchbodynumberOptionalFrom 0.5 to 2. Default 1.
profilebodystringOptionalquality 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

POST

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.

ParameterInTypeRequiredDescription
filebodyfileRequiredAudio file. Omit when you send JSON audio.
languagebodystringRequiredsw for Kiswahili, or suk for Sukuma.
audiobodystringOptionalBase64 audio when file is omitted.
mime_typebodystringOptionalRequired with JSON audio. Example: audio/wav.
profilebodystringOptionalquality or edge.

Request

multipart/form-data
file=<audio>
language=sw

Response

{
  "text": "Habari",
  "language": "sw",
  "duration_seconds": 1.2,
  "request_id": "req_…"
}

Speech

POST

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.

ParameterInTypeRequiredDescription
titlebodystringRequiredName shown in Studio.
scriptbodystringRequiredThe script to store and synthesize.
languagebodystringRequiredsw or suk.
voicebodyuuidOptionalVoice used when the project is rendered.
settingsbodyobjectOptionalOptional speed and pitch.

Request

{ "title": "Greeting", "script": "Habari", "language": "sw", "settings": { "speed": 1 } }

Response

{ "id": "…", "title": "Greeting", "language": "sw", "renders": [] }

Talk

POST

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.

ParameterInTypeRequiredDescription
filebodyfileOptionalRecording. Use this or JSON audio.
audiobodystringOptionalBase64 recording when file is omitted.
mime_typebodystringOptionalMime type for JSON audio.
languagebodystringOptionalsw. Talk rejects other codes.
session_idbodyuuidOptionalExisting session. A new one is created when omitted.
voice_idbodyuuidOptionalReply voice. Must match language.
profilebodystringOptionalquality 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

GET

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/.

ParameterInTypeRequiredDescription
idpathuuidRequiredSession id returned by Talk.

Response

{ "session_id": "…", "reset": true }

Voices

GET

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.

ParameterInTypeRequiredDescription
languagequerystringOptionalsw or suk.
idpathuuidOptionalUsed on GET /v1/voices/{id}/.

Response

[{
  "id": "…",
  "name": "Rafiki Kiswahili",
  "language": "sw",
  "kind": "preset",
  "status": "ready"
}]

Voices

POST

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.

ParameterInTypeRequiredDescription
namebodystringRequiredDisplay name.
languagebodystringRequiredsw or suk.
samplesbodyfile[]RequiredRecordings of the consenting speaker.
consent_acceptedbodybooleanRequiredMust be true.
consent_textbodystringRequiredExact text from GET /v1/voices/consent-script/.

Request

GET /v1/voices/consent-script/
{ "script": "…" }

Response

{ "id": "…", "status": "queued", "consent_accepted": true }

Developers

POST

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/.

ParameterInTypeRequiredDescription
namebodystringRequiredLabel for this key.
envbodystringRequiredtest or live.
scopesbodystring[]Requiredtts, 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

GET

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": []
}