OpenAI Admin API sandbox

OpenAI

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.

REST · 122 endpointsMCP-ready

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.

Live host
openai.sandboxapis.dev
Pinned hosts
7 — generation 5, 6, 8, 9, 10, 11, 12
Serving since
2026-08-18
Lifecycle
Live

Served & 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

Point your client at a different base URL.

No SDK of ours, no shim, no recorded fixtures. The same client library you already use, one environment variable different.

shell
curl -H 'Authorization: Bearer any-key' "https://openai.sandboxapis.dev/v1/organization/users"

Verified drop-in clients

  • openai7.5.0

The 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

Every read surface, grouped the way OpenAI groups it.

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

served & verified
answers with real universe data, and this build checked that response against the vendor's spec.
deviation
served and faithful to the real provider, but failing the vendored spec — usually a bug in the spec.
retired
the vendor removed the endpoint; snapshots pinned before that date still serve it.
planned / deferred
not served yet — an explicit coverage error naming the gap, never invented data.
excluded
out of the claim by policy (writes, and surfaces we refuse); not in any denominator on this page.

Mode — what kind of answer a row gets

derive
the response is computed from artifact rows that already exist
generate
canon does not carry this yet; the generator will produce it, then derive
empty
the true answer for this universe is an empty collection — reason + reviewed date required
refuse
mirror the provider's OWN refusal (e.g. its 403 for a non-admin token) — reason + reviewed date required
read-only
a write named in the manifest because clients probe it; the read-only 403 IS its final response, and it never joins the badge denominator
scratch
a write this replica ACCEPTS, into a per-key 24-hour overlay, answering with the provider's own success shape - reason + reviewed date required. The compiled artifact is unchanged and no other caller ever sees the row; a caller WITHOUT a scratch-enabled key gets the read-only refusal on the identical path. Like read-only it never joins the badge denominator (founder ruling 5, 2026-09-17: the published figure has meant READ operations served since A0.1), and unlike read-only it ANSWERS, so the generation report counts it in its own `scratch` column rather than in (excluded). Scratch never creates a pull request, a branch, a commit or a diff - those are canon structure the overlay cannot invent

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

Full
every published read row has a final answer
Deep
60% up to 100%
Partial
25% up to 60%
Preview
under 25%

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

platform0 of 55 served & verified
GET
/assistants

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

deferred
Long tail
GET
/assistants/{assistant_id}

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

deferred
Long tail
GET
/audio/voice_consents

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

deferred
Long tail
GET
/audio/voice_consents/{consent_id}

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

deferred
Long tail
GET
/batches

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

deferred
Long tail
GET
/batches/{batch_id}

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

deferred
Long tail
GET
/chat/completions

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

deferred
Long tail
GET
/chat/completions/{completion_id}

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

deferred
Long tail
GET
/chat/completions/{completion_id}/messages

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

deferred
Long tail
GET
/conversations/{conversation_id}

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

deferred
Long tail
GET
/conversations/{conversation_id}/items

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

deferred
Long tail
GET
/conversations/{conversation_id}/items/{item_id}

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

deferred
Long tail
GET
/evals

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

deferred
Long tail
GET
/evals/{eval_id}

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

deferred
Long tail
GET
/evals/{eval_id}/runs

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

deferred
Long tail
GET
/evals/{eval_id}/runs/{run_id}

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

deferred
Long tail
GET
/evals/{eval_id}/runs/{run_id}/output_items

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

deferred
Long tail
GET
/evals/{eval_id}/runs/{run_id}/output_items/{output_item_id}

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

deferred
Long tail
GET
/files

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

deferred
Long tail
GET
/files/{file_id}

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

deferred
Long tail
GET
/files/{file_id}/content

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

deferred
Long tail
GET
/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions

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

deferred
Long tail
GET
/fine_tuning/jobs

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

deferred
Long tail
GET
/fine_tuning/jobs/{fine_tuning_job_id}

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

deferred
Long tail
GET
/fine_tuning/jobs/{fine_tuning_job_id}/checkpoints

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

deferred
Long tail
GET
/fine_tuning/jobs/{fine_tuning_job_id}/events

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

deferred
Long tail
GET
/organization/projects/{project_id}/hosted_tool_permissions

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)

deferred
Long tail
GET
/responses/{response_id}

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

