Browse the docsDefault
Image
Identical wire format to OpenWorld - so the OpenAI SDK works unchanged, just with base_url set to …/v1/extract. The difference is server-side: your text and system messages are discarded and the fixed extraction prompt runs against each image on its own.
Sending "text": "only give me the invoice number" here does nothing - it is dropped before inference. If you need instruction-guided output, use OpenWorld.
import base64, mimetypes
from openai import OpenAI
API_KEY = "Your API Key"
BASE_URL = "https://labs-api.petpooja.com/v1/extract"
MODEL = "chitragupta"
client = OpenAI(api_key=API_KEY, base_url=BASE_URL)
IMAGE_PATH = "<IMAGE_PATH>"
mime = mimetypes.guess_type(IMAGE_PATH)[0] or "image/jpeg"
img_b64 = base64.b64encode(open(IMAGE_PATH, "rb").read()).decode()
image_data_uri = f"data:{mime};base64,{img_b64}"
response = client.chat.completions.create(
model=MODEL,
messages=[{
"role": "user",
"content": [
{"type": "text", "text": ""},
{"type": "image_url", "image_url": {"url": image_data_uri}},
],
}],
)
print(response)import fs from "node:fs";
const API_KEY = "Your API Key";
const BASE_URL = "https://labs-api.petpooja.com/v1/extract/chat/completions";
const image = fs.readFileSync("<IMAGE_PATH>").toString("base64");
const res = await fetch(`${BASE_URL}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${API_KEY}`,
},
body: JSON.stringify({
model: "chitragupta",
messages: [{
role: "user",
content: [
{ type: "text", text: "Extract the invoice information as JSON." },
{ type: "image_url", image_url: { url: `data:image/jpeg;base64,${image}` } },
],
}],
}),
});
const data = await res.json();
console.log(data.choices[0].message.content);package main
import (
"encoding/base64"
"fmt"
"io"
"net/http"
"os"
"strings"
)
const (
key = "Your API Key"
url = "https://labs-api.petpooja.com/v1/extract/chat/completions"
model = "chitragupta"
path = "<IMAGE_PATH>"
)
func main() {
data, err := os.ReadFile(path)
if err != nil {
panic(err)
}
b64 := base64.StdEncoding.EncodeToString(data)
body := fmt.Sprintf(`{"model":"%s","messages":[{"role":"user","content":[
{"type":"text","text":"Extract the invoice information from this image as JSON."},
{"type":"image_url","image_url":{"url":"data:image/jpeg;base64,%s"}}
]}]}`, model, b64)
req, _ := http.NewRequest("POST", url, strings.NewReader(body))
req.Header.Set("Authorization", "Bearer "+key)
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
out, _ := io.ReadAll(res.Body)
fmt.Println(res.StatusCode)
fmt.Println(string(out))
}KEY="Your API Key"
BASE="https://labs-api.petpooja.com/v1/extract/chat/completions"
IMAGE="<IMAGE_PATH>"
IMAGE_URI="data:image/jpeg;base64,$(base64 -w0 "$IMAGE")"
cat > /tmp/pp_extract_image.json <<EOF
{
"model": "chitragupta",
"max_tokens": 4000,
"messages": [
{
"role": "user",
"content": [
{
"type": "text",
"text": "Extract all visible text and details from this image."
},
{
"type": "image_url",
"image_url": {
"url": "$IMAGE_URI",
"detail": "high"
}
}
]
}
]
}
EOF
curl -s -i "$BASE" \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d @/tmp/pp_extract_image.jsonEach page of each PDF becomes its own model call, dispatched concurrently, and the per-page results are concatenated in order. A large batch costs roughly the wall-clock of a single page, and one unreadable page never poisons the rest of the document.
Fan-out limit
| Limit | Value | On breach |
|---|---|---|
| Pages + images per request | 25 | 413 page_limit_exceeded |
import base64
from openai import OpenAI
API_KEY = "Your API Key"
BASE_URL = "https://labs-api.petpooja.com/v1/extract"
MODEL = "chitragupta"
client = OpenAI(api_key=API_KEY, base_url=BASE_URL)
PDF_PATH = "<PDF_PATH>"
pdf_b64 = base64.b64encode(open(PDF_PATH, "rb").read()).decode()
pdf_data_uri = f"data:application/pdf;base64,{pdf_b64}"
response = client.chat.completions.create(
model=MODEL,
messages=[{
"role": "user",
"content": [
{"type": "text", "text": "Extract the invoice information from this document as JSON."},
{"type": "file", "file": {"filename": "invoice.pdf", "file_data": pdf_data_uri}},
],
}],
)
print(response)import fs from "node:fs";
const apiKey = "Your API Key";
const baseURL = "https://labs-api.petpooja.com/v1/extract/chat/completions";
const model = "chitragupta";
const pdfPath = "<PDF_PATH>";
async function main() {
const b64 = fs.readFileSync(pdfPath).toString("base64");
const body = {
model,
messages: [{
role: "user",
content: [
{ type: "text", text: "Extract information of last page from this document as JSON." },
{ type: "file", file: { filename: "invoice.pdf", file_data: `data:application/pdf;base64,${b64}` } }
]
}]
};
const res = await fetch(baseURL, {
method: "POST",
headers: {
"Authorization": `Bearer ${apiKey}`,
"Content-Type": "application/json"
},
body: JSON.stringify(body)
});
console.log("HTTP Status:", res.status);
console.log(await res.text());
}
main();package main
import (
"encoding/base64"
"fmt"
"io"
"net/http"
"os"
"strings"
)
const (
apiKey = "Your API Key"
baseURL = "https://labs-api.petpooja.com/v1/extract/chat/completions"
model = "chitragupta"
pdfPath = "<PDF_PATH>"
)
func main() {
data, err := os.ReadFile(pdfPath)
if err != nil {
panic(err)
}
b64 := base64.StdEncoding.EncodeToString(data)
body := fmt.Sprintf(`{"model":"%s","messages":[{"role":"user","content":[
{"type":"text","text":"Extract information of last page from this document as JSON."},
{"type":"file","file":{"filename":"invoice.pdf","file_data":"data:application/pdf;base64,%s"}}
]}]}`, model, b64)
req, _ := http.NewRequest("POST", baseURL, strings.NewReader(body))
req.Header.Set("Authorization", "Bearer "+apiKey)
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
out, _ := io.ReadAll(res.Body)
fmt.Println("HTTP Status:", res.StatusCode)
fmt.Println(string(out))
}KEY="Your API Key"
BASE="https://labs-api.petpooja.com/v1/extract/chat/completions"
PDF="<PDF_PATH>"
PDF_URI="data:application/pdf;base64,$(base64 -w0 "$PDF")"
cat > /tmp/pp_chat_pdf.json <<EOF
{
"model": "chitragupta",
"max_tokens": 8000,
"messages": [
{
"role": "user",
"content": [
{
"type": "text",
"text": "Extract all details from this document and return the extracted information."
},
{
"type": "file",
"file": {
"file_data": "$PDF_URI",
"filename": "document.pdf"
}
}
]
}
]
}
EOF
curl -s -i "$BASE"\
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d @/tmp/pp_chat_pdf.jsonModel response
Both endpoints return a standard chat.completion object. Default packs its per-page results into the single assistant message, each block prefixed with its source tag so you can trace any extracted value back to the exact page it came from.
| Field | Type | Description |
|---|---|---|
| id | string | Completion id. |
| model | string | Always the logical name chitragupta. The underlying provider is never exposed. |
| choices[0].message.content | string | The extracted content. For Default, blocks tagged pdf1_page1:, image1:, in request order. |
| choices[0].finish_reason | string | stop - the model finished. length - output was cut short at a token limit. |
| usage | object | prompt_tokens, completion_tokens, total_tokens - reported for observability. Billing is per page. |
Because max_tokens already defaults to the 40000 ceiling, a length finish almost always means the context window filled up, not the output cap. Raising max_tokens will not fix it - send fewer pages per request.
request_id : "value"
usage : CompletionUsage(completion_tokens="value", prompt_tokens="value", total_tokens="value")
==============================================================================
pdf1_page1: ```json
{"SELLER_DETAILS":{"COMPANY_NAMES" : ["Acme Corp"],"ADDRESS": ["123 Business Rd, Tech Park, New Delhi-110001, India", "Acme...
```
pdf1_page2: ```json
{"SELLER_DETAILS":{"COMPANY_NAMES" : ["Acme Corp"],"ADDRESS": ["123 Business Rd, Tech Park, New Delhi-110001, India", "Acme...
```
pdf1_page3: ```json
{"SELLER_DETAILS":{"COMPANY_NAMES" : ["Acme Corp"],"ADDRESS": ["123 Business Rd, Tech Park, New Delhi-110001, India", "Acme...
```
...