Summary
Access
EKM endpoints are accessible in the Management API via an Admin API Key. https://platform.openai.com/settings/organization/admin-keys (do not use a normal API key). Admin API keys are available to organization owners.
Use
api.external_keys.writeto create or delete external keys, andapi.external_keys.readto list or validate external keys. A single key needs both scopes only if it must perform both read and write operations.We currently need to feature flag your organization into these endpoints. You know you have the feature flag if you see **external_key_id **returned from the existing List Projects endpoint: https://api.openai.com/v1/organization/projects
Usage
Your EKM config is registered at the organization level via a new endpoint https://api.openai.com/v1/organization/external_keys
Registering your EKM config returns an external_key_id in the form extkey_xxxx
EKM configs are activated at the project level by passing in an external_key_id in the body of the existing Create Project https://api.openai.com/v1/organization/projects endpoint
Restrictions
You must first test EKM on a new project via the Management API.
We recommend spinning up new projects for your EKM workloads. However, if you want EKM on an existing project, we can add you to the feature flag. Please note the following best practices before you roll out EKM to your existing production projects.
Test all API features that you use in production in your test EKM API project first
Apply a gradual rollout instead of populating EKM on all production API projects at once
Organization-level endpoints
Register an external key on your organization
AWS
Sample Request
type: string - always “aws”
name: string - A friendly name for your config
role_arn: string - The Role ARN that OpenAI will assume in your cloud
kms_arn: string - The Key Management System ARN for the master key you manage
external_id: string - Your organization id or API project id
curl -X POST \
-H "Content-type: application/json" \
-H "Authorization: Bearer $TOKEN" \
"https://api.openai.com/v1/organization/external_keys" \
-d '{
"type": "aws",
"name": "AWS EKM Config",
"role_arn": "arn:aws:iam::<12_DIGIT_ACCOUNT_NUMBER>:role/<ROLE>",
"kms_arn": "arn:aws:kms:<REGION>:<ACCOUNT_NUMBER>:key/<UUID>",
"external_id": <your org id or project id>
}'Sample Response
{
"id": "extkey_xxxx",
"object": "organization.external_key",
"created_at": 1746175499,
"api_project_ids": [],
"type": "aws",
"name": "AWS EKM Config",
"role_arn": "arn:aws:iam::<ACCOUNT_NUMBER>:role/<ROLE>",
"kms_arn": "arn:aws:kms:<REGION>:<ACCOUNT_NUMBER>:key/<UUID>",
"external_id": <your org id or project id>
} GCP
Sample Request
type: string - always "gcp",
name: string - A friendly name for your config
workload_identity_project_number: string - The 12-digit GCP project number where you registered OpenAI's workload identity
workload_identity_pool_id: string - The pool containing the Workload Identity provider that you registered for OpenAI
workload_identity_provider_id: string - The Workload Identity provider that you registered for OpenAI
audience: string - The audience that OpenAI should pass in the token when we assume a role through your GCP STS
kms_project_id: string - The name of the GCP project where your KMS lives
kms_key_ring_name: string - The Key Management System key ring containing the master key you manage
kms_key_name: string - The name of the Key Management System master key
kms_key_location: string - The region where your Key Management System master key is located
If your KMS lives in a different GCP project from the one where you registered OpenAI's Workload Identity, make sure that the project containing OpenAI's Workload Identity at least has KMS enabled by going to https://console.developers.google.com/apis/api/cloudkms.googleapis.com/overview
curl -X POST \
-H "Content-type: application/json" \
-H "Authorization: Bearer $TOKEN" \
"https://api.openai.com/v1/organization/external_keys" \
-d '{
"type": "gcp",
"name": "GCP EKM Config",
"workload_identity_project_number": "123456789012",
"workload_identity_pool_id": "openai-azure",
"workload_identity_provider_id": "openai-ekm-service-role",
"audience": <your org id or project id>,
"kms_project_id": "adjective-noun-12345",
"kms_key_name": "openai-kms-key",
"kms_key_ring_name": "openai-kms-key-ring",
"kms_key_location": "us-east1"
}'Sample Response
{
"id": "extkey_xxxxxx",
"object": "organization.external_key",
"created_at": 1746174349,
"api_project_ids": [],
"type": "gcp",
"name": "GCP EKM Config",
"workload_identity_project_number": "123456789012",
"kms_key_ring_name": "openai-kms-key-ring",
"kms_key_name": "openai-kms-key",
"kms_key_location": "us-east1",
"audience": <your org id or project id>,
"kms_project_id": "adjective-noun-12345",
"workload_identity_pool_id": "openai-azure",
"workload_identity_provider_id": "openai-ekm-service-role"
}Azure
Sample Request
type: string - always "azure",
name: string - A friendly name for your config
tenant_id: string - Your Azure tenant UUID
vault_uri: string - The URI of the Azure vault containing the master key you manage
key_name: string - The name of the Azure Key Vault master key that you manage.
It must have the form <org-xxx>--<any_name>
where org-xxx is your OpenAI organization ID that you can find at https://platform.openai.com/settings/organization/general
curl -X POST \
-H "Content-type: application/json" \
-H "Authorization: Bearer $TOKEN" \
"https://api.openai.com/v1/organization/external_keys" \
-d '{
"type": "azure",
"name": "Azure EKM Config",
"tenant_id": "<UUID>",
"vault_uri": "https://<VAULT_NAME>.vault.azure.net/",
"key_name": "org-xxx--some-key"
}'Sample Response
{
"id": "extkey_xxxx",
"object": "organization.external_key",
"created_at": 1746174377,
"api_project_ids": [],
"type": "azure",
"name": "Azure EKM Config",
"tenant_id": "<UUID>",
"vault_uri": "https://<VAULT_NAME>.vault.azure.net/",
"key_name": "org-xxx--some-key"
}Delete an external key registered on your organization
Note: You can only delete an external key if it is not associated with any active API projects or workspace. If it is associated with an active API project, archive that project first. If it is associated with a workspace, the key cannot be deleted.
Sample Request
curl -X DELETE \
-H "Authorization: Bearer $TOKEN" \
"https://api.openai.com/v1/organization/external_keys/extkey_xxxx"Sample Response
{
"id": "extkey_xxxxx",
"object": "organization.external_key.deleted",
"created_at": 1746127808,
"api_project_ids": [],
"type": "aws",
"account_number": "123456789012",
"kms_arn": "arn:aws:kms:<REGION>:<ACCOUNT_NUMBER>:key/<UUID>",
"name": "AWS EKM Config",
"role_arn": "arn:aws:iam::<ACCOUNT_NUMBER>:role/<ROLE>"
}Get the external keys registered on your organization
Sample Request
curl -X GET \
-H "Authorization: Bearer $TOKEN" \
"https://api.openai.com/v1/organization/external_keys"Sample Response
{
"object": "list",
"data": [
{
"id": "extkey_xxxx",
"object": "organization.external_key",
"created_at": 1746127808,
"api_project_ids": [],
"type": "aws",
"name": "AWS EKM Config",
"account_number": "123456789012",
"kms_arn": "arn:aws:kms:<REGION>:<ACCOUNT_NUMBER>:key/<UUID>",
role_arn": "arn:aws:iam::<ACCOUNT_NUMBER>:role/<ROLE>"
}
],
"first_id": "extkey_xxxx",
"has_more": false,
"last_id": "extkey_xxxx"
}Validate an external key
You can use this endpoint to check several things
Your external cloud configuration remains valid with OpenAI after you have made changes (you'll see a success response)
Your key revocation is done correctly, is being processed by OpenAI, and will take effect after the 1 hour cache TTLs have expired (you'll see an error response)
Sample Request
curl -X POST -H "Authorization: Bearer $TOKEN"
"https://api.openai.com/v1/organization/external_keys/extkey_xxx/validate"Sample Response
{
"status": "success"
}Or, an error surfaced from the cloud provider.
Project-level endpoints
Create a new project with an external key ID
This is the same as the existing Create Project endpoint, with the addition of the external_key_id parameter in the request and response.
Sample Request
curl -X POST \
-H "Content-type: application/json" \
-H "Authorization: Bearer $TOKEN" \
"https://api.openai.com/v1/organization/projects" \
-d '{
"name": "Some Project",
"external_key_id": "extkey_xxxx"
}'Sample Response
{
"object": "project",
"id": "proj_xxxxx",
"title": "Some Project",
"external_key_id": "extkey_xxxxx",
"created": 1740012721,
"organization_id": "org-xxxxx",
"is_initial": false,
"geography": null,
"scale_tier_enabled": false,
"disable_user_api_keys": false,
"zdr_type": null,
}[Restricted] Update an existing project with an external key ID
This is the same as the existing Update Project endpoint, with the addition of the external_key_id parameter in the request and response.
We recommend spinning up new API projects for your EKM workloads. If you want EKM on all your existing API projects, ask your account director and we will add you to the feature flag. Please note the following best practices before you roll out EKM to your existing production projects.
Test all API features that you use in production in your test EKM API project first
Apply a gradual rollout instead of populating EKM on all production API projects at once
Sample Request
curl -X POST \
-H "Content-type: application/json" \
-H "Authorization: Bearer $TOKEN" \
"https://api.openai.com/v1/organization/projects/proj_xxx" \
-d '{
"external_key_id": "extkey_xxxx"
}'List all the projects on your organization
This is the same as the existing endpoint but with the addition of external_key_id in the API response
Sample Request
curl -X GET \
-H "Authorization: Bearer $TOKEN" \
"https://api.openai.com/v1/organization/projects"Sample Response
{
"object": "list",
"data": [
{
"object": "organization.project",
"id": "proj_xxxx",
"name": "Project Name",
"external_key_id": "extkey_xxxx",
"created_at": 1717798982,
"archived_at": null,
"status": "active"
}
],
"first_id": "proj_xxxx",
"last_id": "proj_xxxx",
"has_more": true
}