API Reference
All four models sit behind https://api.bodhan.ai. The /v1 routes take OpenAI-style requests, so an existing SDK only needs a new base_url.
Authentication
Send your key as a bearer token on every request. Keys live in the dashboard; if you do not have an account yet, create one.
Speech to Text API
https://api.bodhan.ai/v1/audio/transcriptionsmultipart/form-dataTurns speech into text in 25 Indian languages and English. The transcript comes back in the language that was spoken.
- Send the audio as
multipart/form-data. WAV is the documented format; FLAC, OGG and MP3 are also accepted. - Each request takes up to 30 seconds of audio; longer audio is rejected.
- Billing is per second of audio, so trim silence before you send it.
Authentication
Authorization: Bearer <YOUR_BODHAN_KEY>header (required)
Request
Body (multipart/form-data)
-
file(file, required) — The audio to transcribe. -
model(string, required) —indic-transcribe. -
language(enum, optional) — Language of the audio. Omit it and the vendor auto-detects, but naming it is the difference between a correct transcription and a garbled one for non-English audio, so pass it whenever you know it.Available options:
Code Language Code Language asAssamese maiMaithili bhbBhili mlMalayalam bhoBhojpuri mniManipuri bnBengali mrMarathi brxBodo neNepali doiDogri orOdia enEnglish (Indian and global) paPunjabi guGujarati saSanskrit hiHindi satSantali knKannada sdSindhi kokKonkani taTamil ksKashmiri teTelugu urUrdu
Response
200
text(string, required) — The transcript.
415
The audio's duration could not be measured, so the request cannot be metered and was not transcribed. Send WAV, the documented format; FLAC, OGG and MP3 are also accepted. Containers such as M4A, AAC, WebM and AMR are refused with this status.
Translation API
https://api.bodhan.ai/v1/chat/completionsapplication/jsonTranslates text between English and 22 Indian languages, in native or Roman script. You send the text and the two language codes; the gateway writes the prompt.
- One
usermessage, whosecontentis the text itself. Do not put an instruction in it. - Decoding is fixed on the server.
temperature,max_tokens,streamand the other generation settings are rejected with422rather than ignored.
Authentication
Authorization: Bearer <YOUR_BODHAN_KEY>header (required)
Request
Body (application/json)
-
model(string, required) —indic-translate. -
messages(array, required) — Exactly one message,"role": "user", with the text to translate as itscontent. No system message. -
source_language_code(enum, required) — Language of the text. -
target_language_code(enum, required) — Language to translate into. Any pair works, Indic to Indic included. Available options for both:Code Language Code Language Code Language asAssamese knKannada orOdia bnBengali kokKonkani paPunjabi brxBodo ksKashmiri saSanskrit doiDogri maiMaithili satSantali enEnglish mlMalayalam sdSindhi guGujarati mniManipuri taTamil hiHindi mrMarathi teTelugu neNepali urUrdu -
target_script(enum, optional) —native(default) orroman. Roman is the target language written in Latin letters, not a translation into English, so it is rejected whentarget_language_codeisen.
Response
200
A standard chat completion.
choices[0].message.content(string) — The translation.choices[0].finish_reason(string) —stopwhen the translation is complete.lengthmeans it was cut off; the text reads fluently and simply stops, so check this field. Split the text and send the parts.usage(object) — Token counts. Only output tokens are billed.
422
A generation setting was sent; the message shape is off (a system message, more than one message, array content, empty text); a language code is not in the table; or target_script is roman with target_language_code en.
Text to Speech API
https://api.bodhan.ai/v1/audio/speechapplication/jsonReads text aloud in 22 Indian languages and English, in 45 voices. The response is a WAV file.
- The language, and optionally a speaking style, go in
instructionsas a JSON string. Any voice can read any language. - Keep each request to a sentence or two, about 30 seconds of speech. Longer text is not split for you.
- The response is
audio/wav, PCM16 at 24 kHz, mono.
Authentication
Authorization: Bearer <YOUR_BODHAN_KEY>header (required)
Request
Body (application/json)
-
model(string, required) —indic-speak. -
input(string, required) — The text to read. Numbers, dates and currency are read out in the language given. -
voice(enum, required) — The speaker, by name. The 45 voices are grouped below by the language each was recorded in, but any voice can read any of the languages. Available options:Code Language Female Male asAssamese PrastutiAnkurbnBengali IshitaSouravbrxBodo GwrbwSansumadoiDogri PreetiShamguGujarati DharaParthhiHindi Kavya,SuhaniAmitknKannada DeepikaAdarshkokKonkani AnjaliSandeepksKashmiri ZoonIshfaqmaiMaithili VaidehiMadhukarmlMalayalam LakshmiKiranmniManipuri ThoibiChaobamrMarathi AnaghaChinmayneNepali SrijanaSagarorOdia ItishreeAkashpaPunjabi KaurManpreetsaSanskrit BharatiAryamansatSantali PhulmaniSibusdSindhi MoomalRanotaTamil AnithaArunteTelugu SravaniVamsiurUrdu SabaZaid -
instructions(string, required) — A JSON string withlangand, if you want one,style:"{\"lang\": \"hi\", \"style\": \"news\"}".-
lang(required) — Language of the text. Available options:Code Language Code Language asAssamese mniManipuri bnBengali mrMarathi brxBodo neNepali doiDogri orOdia enEnglish paPunjabi guGujarati saSanskrit hiHindi satSantali knKannada sdSindhi kokKonkani taTamil ksKashmiri teTelugu maiMaithili urUrdu mlMalayalam -
style(optional) — Delivery. Leave it out for the voice's neutral reading. Available options:AIR style news,Customer Care,TV style news,advertisements,anger,children's stories,disgust,educational lecture,fear,happy,news,sad,single person narration audiobook,surprise.
-
Response
200
- The WAV audio itself, with
Content-Type: audio/wav. PCM16, 24 kHz, mono.
422
input was empty, voice, lang or style was not one of the values above, or instructions had no lang. The message names the unknown value and lists what is accepted.
Document OCR API
https://api.bodhan.ai/v1/chat/completionsapplication/jsonExtracts text and layout from a document image using Indic-OCR, served as the model
indic-ocr. The page is returned as reading-ordered Markdown, alongside the layout blocks it
was assembled from. Output is in the script of the input document.
The API follows the OpenAI chat completions format, and the transcribed page arrives in
choices[0].message.content. Layout information is returned in an additional top-level
blocks field.
Note:
- Send a whole document page image. The model detects layout and crops blocks itself; pre-cropping is unnecessary.
- We support PNG and JPEG only. PDFs are not supported.
- The image is sent inline as a base64 data URI, in a single user message. We support one image per request; there is no page or batch parameter.
- The request carries no prompt customization support.
- There is no
languagefield. The script is inferred from the image itself. - A single call returns both layout detection and transcription.
Authentication
Authorization: Bearer <YOUR_BODHAN_KEY>header (required)
Request
Body (application/json)
model(string, required): Must be"indic-ocr".messages(array, required): Exactly one user message whosecontentis an array holding a singleimage_urlpart. The image is a data URI:"data:image/png;base64,<base64-encoded bytes>".table_format(enum, optional): How tables are rendered."html"(default) preserves table structure, including merged cells;"markdown"emits a GitHub-style pipe table. See Tables below.max_tokens(integer, optional): Transcription limit per block, not per page. Defaults to2048. Raise it for pages containing large tables; see Truncation below.
Response
200
Successful Response
A standard chat.completion object with one additional top-level field, blocks.
id(string): Request identifier.created(integer): Unix timestamp.model(string):"indic-ocr".object(string):"chat.completion".choices(array): Exactly one choice.finish_reason(string):"stop".index(integer):0.message.role(string):"assistant".message.content(string): The full page as reading-ordered Markdown.
usage(object):prompt_tokens,completion_tokensandtotal_tokens, summed across every block on the page.blocks(array): The detected layout blocks, in reading order.
blocks is present at top-level, not inside choices.
Block object
order(integer): Reading-order index, from0.label(string): The block's layout role, e.g.Paragraph,Section-title. See Layout labels below.type(string): A coarser grouping oflabel, e.g.Text,Title,SectionHeader,Caption,Table,Picture.bbox_xyxy(array of 4 numbers): Bounding box as[x_min, y_min, x_max, y_max], in pixels of the image you uploaded, origin at the top-left.conf(number): Layout detection confidence,0.0to1.0. This scores block detection, not transcription accuracy.text(string): The block's transcribed text, or""for blocks that carry none.
Layout labels
label is drawn from a fixed 37-class taxonomy:
Advertisement |
Equation |
Infobox |
Sub-section-title |
Answer |
Expression |
List |
Sub-sub-section-title |
Author |
Flag |
MCQ |
Table |
Chapter-end-section |
Folio |
Page-number |
Table-caption |
Chapter-title |
Footer |
Paragraph |
Table-of-contents |
Chart |
Footnote |
Placeholder-text |
Title |
Code |
Header |
Question |
Website-link |
Contact-info |
Image |
Reference |
|
Dateline |
Image-caption |
Section-title |
|
Diagram |
Index |
Solved-example |
Some blocks are detected but not transcribed. They are returned with text: "" and keep their
place in reading order, so bounding boxes stay available even where there is no text:
- Pictorial regions, such as
Image,Chart,Diagramand figures. - Page furniture, such as
Header,FooterandAdvertisement.
Markdown output
message.content is the blocks' text joined in reading order, separated by blank lines:
- Headings are not marked up. A
Section-titleappears as a plain paragraph, not as##. Document structure is available fromblocks[].label, not from the Markdown. - Mathematics is LaTeX, using
$...$inline and$$...$$for display equations. Indic script inside a formula is wrapped in\text{...}. - Words split across a line break are rejoined, so
exam-\npleis emitted asexample. - Tables appear as HTML or Markdown according to
table_format. - Pictorial blocks will not be shown in the Markdown, though they remain in
blocks.
Tables
table_format trades structural fidelity against size:
html (default) |
markdown |
|
|---|---|---|
| Merged cells | preserved via rowspan / colspan |
flattened into separate columns |
| In-cell line breaks | <br/> |
removed |
Use the default html when a table has merged or multi-level headers, and markdown when the
table is simple and you want output that reads well as plain text.
Because HTML is substantially larger, a long table is the most common reason to exceed
max_tokens. A 50-row dense table may need max_tokens of 4096 as HTML, but fits the
2048 default as Markdown.
Truncation
max_tokens applies per block, so the default of 2048 is ample for ordinary prose.
Large tables are the realistic exception. If any block exceeds the limit, the request fails
with 502 and the page is not returned.
In that case, please raise max_tokens and retry. For documents known to contain large tables, raise it up front
rather than after a failure.
Errors
401
Missing, invalid, or expired API key.
{
"error": {
"message": "Authentication Error, No api key passed in.",
"type": "auth_error",
"code": "401"
}
}
502
The page could not be transcribed. Either a block exceeded max_tokens (see Truncation), or
the image could not be decoded. The detail field distinguishes the two.