Most organisations using OpenAI and Anthropic cannot say how many API keys they have, who owns each one, or which ones still work after their owner has left. Both providers expose that inventory through an Admin API, but the defaults hide some keys, the fields differ, and Anthropic does not return a last-used date at all. This runbook shows how to pull a complete key inventory from both platforms, enrich it with usage, flag the risky keys (no expiry, departed owner, unused, over-scoped, in the wrong container) and clean them up in a reversible order. It is for identity, platform and security engineers running a periodic access review of model provider credentials. For background on each platform's credential model, see the OpenAI API Keys Security Guide and the Anthropic API Keys Security Guide.
This is an independent guide from NHI Mgmt Group, based on OpenAI's and Anthropic's public API documentation as of November 2026, including OpenAI's published OpenAPI specification. It is not sponsored or reviewed by either provider. Endpoints and fields change, so confirm them against current documentation.
Key takeaways
- Use the Admin APIs, not the dashboards. OpenAI lists keys per project at
/v1/organization/projects/{project_id}/api_keys; Anthropic lists every key at/v1/organizations/api_keys. Both need an admin credential. - Ask OpenAI for every key explicitly. Without
owner_project_access=any, the project key listing applies membership-based visibility rules that "may exclude some enabled keys". - Find keys whose owner has gone. OpenAI's
owner_project_access=inactivereturns enabled keys whose owner no longer has access to the project. - Derive last use for Anthropic from usage data. Anthropic key objects have no last-used field; group the usage report by
api_key_idinstead. - Disable before delete. Anthropic keys can be set to
inactive; OpenAI keys can be given a short expiry or read-only scope before deletion, which cannot be undone.
When you need this
- Quarterly access review: model provider keys are non-human credentials and belong in the same review as cloud and SaaS keys. See How to Run an Access Review for Service Accounts.
- After a leak or a supply chain incident: the LiteLLM PyPI package breach exposed LLM API keys held by developers and pipelines; an inventory tells you which keys to rotate first.
- After staff or vendor offboarding: a user-owned key "acts with its owner's access", in OpenAI's words, and keys created by people who have left often keep running in production.
- Before raising spend limits or usage tiers: know what you are funding. See How to set spend limits on LLM API keys.
Before you start
The two platforms expose different fields. Build your inventory schema from the overlap and fill the gaps from usage data.
| Question | OpenAI (project API key object) | Anthropic (API key object) |
|---|---|---|
| Container | Project (listing is per project) | scope: workspace with workspace_id, or organization for principal-bound keys |
| Owner | owner: user (with email and project role) or service_account | principal (user_actor or service_account_actor) and created_by |
| Does the owner still have access | owner_project_access: active or inactive | Not a field; compare principal with current members |
| Expiry | expires_at (Unix seconds or null) | expires_at (RFC 3339 or null) |
| Last used | last_used_at | Not returned; use the usage report grouped by api_key_id |
| Identifying the secret | redacted_value | partial_key_hint, for example sk-ant-api03-R2D...igAA |
| Status | Listed keys are enabled; expired keys cannot be updated | active, inactive, archived, expired |
Credentials for the audit. OpenAI Admin API keys are created at platform.openai.com/settings/organization/admin-keys and cannot call non-administration endpoints. Anthropic Admin API keys (sk-ant-admin01-) can only be provisioned by members with the admin role, in the Console; the Admin API is not available for individual accounts, and workspace-scoped keys do not work for it. An admin key is the most powerful credential in the organisation, so create a dedicated one for the audit, keep it in a secret manager, give it an expiry and revoke it afterwards if your process allows. Export results to a restricted location: the inventory is a map of credentials.
Normalise before you compare. OpenAI returns timestamps as Unix seconds and Anthropic as RFC 3339 strings, so convert both to one format. Give each row a provider, organisation, container, key ID, owner type, owner identifier, created, expires, last used and status column. Agree the dormancy threshold (90 days is a common starting point) and the wait period between disabling and deleting (two to four weeks catches monthly and quarterly jobs) before the first run, so findings are judged against a rule rather than argued case by case.
Step-by-step
Steps 1 to 5 are read-only. Steps 6 and 7 change keys.
- Inventory the admin keys first. They outrank every key you are about to review. On OpenAI:
Each admin key returnscurl "https://api.openai.com/v1/organization/admin_api_keys?limit=100" \ -H "Authorization: Bearer $OPENAI_ADMIN_KEY"redacted_value,created_at,expires_at,last_used_atand its owning user. On Anthropic, review the Admin keys list in the Console. Any admin key with no expiry, no recent use or a departed owner is the first finding. - List every container. On OpenAI, list projects including archived ones, because archived projects are where forgotten keys hide:
On Anthropic, list workspaces throughcurl "https://api.openai.com/v1/organization/projects?limit=100&include_archived=true" \ -H "Authorization: Bearer $OPENAI_ADMIN_KEY"/v1/organizations/workspacesand passinclude_default=true, because the Default workspace is otherwise left out of the listing. - List every key. On OpenAI, loop over projects and request all enabled keys, paging with
after:
Repeat withcurl "https://api.openai.com/v1/organization/projects/<project_id>/api_keys?limit=100&owner_project_access=any" \ -H "Authorization: Bearer $OPENAI_ADMIN_KEY"owner_project_access=inactiveto tag keys whose owner has lost project access. Also list each project's service accounts (/v1/organization/projects/<project_id>/service_accounts) so keys can be tied to a named workload. On Anthropic, one call covers the organisation, paging withafter_iduntilhas_moreis false:
Run it again withcurl "https://api.anthropic.com/v1/organizations/api_keys?limit=1000&status=active" \ -H "x-api-key: $ANTHROPIC_ADMIN_API_KEY" \ -H "anthropic-version: 2026-10-21"status=inactiveto see keys that were disabled but never archived. Note that filtering byworkspace_idnever returns organisation-scoped keys, so do not build the inventory workspace by workspace. - Add usage. For OpenAI,
last_used_atis on the key; confirm volume with the usage endpoints (for example/v1/organization/usage/completions), which filter byapi_key_idsandproject_idsand group into1m,1hor1dbuckets. For Anthropic, call the usage report and group by key:
Daily buckets allow up to 31 per request, so page through longer periods withcurl "https://api.anthropic.com/v1/organizations/usage_report/messages?starting_at=2026-10-01T00:00:00Z&ending_at=2026-11-01T00:00:00Z&bucket_width=1d&group_by[]=api_key_id" \ -H "x-api-key: $ANTHROPIC_ADMIN_API_KEY" \ -H "anthropic-version: 2026-10-21"next_page. A key that never appears in 90 days of usage is unused. Console playground usage has a nullapi_key_idand will not be attributed to any key. Anthropic's newer Usage and Cost Analytics API is recommended for new integrations; the legacy report above is still documented. - Classify each key. Apply the checks in the table below and record an owner for every key you keep.
Check How to detect Typical action Owner has left or lost access OpenAI owner_project_access=inactive; Anthropic principal not in current membersReplace with a service account key, then disable No expiry expires_atis nullSet an expiry (OpenAI) or schedule replacement with one Unused No usage for 90 days, or last_used_atolder than thresholdDisable, wait, then delete or archive Personal key in production User-owned key with steady machine-like usage Move to a service account key; OpenAI intends user keys for local development Over-scoped OpenAI key with unrestricted scopes used only for reads Restrict scopes, for example ["api.all.read"]for read-onlyWrong container Anthropic key in the Default workspace; several apps sharing one project or workspace Reissue in a dedicated workspace or project with its own spend limit Legacy or unattributed Anthropic created_byis null (legacy, federated or system-created keys)Confirm origin before acting - Contain before you delete. On Anthropic, disable a key:
The same endpoint acceptscurl -X POST "https://api.anthropic.com/v1/organizations/api_keys/<api_key_id>" \ -H "x-api-key: $ANTHROPIC_ADMIN_API_KEY" \ -H "anthropic-version: 2026-10-21" \ -H "Content-Type: application/json" \ -d '{"status": "inactive"}'activeandarchived. On OpenAI, a project key can be updated withPOST /v1/organization/projects/<project_id>/api_keys/<api_key_id>and a body containingexpires_in_seconds(1 to 31,536,000) orscopes; a short expiry or read-only scope is a staged alternative to immediate deletion. Expired OpenAI keys cannot be updated, so do not use a very short expiry on a key you may need back. - Delete or archive after the wait period. On OpenAI,
DELETE /v1/organization/projects/<project_id>/api_keys/<api_key_id>removes the key; deleting a service-account key does not delete the service account or its other keys. On Anthropic, archive keys you no longer need. Archiving a whole workspace archives every key created for it and cannot be undone.
Verify it worked
- Re-run the listings and confirm disabled or deleted keys are gone from the active set and the number of keys with null
expires_athas fallen. - Confirm usage stopped for each contained key in the next usage report.
- Read the audit trail. OpenAI's audit log endpoint (
/v1/organization/audit_logs) filters byevent_types[];api_key.created,api_key.updatedandapi_key.deletedshow who changed which key, andactor_ids[]orproject_ids[]narrow the view. If it returns nothing, confirm audit logging is enabled for the organisation. The Anthropic pages read for this guide do not describe a key audit log endpoint, so keep your own record of changes made during the audit. - Check nothing broke. Watch application error rates for 401 responses during the wait period. See the LLM API 401, 403 and 429 Errors Guide.
Rollback and common errors
| Problem | Cause | Fix |
|---|---|---|
| Inventory smaller than expected | OpenAI listing called without owner_project_access=any; archived projects skipped | Re-run with any and include_archived=true |
| Anthropic keys missing | Built per workspace; organisation-scoped keys never match a workspace_id filter | List once without a workspace filter |
| Admin API returns 401 or 403 | Workspace-scoped key used, or a non-admin OpenAI key | Use an organisation admin credential |
| Application fails after disabling a key | Key was in use despite low usage | Set the Anthropic key back to active, or issue a new OpenAI key; then replace properly |
| Usage attributed to no key | Console playground traffic | Expected; review Console users separately |
| Admin API rate limited | Too many management requests in a loop | Back off; OpenAI returns a too-many-requests error for management calls |
Hardening afterwards
- Prefer service accounts and federation. OpenAI recommends service account keys for deployed applications, scheduled jobs and CI. Anthropic supports service accounts and workload identity federation through its Admin API, so some workloads need no static key at all.
- Set expiry by policy and alert on new keys created without one.
- Stream audit events from OpenAI into your SIEM and alert on
api_key.createdoutside change windows. - Give every key a container and a cap, so the next leak is bounded.
- Scan for the keys you just inventoried. Use the
partial_key_hintandredacted_valuefields to match leaked values found by How to find LLM API keys in code and CI.
Where identity fits
Model provider keys are non-human identities with an owner, a purpose and a lifecycle, and the audit above is the provider-specific part of a wider NHI inventory. Join each key to your identity provider's leaver records and to the owning application in your CMDB; a key without both is an orphan. See How to assign owners to orphaned service accounts.
Target state by key type
Use the audit to move each key towards a clear end state rather than only removing bad ones:
- Admin keys: as few as possible, each named for a single automation or audit job, held in a secret manager, with an expiry and an owner who is still an organisation admin. No admin key on a laptop.
- Production workloads: one service account per application in its own OpenAI project or Anthropic workspace, a key with an expiry no longer than your rotation policy, scopes restricted to what the workload calls, and a spend limit on the container. Where the platform supports federation, no static key.
- Developer keys: user-owned, short-lived, in a sandbox project or workspace with a low cap, removed automatically when the developer leaves the project.
- Third-party tools and gateways: one key per vendor in a dedicated container, recorded against the vendor contract, so revocation is a single action. Router and aggregator platforms that hold your key are covered in the Model Aggregator and LLM Router Key Security guide.
Record the end state as policy so the next audit measures drift from it, not from whatever the previous audit happened to find.
Small team or large organisation
Small teams can run the steps by hand once a quarter with one script and a spreadsheet. Large organisations should run the inventory daily, store it as data, raise tickets automatically for each failed check and include provider keys in the same certification campaigns as cloud service principals. Groups that hold several OpenAI organisations or Anthropic organisations need one admin credential per organisation and should audit each.
Metrics
- Keys without an owner (departed or unattributed). Target zero.
- Keys without expiry as a percentage of active keys.
- Unused keys older than 90 days still active.
- Personal keys carrying production traffic.
- Admin keys in total, and those without expiry.
Framework mapping
| Framework | Reference | How this runbook applies |
|---|---|---|
| NIST SP 800-53 Rev 5 | AC-2 Account Management; AC-2(3) Disable Accounts; IA-5 Authenticator Management | Inventory, owner review, disabling unused keys and enforcing expiry |
| NIST SP 800-53 Rev 5 | AU-6 Audit Record Review, Analysis, and Reporting | Reviewing API key events in audit logs |
| NIST CSF 2.0 | PR.AA-01; ID.AM-08 | Service credentials managed through their life cycle |
| CIS Controls v8.1 | 5.1 Establish and Maintain an Inventory of Accounts; 5.3 Disable Dormant Accounts | The same safeguards applied to provider keys |
| ISO/IEC 27001:2022 Annex A | A.5.16 Identity management; A.5.18 Access rights | Lifecycle and periodic review of non-human access |
| MITRE ATT&CK | T1078.004 Cloud Accounts | Fewer valid, unwatched credentials for an attacker to use |
Practitioner checklist
- Create a dedicated, expiring admin credential for the audit on each provider.
- Inventory admin keys first.
- List OpenAI projects with
include_archived=trueand keys withowner_project_access=any. - List all Anthropic keys without a workspace filter, for every status.
- Add usage per key; derive last use for Anthropic from the usage report.
- Flag departed owners, missing expiry, unused, over-scoped and wrongly placed keys.
- Disable or restrict first, delete or archive after a wait period.
- Verify in usage data and audit logs, then schedule the next review.
Standards and references
- Anthropic: Admin API overview
- Anthropic: List API Keys
- Anthropic: Update API Key
- Anthropic: Usage and Cost API
- OpenAI: Administration API overview
- OpenAI: OpenAPI specification
- OpenAI: API keys guide
- OpenAI: Admin APIs
Related NHI Mgmt Group resources: AI model provider API keys · How to find LLM API keys in code and CI · API Key Management Guide · LLMjacking Guide