deferred
Long tail
GET
/responses/{response_id}?beta=true

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

deferred
Long tail
GET
/responses/{response_id}/input_items

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

deferred
Long tail
GET
/responses/{response_id}/input_items?beta=true

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

deferred
Long tail
GET
/skills

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

deferred
Long tail
GET
/skills/{skill_id}

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

deferred
Long tail
GET
/skills/{skill_id}/content

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

deferred
Long tail
GET
/skills/{skill_id}/versions

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

deferred
Long tail
GET
/skills/{skill_id}/versions/{version}

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

deferred
Long tail
GET
/skills/{skill_id}/versions/{version}/content

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

deferred
Long tail
GET
/threads/{thread_id}

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

deferred
Long tail
GET
/threads/{thread_id}/messages

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

deferred
Long tail
GET
/threads/{thread_id}/messages/{message_id}

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

deferred
Long tail
GET
/threads/{thread_id}/runs

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

deferred
Long tail
GET
/threads/{thread_id}/runs/{run_id}

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

deferred
Long tail
GET
/threads/{thread_id}/runs/{run_id}/steps

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

deferred
Long tail
GET
/threads/{thread_id}/runs/{run_id}/steps/{step_id}

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

deferred
Long tail
GET
/vector_stores

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

deferred
Long tail
GET
/vector_stores/{vector_store_id}

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

deferred
Long tail
GET
/vector_stores/{vector_store_id}/file_batches/{batch_id}

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

deferred
Long tail
GET
/vector_stores/{vector_store_id}/file_batches/{batch_id}/files

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

deferred
Long tail
GET
/vector_stores/{vector_store_id}/files

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

deferred
Long tail
GET
/vector_stores/{vector_store_id}/files/{file_id}

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

deferred
Long tail
GET
/vector_stores/{vector_store_id}/files/{file_id}/content

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

deferred
Long tail
GET
/videos

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

deferred
Long tail
GET
/videos/{video_id}

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

deferred
Long tail
GET
/videos/{video_id}/content

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

deferred
Long tail
GET
/videos/characters/{character_id}

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

deferred
Long tail
usage11 of 11 served & verified
GET
/organization/costs
served & verified
Core
GET
/organization/usage/audio_speeches

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])

served & verified
Core
GET
/organization/usage/audio_transcriptions

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])

served & verified
Core
GET
/organization/usage/code_interpreter_sessions

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])

served & verified
Core
GET
/organization/usage/completions
served & verified
Core
GET
/organization/usage/embeddings

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])

served & verified
Core
GET
/organization/usage/file_search_calls

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])

served & verified
Core
GET
/organization/usage/images

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])

served & verified
Core
GET
/organization/usage/moderations

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])

served & verified
Core
GET
/organization/usage/vector_stores

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])

served & verified
Core
GET
/organization/usage/web_search_calls

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 & verified
Core
<none>2 of 10 served & verified
GET
/organization/projects/{project_id}/spend_limit

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 & verified
Long tail
GET
/organization/spend_limit

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

served & verified
Long tail
GET
/chatkit/threads

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

deferred
Long tail
GET
/chatkit/threads/{thread_id}

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

deferred
Long tail
GET
/chatkit/threads/{thread_id}/items

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

deferred
Long tail
GET
/containers

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

deferred
Long tail
GET
/containers/{container_id}

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

deferred
Long tail
GET
/containers/{container_id}/files

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

deferred
Long tail
GET
/containers/{container_id}/files/{file_id}

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

deferred
Long tail
GET
/containers/{container_id}/files/{file_id}/content

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

deferred
Long tail
groups7 of 10 served & verified
GET
/organization/groups

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 & verified
Long tail
GET
/organization/groups/{group_id}

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 & verified
Long tail
GET
/organization/groups/{group_id}/roles

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 & verified
Long tail
GET
/organization/groups/{group_id}/roles/{role_id}

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 & verified
Long tail
GET
/organization/groups/{group_id}/users

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 & verified
Long tail
GET
/organization/groups/{group_id}/users/{user_id}

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

served & verified
Long tail
GET
/organization/projects/{project_id}/groups

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

served & verified
Long tail
GET
/organization/projects/{project_id}/groups/{group_id}

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

