> For the complete documentation index, see [llms.txt](https://docs.openg2p.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.openg2p.org/platform/platform-services/consent-management/api.md).

# API Reference

The Consent Manager exposes a versioned REST API. This page defines the conventions every endpoint follows; the endpoint pages document the individual contracts.

| Group                       | Page                                                                                                 | API audience                                                           |
| --------------------------- | ---------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- |
| Verification & enforcement  | [Verification API](/platform/platform-services/consent-management/api/verification-api.md)           | **partner-api** — Registry / PEPs (partner-signed, machine-to-machine) |
| Partner onboarding & policy | [Partner & Policy API](/platform/platform-services/consent-management/api/partner-and-policy-api.md) | **staff-api** — Administrators / controller onboarding                 |
| Consent lifecycle           | [Consent Lifecycle API](/platform/platform-services/consent-management/api/consent-lifecycle-api.md) | **beneficiary-api** — origination clients (scaffolded/later)           |
| Subject rights (GDPR)       | [Subject API](/platform/platform-services/consent-management/api/subject-api.md)                     | **beneficiary-api** — authenticated subjects (scaffolded/later)        |

## Base path & versioning

* Base path: `/consent/v1`
* Well-known: `/.well-known/jwks.json` (CM signing keys, unversioned)
* Breaking changes increment the path version (`/consent/v2`).

## Audiences & deployment

The CM ships as a **single chart** but is deployed once **per API audience** — separate Deployments that share the same code and Postgres, differing only in which router/audience they serve and how they authenticate callers. Authentication therefore differs by audience:

| Audience            | Endpoints                                                    | Auth model                                                                                                                                                                                                                                |
| ------------------- | ------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **staff-api**       | partner & policy, AWE approver proxy, audit `/decisions`     | Keycloak, **staff realm**. Roles `CONSENT_MANAGER_ADMIN` (onboarding/policy) and `CONSENT_MANAGER_APPROVER` (approval decisions), from `realm_access` / `resource_access.*`                                                               |
| **partner-api**     | `/validate`, `/consents/{id}/status`, `/receipts/{id}`, JWKS | **No Keycloak.** Trust is the **partner-signed consent object**, verified against Partner Management (PM) keys and replay-guarded by `jti`. The Registry↔CM link is secured at transport (**Istio mTLS**). This deployment is the **PDP** |
| **beneficiary-api** | `/my/*`, `/consent-requests/*`                               | Keycloak, **beneficiary realm**, scoped to the authenticated subject (scaffolded/later)                                                                                                                                                   |
| any                 | receipts, JWKS                                               | Public read (signatures make them self-verifying)                                                                                                                                                                                         |

On **partner-api** there is no caller token: the consent object's own JWS signature (verified via PM keys) is the sole application-layer proof, with Istio mTLS providing transport authentication between the Registry and CM.

## Conventions

* **Content type:** `application/json`; JSON-LD documents use `application/ld+json`.
* **Timestamps:** RFC 3339 / ISO 8601 UTC.
* **Identifiers:** UUIDs unless an external id (`subject_id`, `kid`, purpose code) is referenced.
* **Idempotency:** re-validating the same consent object (`jti`) returns the same `consent_id` / `receipt_id`.
* **Pagination:** list endpoints accept `page` (≥1) and `size` (1–100) and return `{ items, total, page, size, pages }`.

## Decision & error model

The verification endpoint returns a **decision** object (HTTP 200 for both permit and deny so the PEP can read the reason). All other endpoints use standard HTTP status codes with a problem body:

```json
{ "error": "scope_exceeds_policy", "detail": "human-readable explanation", "trace_id": "..." }
```

### Shared reason codes

Used in decisions (`reason_code`) and errors (`error`):

| Code                      | Meaning                                                                     |
| ------------------------- | --------------------------------------------------------------------------- |
| `ok`                      | Permit — all checks passed                                                  |
| `malformed_object`        | Consent object failed schema validation                                     |
| `unknown_partner`         | Partner not onboarded / suspended, or `kid` not found in Partner Management |
| `signature_invalid`       | JWS signature did not verify                                                |
| `audience_mismatch`       | `aud` is not this partner / controller                                      |
| `subject_not_allowed`     | Subject missing or `subject_id_type` not permitted                          |
| `purpose_not_allowed`     | Purpose code outside policy                                                 |
| `scope_exceeds_policy`    | Requested scope not permitted; empty effective intersection                 |
| `validity_exceeds_policy` | Requested validity longer than `max_validity_duration`                      |
| `expired`                 | Consent outside its validity window                                         |
| `revoked`                 | Consent has been revoked                                                    |
| `replay`                  | Duplicate `jti` or stale `issued_at`                                        |

## Implementation

The service is built on [`openg2p-fastapi-common`](https://github.com/OpenG2P/openg2p-fastapi-common) with **PostgreSQL** for storage. It is **stateless and horizontally scalable** — scale by adding pods/workers behind a load balancer; the only shared state is Postgres. Consent expiry runs as an external CronJob (`python -m openg2p_consent_manager.expire`) rather than an in-pod scheduler, and the hot path lazily expires on read. Partner keys/policies are cached per pod with a short TTL to keep `/validate` cheap under high request rates.

These pages are the **normative source** for the contract — the API is documented here in GitBook directly (FastAPI also serves a live OpenAPI/Swagger UI at `/docs` for the running service).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.openg2p.org/platform/platform-services/consent-management/api.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
