API reference

Teams

A shared account for several people. Off unless the operator enables it; every route answers 404 feature_disabled until then.

GET /v1/orgs

My teams

Teams the caller owns or has accepted membership of, with the caller's role in each.

Auth
session cookie or API key
Capability
orgs
Success
HTTP 200

Parameters

None.

Request body

None.

Example request

curl

curl -sS -X GET "https://api.afaprotocol.com/v1/orgs" \
  -H "X-API-Key: afa-beta-EXAMPLE-e4qs"

Python

import requests

API = "https://api.afaprotocol.com"
headers = {"X-API-Key": "afa-beta-EXAMPLE-e4qs"}

r = requests.get(f"{API}/v1/orgs", headers=headers, timeout=30)
r.raise_for_status()
print(r.json())

Example response

HTTP 200
{
  "orgs": [
    {
      "created_at": "2026-09-07T13:00:00+00:00",
      "name": "Acme Robotics",
      "org_id": "org-3f8a1c9e2b7d4056",
      "owner_user_id": "2f6e1a0c-9b4d-4e8a-8c31-5d7f0a2b9c14",
      "role": "owner"
    }
  ]
}

Errors

StatusCodeMeaning
401missing_token / invalid_or_expired_api_keyNo credential, an expired session, or a revoked or expired key.
403scope_missingA key limited by scopes lacks orgs; the body names it.
404feature_disabledteams are not enabled on this deployment

What would show this is false

An invited but not yet accepted team does not appear here. Accept first.

POST /v1/orgs

Create a team

Creates a team owned by the caller. Requires the operator to have enabled teams on this deployment.

Auth
session cookie or API key
Capability
orgs
Success
HTTP 201

Parameters

None.

Request body

name string required
No description in the schema.

Example request

curl

curl -sS -X POST "https://api.afaprotocol.com/v1/orgs" \
  -H "X-API-Key: afa-beta-EXAMPLE-e4qs" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Acme Robotics"
}'

Python

import requests

API = "https://api.afaprotocol.com"
headers = {"X-API-Key": "afa-beta-EXAMPLE-e4qs"}
payload = {
    "name": "Acme Robotics"
}

r = requests.post(f"{API}/v1/orgs", headers=headers, json=payload, timeout=30)
r.raise_for_status()
print(r.json())

Example response

HTTP 201
{
  "org": {
    "created_at": "2026-09-07T13:00:00+00:00",
    "name": "Acme Robotics",
    "org_id": "org-3f8a1c9e2b7d4056",
    "owner_user_id": "2f6e1a0c-9b4d-4e8a-8c31-5d7f0a2b9c14",
    "role": "owner"
  }
}

Errors

StatusCodeMeaning
401missing_token / invalid_or_expired_api_keyNo credential, an expired session, or a revoked or expired key.
403scope_missingA key limited by scopes lacks orgs; the body names it.
422validation errorA required field is missing or a value has the wrong type.
404feature_disabledteams are not enabled on this deployment

What would show this is false

GET /v1/orgs lists it with role owner. A second account cannot read it until invited and accepted.

GET /v1/orgs/{org_id}

One team

The team record with member and pending-invite counts.

Auth
session cookie or API key
Capability
orgs
Success
HTTP 200

Parameters

org_id path, string required
No description in the schema.

Request body

None.

Example request

curl

curl -sS -X GET "https://api.afaprotocol.com/v1/orgs/org-3f8a1c9e2b7d4056" \
  -H "X-API-Key: afa-beta-EXAMPLE-e4qs"

Python

import requests

API = "https://api.afaprotocol.com"
headers = {"X-API-Key": "afa-beta-EXAMPLE-e4qs"}

r = requests.get(f"{API}/v1/orgs/org-3f8a1c9e2b7d4056", headers=headers, timeout=30)
r.raise_for_status()
print(r.json())

Example response

