Skip to main content

Privacy Budget

The Privacy Budget API tracks the org's cumulative differential-privacy spend across federated learning rounds and DP-noised aggregate queries. Differential privacy is a mathematical accounting system — every query that emits noise consumes a budget, and once the budget is exhausted no further DP queries can run until the window resets. This resource is the operator's view onto the accounting and the configuration surface for setting per-org caps. Tested against API version v1. Mounted at /api/v1/privacy-budget. JWT auth on every endpoint; plan-gated by privacyBudget (Enterprise+).

This resource is the transparency layer for the federated work; the actual epsilon-spend events come from the Federated Learning API. A regulator auditing a federated consortium reads here to confirm no participant exceeded their declared budget.

The DP-budget model

Differential privacy bounds the maximum amount of information any single query can leak about an individual record. The two parameters that bound it are:

  • ε (epsilon) — the privacy loss; lower means stronger privacy. Composes additively across queries.
  • δ (delta) — the probability the bound fails; must remain << 1/n for n records in the dataset.

Each DP-noised query — a federated round contribution, an aggregate dashboard metric — consumes some ε and δ. When cumulative spend reaches the cap, the budget status flips to exhausted and the participating services (Federated Learning, aggregate dashboards, decision-mining) refuse new DP queries until windowResetsAt.

Endpoints

GET    /api/v1/privacy-budget
PATCH /api/v1/privacy-budget/caps

Get budget status

GET /api/v1/privacy-budget

Returns the org's current privacy-budget state. Lazy-creates a default budget on first call (epsilonCap 10.0, deltaCap 1e-4, 30-day window) so the dashboard's first-load pattern works without a bootstrap call.

curl
curl https://api.adjudon.com/api/v1/privacy-budget \
-H "Authorization: Bearer $ADJUDON_JWT"

Response (200 OK):

{
"success": true,
"data": {
"organizationId": "65a8b2c1...",
"epsilonCap": 10.0,
"epsilonSpent": 4.32,
"deltaCap": 0.0001,
"deltaSpent": 0.000018,
"windowDurationMs": 2592000000,
"windowStartedAt": "2026-04-15T00:00:00.000Z",
"windowResetsAt": "2026-05-15T00:00:00.000Z",
"spendByPurpose": {
"federated-fraud-q2-2026": 2.87,
"decision-mining-aggregate": 1.45
},
"status": "active"
}
}
FieldTypeDescription
epsilonCapnumberMax cumulative epsilon allowed in the window; default 10.0
epsilonSpentnumberCumulative epsilon consumed in the current window
deltaCapnumberMax cumulative delta; default 1e-4
deltaSpentnumberCumulative delta consumed
windowDurationMsnumberRolling-window length; default 30 days
windowStartedAtstring (ISO 8601)Window opening timestamp
windowResetsAtstring (ISO 8601)When epsilonSpent and deltaSpent zero out automatically
spendByPurposeobjectPer-purpose epsilon-spend breakdown for transparency (free-text purpose strings, e.g. federated-<round-name>)
statusenumactive, exhausted, paused

status: 'exhausted' is what blocks downstream services; the budget enters this state automatically when epsilonSpent >= epsilonCap or deltaSpent >= deltaCap. Either ceiling triggers the exhaust.

Update the caps

PATCH /api/v1/privacy-budget/caps
Body fieldRequiredDescription
epsilonCapnoNew ε ceiling; must be > 0 and >= epsilonSpent
deltaCapnoNew δ ceiling; must be > 0
windowDurationMsnoNew rolling-window length in milliseconds
curl — tighten the cap mid-window
curl -X PATCH https://api.adjudon.com/api/v1/privacy-budget/caps \
-H "Authorization: Bearer $ADJUDON_JWT" \
-H "Content-Type: application/json" \
-d '{ "epsilonCap": 5.0, "deltaCap": 5e-5 }'

Tightening the cap below epsilonSpent is rejected synchronously — the regulator-readable accounting cannot suddenly show more spent than the cap allowed. Tightening at or above the current spend is permitted and writes a compliance.privacy-budget.updated audit entry. Loosening the cap is permitted but also audit-logged; an auditor reading the audit log can reconstruct every cap change in the attestation history.

Errors: 400 VALIDATION_ERROR (cap below current spend; cap not positive), 401, 403 UPGRADE_REQUIRED (plan), 500.

Window reset semantics

The window is a rolling fixed-length window, not a calendar window. Setting windowDurationMs to 30 days and starting the window on 2026-04-15 means the window resets at 2026-05-15T00:00:00Z; the reset zeros epsilonSpent, deltaSpent, and spendByPurpose, then advances windowStartedAt to the reset moment. The reset runs on demand (next read after windowResetsAt) rather than via a background job, so a budget that is never read after the reset moment stays in its prior state until queried.

Common gotchas

  • Plan-gated. Privacy Budget is Enterprise+. Sandbox / Scale / Governance receive 403 UPGRADE_REQUIRED. Federated Learning is itself Custom-only, so this resource is most load-bearing for Custom-plan customers.
  • Lazy initialisation. First GET creates the default budget; do not pre-create. Treat empty values as legitimate first-load state.
  • Cap downgrade has a floor. PATCHing epsilonCap below epsilonSpent returns 400 VALIDATION_ERROR; the mathematical contract requires the cap to dominate the spend.
  • Reset is read-triggered. No background job rolls the window. A budget that has not been read since windowResetsAt displays the prior window's state until the next call.
  • Idempotency. Idempotency-Key middleware is wired only on POST /traces. PATCH is itself idempotent (re-PATCH with the same body produces the same end state); duplicate caps defended by the same-cap-no-op pattern.
  • No spend-event API today. Individual epsilon-spend events are recorded by the consuming services (Federated Learning, aggregate dashboards) but not surfaced via this resource as a feed. The spendByPurpose aggregate is the current transparency surface; per-event listing is on the roadmap.

See also