Develop
API essentials
The API is how your software talks to Mobius directly. Your product can put its own interface in front of an agent, an internal service can start a loop, or a setup process can create the same resources repeatedly.
Use an SDK when one is available for your language. Use the raw HTTP API when you need direct control or are integrating from a different stack. Both use the same resources, authentication, errors, and idempotency rules described here.
Choose the right entry point
Start from the job your software needs to do:
Send a message to an agent. Start with agent invocation. It handles conversation lookup, creation, and streaming through one operation.
React to something outside Mobius. When the other system can call a URL, an HTTP trigger can start a run without custom API code. Use the runs API when your software needs to choose the loop, input, budget, or idempotency key itself.
Create the same setup repeatedly. See blueprints and provisioning.
Operate from a terminal or pipeline. Prefer the
mobius CLI when it already exposes the task. It
handles authentication, formatting, and pagination for you.
What a request looks like
Here's the whole idea. Ask Mobius for the loops in one project, using curl,
a program for making web requests that's already on your Mac:
curl https://api.mobiusops.ai/v1/projects/ridgeline/loops \
-H "Authorization: Bearer $MOBIUS_API_KEY"{
"items": [
{
"id": "loop_9q2m7x5v3p8n4r6t",
"name": "Triage tickets",
"status": "active",
"created_at": "2026-06-15T14:00:00Z",
"updated_at": "2026-06-15T14:00:00Z"
}
],
"has_more": false
}A web address, a key that proves who you are, and some structured text back. That's the shape of every request on this page. Everything else is detail.
Every address starts with https://api.mobiusops.ai/v1. There is no v0, and
the v1 won't change under you.
Three ways in
Most of the API works like the request above: you ask, we answer, done. Two things don't, because they're still happening while you're listening.
| How | What it's for |
|---|---|
| Ordinary requests | Everything list-shaped or form-shaped. The bulk of it. |
| A stream you hold open | Watching a run unfold, or an agent's reply arriving word by word. |
| A two-way connection | The worker, which stays connected so we can hand it work. |
The streams use Server-Sent Events, which is a long-lived HTTP response the browser and most languages already know how to read. Nothing exotic.
Agent conversations mostly go through one address:
POST /v1/projects/{project}/agents/invokeSend a message, get a reply or a stream of one. We find or create the conversation for you. Reach for the lower-level session endpoints only when your own software wants to own the conversation:
POST /v1/projects/{project}/sessions
POST /v1/projects/{project}/sessions/{session_id}/turns
GET /v1/projects/{project}/sessions/{session_id}/streamStart with invoke. See agent invocation for
the request shape and sessions and turns for direct
control.
Your key
Every request carries a key in a header called Authorization:
Authorization: Bearer mbx_..."Bearer" is just the word the header expects before the key. It doesn't mean anything you need to care about.
Keys starting with mbx_ are API keys, which you create in the app under
Settings > Access. Two kinds:
| Kind | What it can reach | Use it for |
|---|---|---|
| Project key | One project | Almost everything, including workers |
| Organization key | Every project | Setup scripts and cross-client admin |
Use a project key unless you genuinely need to work across clients. A key that can only touch Ridgeline Dental cannot accidentally touch Acme.
Neither kind carries permissions of its own. A project key signs in as an API client and inherits that client's role; an organization key gets the role you pick when you create it. Change the role, change what the key can do, without reissuing anything.
Keys starting with mbc_ are different: those belong to the mobius CLI and
act as the person who logged in. You won't create those by hand.
Warning: Anyone holding the key can do everything the key can do. Put it in your secret store, not in a script, a config file you commit, or an email.
Which project
Nearly every address has the project in it:
/v1/projects/{project}/...Use the project's handle, the short name you gave it. If you run one project per client, that handle is the client.
A few addresses sit above projects, because they're about the whole
organization: /v1/projects itself, /v1/audit-logs, and /v1/api-keys.
Those are the exceptions and they look like exceptions.
What comes back
IDs tell you what they are. Every ID starts with a short prefix, so a
stray one in a log is identifiable at a glance: loop_ for loops, run_ for
runs, job_ for worker jobs, key_ for API keys.
Long lists arrive in pages. A list response includes has_more and
next_cursor. If has_more is true, send next_cursor back as cursor on
your next request and you'll get the following page. Don't try to read
next_cursor; it's deliberately meaningless.
Times are UTC, written like 2026-06-15T14:00:00Z.
Errors explain themselves. Anything that isn't a success comes back with a
code you can branch on and a message you can show a human:
{
"error": {
"code": "bad_request",
"message": "invalid request body",
"details": {
"fields": [
{
"field": "actions.selector_type",
"message": "expected string, got number",
"expected": "string",
"actual": "number"
}
]
}
}
}When details.fields is present, each field is a path into what you sent.
If you're building a form, show the message next to that field. Some
operational failures use details too, for things like rate limits and
duplicate-request conflicts.
Sending the same thing twice
Networks drop responses. Your request went through, you never heard back, and now you don't know whether to retry.
For anything that shouldn't happen twice, send an Idempotency-Key header
with a value you make up. If we've already handled a request with that key,
we return the original result instead of doing the work again. Starting a run
and invoking an action both accept it.
Pick a key that describes the thing, not the attempt: ticket-4182-triage,
not a random string you generate on each retry. A random one defeats the
entire point.
Use the CLI or an SDK when you can
The mobius CLI and the Go, TypeScript, and Python libraries speak this same
API and handle the tedious parts. Some things you should not build by hand:
- Recovering a run.
mobius runs resumeandmobius runs retryassemble the right request and print what happened. - Running a worker. The libraries handle the connection, the leases, the heartbeats, and the reconnects. This one is genuinely hard to get right.
- Checking a webhook is really from us. The libraries ship a
verifyWebhookhelper that does the signature check, the clock-drift check, and the replay check in one call. - Paging through a long list. The CLI follows the cursors for you; the libraries hand you something you can loop over.
If you catch yourself implementing any of those, look in the
mobius repo first.
The rest of these pages
Putting an agent in your own software
- Agent invocation: start a conversation, stream the reply, retry safely.
- Sessions and turns: read a transcript, stream it, steer a reply mid-flight, keep a long conversation from growing forever.
- Agent definitions: send the agent's behavior with the request, or have us fetch it from your backend.
- Structured output: get an answer back in a shape your code can use.
- Embedded OAuth return: let your users connect their own Google or Slack account from inside your product.
Setting up clients in bulk
- Provisioning: create projects and their people.
- Blueprints: stamp out the same project setup repeatedly.
- Access control: who and what can do which things.
- Secrets: store credentials and rotate them.
Reaching in and out
- Actions: run one specific thing directly, and the reply format your own HTTP actions have to return.
- Interactions: the approvals and questions a run waits on.
- Webhooks: have Mobius tell your system when something happens.
- Event catalog: every event that can start a run, and what's inside it.
Data
- Artifacts: the files a run produced.
- Tables: shared rows your agents read and write.
- Environments: the workspaces a run can use.
When something went wrong
- Recover a failed run: resume from where it stopped, or start it over.
The full list
Every address, every field, every error code lives in the interactive reference. It's generated from the API itself, so it can't drift. If a page here disagrees with it, believe the reference and tell us.