Skip to content

AI in your application

Markdown

Your application can ask a model to read text, PDFs and images and to answer in text, or in JSON that follows a schema you give. Apigami calls the model in its own name, in the EU: you need no AI account, no key and no server. What you send is processed without being stored and is never used for training.

POST /call
{
"op": "ai.generate",
"params": {
"instructions": "Extract the person's name and city. Use null for what the text does not say.",
"input": [{ "text": "Jean Dupont, developer, lives in Lyon." }],
"output_schema": {
"type": "object",
"properties": {
"name": { "type": "string" },
"city": { "type": ["string", "null"] }
},
"required": ["name", "city"]
}
}
}
Result
{
"result": {
"output": { "name": "Jean Dupont", "city": "Lyon" },
"finish_reason": "stop",
"usage": { "input_tokens": 188, "output_tokens": 43 }
}
}

ai.generate is answered by Apigami itself, never by a browser: it takes no domain, no user_ref, and opens no approval window.

The AI is in preview, open to a few teams. Any other team’s call answers 403 ai is not open to this group yet.

  1. Declare the permission in your manifest, beside your sites (Permissions: ai):

    "x-apigami": { "permissions": ["ai"] }

    The version whose code calls must declare it: the one a run executes, the production version for your apg_ key and for APIGAMI_KEY. A brick’s production version must declare it too, since that is what the connect page of the applications using it shows.

  2. Deploy, and publish to call from your server with your API key. The connect page then lists, among what your application may do, « Use an AI: what you entrust to it is processed in the cloud, without storage or training ». Nothing to tick.

Caller Credential
Your server your API key, apg_…
The action of a cron, for several people env.APIGAMI_KEY, the production version’s key
An action, a trigger, a schedule the run token in X-Apigami-Run

The AI answers your application, not a person: a run with nobody behind it, such as an open_action or a schedule, calls it like any other. A page cannot: its token is the visitor’s, who could write the instructions. Call an action of yours from the page with apigami.call, and call the AI from that action.

actions/extract.ts
export const extractPerson = async (env, runToken: string, pdfBase64: string) => {
const answer = await fetch(`${env.APIGAMI_API_URL}/call`, {
method: 'POST',
headers: { 'X-Apigami-Run': runToken, 'Content-Type': 'application/json' },
body: JSON.stringify({
op: 'ai.generate',
params: {
instructions: 'Extract the person this resume is about.',
input: [{ file: { media_type: 'application/pdf', data_base64: pdfBase64 } }],
output_schema: { type: 'object', properties: { name: { type: 'string' } }, required: ['name'] },
},
}),
})
const body = await answer.json()
// Never log the input or the output: your logs are kept, and the content is someone else's.
if (!answer.ok) throw new Error(`ai refused: ${answer.status} ${body.error}`)
return body.result.output
}
Param
instructions required What the model must do, 1 to 32 000 characters
input required 1 to 10 parts, read in order: { "text": "…" } or { "file": { "media_type": "…", "data_base64": "…" } }
output_schema optional A JSON Schema of the answer, 16 kB at most. Absent, the answer is text
max_output_tokens optional 1 to 16 384, 4 096 by default

The model, its temperature and its settings are Apigami’s: they may change, never the contract.

  • Text parts total 500 000 characters at most.
  • A file is a PDF (application/pdf), plain text (text/plain) or an image (image/png, image/jpeg, image/webp), in standard base64. Its first bytes must match its type.
  • 14 MB of files at most per call, decoded, all files together.
  • A Word or OpenDocument file is refused with a 415: convert it to PDF or text first.

With output_schema, output is the parsed JSON, which follows the schema. A schema written by zod’s z.toJSONSchema or pydantic passes as it is. The keywords the model reads are type, properties, required, items, prefixItems, additionalProperties, enum (strings or numbers), anyOf, oneOf, title, description, format, minItems, maxItems, minimum, maximum, propertyOrdering, $schema, $id, $anchor, $defs and $ref. Any other, such as pattern or minLength, is refused with its path rather than silently ignored. A value that may be absent is written "type": ["string", "null"].

description is read by the model: say there what a field holds, and what to answer when the document does not say.

usage counts the tokens of the call. output_tokens includes the model’s reasoning. Without a schema, finish_reason is max_output_tokens when the text was cut short; with a schema, a cut answer is a 422, since half a JSON is of no use.

Status error What to do
400 ai answers the caller, not a person: remove user_ref and install_ref Send neither
403 a page cannot call the ai: … Call it from an action, which the page calls with apigami.call
403 the calling app does not declare this app in its dependencies A brick’s run, after the application calling it removed it
409 publish a version with app_publish before an api key calls the ai: … Publish once: your key runs production’s manifest
403 ai not permitted for this app: … Declare "permissions": ["ai"] in the version that calls, and deploy
403 ai is not open to this group yet The AI is in preview: write to contact@apigami.com
400 invalid ai params: params.input[1].file.data_base64: does not start like application/pdf Fix the field it names
413 ai input too large: at most 14 MB of files per call Send fewer or smaller files
415 unsupported media type …: send pdf, text or an image Convert the file to PDF or text
400 invalid ai params: the model cannot read this input, … Check the files, and the schema
503 ai is not configured Apigami’s side: write to contact@apigami.com
503 the model is busy, try again in a minute Wait for Retry-After, then try again
502 the model could not answer, try again later Try again later
422 the model declined to answer: safety The content was refused by the model’s filters: do not retry as is
422 ai output cut at max_output_tokens: … Raise max_output_tokens, or ask for less

A refusal never repeats what you sent. Apigami never retries a call by itself: a call is billed once.

  • Apigami keeps one line per call: the application, its version, the model, the tokens, the duration and whether it answered. Never the instructions, the files nor the answer.
  • The model’s provider, Google Cloud, processes the call in the EU and stores nothing of it, with one exception: a request its abuse filters flag may be kept up to 90 days, in the EU, for review. Nothing is used for training.
  • Your application is responsible for what it does with the answers. Never write an input or an output of the AI to your logs: they are kept.