Mint a token. Curl your campaign.
A REST API for Your D&D Campaign
Campaign tools usually end at their own edges. Whatever you have built up inside one lives there, and getting it anywhere else means a scraper, a CSV, or giving up. That is fine until you want a Discord command that answers questions about your own world, or a site that lists your factions, or a script that checks nobody has been left out of a session.
Realms of Shod publishes an HTTP API over the same realm you play in. Thirty-two endpoints cover realms, sessions, full transcripts, compendium entities and their relationships, notes, and quests. You mint a bearer token from the H.U.B., send it in a header, and get JSON back. It is an ordinary API, which is the point.
The Quick Answer
| Detail | The answer |
|---|---|
| Base URL | https://realmsofshod.com/api/v1 |
| Auth | Bearer token in the Authorization header |
| Token format | Prefixed ros_, 68 characters |
| Endpoints | 32, across five resource groups |
| Paging | Opaque cursors; 50 per page, 100 maximum |
| Rate limit | About 100 requests per 60 seconds, per token |
| Format | JSON in, JSON out |
| Price | Included with your account |
Nothing exotic. If you have used any REST API in the last decade, you already know how this one behaves.
What People Build With It
The API exists because the useful thing to do with a campaign record is rarely the thing the app happens to put on screen. A few shapes that come up often:
A site for the world
Pull the compendium and render it however your group likes: a static gazetteer, a faction directory, a family tree for the dynasty everyone has lost track of. Entities come back with their descriptions and types, relationships come back as pairs of ids with a type on the edge, so a graph falls out of two requests rather than a scraping project.
A bot that knows the campaign
Put a slash command in your Discord that answers who somebody is, or posts the last session's summary into the channel on a schedule. Sessions carry both a short and a full summary, so a bot can choose how much to say without generating anything itself.
Analysis nobody asked for
Transcript segments come back with a speaker, the text, and start and end timestamps in milliseconds. That is enough to work out who actually talked last Thursday, which is a number some tables find funny and others find confronting. It is also enough to find the session where a name was first said.
Writing back
It is not a read-only API. You can create entities and relationships, write and share notes, and drive quests through their step timeline, which means a tool you build can put work into the realm rather than just reporting on it. Anything designed to run on its own is worth pointing at an account whose role only allows what you intend.
The 32 Endpoints
| Group | Count | What it covers |
|---|---|---|
| Realms | 4 | List and get the realms you belong to; create one; rename one |
| Sessions | 3 | List sessions, get one with its summaries, page through its transcript |
| Entity graph | 12 | Entities and relationships: list, get, create, update, delete, merge, personal notes, image upload |
| Notes | 5 | Named compendium documents: list, get, create, update, delete |
| Quests | 8 | Quests and their step timelines, filterable by status and linked entity |
Two details worth knowing before you write against it. Entity images are a two-step upload, one call to request the slot and another to finalize it, rather than posting bytes to a single endpoint. And a quest's status is not a field you set: it follows from the step timeline, so you finish a quest by adding a completed, failed, or abandoned step. Statuses are active, completed, failed, and abandoned, and quests carry tags from a fixed vocabulary covering both the shape of the job and the reason for taking it.
Every endpoint is written out with its parameters, response shape, and examples in the API reference.
Tokens
Tokens are minted in the H.U.B., from the Configure API panel on the drawer rail at the bottom right. You give one a name, choose whether it expires, and copy the value before closing the panel.
- Shown once. The raw value appears immediately after creation and never again. Only the first eight characters are kept, so the panel can tell tokens apart later.
- Optional expiry. Pick 1, 7, 30, or 120 days, or unlimited. An expired token authenticates exactly as well as a made-up one, which is to say not at all.
- Disable or revoke. Disabling pauses a token without destroying it, for when something is misbehaving and you want it to stop right now. Revoking is immediate and permanent.
- It carries your access. A token acts as the account that made it, with the same realm roles and the same per-entry access. It is not a skeleton key.
The last point is the one to hold on to. Because a token inherits the access of the account behind it, the safest way to run something unattended is to give it its own account at the role it actually needs, rather than handing a script the keys to your own. The authentication reference covers minting, rotation, and revocation in full.
Paging, Errors, and Rate Limits
The unglamorous half of an API is where you find out whether anyone thought about the people using it. Three things worth stating.
Paging is the same everywhere
Every list endpoint answers with the same envelope: your results, a cursor for the next page, and a flag saying whether there is one. Pages default to fifty and cap at a hundred. Cursors are opaque, so you pass back what you were given rather than constructing offsets, and a realm with years of sessions in it pages the same way a fresh one does.
Errors come in two flavours
Anything about your token or your rate is plain text with a status code: 401 when the token is missing or dead, 429 when you are going too fast, 500 when something broke on our side. Anything about the request itself answers with JSON carrying a human-readable message and a machine code beside it, which is what you want when your handler needs to tell a missing realm apart from a malformed cursor.
Rate limits are honest about being approximate
Roughly a hundred requests a minute per token, counted in a fixed window, which can overshoot a little when requests land at once. Exceeding it returns a 429 with a Retry-After header in seconds. Read that header rather than guessing, and a backfill job will finish without anyone having to intervene.
API or MCP?
Both reach the same realm, and they are not competing. The difference is who decides what happens next: your code, or a model.
| If | Reach for |
|---|---|
| You are writing code | The API |
| An assistant is doing the thinking | MCP |
| Something runs on a schedule | The API |
| The steps are known in advance | The API |
| The steps depend on what it finds | MCP |
| You want a deterministic result | The API |
A nightly job that posts last week's summary to Discord should be an API call, because you know exactly what it will do every time. A question like “which threads have we dropped” should go through MCP, because working out which sessions to read is most of the job. Plenty of people end up using both, and nothing stops you.
What It Does Not Cover
The edges, before you plan around them:
- No webhooks. Nothing calls you when a session ends. If you need to know, you poll.
- No live session control. Recording, voice, video, and the gamestream are not reachable. The API covers the record, not the room.
- No member or billing management. Invites, roles, and coins stay in the app.
- One version, no sandbox. Calls hit your real realm, so point writes at a realm you are willing to see change.
The polling one is the constraint most likely to shape what you build. Sessions are not frequent events, so checking every few minutes is usually plenty, and the rate limit leaves room for it many times over.
API FAQ
Does Realms of Shod have a public API?
Yes. It is an HTTP API at https://realmsofshod.com/api/v1, with 32 endpoints covering realms, sessions and transcripts, compendium entities and relationships, notes, and quests. Requests carry a bearer token and responses are JSON.
How do I get an API key for my D&D campaign?
Mint one in the H.U.B. from the Configure API panel on the drawer rail at the bottom right. Give the token a name, choose an expiry of 1, 7, 30, or 120 days or leave it unlimited, and copy the value before closing the panel — it is shown only once.
What does the API cost?
Nothing beyond your account. There is no separate API plan. Coins pay for recording and processing sessions, not for reading them back.
What are the rate limits?
About 100 requests per 60 seconds per token, counted in a fixed window that can overshoot slightly under concurrency. Going over returns 429 Too Many Requests with a Retry-After header in seconds.
Can the API write to my campaign, or only read it?
It writes. You can create and update entities, relationships, notes, and quests, merge duplicate entities, and upload entity images. Every write is checked against the realm role of the account whose token you used.
How does pagination work?
Every list endpoint returns your results alongside a nextCursor and a hasMore flag. Pass the cursor back to get the following page. Pages default to 50 items and cap at 100.
Are there webhooks?
Not yet. Nothing calls out to you when a session ends or an entity changes, so anything that needs to react polls instead. Sessions are infrequent enough that a check every few minutes sits well inside the rate limit.
Should I use the API or the MCP server?
Use the API when you are writing code and you know the steps in advance, such as a scheduled job or a site that renders your compendium. Use MCP when an AI assistant is deciding what to look at. They reach the same data and many people use both.
Why am I getting 403 Access Denied?
The token is valid but API access is not switched on for that account. 401 means the token itself is missing, expired, or revoked, which is a different problem: mint a fresh one and check the Authorization header reads "Bearer" followed by the token.
Your Campaign, Addressable
A campaign that only exists inside one product is a campaign you are renting. Being able to fetch it, render it somewhere else, and write back into it is the difference between a tool you use and a tool you can build on. The token takes a minute to make.
Start in the API reference, which has the curl you need to make a first call. If you would rather an assistant did the calling, the MCP server covers the same realm, and the campaign wiki is what both of them are reading.
