Paid
Chat without naming a genie
POST
/api/v1/chat4p- Scope
ai:chat- Price
- 4p per call
One stateless turn with our general study tutor, or with a custom genie you shape per request. Same price as a subject genie message, and nothing you send is kept.
What to know
- NO "genie" BLOCK GIVES YOU THE GENERAL STUDY TUTOR: our subject-agnostic tutor for students following the UK curriculum, across every subject, plus study skills and revision technique. It is the right default when you do not know what your user will ask about.
- A "genie" BLOCK SHAPES TONE AND SCOPE, AND NOTHING ELSE. Your settings change how the tutor sounds, what it concentrates on and what it will additionally decline to discuss. They cannot make it anything other than an educational tutor for school-age students, cannot switch off or soften the safety rules, and cannot unlock content it would otherwise refuse. A setting that tries to is simply outranked.
- NOTHING YOU SEND IS STORED. There is no genie record to create, list, edit or delete: your settings are read, used to build one prompt, and dropped when the response ends. The conversation is not persisted either, so send the history on every call and keep your own copy.
- SAFEGUARDING DETECTION IS ALWAYS ON AND CANNOT BE TURNED OFF, on this endpoint exactly as on the subject genies, and no field in the "genie" block affects it. Where a message suggests a user may be at risk you get a `refusal` event with a reason instead of an answer, and the call is not charged. Your product must handle it responsibly: show the user something appropriate, give them a route to real help, and never hide the event or retry to get past it (developer terms clause 8.7).
- DO NOT SEND US PERSONAL DATA ABOUT YOUR USERS, in message content or in the "genie" block. Names, contact details and school details must not appear. Your users are yours; we are not your processor for them (developer terms clause 8.4).
- THE PRICE IS THE SAME AS A SUBJECT GENIE MESSAGE, and it is the same charge: both endpoints bill one assistant message at the same rate, so you can move between them without a second figure to budget for.
- WANT A SPECIFIC QUALIFICATION AND BOARD? Use POST /api/v1/genies/{shortName}/chat instead. A subject genie is written against a real specification and knows its board’s terminology and conventions; naming a subject here scopes the conversation but does not fetch a specification.
- A stream that ends mid-answer emits an `error` event. Content already delivered is charged; a stream that produces nothing at all is refunded.
- THE HISTORY IS TRUNCATED TO A TOKEN BUDGET, exactly as on the subject-genie endpoint. The price is the same whatever you send, so we cap what reaches the model at roughly 6,000 tokens of conversation, keeping the newest turns and always the final user message. Whole messages are dropped, never half of one, and `usage.truncatedHistory` tells you when it happened.
- Any surface in your product powered by this endpoint must show "Powered by Revision Genie" where the user can see it (developer terms clause 4.1).
Request body
| Field | Type | Required | Description |
|---|---|---|---|
| messages | array | Yes | The whole conversation, oldest first. Each entry is { role: "user" | "assistant", content: string }. Between 1 and 40 entries, each up to 8,000 characters, and the last one must have role "user". |
| stream | boolean | No | Defaults to true, which returns NDJSON. Set false to get one JSON object once the turn is finished. |
| options.hintFirst | boolean | No | Defaults to true. The genie leads a student towards the answer before giving it, and always gives it by its second reply. Set false for straight answers, which is usually right when your user is a teacher. Applies whether or not you send a "genie" block. |
| genie | object | No | Omit it and you get the general study tutor. Send it and you get a custom genie shaped by the fields below, for this one request only. An empty object is the same as omitting it. |
| genie.name | string | No | What your product calls the tutor, up to 60 characters. It answers to the name. It does not change what the tutor knows or what it will discuss. |
| genie.subject | string | No | What the conversation is about, up to 80 characters, for example "GCSE Biology" or "Year 9 algebra". The tutor keeps to it and steers a student back if they drift. |
| genie.teachingStyle | string | No | One of friendly, socratic, concise, step-by-step. Anything else is refused rather than ignored, so you never pay for a style that did not apply. |
| genie.instructions | string | No | Your own tone and focus preferences, up to 500 characters. They shape how the tutor sounds and what it concentrates on. They cannot change what it fundamentally is. |
| genie.avoidTopics | string | No | Things the tutor should politely decline to discuss, up to 300 characters. It only ever ADDS to what is already refused; it cannot subtract. |
Example request
curl
curl -X POST "https://www.revisiongenie.com/api/v1/chat" \
-H "Authorization: Bearer rgk_live_YOUR_KEY_HERE" \
-H "Content-Type: application/json" \
-d '{"messages":[{"role":"user","content":"Why do plants need magnesium?"}],"stream":false,"genie":{"name":"Ada","subject":"GCSE Biology","teachingStyle":"concise"}}'Example response
json
// no "genie" block: the general study tutor
{
"message": "Magnesium sits at the centre of every chlorophyll molecule ...",
"usage": { "costPence": 4, "balancePence": 4812, "truncatedHistory": false }
}
// stream: true (application/x-ndjson, one JSON object per line)
{"type":"delta","text":"Magnesium sits at "}
{"type":"delta","text":"the centre of every "}
{"type":"done","usage":{"costPence":4,"balancePence":4812,"truncatedHistory":false}}
// a safeguarding refusal, uncharged, HTTP 200
{"type":"refusal","reason":"safeguarding","message":"This message raises a wellbeing concern. Your application is responsible for directing the user to appropriate support."}Errors
Every error carries the same shape: a stable error code to branch on and a message for a human. Codes specific to this endpoint come first.
| Code | Status | When |
|---|---|---|
| insufficient_balance | 402 | The balance does not cover the call. The body carries `balancePence` and a top-up link. |
| billing_not_enabled | 403 | The paid endpoints are not enabled on this developer account. |
| invalid_request | 400 | The body is not JSON, is not a JSON object, or a field failed validation. The message names the field. |
| request_too_large | 413 | The request body is larger than 32 KB. Trim the oldest turns. |
| upstream_failed | 502 | The model was unavailable or returned nothing. The call is not charged. |
| invalid_key | 401 | The key is missing, malformed, revoked, expired, or is not a developer key. |
| forbidden | 403 | The key is valid but does not hold the scope this endpoint requires. |
| suspended | 403 | The developer account is suspended. Data reads stop as well as billable calls. |
| rate_limited | 429 | The key went past its ceiling: 120 calls a minute overall, 30 a minute on the paid endpoints. Also returned after repeated failed authentication from one address. |
| server_error | 500 | Something failed on our side. Retry; a paid call is refunded. |