HTTP 200
{
  "invited_count": 0,
  "member_count": 2,
  "org": {
    "created_at": "2026-09-07T13:00:00+00:00",
    "name": "Acme Robotics",
    "org_id": "org-3f8a1c9e2b7d4056",
    "owner_user_id": "2f6e1a0c-9b4d-4e8a-8c31-5d7f0a2b9c14",
    "role": "owner"
  }
}

Errors

StatusCodeMeaning
401missing_token / invalid_or_expired_api_keyNo credential, an expired session, or a revoked or expired key.
403scope_missingA key limited by scopes lacks orgs; the body names it.
422validation errorA required field is missing or a value has the wrong type.
404not a member, or teams disabled

What would show this is false

A non-member receives 404, not 403: the team's existence is not disclosed.

POST /v1/orgs/{org_id}/accept

Accept an invitation

The invited person, signed in with the invited email, joins the team.

Auth
session cookie or API key
Capability
orgs
Success
HTTP 200

Parameters

org_id path, string required
No description in the schema.

Request body

None.

Example request

curl

curl -sS -X POST "https://api.afaprotocol.com/v1/orgs/org-3f8a1c9e2b7d4056/accept" \
  -H "X-API-Key: afa-beta-EXAMPLE-e4qs" \
  -H "Content-Type: application/json" \
  -d '{}'

Python

import requests

API = "https://api.afaprotocol.com"
headers = {"X-API-Key": "afa-beta-EXAMPLE-e4qs"}
payload = {}

r = requests.post(f"{API}/v1/orgs/org-3f8a1c9e2b7d4056/accept", headers=headers, json=payload, timeout=30)
r.raise_for_status()
print(r.json())

Example response

HTTP 200
{
  "member": {
    "created_at": "2026-09-07T13:05:00+00:00",
    "email": "reviewer@example.com",
    "org_id": "org-3f8a1c9e2b7d4056",
    "role": "member",
    "status": "active",
    "user_id": "9c4b2a1d-7e6f-4a3b-8c5d-1e2f3a4b5c6d"
  }
}

Errors

StatusCodeMeaning
401missing_token / invalid_or_expired_api_keyNo credential, an expired session, or a revoked or expired key.
403scope_missingA key limited by scopes lacks orgs; the body names it.
422validation errorA required field is missing or a value has the wrong type.
404no pending invitation for the caller's email

What would show this is false

After accepting, GET /v1/orgs on the invited account lists the team with role member.

POST /v1/orgs/{org_id}/invite

Invite by email

Owners invite an email address with a role. Nothing is granted until that person signs in and accepts.

Auth
session cookie or API key
Capability
orgs
Success
HTTP 201

Parameters

org_id path, string required
No description in the schema.

Request body

email string required
No description in the schema.
role string required
owner, member or viewer

Example request

curl

curl -sS -X POST "https://api.afaprotocol.com/v1/orgs/org-3f8a1c9e2b7d4056/invite" \
  -H "X-API-Key: afa-beta-EXAMPLE-e4qs" \
  -H "Content-Type: application/json" \
  -d '{
  "email": "reviewer@example.com",
  "role": "member"
}'

Python

import requests

API = "https://api.afaprotocol.com"
headers = {"X-API-Key": "afa-beta-EXAMPLE-e4qs"}
payload = {
    "email": "reviewer@example.com",
    "role": "member"
}

r = requests.post(f"{API}/v1/orgs/org-3f8a1c9e2b7d4056/invite", headers=headers, json=payload, timeout=30)
r.raise_for_status()
print(r.json())

Example response

HTTP 201
{
  "member": {
    "created_at": "2026-09-07T13:05:00+00:00",
    "email": "reviewer@example.com",
    "org_id": "org-3f8a1c9e2b7d4056",
    "role": "member",
    "status": "invited",
    "user_id": null
  }
}

Errors

