Skip to main content

Provider Credentials

Quick example​

# Vault an OpenAI key
curl "$TRINITITE_BASE/v1/provider-credentials" \
-H "Authorization: Bearer $TRINITITE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"provider": "openai",
"name": "openai-prod",
"secret": "sk-prod-XXX",
"model_allowlist": ["gpt-4o", "gpt-4o-mini"]
}'

The raw secret is returned only once at creation. After that, only the redacted ID is accessible.


Overview​

Provider Credentials store upstream LLM API keys (OpenAI, Anthropic, Azure OpenAI, custom) encrypted at rest. They're referenced from proxy calls via the X-Trinitite-Credential-Id header — your applications never handle raw provider keys.

Authentication: Authorization: Bearer <session_token | api_key> with the relevant provider_credentials:* permission.


Endpoints​

MethodPathPermission
GET/v1/proxy/credentialsprovider_credentials:read
POST/v1/proxy/credentialsprovider_credentials:create
GET/v1/proxy/credentials/{id}provider_credentials:read
PATCH/v1/proxy/credentials/{id}provider_credentials:create
DELETE/v1/proxy/credentials/{id}provider_credentials:delete

Org-wide spend caps and rate limits per credential — see Governance Controls.


Credential object​

{
"credential_id": "cred_01JF8RCRD1A2B3C4D5E6F7G8H9I",
"provider": "openai",
"label": "production-openai-primary",
"key_prefix": "sk-proj-...",
"key_suffix": "...d8f9",
"base_url": null,
"allowed_models": ["gpt-4o", "gpt-4o-mini", "o3-mini"],
"status": "active",
"created_at": "2026-04-01T00:00:00Z",
"last_used_at": "2026-05-01T15:42:00Z",
"monthly_spend_cap_usd": "5000.00",
"rpm_limit": 600,
"disabled": false
}
FieldDescription
credential_idStable ID (cred_*). Used in X-Trinitite-Credential-Id
provideropenai, anthropic, azure_openai, custom
labelHuman-readable label
key_prefix / key_suffixTruncated bookends for identification — the raw key is never returned after creation
base_urlOverride base URL (for Azure deployments or self-hosted custom endpoints)
allowed_modelsIf set, only these model names are permitted via this credential
monthly_spend_cap_usdDecimal string (USD); null means unbounded
rpm_limitPer-credential requests-per-minute cap

POST /v1/proxy/credentials​

Store a new credential.

{
"provider": "openai",
"label": "production-openai-primary",
"plaintext_key": "sk-proj-4f8d9e2a1c6b7f3a9e1d2c4b5a6f7e8d",
"allowed_models": ["gpt-4o", "gpt-4o-mini", "o3-mini"]
}
FieldTypeRequiredDescription
providerenumYesopenai, anthropic, azure_openai, custom
labelstringYes1–100 chars; unique within your org
plaintext_keystringYesRaw API key. Encrypted before storage; not returned on subsequent reads
base_urlstringNoOverride base URL — required for azure_openai and custom
allowed_modelsstring[]NoIf set, only listed models are permitted

Response — 201 Created returns the credential object including plaintext_key once. Store it in your secrets manager — subsequent reads redact it.


GET /v1/proxy/credentials​

Returns the redacted list (no plaintext_key).

QueryTypeDescription
providerstringFilter by provider
statusstringactive or revoked
limit / cursor—Cursor pagination
{
"data": [
{ "credential_id": "cred_01JF...", "provider": "openai", "label": "production-openai-primary", "status": "active", ... }
],
"page": { "next_cursor": null, "has_more": false }
}

GET /v1/proxy/credentials/{id}​

Returns one credential, redacted.


PATCH /v1/proxy/credentials/{id}​

Partial update. Use plaintext_key to rotate the underlying provider key — the old key is destroyed atomically and in-flight calls switch over with no application changes.

{
"label": "production-openai-primary-rotated-2026-05",
"plaintext_key": "sk-proj-NEWKEYHERE",
"allowed_models": ["gpt-4o", "gpt-4o-mini", "o3-mini", "gpt-5"]
}
FieldDescription
labelNew label
plaintext_keyNew key (rotation). Returned once in the response
base_urlNew base URL
allowed_modelsReplace allowlist

DELETE /v1/proxy/credentials/{id}​

Revoke. In-flight proxy calls using the credential start failing with 404 credential_not_found. Returns 204 No Content.


Errors​

HTTPerror.codeCause
400validation_errorMissing required field; invalid provider; base_url required for custom
401unauthenticatedMissing or invalid credential
403forbiddenCaller lacks the required scope
404not_found / credential_not_foundCredential does not exist or is revoked
409conflictA credential with the same label already exists

Best practices​

  • Rotate quarterly. Use PATCH with plaintext_key — clients pick up the new key on the next request without redeploys.
  • Scope by environment. Issue separate credentials for dev, staging, production. Combine with API key environment scoping for blast-radius isolation.
  • Lock down allowed_models. Restricting a credential to known-good models prevents accidental usage of expensive or unapproved tiers.
  • Cap spend. monthly_spend_cap_usd is a hard limit — Trinitite trips the credential into a soft-fail state once tripped (see Governance Controls).

Next steps​