Enter or rotate the Organization's credential for a Provider
PUT /v1/provider-credentials/{provider}
| Property | Value |
|---|---|
| Operation | put_provider_credential |
| Group | Providers and credentials |
| Scope | credentials:write |
| Route class | control |
| Idempotency | No Idempotency-Key |
| Audit | Audited provider_credential.put (mutation) |
| Released in | 1.28.0 |
| Phase 0 host | Served (the hosted api pins 1.65.0) |
Checks the key with the vendor where the vendor offers a cheap read, then seals it as the Provider's next version for the caller's Organization and revokes the active one (1.28.0). From then on every chain entry of the Organization's Calls that names the Provider runs on this key; running Calls keep the version they were issued. A Provider whose descriptors do not list byok is refused with validation_failed and the issue credential_mode_unavailable; a key the vendor refuses, with validation_failed and the issue credential_invalid; a vendor that does not answer, with dependency_unavailable; in each case nothing is stored. The request body is never logged, never stored in clear and never returned; the response and the Audit event name the Provider, the version and the verification outcome, never the secret or the hint. Session only: the api refuses the route to every API key, whatever its scopes, and accepts a Member ID token with credentials:write.
Request
Set VOCAL_API to the base URL of your API and VOCAL_API_KEY to an API key with the credentials:write scope (Authentication and keys). Replace each placeholder, such as agt_... or <name>, with your own value.
curl -X PUT "$VOCAL_API/v1/provider-credentials/mock" \
-H "Authorization: Bearer $VOCAL_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "secret": "<secret>" }'const response = await fetch(`${process.env.VOCAL_API}/v1/provider-credentials/mock`, {
method: 'PUT',
headers: {
Authorization: `Bearer ${process.env.VOCAL_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"secret": "<secret>"
}),
});
console.log(response.status, await response.text());import os
import requests
response = requests.put(
f"{os.environ['VOCAL_API']}/v1/provider-credentials/mock",
headers={
"Authorization": f"Bearer {os.environ['VOCAL_API_KEY']}",
},
json={
"secret": "<secret>",
},
)
print(response.status_code, response.text)Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
provider | path | ProviderId | yes | A Provider: a vendor or in-process model behind a stage. The provider catalog says which stages each serves and whether it is available. From 1.38.0 openai is deprecated (workspace ADR 0085): its descriptors read deprecated, a deprecated Provider still resolves, and the id is kept until a major release; deepseek is new. From 1.53.0 amazon_titan serves embeddings, reserved until its adapter is built. |
Request body
Content type application/json, required: ProviderCredentialPutRequest.
| Field | Type | Required | Description |
|---|---|---|---|
label | string | no | A note on the key. |
secret | string (password) | yes | The vendor key, sent once. The api seals it, never logs it and never returns it. |
Responses
| Status | Content type | Shape | Error codes |
|---|---|---|---|
200 | application/json | ProviderCredential | |
400 | application/json | ErrorEnvelope | invalid_request |
401 | application/json | ErrorEnvelope | unauthenticated |
403 | application/json | ErrorEnvelope | forbidden, org_suspended |
422 | application/json | ErrorEnvelope | validation_failed |
429 | application/json | ErrorEnvelope | rate_limited |
500 | application/json | ErrorEnvelope | internal_error |
503 | application/json | ErrorEnvelope | dependency_unavailable |
Fields of the 200 answer
The shape is ProviderCredential.
| Field | Type | Required | Description |
|---|---|---|---|
account | VendorAccountUsage | no | The last reading the api took of the vendor account behind the key (1.40.0): its status, the units used and allowed and the plan's tier. Absent when the api has taken none, when the vendor has no account request, or from an api older than 1.40.0. A key that passed can still read exhausted. |
created_at | Timestamp | yes | |
created_by | ActorRef | yes | |
hint | string | yes | The last four characters of the secret, to tell keys apart; never more. |
id | ProviderCredentialId | yes | The credential id, the key id the Session configuration and the trace name for a stage on this key. |
label | string or null | yes | A note of the Member who entered the key, or null. |
object | "provider_credential" | yes | |
provider | ProviderId | yes | |
revoked_at | Timestamp or null | yes | Null while the version is active. |
status | ProviderCredentialStatus | yes | |
verification | ProviderCredentialVerification | yes | |
verified_at | Timestamp or null | yes | When the vendor answered the check; null when the check is not_offered. |
version | integer | yes | Counts the Organization's entries for the Provider from 1. |