Get started
Authentication
Every request to Rytiv carries an API key as a bearer token. Create keys in the console, with the CLI or over the API, narrow them with scopes or an agent class, and revoke them at any time.
Rytiv has one kind of credential for programs: an API key. It belongs to your organization, it is sent as a bearer token, and the same key works for the REST API, the MCP server and the CLI.
Authorization: Bearer ryt_...Keys start with ryt_. Rytiv stores only a hash of a key, so a key is shown exactly once, when it is created. After that, only its first characters (the prefix) are visible.
Create a key
Section titled “Create a key”ry tokens create ci-deploycurl -X POST https://api.rytiv.app/v1/tokens \ -H "Authorization: Bearer $RYTIV_TOKEN" \ -H "Content-Type: application/json" \ -d '{"name": "ci-deploy"}'const res = await fetch("https://api.rytiv.app/v1/tokens", { method: "POST", headers: { Authorization: `Bearer ${process.env.RYTIV_TOKEN}`, "Content-Type": "application/json", }, body: JSON.stringify({ name: "ci-deploy" }),});const { id, prefix, token } = await res.json(); // token is shown only in this answerPOST /v1/tokens takes a name (1 to 120 characters) and answers 201 with id, name, prefix and token. Store token right away: neither the API nor the CLI can show it again.
You can also create a key in the Rytiv console. Every way creates the same kind of key. Creating a key needs a full key: a key narrowed by scopes or an agent class cannot create, reveal or revoke keys.
Request fields
Section titled “Request fields”| Field | Type | Notes |
|---|---|---|
name |
string | 1 to 120 characters |
scopes |
string[] | Up to 20 scopes. Without it, the key is the whole organization. |
ttlSeconds |
integer | The key stops working after this long: 60 seconds to 365 days |
expiresAt |
string | Or: the moment it stops working (ISO 8601). Not together with ttlSeconds. |
agent |
object | Makes it an agent key: {class, apps, prodDataRead} |
Narrow a key: scopes
Section titled “Narrow a key: scopes”A key without scopes may do everything your organization may do. A scope list makes it do less, never more:
| Scope | What it allows |
|---|---|
read |
Every read of the product API, except credentials and billing |
deploy |
The deploy routes of every app: build, deploy, rollback, releases, logs, secrets. Never create or delete an app, never a key. |
deploy:<app> |
The same for exactly that app |
mail:send |
Sending mail from any of your sending domains |
mail:send:<domain> |
Sending mail from exactly that domain |
ry tokens create ci --deploy web --expires-in 30dA scope the platform does not know is refused with 400 when the key is created, never stored as a key that silently does less than its name says.
Agent keys
Section titled “Agent keys”A coding agent works with a key a person handed over without watching every request. So the platform, not the agent’s prompt, holds the key to what it is meant for. agent on POST /v1/tokens takes:
| Field | Type | Notes |
|---|---|---|
class |
string | sandbox, twin or production |
apps |
string[] | Optional, 1 to 50 app names. Without it, the whole organization. |
prodDataRead |
boolean | production only: may the agent read what production holds (the database, files, a shell), not only what it says about itself |
ry tokens create claude-code --agent sandbox --app web --app workerry tokens create claude-code-prod --agent production --read-prod-dataWhat every request with an agent key is judged by, in this order:
- Credentials are never reachable. Creating, revealing or revoking keys, SSH keys, webhooks and Git installations, approving a device login, administering the organization: refused for every class with
403and the codeagent-token-credential. - The app list, when there is one. A request that names an app outside the list, or a change that names no app at all, is refused with
403andagent-token-app-scope. - The class.
sandboxandtwinmay do what a key of your organization may do.productionmay read what the platform says about a resource (status, releases, logs); a change answers403withagent-token-production-readonly, and reading what production holds answers403withagent-token-production-dataunless the key hasprodDataRead. - Its own organization only. The header
X-Rytiv-Orgis refused withagent-token-delegation.
scopes and agent combine: the platform holds both, and the narrower one wins.
Every action of an agent key is written to an audit before it runs; if the audit cannot be written, the action does not run (503, agent-audit-unavailable). GET /v1/agent-actions lists the audit of your organization, newest first, with ?token=<id> for one key and ?limit= up to 500.
A key’s class is what the person who created it says it is for. The platform does not know yet which app is production; the app list is what keeps a sandbox key away from production apps today. With projects the class picks the environment of the project, and the list goes.
List and revoke keys
Section titled “List and revoke keys”| Method | Path | What it does |
|---|---|---|
GET |
/v1/tokens |
Your keys, without their values: id, name, prefix, createdAt, lastUsedAt, and scopes, agent, expiresAt where set |
DELETE |
/v1/tokens/:id |
Revokes a key. Requests already using it are rejected right away. Answers 204. |
ry tokens listry tokens revoke tok-1a2b3c4dConnect without a key
Section titled “Connect without a key”A hosted connector has no place to paste a key, so /v1/mcp also accepts OAuth 2.1. A client that supports it needs nothing but the address https://api.rytiv.app/v1/mcp:
- A request without a token answers
401withWWW-Authenticate: Bearer resource_metadata=.... The client reads/.well-known/oauth-protected-resource/v1/mcpand/.well-known/oauth-authorization-serverfrom there. - It registers itself at
POST /v1/oauth/register(RFC 7591) and gets a client id. There are no client secrets: every client is a public client, and the exchange is bound to PKCE withS256. GET /v1/oauth/authorizesends you to the Rytiv console, where you see which client wants to connect to which organization and approve or deny it once.- The client exchanges the code at
POST /v1/oauth/tokenfor an access token, valid for one hour, and a refresh token, valid for 30 days and rotated on every use.
The scopes are mcp and offline_access, nothing finer. The access token is an API key of the organization that approved, named after the client; it appears in GET /v1/tokens and is revoked like any other key, which ends the connection. Redirect addresses must be https, a loopback http address, or a native app’s own scheme.
Sign in with the CLI
Section titled “Sign in with the CLI”On your own machine, ry login is the easier way. It shows a code, you confirm it in the console, and the CLI stores a key for itself.
ry loginWhere nobody can open a browser (CI, a container, a coding agent), give the CLI a key instead:
ry login --token <token>Or set it in the environment, which the CLI never writes to disk:
| Variable | Meaning |
|---|---|
RYTIV_TOKEN |
The API key for this shell. Takes precedence over a saved login. |
RYTIV_ENDPOINT |
The API endpoint to talk to. Without it, the CLI uses https://api.rytiv.app. |
RYTIV_PROFILE |
Which saved login to use, if you keep several (ry profile). |
The CLI keeps saved logins in ~/.rytiv/config.json, readable only by you.
Errors
Section titled “Errors”A request without a key answers 401 with missing api token (Authorization: Bearer <token>), a request with an unknown, expired or revoked key answers 401 with invalid api token. A key that may not do what the request asks answers 403 with one of the codes above. All of them follow the error format.
What a key can do
Section titled “What a key can do”A key acts as your organization: it reaches every app, database, computer and sandbox the organization has, and nothing of any other organization. A name that belongs to another organization is answered exactly like a name that does not exist. Scopes and an agent class narrow that, and the platform enforces both. The guide Agents and tokens walks through a key per agent, OAuth for hosted clients and the audit of what an agent did.