Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.opper.ai/llms.txt

Use this file to discover all available pages before exploring further.

Use the JSON API when you have a clear, one-shot task, like parsing a receipt, extracting fields from a document, or classifying a ticket. You give it a name, a short instruction, an input (text, image, audio, PDF, and so on), and the shape of what you want back. You get a typed JSON object. Unlike a chat loop, there’s no message history and no roles. You send a task and get a result.

Your first call

Here we parse a receipt. The instruction says what to do, the input is the receipt text, and the output_schema describes the JSON we want back.
import os
from pydantic import BaseModel
from opperai import Opper

class Receipt(BaseModel):
    merchant: str
    total: float
    currency: str

opper = Opper(http_bearer=os.getenv("OPPER_API_KEY", ""))

result = opper.call(
    name="parse-receipt",
    instructions="Extract the merchant, total, and currency from the receipt text.",
    input="Starbucks\n2x Latte\nSubtotal: $9.50\nTax: $0.75\nTotal: $10.25",
    output_schema=Receipt,
)

print(result.json_payload)
You get back a typed JSON object:
Response
{
  "data": {
    "merchant": "Starbucks",
    "total": 10.25,
    "currency": "USD"
  },
  "meta": {
    "name": "parse-receipt",
    "execution_ms": 412,
    "models_used": ["openai/gpt-5-mini"],
    "usage": { "input_tokens": 41, "output_tokens": 23 }
  }
}
Over the API the payload sits under data; the SDK exposes it as result.json_payload. The meta field tells you which model ran, how long it took, and what it cost.

Multiple input fields

When you have more than one piece of input, pass an object. Each key gets passed to the model alongside the instruction.
from pydantic import BaseModel

class Triage(BaseModel):
    category: str
    priority: str
    confidence: float

result = opper.call(
    name="classify-ticket",
    instructions="Pick the best category and priority for the support ticket.",
    input={
        "subject": "Can't reset my password",
        "body": "I clicked the reset link but the page is broken.",
    },
    output_schema=Triage,
)

print(result.json_payload)
Response
{
  "data": {
    "category": "account-access",
    "priority": "high",
    "confidence": 0.92
  },
  ...
}

Parse a PDF, image, or audio file

This is where the JSON API shines. Any input field can be a base64-encoded file. Mark its type in the input_schema and the model reads the file directly, no OCR or pre-processing on your side. Here’s a full invoice parse, line items and all, straight from a PDF:
Python
import os
import base64
from pathlib import Path
from pydantic import BaseModel
from opperai import Opper

class LineItem(BaseModel):
    description: str
    quantity: int
    amount: float

class Invoice(BaseModel):
    vendor: str
    invoice_number: str
    date: str
    currency: str
    line_items: list[LineItem]
    total: float

opper = Opper(http_bearer=os.getenv("OPPER_API_KEY", ""))

pdf_b64 = base64.b64encode(Path("invoice.pdf").read_bytes()).decode()

result = opper.call(
    name="parse-invoice",
    instructions="Extract the invoice details from the attached PDF.",
    input={"document": pdf_b64},
    input_schema={
        "type": "object",
        "properties": {
            "document": {
                "type": "string",
                "contentMediaType": "application/pdf",
                "contentEncoding": "base64",
            }
        },
        "required": ["document"],
    },
    output_schema=Invoice,
)

print(result.json_payload)
result.json_payload comes back as a dict with the invoice fields, nested line items included:
{
  "vendor": "ACME SUPPLIES AB",
  "invoice_number": "INV-2024-0815",
  "date": "2024-11-06",
  "currency": "SEK",
  "line_items": [
    {"description": "Large wooden sled", "quantity": 1, "amount": 1799.0},
    {"description": "Reindeer harness",  "quantity": 2, "amount": 300.0},
    {"description": "Gift wrapping",      "quantity": 1, "amount": 49.0}
  ],
  "total": 2685.0
}
Swap application/pdf for image/jpeg, audio/wav, or any other supported type. Schemas has the full media-type list.

Pick a specific model

By default Opper picks the model. To pin one, pass model:
Python
result = opper.call(
    name="parse-receipt",
    instructions="Extract the merchant, total, and currency.",
    input="...",
    output_schema=Receipt,
    model="anthropic/claude-sonnet-4-6",
)
To say “go fast” or “go cheap” without naming a model, use Hints.

Why the name matters

The name (like parse-receipt or classify-ticket) identifies the task. It does two things:
  • Labels the call on its trace, so you can see what each call was for.
  • Acts as a cache key, so reusing the same name makes repeat calls of the same task faster.
Use one stable, descriptive name per task. For workflows and repeated tasks, reuse the name instead of generating a new one each call.
Name by task, not by request: parse-receipt, not parse-receipt-{uuid}.

Request fields

name
string
required
A short identifier for what this call does. Use the same name for the same task across your app.
instructions
string
What the model should do. Plain English. Keep it short.
input
string | object
What you want it done with. Can be a string or an object with any fields, including base64 media.
input_schema
JSON Schema
Optional. Validates the shape of input before it goes to the model, and lets you mark fields as images, PDFs, or audio.
output_schema
JSON Schema | Pydantic | Zod
Optional but recommended. Tells the model exactly what JSON to return, and validates it.
model
string
Optional. Pin a model, e.g. openai/gpt-5-mini. If omitted, Opper picks one.
hints
object
Optional. Soft preferences like prefer: "cheap" or temperature: 0.2. See Hints.

What’s next

Schemas

Pydantic, Zod, raw JSON Schema, and media types in depth.

Streaming

See fields arrive one at a time as the model generates them.

Hints

Optimize for cost, speed, or quality without picking a model.

Control Plane

Govern, score, and improve every call.