{
  "page": "docs/org-api",
  "title": "Org API: everything the dashboard does",
  "slug": "org-api",
  "description": "Org keys drive every dashboard action through the API: agents, budgets, approvals, receipts, billing, webhooks and team.",
  "section": "Running an org",
  "updated": "2026-09-30",
  "blocks": [
    {
      "type": "p",
      "text": "Anything a person can do in the dashboard, an agent can do through the API. Agent keys (`sk_…`) buy results; **org keys** (`ok_…`) run the org: make agents and set their budgets, decide approvals, read receipts, top up, manage webhooks and the team."
    },
    {
      "type": "h2",
      "id": "org-keys",
      "text": "Org keys"
    },
    {
      "type": "list",
      "items": [
        "An owner makes them on the Team page while signed in (or `POST /v1/orgs/{orgId}/keys` with a session). The key is shown once.",
        "Scope `read` can only read; anything else gets `403 forbidden` (\"This org key is read-only\"). Scope `write` can do anything its maker can do on the dashboard.",
        "A key acts as the owner who made it, works only on `/v1/orgs/{orgId}/…` for its own org, and stops working if that owner leaves the org.",
        "Keys can't make or revoke keys, and can't ask for data deletion: both need a person signed in.",
        "Up to 20 active keys per org. 300 requests a minute per key; see [rate limits](/docs/rate-limits)."
      ]
    },
    {
      "type": "p",
      "text": "Send it as `Authorization: Bearer ok_…`. The org's id is in the dashboard's URLs (`?org=…`) and in `GET /v1/me`."
    },
    {
      "type": "h2",
      "id": "examples",
      "text": "Worked examples"
    },
    {
      "type": "h3",
      "id": "create-agent",
      "text": "Make an agent and read its key"
    },
    {
      "type": "code",
      "title": "curl",
      "lang": "bash",
      "code": "curl https://api.arettic.com/v1/orgs/$ORG_ID/agents \\\n  -H \"Authorization: Bearer $ARETTIC_ORG_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{ \"name\": \"Lead research\", \"mode\": \"live\", \"monthly_budget_credits\": 100000 }'\n# → { \"agent\": { \"id\": \"…\", … }, \"key\": \"sk_live_…\", \"key_note\": \"…\" }  (the key is shown once)"
    },
    {
      "type": "code",
      "title": "TypeScript",
      "lang": "ts",
      "code": "import { AretticOrg } from \"@arettic/sdk\";\n\nconst org = new AretticOrg({ apiKey: process.env.ARETTIC_ORG_KEY, orgId: \"your-org-id\" });\nconst { agent, key } = await org.agents.create({ name: \"Lead research\", mode: \"live\" });\nawait org.agents.update(agent.id, { monthly_budget_credits: 100_000, approval_threshold_credits: 20_000 });"
    },
    {
      "type": "code",
      "title": "Python",
      "lang": "python",
      "code": "import os\n\nfrom arettic import AretticOrg\n\norg = AretticOrg(os.environ[\"ARETTIC_ORG_KEY\"], os.environ[\"ARETTIC_ORG_ID\"])\nmade = org.agents.create(name=\"Lead research\", mode=\"live\")\norg.agents.update(made[\"agent\"][\"id\"], monthly_budget_credits=100_000, approval_threshold_credits=20_000)"
    },
    {
      "type": "h3",
      "id": "month-of-receipts",
      "text": "A month of receipts, and the CSV"
    },
    {
      "type": "code",
      "title": "TypeScript",
      "lang": "ts",
      "code": "const page = await org.receipts.list({ from: \"2026-09-01\", to: \"2026-09-30\", limit: 200 });\nconst csv = await org.receipts.exportCsv({ from: \"2026-09-01\", to: \"2026-09-30\" });"
    },
    {
      "type": "code",
      "title": "Python",
      "lang": "python",
      "code": "page = org.receipts.list(from_=\"2026-09-01\", to=\"2026-09-30\", limit=200)\ncsv = org.receipts.export_csv(from_=\"2026-09-01\", to=\"2026-09-30\")"
    },
    {
      "type": "h3",
      "id": "decide-approval",
      "text": "Decide an approval"
    },
    {
      "type": "code",
      "title": "curl",
      "lang": "bash",
      "code": "curl https://api.arettic.com/v1/orgs/$ORG_ID/approvals/$APPROVAL_ID/decision \\\n  -H \"Authorization: Bearer $ARETTIC_ORG_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{ \"decision\": \"approve\", \"note\": \"Q4 list\" }'"
    },
    {
      "type": "code",
      "title": "TypeScript",
      "lang": "ts",
      "code": "const pending = await org.approvals.list({ status: \"pending\" });\nfor (const a of pending) await org.approvals.decide(a.approval_id, { decision: \"approve\" });"
    },
    {
      "type": "code",
      "title": "Python",
      "lang": "python",
      "code": "for a in org.approvals.list(status=\"pending\")[\"approvals\"]:\n    org.approvals.decide(a[\"approval_id\"], \"approve\")"
    },
    {
      "type": "h3",
      "id": "add-webhook",
      "text": "Add a webhook"
    },
    {
      "type": "code",
      "title": "TypeScript",
      "lang": "ts",
      "code": "const hook = await org.webhooks.create({ url: \"https://example.com/arettic-hook\", events: [\"job.completed\"] });\n// hook.webhook.secret is shown once: store it to verify signatures"
    },
    {
      "type": "code",
      "title": "Python",
      "lang": "python",
      "code": "hook = org.webhooks.create(\"https://example.com/arettic-hook\", events=[\"job.completed\"])\nsecret = hook[\"webhook\"][\"secret\"]  # shown once"
    },
    {
      "type": "p",
      "text": "Verifying deliveries is on [webhooks](/docs/webhooks). The dashboard's overview numbers (balance, spend by day, agent and tool, items not charged, budgets, pending approvals and disputes) are `GET /v1/orgs/{orgId}/dashboard`."
    },
    {
      "type": "h2",
      "id": "errors",
      "text": "Errors you'll meet"
    },
    {
      "type": "list",
      "items": [
        "`403 forbidden`: a read key tried to change something, a key was used on another org, or a member tried an owner-only action.",
        "`402 plan_limit`: the plan's agents, seats or webhook endpoints are used up.",
        "`404 not_found`: the thing isn't in this org.",
        "`429 rate_limited`: over 300 requests a minute."
      ]
    },
    {
      "type": "h2",
      "id": "parity",
      "text": "Every dashboard action and its endpoint"
    },
    {
      "type": "p",
      "text": "Generated from the list our tests check: every server action in the dashboard is here, every endpoint is in [/openapi.json](/openapi.json), and an org key is tested against every row marked yes."
    },
    {
      "type": "table",
      "caption": "Dashboard ↔ API",
      "head": [
        "Action",
        "Dashboard page",
        "Endpoint",
        "Org key"
      ],
      "rows": [
        [
          "Email me a sign-in link",
          "`/app`",
          "`POST /auth/email/start`",
          "no: a person signed in"
        ],
        [
          "Sign out",
          "`/app`",
          "`POST /auth/logout`",
          "no: a person signed in"
        ],
        [
          "Create an org",
          "`/app`",
          "`POST /v1/orgs`",
          "no: a person signed in"
        ],
        [
          "Accept an invite",
          "`/invite`",
          "`POST /v1/invites/accept`",
          "no: a person signed in"
        ],
        [
          "Balance, spend and refund rate",
          "`/app`",
          "`GET /v1/orgs/{orgId}/dashboard`",
          "yes"
        ],
        [
          "List agents",
          "`/app/agents`",
          "`GET /v1/orgs/{orgId}/agents`",
          "yes"
        ],
        [
          "Add an agent (key shown once)",
          "`/app/agents`",
          "`POST /v1/orgs/{orgId}/agents`",
          "yes"
        ],
        [
          "Change name, budget, approval threshold, IP allowlist or status",
          "`/app/agents`",
          "`PATCH /v1/orgs/{orgId}/agents/{agentId}`",
          "yes"
        ],
        [
          "Rotate an agent key",
          "`/app/agents`",
          "`POST /v1/orgs/{orgId}/agents/{agentId}/rotate-key`",
          "yes"
        ],
        [
          "Revoke an agent key",
          "`/app/agents`",
          "`POST /v1/orgs/{orgId}/agents/{agentId}/revoke-key`",
          "yes"
        ],
        [
          "Approval requests",
          "`/app/approvals`",
          "`GET /v1/orgs/{orgId}/approvals`",
          "yes"
        ],
        [
          "Approve or reject a purchase",
          "`/app/approvals`",
          "`POST /v1/orgs/{orgId}/approvals/{id}/decision`",
          "yes"
        ],
        [
          "Receipt explorer",
          "`/app/receipts`",
          "`GET /v1/orgs/{orgId}/receipts`",
          "yes"
        ],
        [
          "One receipt",
          "`/app/receipts/[id]`",
          "`GET /v1/orgs/{orgId}/receipts/{id}`",
          "yes"
        ],
        [
          "Export receipts as CSV",
          "`/app/receipts`",
          "`GET /v1/orgs/{orgId}/exports/receipts.csv`",
          "yes"
        ],
        [
          "Dispute a charged item",
          "`/app/receipts/[id]`",
          "`POST /v1/orgs/{orgId}/disputes`",
          "yes"
        ],
        [
          "Disputes and their decisions",
          "`/app/disputes`",
          "`GET /v1/orgs/{orgId}/disputes`",
          "yes"
        ],
        [
          "Invoices",
          "`/app/invoices`",
          "`GET /v1/orgs/{orgId}/invoices`",
          "yes"
        ],
        [
          "One invoice (JSON or printable HTML)",
          "`/app/invoices`",
          "`GET /v1/orgs/{orgId}/invoices/{id}`",
          "yes"
        ],
        [
          "Balance and credit lots",
          "`/app/billing`",
          "`GET /v1/orgs/{orgId}/balance`",
          "yes"
        ],
        [
          "Top-up history",
          "`/app/billing`",
          "`GET /v1/orgs/{orgId}/topups`",
          "yes"
        ],
        [
          "Buy credits (returns a checkout link)",
          "`/app/billing`",
          "`POST /v1/orgs/{orgId}/topups`",
          "yes"
        ],
        [
          "Auto-reload settings",
          "`/app/billing`",
          "`GET /v1/orgs/{orgId}/auto-reload`",
          "yes"
        ],
        [
          "Turn auto-reload on or off",
          "`/app/billing`",
          "`PUT /v1/orgs/{orgId}/auto-reload`",
          "yes"
        ],
        [
          "Low-balance alert level",
          "`/app/billing`",
          "`PUT /v1/orgs/{orgId}/notifications`",
          "yes"
        ],
        [
          "Plan, limits and subscriptions",
          "`/app/billing`",
          "`GET /v1/orgs/{orgId}/plan`",
          "yes"
        ],
        [
          "Start the Pro plan (returns a checkout link)",
          "`/app/billing`",
          "`POST /v1/orgs/{orgId}/subscriptions`",
          "yes"
        ],
        [
          "Cancel a plan at period end",
          "`/app/billing`",
          "`DELETE /v1/orgs/{orgId}/subscriptions/{plan}`",
          "yes"
        ],
        [
          "Billing name, address, country and tax ID",
          "`/app/billing`",
          "`PATCH /v1/orgs/{orgId}/billing`",
          "yes"
        ],
        [
          "Webhook endpoints and event types",
          "`/app/webhooks`",
          "`GET /v1/orgs/{orgId}/webhooks`",
          "yes"
        ],
        [
          "Recent deliveries",
          "`/app/webhooks`",
          "`GET /v1/orgs/{orgId}/webhook-deliveries`",
          "yes"
        ],
        [
          "Recent events",
          "`/app/webhooks`",
          "`GET /v1/orgs/{orgId}/events`",
          "yes"
        ],
        [
          "Add an endpoint (secret shown once)",
          "`/app/webhooks`",
          "`POST /v1/orgs/{orgId}/webhooks`",
          "yes"
        ],
        [
          "Send a test event",
          "`/app/webhooks`",
          "`POST /v1/orgs/{orgId}/webhooks/{id}/test`",
          "yes"
        ],
        [
          "Delete an endpoint",
          "`/app/webhooks`",
          "`DELETE /v1/orgs/{orgId}/webhooks/{id}`",
          "yes"
        ],
        [
          "Members and pending invites",
          "`/app/team`",
          "`GET /v1/orgs/{orgId}/members`",
          "yes"
        ],
        [
          "Invite by email",
          "`/app/team`",
          "`POST /v1/orgs/{orgId}/invites`",
          "yes"
        ],
        [
          "Withdraw an invite",
          "`/app/team`",
          "`DELETE /v1/orgs/{orgId}/invites/{inviteId}`",
          "yes"
        ],
        [
          "Make a member an owner, or back",
          "`/app/team`",
          "`PATCH /v1/orgs/{orgId}/members/{userId}`",
          "yes"
        ],
        [
          "Remove a member, or leave",
          "`/app/team`",
          "`DELETE /v1/orgs/{orgId}/members/{userId}`",
          "yes"
        ],
        [
          "Org API keys",
          "`/app/team`",
          "`GET /v1/orgs/{orgId}/keys`",
          "no: a person signed in"
        ],
        [
          "Make an org API key (shown once)",
          "`/app/team`",
          "`POST /v1/orgs/{orgId}/keys`",
          "no: a person signed in"
        ],
        [
          "Revoke an org API key",
          "`/app/team`",
          "`DELETE /v1/orgs/{orgId}/keys/{id}`",
          "no: a person signed in"
        ],
        [
          "Data-deletion requests",
          "`/app/team`",
          "`GET /v1/orgs/{orgId}/deletion-requests`",
          "yes"
        ],
        [
          "Ask us to delete stored inputs and results (within 24 hours)",
          "`/app/team`",
          "`POST /v1/orgs/{orgId}/deletion-requests`",
          "no: a person signed in"
        ],
        [
          "Private test sets and included calls",
          "`/app/benchmarks`",
          "`GET /v1/orgs/{orgId}/test-sets`",
          "yes"
        ],
        [
          "Private benchmark runs",
          "`/app/benchmarks`",
          "`GET /v1/orgs/{orgId}/benchmarks`",
          "yes"
        ],
        [
          "One run: per-case results, segments, failure reasons",
          "`/app/benchmarks/[id]`",
          "`GET /v1/orgs/{orgId}/benchmarks/{id}`",
          "yes"
        ],
        [
          "Make a private test set (JSON Lines)",
          "`/app/benchmarks`",
          "`POST /v1/orgs/{orgId}/test-sets`",
          "yes"
        ],
        [
          "Add cases to a test set",
          "`/app/benchmarks`",
          "`POST /v1/orgs/{orgId}/test-sets/{id}/cases`",
          "yes"
        ],
        [
          "Delete a test set and its results",
          "`/app/benchmarks`",
          "`DELETE /v1/orgs/{orgId}/test-sets/{id}`",
          "yes"
        ],
        [
          "Run tools against a test set",
          "`/app/benchmarks`",
          "`POST /v1/orgs/{orgId}/benchmarks`",
          "yes"
        ],
        [
          "Your tools' scores, inputs and rank (read-only)",
          "`/app/provider`",
          "`GET /v1/orgs/{orgId}/provider`",
          "yes"
        ],
        [
          "Claim a provider",
          "`/app/provider`",
          "`POST /v1/orgs/{orgId}/provider/claims`",
          "yes"
        ],
        [
          "Ask for a re-test (Insights, Pro)",
          "`/app/provider`",
          "`POST /v1/orgs/{orgId}/provider/retests`",
          "yes"
        ]
      ]
    }
  ]
}