Credential Vending Endpoints
Request field-level credentials from connected services on behalf of an active agent session.
Request Credentials
POST /api/v1/agent/sessions/{id}/credentials
Vend one or more credential fields from a registered service. If an approval policy is attached to the service or the requested fields, Bulwark initiates a CIBA out-of-band approval and returns 202 with a poll URL.
Headers
| Header | Required | Description |
|--------|----------|-------------|
| Authorization | Yes | Bearer <agentApiKey> |
| X-Bulwark-Token | Yes | Biscuit token issued for this session |
| X-Bulwark-Tenant | Yes | Tenant ID |
Path Parameters
| Parameter | Description |
|-----------|-------------|
| id | Active agent session ID (sess_01j...) |
Body
{
"service_name": "stripe",
"fields": ["secret_key", "webhook_secret"],
"approval_id": "auth_req_01j..."
}
| Field | Required | Description |
|-------|----------|-------------|
| service_name | Yes | Name of the registered service (e.g. stripe, github, sendgrid) |
| fields | Yes | Array of credential field names to vend |
| approval_id | No | CIBA approval ID to complete a previously initiated approval flow |
Response 200 — Credentials Granted
{
"data": {
"grant_id": "grant_01j...",
"service_name": "stripe",
"credential_type": "api_key",
"fields": {
"secret_key": "sk_live_...",
"webhook_secret": "whsec_..."
},
"expires_at": "2026-03-30T14:00:00Z",
"session_id": "sess_01j...",
"granted_at": "2026-03-30T13:00:00Z"
}
}
Fields contain the decrypted credential values. Every grant is logged to the audit trail and associated with the session.
Response 202 — Approval Required (CIBA)
Returned when the requested service or fields are governed by an approval policy and no approval_id was supplied (or the supplied ID is not yet resolved).
{
"data": {
"approval_required": true,
"approval_id": "auth_req_01j...",
"poll_url": "/api/v1/ciba/token/auth_req_01j...",
"expires_in": 300,
"interval": 5,
"binding_message": "Agent my-assistant is requesting your Stripe secret key."
}
}
The agent should poll poll_url at the indicated interval (seconds). Once the user approves, re-submit this endpoint with the approval_id to receive the 200 grant.
Response 403 — Scope Denied
{
"error": {
"code": "CREDENTIAL_SCOPE_DENIED",
"message": "The Biscuit token does not grant access to field 'secret_key' on service 'stripe'."
}
}
Response 404 — Session or Service Not Found
{
"error": {
"code": "NOT_FOUND",
"message": "Session not found or service 'stripe' is not registered for this tenant."
}
}
Grant Reuse
Within a single session, Bulwark caches credential grants keyed on (session_id, service_name, fields[]). Subsequent requests for the same fields return the existing grant until it expires, avoiding redundant approval flows.
To force a fresh grant, include "force_refresh": true in the request body.
{
"service_name": "stripe",
"fields": ["secret_key"],
"force_refresh": true
}