StatusCodeMeaning
401missing_token / invalid_or_expired_api_keyNo credential, an expired session, or a revoked or expired key.
403scope_missingA key limited by scopes lacks orgs; the body names it.
422validation errorA required field is missing or a value has the wrong type.
403caller is a viewer or member, not an owner
422role outside owner, member, viewer

What would show this is false

GET members shows status invited with user_id null until accepted.

GET /v1/orgs/{org_id}/keys

Keys issued against the team

Metadata of member keys issued against this team: prefix, machine, label, expiry. Never the token.

Auth
session cookie or API key
Capability
orgs
Success
HTTP 200

Parameters

org_id path, string required
No description in the schema.

Request body

None.

Example request

curl

curl -sS -X GET "https://api.afaprotocol.com/v1/orgs/org-3f8a1c9e2b7d4056/keys" \
  -H "X-API-Key: afa-beta-EXAMPLE-e4qs"

Python

import requests

API = "https://api.afaprotocol.com"
headers = {"X-API-Key": "afa-beta-EXAMPLE-e4qs"}

r = requests.get(f"{API}/v1/orgs/org-3f8a1c9e2b7d4056/keys", headers=headers, timeout=30)
r.raise_for_status()
print(r.json())

Example response

HTTP 200
{
  "keys": [
    {
      "created_at": "2026-09-07T13:10:00+00:00",
      "expires_at": "2026-10-07T13:10:00+00:00",
      "id": "7a1c3e5b-2d4f-4a6b-9c8e-0f1a2b3c4d5e",
      "label": "ci",
      "machine": "worker-host",
      "prefix": "afa-beta-",
      "revoked_at": null,
      "scopes": [
        "events:write",
        "grants"
      ]
    }
  ],
  "org_id": "org-3f8a1c9e2b7d4056"
}

Errors

StatusCodeMeaning
401missing_token / invalid_or_expired_api_keyNo credential, an expired session, or a revoked or expired key.
403scope_missingA key limited by scopes lacks orgs; the body names it.
422validation errorA required field is missing or a value has the wrong type.

What would show this is false

No field here can be used to sign in. A key is shown once, at creation, to the account that created it.

GET /v1/orgs/{org_id}/members

Members

Everyone on the team, active and invited, with roles.

Auth
session cookie or API key
Capability
orgs
Success
HTTP 200

Parameters

org_id path, string required
No description in the schema.

Request body

None.

Example request

curl

curl -sS -X GET "https://api.afaprotocol.com/v1/orgs/org-3f8a1c9e2b7d4056/members" \
  -H "X-API-Key: afa-beta-EXAMPLE-e4qs"

Python

import requests

API = "https://api.afaprotocol.com"
headers = {"X-API-Key": "afa-beta-EXAMPLE-e4qs"}

r = requests.get(f"{API}/v1/orgs/org-3f8a1c9e2b7d4056/members", headers=headers, timeout=30)
r.raise_for_status()
print(r.json())

Example response

HTTP 200
{
  "members": [
    {
      "created_at": "2026-09-07T13:00:00+00:00",
      "email": "owner@example.com",
      "org_id": "org-3f8a1c9e2b7d4056",
      "role": "owner",
      "status": "active",
      "user_id": "2f6e1a0c-9b4d-4e8a-8c31-5d7f0a2b9c14"
    },
    {
      "created_at": "2026-09-07T13:05:00+00:00",
      "email": "reviewer@example.com",
      "org_id": "org-3f8a1c9e2b7d4056",
      "role": "member",
      "status": "active",
      "user_id": "9c4b2a1d-7e6f-4a3b-8c5d-1e2f3a4b5c6d"
    }
  ],
  "org_id": "org-3f8a1c9e2b7d4056"
}

Errors

StatusCodeMeaning
401missing_token / invalid_or_expired_api_keyNo credential, an expired session, or a revoked or expired key.
403scope_missingA key limited by scopes lacks orgs; the body names it.
422validation errorA required field is missing or a value has the wrong type.

What would show this is false

The owner is always present with role owner and status active.