API reference
Organizations
Every user has a personal organization, created at first sign-in. It is an ordinary organization with ordinary membership rules, except that it cannot be deleted. Organizations are called publishers in some error messages.
The organization object#
| Field | Type | Meaning |
|---|---|---|
id |
UUID | |
slug |
string, 2 to 48 characters | Lowercase words joined by -. |
name |
string, 1 to 80 characters | |
description |
string or null | Up to 500 characters. |
website |
URL or null | |
logo_url |
URL or null | |
accent |
#rrggbb or null |
|
verified |
boolean | |
personal |
boolean | A user's personal organization. |
created_at, updated_at |
date-time |
List organizations#
GET /v1/organizations
Open. With mine=true, session only.
| Query | Type | Meaning |
|---|---|---|
slug |
slug | Only this organization. |
mine |
true |
The caller's organizations, each with a role (owner, admin, or member). |
Response 200 { "organizations": [ ... ] }.
Create an organization#
POST /v1/organizations
Session only. The creator becomes owner.
| Field | Type | Meaning |
|---|---|---|
slug |
slug, 2 to 48 characters | Required. |
name |
string, 1 to 80 characters | Required. |
description |
string, 1 to 500 characters | |
website |
URL | |
accent |
#rrggbb |
Response 201: the organization.
Get an organization#
GET /v1/organizations/:id
Open. Response 200: the organization.
Update an organization#
PATCH /v1/organizations/:id
Key org:admin with manager creator, or session: manager.
| Field | Type |
|---|---|
name |
string, 1 to 80 characters |
description |
string up to 500 characters, or null |
website |
URL or null |
accent |
#rrggbb or null |
Response 200: the organization.
Delete an organization#
DELETE /v1/organizations/:id
Session: owner only, from the dashboard. A key can never delete its own organization. Deletes the organization's members, keys, Workbenches, versions, submissions, and images, and is audited. 409 for a personal organization. Response 200 { "deleted": true }.
Members#
List members#
GET /v1/memberships?organization_id=<uuid>
Session: member. Response 200:
{
"members": [
{
"id": "uuid",
"name": "Ada Lovelace",
"email": "ada@example.com",
"image": null,
"role": "owner",
"current": true,
"created_at": "..."
}
]
}current marks the caller.
Remove a member#
DELETE /v1/memberships/:id
Session: member. Response 200 { "deleted": true }. Removing a member, or a member leaving, revokes every key that person created in the organization.
Invitations#
List invitations#
GET /v1/invitations?organization_id=<uuid>
Session: member. Response 200 { "invitations": [ { "id", "email", "status", "expires_at", "created_at" } ] }. status is pending, accepted, revoked, or expired.
Invite#
POST /v1/invitations
Session: member.
| Field | Type |
|---|---|
organization_id |
UUID |
email |
email address |
Response 201:
| Field | Meaning |
|---|---|
invitation |
The invitation. |
delivery |
sent, preview, or failed. |
acceptance_url |
The link to accept, or null. |
Refused with 402 plan_limit when members and live pending invitations are at the plan's member cap.
Revoke an invitation#
DELETE /v1/invitations/:id
Session: member. Response 200 { "deleted": true }.
Accept an invitation#
POST /v1/acceptances with { "token": "..." } (32 to 256 characters)
Session only. The signed-in email must match the invited email. Response 201: the organization. Refused when the organization's joined members are at the cap.
Logos#
:id is the organization's ID.
| Method | Path | Auth | Result |
|---|---|---|---|
| GET | /v1/logos/:id |
Open | The logo bytes. Supports If-None-Match. |
| PUT | /v1/logos/:id |
Key org:admin with manager creator, or session: manager |
Upload a logo: the raw image as the body, with its content-type. Returns the organization. |
| DELETE | /v1/logos/:id |
Key org:admin with manager creator, or session: manager |
Remove the logo. Returns the organization. |
Analytics#
POST /v1/analytics with { "organization_id": "uuid" }
Key catalog:read, or session: member. Save and run counts for the organization's Workbenches, as the CLI reports them:
{
"totals": { "saves": 12, "runs": 40, "workbenches": 3 },
"series": [{ "day": "2026-10-28", "saves": 1, "runs": 4 }]
}series holds up to 30 days.