deferred
Long tail
GET
/projects/{project_id}/groups/{group_id}/roles

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

deferred
Long tail
GET
/projects/{project_id}/groups/{group_id}/roles/{role_id}

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

deferred
Long tail
projects9 of 10 served & verified
GET
/organization/projects
served & verified
Core
GET
/organization/projects/{project_id}
served & verified
Core
GET
/organization/projects/{project_id}/api_keys
served & verified
Core
GET
/organization/projects/{project_id}/api_keys/{api_key_id}
served & verified
Core
GET
/organization/projects/{project_id}/model_permissions

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])

served & verified
Core
GET
/organization/projects/{project_id}/rate_limits

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])

served & verified
Core
GET
/organization/projects/{project_id}/service_accounts

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])

served & verified
Core
GET
/organization/projects/{project_id}/users
served & verified
Core
GET
/organization/projects/{project_id}/users/{user_id}
served & verified
Core
GET
/organization/projects/{project_id}/service_accounts/{service_account_id}

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

planned
Core
roles8 of 8 served & verified
GET
/organization/roles

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 & verified
Long tail
GET
/organization/roles/{role_id}

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 & verified
Long tail
GET
/organization/users/{user_id}/roles

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 & verified
Long tail
GET
/organization/users/{user_id}/roles/{role_id}

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 & verified
Long tail
GET
/projects/{project_id}/roles

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 & verified
Long tail
GET
/projects/{project_id}/roles/{role_id}

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 & verified
Long tail
GET
/projects/{project_id}/users/{user_id}/roles

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 & verified
Long tail
GET
/projects/{project_id}/users/{user_id}/roles/{role_id}

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 & verified
Long tail
spend-alerts4 of 4 served & verified
GET
/organization/projects/{project_id}/spend_alerts

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 & verified
Long tail
GET
/organization/projects/{project_id}/spend_alerts/{alert_id}

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 & verified
Long tail
GET
/organization/spend_alerts

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 & verified
Long tail
GET
/organization/spend_alerts/{alert_id}

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

served & verified
Long tail
certificates2 of 3 served & verified
GET
/organization/certificates

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

served & verified
Long tail
GET
/organization/projects/{project_id}/certificates

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

served & verified
Long tail
GET
/organization/certificates/{certificate_id}

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)

deferred
Long tail
admin-keys2 of 2 served & verified
GET
/organization/admin_api_keys
served & verified
Core
GET
/organization/admin_api_keys/{key_id}
served & verified
Core
data-retention2 of 2 served & verified
GET
/organization/data_retention

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 & verified
Long tail
GET
/organization/projects/{project_id}/data_retention

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

served & verified
Long tail
invites1 of 2 served & verified
GET
/organization/invites

every member of this org accepted; no invite is pending (DECISIONS 2026-08-20 [P31/openai])

served & verified
Core
GET
/organization/invites/{invite_id}

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

planned
Core
models2 of 2 served & verified
GET
/models
served & verified
Core
GET
/models/{model}
served & verified
Core
users2 of 2 served & verified
GET
/organization/users
served & verified
Core
GET
/organization/users/{user_id}
served & verified
Core
audit-logs1 of 1 served & verified
GET
/organization/audit_logs

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

served & verified
Next

03 / What's simulated

One data set, rendered in OpenAI's dialect.

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):

What another provider has to agree with, and the test that makes it

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.

05 / Pinned snapshots

Universes that never change, on their own hostnames.

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.

PinHostUniverse generationOpenAI API versionRepository files
openai-2020-10openai-2020-10.snap.sandboxapis.devgeneration 52020-10-01served
openai-2020-10-g10openai-2020-10-g10.snap.sandboxapis.devgeneration 102020-10-01served
openai-2020-10-g11openai-2020-10-g11.snap.sandboxapis.devgeneration 112020-10-01served
openai-2020-10-g12openai-2020-10-g12.snap.sandboxapis.devgeneration 122020-10-01served
openai-2020-10-g6openai-2020-10-g6.snap.sandboxapis.devgeneration 62020-10-01served
openai-2020-10-g8openai-2020-10-g8.snap.sandboxapis.devgeneration 82020-10-01served
openai-2020-10-g9openai-2020-10-g9.snap.sandboxapis.devgeneration 92020-10-01served

Need 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.

Request coverage