GraphQL APIRead and edit the catalog
One GraphQL endpoint reads and edits the whole catalog. Reading requires no authentication; editing requires a token, which you can issue yourself. Every change is kept, attributed and reversible, which is what makes it safe to hand the job to an agent.
https://findopera.com/api/graphqlReading
No token required. Search by name, filter recordings by the people on them, or fetch anything by id.
curl -s https://findopera.com/api/graphql \
-H 'Content-Type: application/json' \
-d '{"query": "{ searchOperas(query: \"Boheme\", first: 3) { title } }"}'Name searches ignore case and accents and match on part of a word, so Boheme finds La Bohème. That is worth leaning on: a short distinctive fragment beats a full title somebody may have transliterated differently.
Tokens
Mutations need one, and it raises the read limit too, so send it on every request rather than only on writes. Nobody is asked to prove who they are — the token is not there to identify you, it is there so your requests can be told apart from everyone else's. That is what lets an edit be attributed, and a run of bad ones be found together and undone.
Authorization: Bearer fo_…Issue one on your account page if you have signed in, or ask for a fresh account with createAccessToken. It is shown once and stored only as a hash, so a lost one is replaced rather than recovered. The username you pick is public and appears on every edit you make; the optional email never is.
Editing
Three mutations for every type in the schema: addSinger, updateRecording, deleteCharacter.
mutation {
updateSinger(
id: "1234"
input: { born: 1927 }
justification: "Born 1927 per https://www.example.org/…"
) { id }
}The same thing over the wire, with the token that makes it yours:
curl -s https://findopera.com/api/graphql \
-H 'Authorization: Bearer fo_…' \
-H 'Content-Type: application/json' \
-d '{"query": "mutation { updateSinger(id: \"1234\", input: {born: 1927}, justification: \"Born 1927 per https://example.org/…\") { id } }"}'Every mutation requires a justification, and it should carry a verifiable source — a URL to somewhere reputable — along with whatever context makes the change make sense. It is not a formality: records here are immutable and anyone may become an editor, so the reason you give is the whole of what a later reader has to judge the change by. You can watch them arrive on Live Changes.
Rate limits
- With a token — 600 requests a minute.
- Anonymous — 60 a minute, keyed on your address.
createAccessToken— 5 an hour.submitFeedback— 10 an hour.
Over one and you get HTTP 429 with a Retry-After header, and a GraphQL error whose extensions.retryAfter is the seconds to wait. Wait that long; do not retry straight away.
Something wrong?
The catalog is community maintained and has gaps. If you find one, the fix is to close it — that is what the mutations are for. If you would rather just point at it, every record page has a Report Issue link.
Elsewhere
- Playground — run a query here, no token needed to read.
- schema.graphql — every type and field, about 92kb.
- llms.md — the full reference, written for an agent to read.
- The CLI — all of this without writing a query.