# Grant management & lifecycle

> How grants work on openfeed: the durable handle for a consumer share, how to create, amend, query and revoke them, and how to handle grant state in your app.

- Category: guides
- Audience: developers
- Updated: 2026-07-17
- Canonical: https://openfeed.au/resources/grant-management-and-lifecycle

---

## Grants, briefly

A **grant** is the durable authorization artifact that represents what a consumer has shared with
your app. There is exactly **one grant per user per app**. Its permissions evolve over time as the
consumer amends or revokes what they share.

- **Grant** — the artifact. Identified by a `grant_id`. Its content revision (`revision`) bumps
  every time it changes.
- **Consent** — the *event* that mutates a grant (create, amend, revoke). One grant has many
  consent events over its lifetime.

Your app receives the `grant_id` within the token payload response (as a claim) or can be retrieved 
by using a valid access token against the introspection endpoint at `https://auth.openfeed.au/token/introspection`. 
From then on, treat it as a versioned, revocable resource by either reacting dynamically to `403 disclosure_grant_required`
or establishing a poll mechanism to the `GET /v1/app/grants` endpoint.

For the end-to-end auth flow, start with the [quickstart](/resources/quickstart).

## The grant lifecycle

openfeed implements the OIDF **[Grant Management for OAuth 2.0](https://openid.bitbucket.io/fapi/oauth-v2-grant-management.html)** draft, so the terminology and
semantics are portable across other data sharing ecosystems that adopt the same spec.

A grant goes through these transitions:

1. **`create`**: the consumer authorises your app for the first time. A new `grant_id` is minted
   and returned as a claim on your access token.
2. **`replace`**: the consumer can change what they share, making adds or removes, 
   an unlimited number of times. The `grant_id` **stays the same**, the `revision` **bumps**, and the authorised
   account set is replaced atomically. The user may do this directly via the openfeed dashboard or the app may initiate
   by including `grant_management_action=replace` and `grant_id=<current grant id>` in a PAR request.
3. **`revoke`** — the grant is ended. Revocation is one-way; you can't undo it. This can occur either by the user clicking
   *Revoke* within the openfeed dashboard or the app calling `DELETE /v1/app/grants/{grantId}` with an active 
   access token. To resume sharing, the consumer must start a new grant, producing a new `grant_id`.

Revoking a disclosure grant **never** touches the consumer's underlying CDR arrangement with the
data holder — see
[Disclosure consent vs. CDR arrangements](/resources/onward-disclosure-explained).

## Establishing and amending grants

You don't call these actions directly, instead you use your OAuth 2.0 client library to include them in the request object
you submit via Pushed Authorization Request. Since Grant Management is an emerging spec we try to provide some sane defaults for
situations where an implementer doesn't explicitly support the Grant Management specification.

| Situation               | Mandatory PAR Attributes | Recommended PAR Attributes                                |
|-------------------------|--------------------------|-----------------------------------------------------------|
| New grant               | None                     | `grant_management_action=create`                          |
| Amend an existing grant | `grant_id=<existing>`    | `grant_management_action=replace` + `grant_id=<existing>` |

The consumer sees the openfeed disclosure screen and confirms which accounts to share; the
resulting grant reflects exactly what they approved.

## Reading your grants

openfeed exposes grants through a set of API endpoints.

| Endpoint                          | Token | Description                                             |
|-----------------------------------|-------|---------------------------------------------------------|
| `GET /v1/app/grants`              | M2M   | Paginated index of `{id,revision,lastUpdated}` per grant |
| `GET /v1/app/grants/{grantId}`    | Grant | Retrieve detailed grant information                     |
| `DELETE /v1/app/grants/{grantId}` | Grant | Revoke a grant                                          |

## What detailed grant information contains

Detailed grant information includes the following information:

- `bankingAccountIds` / `energyAccountIds`: the account identifiers accessible under this grant
- `grantId`: Unique identifier of the grant
- `userId`: Unique user identifier for the grant
- `appId`: Developer App identifier attached to the grant
- `grantRevision`: An incrementing version integer
- `grantStatus`: `ACTIVE` or `REVOKED` reflects the **consumer's** consent
- `meteringState` — `ACTIVE` or `SUSPENDED` reflects the **app developers** billing status

Both `grantStatus` and `meteringState`must be `ACTIVE` for data calls to succeed.


## Handling grant state in your app

Data endpoints are gated on live grant state. The data endpoint responds with the following errors allowing
apps to react appropriately:

- **`403 disclosure_grant_required`** — no active grant is resolvable. The grant is absent or
  revoked (this also covers an unregistered or unapproved app). Stop in-flight requests, clear
  local data, and deep-link the consumer back to the consent screen to re-establish a grant.
- **`402 credit_exhausted`** — the grant is suspended because your credits are exhausted. The
  consumer's consent is intact; you need to top up credits to resume access.

See [Handling errors from the openfeed API](/resources/error-handling) for the complete response
catalogue.

## Checklist

- [ ] Read the `grant_id` claim from your token response (or introspect an access token) and store it against the user.
- [ ] Poll `GET /v1/app/grants` on a schedule to detect when a grant changes based on `revision`
- [ ] Poll `GET /v1/grants/{grantId}` to update current status after scheduled detection or error response
- [ ] Handle `403 disclosure_grant_required` by initiating a grant amendment sending the user back through the consent flow
- [ ] Handle `402 credit_exhausted` by tracking it's presence and recharging available tokens
- [ ] Treat every grant as revocable at any time.

## References

- [Grant Management for OAuth 2.0](https://openid.net/specs/fapi-grant-management.html): the OpenID Foundation FAPI Working Group specification that openfeed implements.
- [openfeed OpenAPI specification](/openapi.yaml): the machine-readable source of truth for every
  grant and data endpoint.
