API overview
The /v1 REST API: base URL, bearer authentication, the two kinds of API key, errors, and rate limits.
Everything a script, a self-hosted instance, or an outside agent needs lives under one path prefix on the cloud API. The same routes back the geni CLI, so anything the CLI can do, a key with the matching scope can do too.
https://cloud.generalinput.com/v1Requests and responses are JSON. Send Content-Type: application/json on any request with a body. Ids are opaque strings with a type prefix (cred_…, wf_…, skl_…), except operation ids, which are UUIDs.
Authentication
Every request carries a bearer token:
Authorization: Bearer gi_org_…Three kinds of bearer reach /v1. The prefix tells them apart.
| Bearer | Prefix | Acts as | Get one from |
|---|---|---|---|
| Personal API key | gi_sk_ | You, in one workspace | Settings, API keys (details) |
| Platform API key | gi_org_ | The workspace, for an instance or agent | Settings, API keys (details) |
| CLI session | geni_rs_ | You, switchable between workspaces | geni login. Never paste one into a script. |
A key is bound to one workspace when it is created. There is no header to switch workspaces; create a key per workspace instead. The MCP endpoint is the exception to all of this: it takes OAuth access tokens only, never a key. See MCP.
Scopes
Each route is mounted behind one scope, and one route (issue a token) adds a second on top of its mount. A key holds a set of scopes chosen at creation, and the two key kinds hold disjoint sets: a personal key can never hold docs:read, and a platform key can never hold workflows:manage. The API keys page has the full table. Every endpoint page states its scope in an Access line.
A CLI session is unscoped. It passes every scope gate because it is the interactive, revocable credential of a signed-in member.
Errors
Errors are a JSON object carrying an error string.
{ "error": "Insufficient scope" }Two cases add to that shape: a 426 also carries minVersion and clientVersion, and a hosted service's own error passes straight through with whatever shape that service uses.
| Status | Meaning |
|---|---|
400 | The body or query failed validation. Most routes name the field; the vault routes answer with one canned message either way. |
401 | Missing, unknown, or revoked bearer. The reason is never disclosed. |
402 | The workspace has no credit balance. Hosted services only. |
403 | The key lacks the scope, the route needs a CLI session, or the workspace lacks a required feature. |
404 | Not found, or not visible to the member the key acts as. The two are deliberately indistinguishable. |
409 | The resource changed underneath you. Refetch and retry (skills). |
426 | Only for geni. The CLI is below the minimum supported version. Other clients are never gated on version. |
429 | Rate limited. Slow down and retry after a moment. |
500 | An unexpected server failure. A few hosted services also surface a rejected request this way, not as a 400. |
503 | The authentication service could not be reached. Retry. |
Rate limits
Authenticated /v1 traffic is limited per client IP:
| Traffic | Limit |
|---|---|
| Authenticated requests | 1200 / minute |
| Device-code login endpoints (unauthenticated) | 600 / minute |
The limit is sized for agent fan-out (a run posting to fifty channels in parallel fits comfortably) while still capping a runaway loop. Revoking a key cuts off a misbehaving client immediately, without waiting for the window.
The MCP endpoint carries the same ceiling but is not counted per IP: a hosted connector calls from its own servers, so one address fronts every customer using it. Its bucket follows the caller's own credential instead.
What is where
| Area | Prefix | Scope |
|---|---|---|
| Integration docs | /v1/integrations, /v1/operations | docs:read |
| Vault | /v1/credentials, /v1/connections | vault:read, vault:connect, vault:token |
| Hosted services | /v1/platform/<service> | platform:use |
| Workflows and apps | /v1/workflows | workflows:manage |
| Skills | /v1/skills | skills:manage |
| Projects | /v1/projects | projects:manage |
| Memory | /v1/memory | memory:manage |
| Triggers | /v1/triggers | triggers:manage |
| CLI session endpoints | /v1/auth, /v1/workspaces, /v1/exec, /v1/browser | CLI session only |
A first request
Create a platform API key with the docs:read scope, then search the operation catalog:
curl -s "https://cloud.generalinput.com/v1/operations?q=send%20slack%20message" \
-H "Authorization: Bearer $GI_API_KEY"{
"results": [
{
"service": "slack",
"serviceTitle": "Slack",
"operations": [
{
"id": "4c21e1ee-4d54-4413-a4f2-80a80dff4c99",
"title": "Send a Message",
"description": "Sends a message to a channel, DM, or group conversation.",
"score": 0.91
}
]
}
]
}