BBramaDocs
Browse documentation

List, donate, and retire subscriptions

Goal: operate the agent-scoped subscription lifecycle without exposing provider credentials.

Status: written against the 0.1.0 contract and not re-verified against the newest published release.

Risk: listing is authenticated read-only; donation and retirement are security mutations. Donation may involve provider OAuth outside Brama. Explicit owner approval is required for every mutation.

Environment: approved HTTPS or authenticated loopback.

Preconditions: dedicated bearer, matching AGENT_ID, current HMAC signature over exact body bytes, Skarbiec capability broker, and owner authorization. Use the signing procedure in ../core/call-agent-selectors.md; GET and DELETE-without-body use an empty body hash.

Inputs: donation provider/label plus a provider credential read from an owner-only capability file; retirement body names the exact subscription. The current donation API necessarily carries the credential in the body over HTTPS, so the temporary body must be owner-only, short-lived, and never committed or logged.

Artifacts and side effects: donation creates/updates vault-owned capability state; retirement appends a non-secret local marker and prevents future dispatch. Mutation audit evidence is retained by owning systems.

List owned subscriptions

curl --fail --silent --show-error \
  -H "Authorization: Bearer $BRAMA_BEARER" \
  -H "x-agent-id: $AGENT_ID" \
  -H "x-agent-timestamp: $AGENT_TIMESTAMP" \
  -H "x-agent-signature: $AGENT_SIGNATURE" \
  "$BRAMA_URL/v1/subscription-pool"

Expected result is metadata for that exact agent only; credential bytes never appear.

After explicit owner approval, materialize the provider credential through its approved consumer at PROVIDER_CREDENTIAL_FILE, then create an owner-only exact body without placing the credential in shell history:

umask 077
python3 - "$PROVIDER_CREDENTIAL_FILE" >donation.json <<'PY'
import json, pathlib, sys
credential = pathlib.Path(sys.argv[1]).read_text()
json.dump({"provider":"claude_code","label":"approved-delegation","api_key":credential}, sys.stdout, separators=(",", ":"))
PY

Sign the exact donation.json bytes using the procedure in ../core/call-agent-selectors.md, then send:

curl --fail --silent --show-error \
  -X POST \
  -H "Authorization: Bearer $BRAMA_BEARER" \
  -H "x-agent-id: $AGENT_ID" \
  -H "x-agent-timestamp: $AGENT_TIMESTAMP" \
  -H "x-agent-signature: $AGENT_SIGNATURE" \
  -H 'Content-Type: application/json' \
  --data-binary @donation.json \
  "$BRAMA_URL/v1/subscription-pool"

Success is endpoint JSON identifying metadata/state, not a returned secret.

Retire exact delegated access

After explicit owner approval, place only the exact subscription identity in retire.json, sign it, then:

curl --fail --silent --show-error \
  -X DELETE \
  -H "Authorization: Bearer $BRAMA_BEARER" \
  -H "x-agent-id: $AGENT_ID" \
  -H "x-agent-timestamp: $AGENT_TIMESTAMP" \
  -H "x-agent-signature: $AGENT_SIGNATURE" \
  -H 'Content-Type: application/json' \
  --data-binary @retire.json \
  "$BRAMA_URL/v1/subscription-pool"

Failure and recovery

401 means signature/bearer repair; 403 means identity ownership mismatch; 404 means the exact item is not visible; 409 conflict means lifecycle state prevents the mutation. Do not retry mutation blindly. Re-list metadata, reconcile owner intent, and issue a newly signed exact request. Brama retirement is not vault deletion; restore/re-donate only through the owning lifecycle.

Cleanup

Delete owner-only request files immediately, unset process-local values, and revoke any temporary credential-file grant. Never delete a capability item merely to make an example appear clean.

Next

For bounded evidence refresh, see collect-task-quality.md.