Overview
Fikra API is an OpenAI-compatible AI inference API. You send chat-completions requests to POST https://api.fikraapi.co.ke/v1/chat/completions and get OpenAI-style responses back, streaming included. Because the base URL is interchangeable with OpenAI's, you can point the OpenAI SDK at Fikra API and loop over your language list.
For translation work, the cheapest model in the catalogue is deepseek-v4-flash-0731 at 0.09 USD per 1M input tokens and 0.15 USD per 1M output tokens. Localizing the same source string into 30 languages means 30 small output requests, so cost stays low per string. Billing is a token-credit wallet topped up by M-Pesa or card via Paystack, and you can pay in USD or KES.
Prerequisites
- A Fikra API key. No credit-card gate is required to get started.
- Python 3 and the
openaiSDK installed. - Your source copy on hand, one string or file per batch you want localized.
- Your wallet topped up before running large batches.
- Environment variable
FIKRA_API_KEYset in your shell or host , never hardcode the key in source files that get committed.
Step-by-step
- Export your key server-side:
export FIKRA_API_KEY="your-fikra-api-key"
- Create a client pointed at Fikra API:
import os
from openai import OpenAI
client = OpenAI(
base_url="https://api.fikraapi.co.ke/v1",
api_key=os.environ["FIKRA_API_KEY"],
)
- Define your target languages:
LANGUAGES = [
"Swahili", "French", "Spanish", "Portuguese", "German",
"Italian", "Dutch", "Arabic", "Turkish", "Russian",
"Polish", "Ukrainian", "Hindi", "Bengali", "Urdu",
"Indonesian", "Vietnamese", "Thai", "Filipino", "Malay",
"Japanese", "Korean", "Simplified Chinese", "Traditional Chinese",
"Hebrew", "Greek", "Czech", "Romanian", "Swedish", "Danish",
]
- Send one request per language, keeping the source copy identical and only the target language changing:
source = "Your subscription renews automatically. Cancel anytime."
for language in LANGUAGES:
response = client.chat.completions.create(
model="deepseek-v4-flash-0731",
messages=[
{
"role": "system",
"content": (
"You are a localization editor. Translate the user's copy "
"into the requested language. Preserve placeholders, product "
"names, and tone. Return only the translated text."
),
},
{
"role": "user",
"content": f"Target language: {language}\n\n{source}",
},
],
)
print(language, "->", response.choices[0].message.content)
-
Throttle the loop to stay inside your rate limit. Unverified accounts are limited to 30 requests/min; trusted accounts get 100 requests/min. Thirty languages per string fits comfortably under either limit, but chunk large batches and add a short sleep between requests.
-
Store the outputs keyed by language and source-string ID so re-runs only translate what changed.
Verify it works
Run the loop with a single language first and confirm you get a translated string back:
response = client.chat.completions.create(
model="deepseek-v4-flash-0731",
messages=[{"role": "user", "content": "Translate to Swahili: Cancel anytime."}],
)
print(response.choices[0].message.content)
Then check that placeholders such as {name} or %s survive translation unchanged in every language before you ship the strings. Streaming is supported if you want to render output as it arrives.
Costs
Pricing is per 1M tokens and starts at 0.09 USD input / 0.15 USD output for deepseek-v4-flash-0731.
| Model | Input (USD / 1M tokens) | Output (USD / 1M tokens) |
|---|---|---|
| deepseek-v4-flash-0731 | 0.09 | 0.15 |
| deepseek-v4.1-flash | 0.25 | 0.80 |
| deepseek-v4.1-flash-1017 | 0.30 | 0.85 |
| fikra-auto | 0.40 | 0.40 |
| fikra-auto-pro | 6.00 | 12.00 |
| fikra-code-35b | 1.00 | 1.00 |
Localization is many short requests, so deepseek-v4-flash-0731 is the usual starting point; move up only if quality on a given language pair demands it. For exact current numbers, check the pricing page. Top up the token-credit wallet with M-Pesa or card via Paystack, in USD or KES.
Common errors
- 401 Unauthorized , the key is wrong, revoked, or inactive. Generate a fresh scoped key and confirm
FIKRA_API_KEYis set in the environment the process actually runs in. - 400 Bad Request , the
modelvalue is unsupported. Use one of the model IDs listed in Costs; they are exact strings. - 429 Too Many Requests , you exceeded your rate limit (30 requests/min unverified, 100 requests/min trusted). Back off and retry, and cap concurrency in your language loop.
- 503 Service Unavailable , the upstream model is busy. Retry with exponential backoff rather than failing the whole batch.
Keys are scoped and revocable and never shared between users; keep them server-side in every example you deploy.