OpenAI Admin API sandbox
Point the official openai SDK (or curl) at https://openai.sandboxapis.dev via the client's baseURL option. Auth is a Bearer admin key (sk-admin-…; any value is accepted here). This is the org's OpenAI platform telemetry: users, projects, admin-key metadata, completions usage, and costs: the codex cohort's usage, reconciling with the git activity on the git hosts.
Coverage badge
Full122/122 · 100%
The share of read rows with a final answer — served and verified, a deviation, retired upstream, or a reviewed empty/refusal. Computed in the coverage manifest, copied here.
openai.sandboxapis.devServed & verified
53 / 43%
Answering with real universe data, each response checked against OpenAI's published spec by the conformance suite on this build.
The full read API
122
Every read surface OpenAI publishes, deferred long tail included, minus the rows excluded by policy. Writes are out of scope: this universe is read-only.
Not served yet
69
Each returns an explicit, provider-shaped coverage error naming the gap — never invented data.
01 / The swap
No SDK of ours, no shim, no recorded fixtures. The same client library you already use, one environment variable different.
curl -H 'Authorization: Bearer any-key' "https://openai.sandboxapis.dev/v1/organization/users"Verified drop-in clients
openai7.5.0The versions the conformance suite drives against this host on every build — pinned in coverage/client-pins.yaml, and watched weekly for upstream releases, because a client library moving without us is how a shipped integration breaks silently.
02 / Coverage by family
All 122 rows the coverage manifest carries for OpenAI, deferred long tail included and nothing capped. Open a family, or filter by path to find the exact endpoint your client calls.
Status — what a conformance test found
Mode — what kind of answer a row gets
A row with no mode shown has not been judged yet. Modes are the manifest's own words, from coverage/MODES.yaml; every empty and refuse carries a written reason and a review date before it counts as final.
Badge — where Full starts
REST + GraphQL + git rows that are not `excluded`. Write operations are NOT rows (DECISIONS 2026-09-01 decision 9): they are counted in meta.write_operations and never enter this ratio.
122 read surfaces in 14 families
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the vendored document declares security: [{AdminApiKeyAuth: []}] on retrieve-project-hosted-tool-permissions - the SAME scheme as /organization/users, /organization/costs and the sibling /organization/projects/{project_id}/model_permissions this replica serves at 200 - so the sandbox admin key IS the right credential here and a 401 invalid_api_key would contradict the document; this org configures no hosted-tool permission set, so OpenAI's own 404 for an object that does not exist is the answer, the same shape as /organization/certificates/{certificate_id} (founder ruling 2026-09-03 on proposal 1 of coverage/reviews/2026-09-03-openai-refuse-shapes.md, superseding the INFERENCE-plane 401 read that grouped this row by its "Hosted tools" tag rather than by its plane)
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
refuse — the sandbox key is an OpenAI ADMIN key and this row is on the INFERENCE plane (assistants, threads, responses, files, batches, evals, fine-tuning, vector stores, skills, videos, conversations, audio consents); OpenAI answers 401 invalid_api_key when an admin key reads it, and SandboxAPIs mirrors the admin surface, not the inference surface
this org's OpenAI story is coding: it recorded no speech usage in the window, so the family's page is real, spec-validating and empty (DECISIONS 2026-08-20 [P31/openai])
this org's OpenAI story is coding: it recorded no transcription usage in the window, so the family's page is real, spec-validating and empty (DECISIONS 2026-08-20 [P31/openai])
this org's OpenAI story is coding: it recorded no code-interpreter usage in the window, so the family's page is real, spec-validating and empty (DECISIONS 2026-08-20 [P31/openai])
this org's OpenAI story is coding: it recorded no embedding usage in the window, so the family's page is real, spec-validating and empty (DECISIONS 2026-08-20 [P31/openai])
this org's OpenAI story is coding: it recorded no file-search usage in the window, so the family's page is real, spec-validating and empty (DECISIONS 2026-08-20 [P31/openai])
this org's OpenAI story is coding: it recorded no image usage in the window, so the family's page is real, spec-validating and empty (DECISIONS 2026-08-20 [P31/openai])
this org's OpenAI story is coding: it recorded no moderation usage in the window, so the family's page is real, spec-validating and empty (DECISIONS 2026-08-20 [P31/openai])
this org's OpenAI story is coding: it recorded no vector-store usage in the window, so the family's page is real, spec-validating and empty (DECISIONS 2026-08-20 [P31/openai])
this org's OpenAI story is coding: it recorded no web-search usage in the window, so the family's page is real, spec-validating and empty (DECISIONS 2026-08-20 [P31/openai])
SERVED 2026-09-14 (hello-20): the same cap one scope down — the cap on the TEAM the project is (reader.spendLimits({ vendor: 'openai', kind: 'team' })), resolved against the peak month of the spend ATTRIBUTED to that project. The fold is attribution() and not the project's member list, because attribution() is the map /organization/costs?group_by=project_id already groups by: a person who holds seats in two seat-holding teams attributes to ONE project there, and a cap folded over memberships would count their month twice and stand above a peak no report publishes. THE DEFAULT PROJECT HAS NO CAP AND THAT IS DATA RATHER THAN A MODE — canon scopes a cap to a team that holds a seat on this vendor's tool and the Default project is no team, so the project resolves and its cap answers OpenAI's own 404; the conformance row walks the project list for one that HAS a cap rather than naming one, so a canon change that moved the caps cannot leave it validating a miss and calling it green. Same five members as the organization's under the project.spend_limit object word. hello-19 and older answer the noBillingPeriods generation gap
SERVED 2026-09-14 (hello-20): this organization's hard spend cap — reader.spendLimits({ vendor: 'openai', kind: 'org' }) — resolved against THIS host's own price list. A CAP CARRIES NO AMOUNT IN THE ARTIFACT: canon stores a MULTIPLE of the worst month (BILLING_HEADROOM_MULTIPLE, packages/canon/src/billing-periods.ts) because the dollar figure it resolves to needs a price list, and this host has owned one since P31 — totalMicroCents in renderer-openai/src/render.ts, which /organization/costs already reconciles against — so threshold_amount is `headroom_multiple × the peak calendar month of model spend`, in cents, and ONE number stands behind the cap, its alert and the cost report a caller can add up themselves. PARTIAL MONTHS COUNT AS THEY ARE: the window's first and last are clipped, exactly as canon's billing_period clips them, because a period may not claim days the artifact does not hold. `interval` is month and `currency` is USD because the document declares exactly one member for each; enforcement.status reads canon's `enforced`, itself read off this organization's hard-failing config policy rather than chosen. Conformance re-derives the peak from canon's OWN billingMonthsIn and asserts the served amount, which is what keeps the renderer's month bucketing honest — a renderer depends on @sandboxapis/artifact and never on @sandboxapis/canon, so the arithmetic is restated and bound rather than imported. hello-19 and every older artifact answer the noBillingPeriods generation-gap 404 naming generation hello-20, never a zero, which would say this organization capped itself at nothing
refuse — the same inference plane as the tagged platform rows — chatkit threads and code-interpreter containers only read as separate here because the spec leaves their tag empty; an OpenAI admin key gets 401 invalid_api_key for them too
refuse — the same inference plane as the tagged platform rows — chatkit threads and code-interpreter containers only read as separate here because the spec leaves their tag empty; an OpenAI admin key gets 401 invalid_api_key for them too
refuse — the same inference plane as the tagged platform rows — chatkit threads and code-interpreter containers only read as separate here because the spec leaves their tag empty; an OpenAI admin key gets 401 invalid_api_key for them too
refuse — the same inference plane as the tagged platform rows — chatkit threads and code-interpreter containers only read as separate here because the spec leaves their tag empty; an OpenAI admin key gets 401 invalid_api_key for them too
refuse — the same inference plane as the tagged platform rows — chatkit threads and code-interpreter containers only read as separate here because the spec leaves their tag empty; an OpenAI admin key gets 401 invalid_api_key for them too
refuse — the same inference plane as the tagged platform rows — chatkit threads and code-interpreter containers only read as separate here because the spec leaves their tag empty; an OpenAI admin key gets 401 invalid_api_key for them too
refuse — the same inference plane as the tagged platform rows — chatkit threads and code-interpreter containers only read as separate here because the spec leaves their tag empty; an OpenAI admin key gets 401 invalid_api_key for them too
refuse — the same inference plane as the tagged platform rows — chatkit threads and code-interpreter containers only read as separate here because the spec leaves their tag empty; an OpenAI admin key gets 401 invalid_api_key for them too
SERVED 2026-09-10 (hello-15): canon's IdentityGroup — reader.listIdentityGroups(org) (reader.ts:2472) — in the vendored GroupListResource envelope. A GROUP IS NOT A TEAM and this reads neither a team nor a roster: the generator builds each group out of an access fact canon already records (everyone who writes code, everyone who has reviewed something, everyone who may cut a release, the machine accounts) and the canon suite asserts no group has exactly a team's membership, which groups.test.ts re-asserts over the served rows. `is_scim_managed` is the FEDERATION's fact, read off IdentityProviderConfig.scim_enabled, so every group this provider asserts reports the same value. `group_type` is `group` and never `tenant_group`: a tenant group belongs to an OpenAI enterprise tenant standing above the organization, and these are asserted by the organization's own provider. The id is openaiId("group_", "idgroup-00N") — the same fnv-1a derivation user-/proj_/key_ ride, so it is a pure function of the canonical id rather than a counter over an iteration order. Older pins answer the noIdentityGroups generation-gap 404 naming openai-2020-10-g10, never an empty list
SERVED 2026-09-10 (hello-15): the same IdentityGroup by id, byte-identical to the row the list publishes — conformance asserts every group both ways. GroupResponse carries NO `object` field and spells the flag `is_scim_managed`; the document's `Group` schema (the summary embedded in a role assignment) carries `object: "group"` and `scim_managed` instead, and these two operations return GroupResponse. A canonical `idgroup-00N` does NOT address a group here, which conformance asserts too
SERVED 2026-09-12 (hello-17): the ORGANIZATION role an identity group holds, from the `scope_kind = 'group'` membership hello-17's features.grants writes — reader.groupRole(group) — in the vendored RoleListResource envelope. ONE ROW OR NONE, and that is canon's shape rather than a slice taken in the renderer: a group's role is the FLOOR of its members' own authority, because a grant to a group reaches everyone in it and granting more than its least-authorised member already holds would elevate that person through the directory, so canon writes exactly one row per group (decisions/2026-09-11-2304-hello-17-grants.md). The objects are the SAME AssignedRoleDetails under the SAME ids the user assignments publish — one catalog, two kinds of principal — which groups.test.ts asserts directly, because a schema cannot. Paged by the Roles API's own bounds: list-group-role-assignments declares no limit default and no order default, exactly as list-user-role-assignments does not, so both take 0..1000 / default 1000 / order asc from list-roles. hello-16 and every older artifact answer the noGrants generation-gap 404 naming generation hello-17 — never an empty list, which would be a claim about the ORGANIZATION rather than about the snapshot the caller pinned (the 2026-09-02 ruling). FOUNDER RULING 2026-09-10, round 13
SERVED 2026-09-12 (hello-17): the same assignment by id, byte-identical to the row the list publishes — conformance asserts every group both ways. A REAL catalog role this group does not hold misses here too, the way it does for a user one route over: which role is held is the question the route answers, and a group holds exactly one. The by-id half was PROPOSED as a `refuse` on the reading that no role id could ever resolve for a group; hello-17's grant makes exactly one resolve per group, so the proposal is withdrawn rather than ruled and this is a `derive` like its list. FOUNDER RULING 2026-09-10, round 13
SERVED 2026-09-10 (hello-15): a group's canonical members (IdentityGroup.members) INTERSECTED with this organization's own roster, in the vendored UserListResource envelope. THE INTERSECTION IS THE JUDGMENT AND IT IS THE ONLY COHERENT ONE: an OpenAI organization user on this replica is a codex seat holder (renderer-openai/src/render.ts members()), canon's group rosters are rosters of PEOPLE, and serving a person with no account here would publish a user id that 404s against /organization/users/{user_id} standing right beside it — invariant #5 broken in one response pair. OpenAI's own question is which USERS are assigned to the group, and a person with no account is not one of its users; the same reading /v3/enterprise/members/service-users takes on Devin. NOTHING IS HIDDEN, because no shape here publishes a member count: GroupResponse is {id, name, created_at, is_scim_managed, group_type} and carries neither a size nor canon's description. Two of the four groups therefore list nobody, which is DATA rather than a mode — the Default project lists no API key for the same kind of reason — and conformance asserts the served set equals the intersection FROM BOTH SIDES, so a widening and a narrowing are both red. `order` defaults to DESC here and asc on every sibling, which is the document's own default. Older pins answer the noIdentityGroups generation gap
SERVED 2026-09-10 (hello-15): the same membership addressed by (group, user), in the vendored GroupMemberUser shape — the list item plus three fields. A real organization user who is NOT in this group misses here too, because group membership is the question this route answers. `picture` is null because nothing in this universe is a profile-picture URL: canon holds identicon bytes for an org and a repo and nothing keyed to a person, and an authored URL would resolve nowhere (invariant #4). `is_service_account` READS person.is_bot rather than being hard-coded, so it follows rather than being asserted; it is false for everyone this route can reach today because canon's only non-human identity is the CI bot and it holds no codex seat. `user_type` is `user` and never `tenant_user`, for the reason group_type is never tenant_group
no identity group has access to a project, and no generation of this universe grants one. The vendored summary on list-project-groups is "Lists the groups that have ACCESS to a project" and its item, ProjectGroup, is a GRANT object (object + project_id + group_id + group_name + group_type + created_at) rather than a group — so this list can only carry rows canon does not have. hello-17's features.grants writes one `scope_kind = 'group'` membership per identity group, which attaches the group to a ROLE; IdentityGroup itself carries an org, a provider, a name slot, a member list and a creation instant and nothing that names a container, and a project on this host is minted per TEAM holding a codex seat (renderer-openai/src/render.ts projects()) with no group on either side of it. UNGATED BY GENERATION, deliberately: a generation gap would say the caller's snapshot is too old to answer where the true statement is that the answer is the same on every snapshot there is. The project still has to resolve — a ruling about a project nobody has is a typo answered confidently — and the bounds validated are this operation's own (limit 0..100 default 20, order default asc), which differ from every sibling's. FOUNDER RULING 2026-09-11, round 17
refuse — the id half of the project-groups pair: its list is empty because no identity group has access to a project, so no (project, group) grant can resolve and OpenAI's own 404 is the only possible answer — the certificates/invites shape ruled 2026-09-01. It addresses a ProjectGroup (the grant) and not a Group, so there is nothing for {group_id} to resolve against and a REAL group id misses here exactly as an invented one does, which is the ruling rather than a gap. Parent-guarded (the project resolves first) and ungated by generation, for the reason the list carries. FOUNDER RULING 2026-09-11, round 17
refuse — NOT the project-scoped twin of /organization/groups/{group_id}/roles, and the difference is what decides the mode: this one is scoped BY a group's access to a project, and /organization/projects/{project_id}/groups is `empty` because no identity group has that access in any generation (founder ruling 2026-09-11, round 17). So the (project, group) pair never resolves and OpenAI's own 404 is the only possible answer — the same reading /projects/{project_id}/users/{user_id}/roles already takes one route over, where a person who is not in the project misses rather than getting an empty list. hello-17's features.grants attaches a group to an ORGANIZATION role, which /organization/groups/{group_id}/roles serves; it attaches nothing to a container. The refusal names the GROUP and not the role, because the group's access is the first thing that fails and the request never reaches a role. Parent-guarded (the project resolves first) and ungated by generation, for the reason the project-groups pair carries. FOLLOWS FROM FOUNDER RULING 2026-09-11, round 17
refuse — the id half of the project group-roles pair: its list refuses because no identity group has access to a project, so the (project, group) pair never resolves and no role id under it can either — OpenAI's own 404, naming the group rather than the role for the reason the list gives. Same guard, same ungating, same ruling. FOLLOWS FROM FOUNDER RULING 2026-09-11, round 17
an empty DENY list — no model is denied, which is exactly a universe with no restriction evidence; an empty ALLOW list would claim no model may be called, which the usage report disproves (DECISIONS 2026-08-20 [P31/openai])
these are policy NUMBERS and this org configures no override; any figure printed here would be a placeholder copied off the spec's example, which invariant #4 forbids. The empty list says 'no override configured' (DECISIONS 2026-08-20 [P31/openai])
the canon's only non-human identity is the CI bot: it holds no codex seat, belongs to no team and produced no OpenAI usage, so nothing here is a project-scoped machine identity (DECISIONS 2026-08-20 [P31/openai])
refuse — the id half of the service-account pair: /organization/projects/{project_id}/service_accounts is `empty` because the CI bot is not a project-scoped machine identity, so no service-account id can resolve and OpenAI's own 404 is the only possible answer (DECISIONS 2026-09-01 [coverage/A0]). The refusal suite owns this row: its OPENAI_ENDPOINTS expectMiss entry was removed 2026-09-03 (founder ruling on proposal 2 of coverage/reviews/2026-09-03-openai-refuse-shapes.md) because it made a refuse row read `green`, and a refusal is terminal by mode, never green by status
SERVED 2026-09-10 (hello-16): reader.listMembershipRoles() (packages/artifact/src/reader.ts:3042) in the vendored PublicRoleListResource envelope. Five catalog ROWS rather than an enum rendered at request time: `Role.permissions` is REQUIRED, and a permission list composed inside a renderer is a fact invented at serving time. `permissions` stays canon's closed `scope:level` vocabulary, which the schema types `array<string>` with no enum; `resource_type` is `api.organization`, the document's own example for this scope; and `predefined_role` is DERIVED — a role minted at the organization's own creation instant was created by nobody in it, which conformance asserts as a biconditional rather than as the current answer
SERVED 2026-09-10 (hello-16): the same catalog row by id — reader.listMembershipRoles() (reader.ts:3042) addressed by openaiId("role_", …), byte-identical to the row the catalog serves, which conformance asserts for all five. An id the catalog does not carry is OpenAI's own `Role <id> not found`, never the empty-body coverage miss
SERVED 2026-09-10 (hello-16): the role on this person's ACTIVE organization membership — reader.listMemberships("org", org) (reader.ts:3020) — rendered as the catalog row it names, in the vendored RoleListResource envelope. A pending membership is an invitation and is not an assignment, which is the only place that distinction could have been lost. The four nulls are facts: canon records no edit to a catalog row (`updated_at`), no author for one (`created_by`), and every assignment is held directly rather than inherited (`assignment_sources`)
SERVED 2026-09-10 (hello-16): the same assignment addressed by (user, role) — reader.listMemberships("org", org) (reader.ts:3020). A REAL catalog role this person does not hold misses here too, because which role you hold is the question this route answers; conformance drives both halves
SERVED 2026-09-10 (hello-16): the same reader.listMembershipRoles() catalog (reader.ts:3042) at project scope — `resource_type: api.project`, the document's own example for this scope, under ids of its own because OpenAI addresses an organization role and a project role as different objects. Same name, same description, same permissions, same created_at as the organization row, which conformance asserts; an organization role id does NOT address a project role, which it asserts too
SERVED 2026-09-10 (hello-16): the project catalog row by id — reader.listMembershipRoles() (reader.ts:3042). The project must still resolve, so an unknown {project_id} is OpenAI's own `Project <id> not found` rather than a cheerful empty catalog
SERVED 2026-09-10 (hello-16): the role on this person's membership in the container the PROJECT IS — reader.listMemberships("team", team) for a team project and reader.listMemberships("org", org) for the Default project (reader.ts:3020), since a project here is a team holding a codex seat and Default is the organization's own project. One rule, total over every project this renderer mints, which is why an assignment can never name somebody outside the container; a user who is not in the project misses rather than getting an empty list
SERVED 2026-09-10 (hello-16): the same project assignment addressed by (project, user, role) — reader.listMemberships over team and org scope (reader.ts:3020). Byte-identical to the row the list serves, and a role the person does not hold in THIS project is OpenAI's own 404
SERVED 2026-09-14 (hello-20): the project's own alert, derived from the project's own cap exactly as the organization's is from its own — same percentage, same recipient, same null subject prefix, under the project.spend_alert object word. THE DEFAULT PROJECT LISTS NONE and that is a COMPUTATION rather than a claim about the universe: it holds no cap, so there is no cap to warn about, and an empty page a computation produces is not the `empty` mode (the same reading the Default project's empty API-key list already takes on this host). The project still has to resolve — a ruling about a project nobody has is a typo answered confidently — and the bounds validated are this operation's own (limit 0..100 default 20, order default asc, both cursors). hello-19 and older answer the noBillingPeriods generation gap
SERVED 2026-09-14 (hello-20): the same alert by (project, id), byte-identical to the row the project's list publishes. Parent-guarded — an unknown {project_id} is the ordinary `Project <id> not found` before the alert is looked for — and scope-guarded: the ORGANIZATION's alert misses here, because which project an alert belongs to is the question this route answers. An id this project's list does not carry is OpenAI's own 404
SERVED 2026-09-14 (hello-20): ONE ALERT PER CAP, DERIVED FROM THE CAP RATHER THAN SET BESIDE IT. Canon stores alert_threshold_percent as floor(100 / headroom_multiple) precisely so the warning fires when this organization is back at the level of its worst month — one constant, not two — so the alert's threshold_amount is that percentage of the cap standing beside it, and a second independently rounded figure here would be exactly the drift the derivation exists to prevent. notification_channel.recipients is the address of the person canon's `notify` names (the author of this organization's policies), composed with the org-wide email convention render.ts uses for every member, because canon names a PERSON and never an address. subject_prefix IS NULL rather than a string, and the document's own anyOf [string, null] is what makes that honest: a subject prefix is a line somebody types into a settings box, canon records no such act, and any string would be the placeholder invariant #4 forbids. The id is openaiId("alert_", <the cap's canonical id>) — the same fnv-1a derivation user-/proj_/key_/role_/group_ ride. Paged by this operation's OWN bounds, which differ from every sibling's on this host: the classic first_id/last_id/has_more envelope but limit 0..100 default 20, order default asc, and BOTH cursors — an unknown `after` or `before` is a 400 rather than a silent restart (cursorPage's posture). hello-19 and older answer the noBillingPeriods generation gap, never an empty list, which would say this organization set no alert
SERVED 2026-09-14 (hello-20): the same alert by id, byte-identical to the row the list publishes, which conformance asserts. A PROJECT's alert id misses here and the organization's misses on the project route: which scope an alert belongs to is the question these two routes answer, and both were derived from different caps over different folds. An id neither list carries is OpenAI's own `Spend alert <id> not found`, never the empty-body coverage miss
OpenAI answers {"data": []} to an admin key for the org certificate list when no mTLS certificate has been uploaded, and this org uploaded none — refusing would be false to the provider
OpenAI answers {"data": []} to an admin key for a project certificate list when no mTLS certificate has been uploaded, and this org uploaded none — refusing would be false to the provider
refuse — the id half of the certificate pair: this org uploaded no mTLS certificate, so no certificate id can resolve and OpenAI's own 404 is the only possible answer (the by-id shape ruled in DECISIONS 2026-09-01 [coverage/A0] for the invite and service-account rows)
SERVED 2026-09-14 (hello-20): canon's retention PAIR — how many days a request payload is kept and whether a copy is retained for abuse review (reader.retentionPolicy({ vendor: 'openai', kind: 'org' })) — mapped to OpenAI's own closed word. STRUCTURE, NOT A VENDOR'S SPELLING is canon's rule for this entity, and renderer-openai/src/render-billing.ts#retentionWord is the one place the word is chosen. This universe's pair is (0 days, no abuse copy) and it is a MEASUREMENT rather than a default: NO TABLE IN THIS ARTIFACT STORES A MODEL PROMPT OR COMPLETION, because the 2026-08-20 policy refuses to invent an agent's prose and F13 built agent_session_turn with no body column to honour it — so the word is zero_data_retention, and the conformance suite asserts the absence over the AI tables rather than trusting the sentence. The two `enhanced_` rungs are unreachable from any pair this canon can hold: they name an enterprise agreement over and above the control itself and nothing here evidences one. hello-19 and older answer the noBillingPeriods generation gap
SERVED 2026-09-14 (hello-20): the project's own control, and `organization_default` is reachable two ways here — both meaning the same thing and neither a gap. A TEAM project HAS a canon row, and a row whose pair equals the organization's IS that word: canon says so in as many words ("a project row whose pair equals the organization's IS the default, which is how that member is reachable without a canon member for it"). The DEFAULT project has no row at all, because canon scopes a retention policy to a team and the Default project is no team — and "no project-level override" is the same sentence. So both answer organization_default, and a project that ever diverged would answer its own word without the mapping changing, which conformance asserts as a biconditional rather than as today's answer. The project still has to resolve. hello-19 and older answer the noBillingPeriods generation gap
every member of this org accepted; no invite is pending (DECISIONS 2026-08-20 [P31/openai])
refuse — the id half of the invites pair: /organization/invites is `empty` because every member already accepted, so no invite id can resolve and OpenAI's own 404 is the only possible answer (DECISIONS 2026-09-01 [coverage/A0]); `derive` was the wrong word for that answer. The refusal suite owns this row: its OPENAI_ENDPOINTS expectMiss entry was removed 2026-09-03 (founder ruling on proposal 2 of coverage/reviews/2026-09-03-openai-refuse-shapes.md) because it made a refuse row read `green`, and a refusal is terminal by mode, never green by status
SERVED 2026-09-14 (hello-20): the administrative register hello-20's features.auditActor writes — admin_audit_event rows whose actor is a PERSON on the engineering roster — read through reader.personAuditEventsForTarget() and NEVER the bare accessor, which defaults to the support desk's half of the same table and would publish a Zendesk instance's account audit log on a Platform surface. AuditLogEventType IS A CLOSED ENUM OF OPENAI'S OWN EVENTS, and that is what makes this host's answer a SUBSET rather than the whole register: Jira and GitLab can print canon's own noun for an object their vocabulary has no word for (renderer-zendesk's AUDIT_SOURCE_TYPE[...] ?? row.target_kind rule), and here a `type` the document does not declare fails its own schema. So a canonical act is published only where this host has BOTH an event word and an object, and each exclusion is a claim rather than a gap. PUBLISHED: every canonical MEMBERSHIP act as role.assignment.created — an org membership held by a codex seat holder IS the assignment /organization/users/{user_id}/roles serves, and a membership in a team that holds a seat IS the one /projects/{project_id}/users/{user_id}/roles serves, under the SAME role id, with resource_type api.organization or api.project and the project named on the entry exactly at project scope (the document's own "absent for actions not scoped to projects"). NOT PUBLISHED: the organization's and a repository's creation and a protected ref, because the enum has no organization.created and the Platform has no concept of the other two; a TEAM's creation, because a project here is MINTED from a team that holds a seat and its created_at is the earliest seat instant (render.ts projects()), so project.created at canon's team instant would give a caller two answers to one question — invariant #5 broken in one response pair; and a credential's issue or revocation, because canon's credentials are the GIT host's and api_key.created would claim an OpenAI key was minted. THE ACTOR IS A SESSION AND ITS id IS PUBLISHED ONLY WHEN IT RESOLVES: this organization's users are its codex seat holders, the administrator who performed these acts need not be one, and minting user-… for a person /organization/users/{user_id} misses would be a reference that does not resolve — AuditLogActorUser declares both members optional for exactly that case, so the org-wide email is always published and the id only when this host can answer for it. ip_address is the register's own, RFC 5737 documentation or RFC 1918 private space. Filters are the document's: effective_at[gt|gte|lt|lte], event_types[], project_ids[], resource_ids[], actor_ids[], actor_emails[] (matched against exactly the two values the response publishes) and tenant_only, which selects the enterprise-tenant events this organization has none of. hello-19 and older answer the noAuditActor generation-gap 404 naming hello-20 — and the probe asks for a `person` ROW rather than for the table, which has existed since hello-15 with the desk's rows in it
03 / What's simulated
Every OpenAI call resolves against the same simulated data set every other provider serves. Counted from the openai-2020-10-g12 artifact (universe generation 12):
Each line below is one assertion in the conformance suite named beside it — run on every build, over one artifact, through the real renderers. Nothing is claimed here that no expect checks.
This surface and the Codex Analytics surface serve ONE cohort: the set of `actor.user_id` in Codex usage equals the set of `/v1/organization/users` ids, the emails match per id, and the two hosts' uncached-input and output token totals are equal.
Against Codex Analytics · parity/m3-parity.test.ts
This vendor's user roster is disjoint from the GitHub Copilot cohort and from Anthropic's, Cursor's and Devin's, so nobody holds two vendors' seats; and the token totals summed across the paged usage endpoint equal its own slice of the canonical seat table.
Against GitHub, Anthropic, Cursor, Devin · parity/m3-parity.test.ts
Every identity this host bills for resolves as a user on the GitHub host with the same name.
Against GitHub · parity/m3-parity.test.ts
05 / Pinned snapshots
Each pin regenerates byte-identically on every request, so a test written against one never drifts. Generations are DIFFERENT universes, not versions of one — never swap a suffix expecting the same data.
openai-2020-10.snap.sandboxapis.devgeneration 52020-10-01servedopenai-2020-10-g10.snap.sandboxapis.devgeneration 102020-10-01servedopenai-2020-10-g11.snap.sandboxapis.devgeneration 112020-10-01servedopenai-2020-10-g12.snap.sandboxapis.devgeneration 122020-10-01servedopenai-2020-10-g6.snap.sandboxapis.devgeneration 62020-10-01servedopenai-2020-10-g8.snap.sandboxapis.devgeneration 82020-10-01servedopenai-2020-10-g9.snap.sandboxapis.devgeneration 92020-10-01servedNeed an endpoint that is not served yet?
Every row OpenAI's manifest carries is on this page, so “not here” is an answer rather than a gap in the rendering. Tell us which path and which client, and it moves up the queue — the order is set by what people ask for.