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
}