Create Usage Revocation
Creates a revocation request that refunds fund debits and marks analytics facts as revoked. The original usage event rows stay immutable.
POST /v1/projects/:project_id/usage/revocationsAuthentication
Section titled “Authentication”Authorization: Bearer <api-key>Requires usage:revocation.
Path Parameters
Section titled “Path Parameters”| Field | Required | Description |
|---|---|---|
project_id |
Yes | Project that owns the events. |
Request Body
Section titled “Request Body”Provide exactly one selector: raw_event_ids or filter.
| Field | Required | Description |
|---|---|---|
raw_event_ids |
No | Revoke usage events for these raw event IDs. Max 1000. |
filter |
No | Whitelisted filter object used to discover candidate events. occurred_at.from and occurred_at.to are required (unix seconds, second precision) inside filter; all other keys are optional. Max 100,000 matching usage events per request; create counts first and rejects oversized filters. |
purpose |
Yes | revoke or reprice. Reprice-purpose requests unlock Continue reprice. |
reason |
Yes | Human-readable reason recorded on the request and audit log. |
idempotency_key |
No | Tenant/project scoped create idempotency key. |
Filter discovery is capped at 100,000 usage events. Call
Estimate Usage Revocation with the same
filter to preview event_count before create. Oversized filters return an
error instead of silently truncating.
Example
Section titled “Example”By raw event IDs:
curl -X POST 'http://127.0.0.1:8080/v1/projects/proj_gateway/usage/revocations' \ -H 'Authorization: Bearer <api-key>' \ -H 'Content-Type: application/json' \ -d '{ "raw_event_ids": ["raw_001", "raw_002"], "purpose": "revoke", "reason": "duplicate gateway report", "idempotency_key": "revoke-batch-001" }'By whitelisted filter (async discovery against Doris usage facts):
curl -X POST 'http://127.0.0.1:8080/v1/projects/proj_gateway/usage/revocations' \ -H 'Authorization: Bearer <api-key>' \ -H 'Content-Type: application/json' \ -d '{ "filter": { "occurred_at": { "from": 1704067200, "to": 1706745600 }, "subject_type": "user", "subject_id": "user_001", "billing_account_id": "acct_001", "source": "gateway", "metrics": ["input_tokens"], "extractor_rule_set_id": "ers_old", "dimensions": { "model": "gpt-4o" } }, "purpose": "revoke", "reason": "test data cleanup", "idempotency_key": "revoke-filter-001" }'Allowed filter keys: occurred_at, subject_type, subject_id,
billing_account_id, source, external_event_id, extractor_rule_set_id,
extractor_version, metrics, dimensions.
occurred_at is required and must provide both from and to as unix
seconds (second precision); to must be strictly after from. All other
filter keys are optional.
Use top-level raw_event_ids for explicit ID lists.
Singular metric, raw_event_id, and raw_event_id are not accepted inside
filter.
Response
Section titled “Response”202 Accepted
{ "revocation_id": "urv_001", "status": "enqueueing"}The request is durable before the worker queue publish is attempted. If the
queue publish fails, the API still returns 202 with "status": "enqueue_failed"; the request exists and can be re-published via the retry
endpoint (or by re-sending this request with the same idempotency_key).
Poll GET /v1/projects/:project_id/usage/revocations/:revocation_id for progress.
Targets and fund/Doris entries are available on the nested list endpoints.