Overrides
Change one customer without a new plan.
An override changes what a single customer gets. The plan stays as it is, and everyone else on it keeps the old value.
Sales promised one customer 25 seats when the plan gives 10. That is an override. The change lives on their subscription, and beats the plan value on every check.
Boolean, gauge, and static metrics can be changed this way. A metered metric cannot. Change what a metered metric costs with a metering rule instead.
One subscription holds one override per metric. Asking for a second one on the same metric returns a conflict.
An override can end on its own. Set expires_at and QuotaStack goes back to
the plan value after that date, with nothing for you to remember.
Writing the same override for the third time is a sign. Build a plan variant instead, and move those customers onto it.
Which call do I want?
- One customer needs a different entitlement, and only that customer →
POST /v1/subscriptions/{id}/overrides - Many customers need it →
createPlanVariantAn override changes one subscription. A new plan variant changes everyone on it. Reach for a variant when you find yourself writing the same override twice. - You want to see what a customer already has, override or not →
checkEntitlementThis object lists only the changes. The entitlement check tells you what the customer really gets. - The special treatment should end on a date →
POST /v1/subscriptions/{id}/overridesSetexpires_at. QuotaStack goes back to the plan value on its own after that.
List overrides
/v1/subscriptions/{id}/overrides | Idempotency-Key | Not used. This is a read. |
|---|---|
| Environment | Sandbox and Live |
| Auth | Tenant API key |
| Writes | Nothing. A read has no side effects. |
| Fires | No webhooks. |
This call returns every live override on one subscription. The reply is shaped {"overrides": [...]}. Other lists on this API use data and a pagination block. This one does neither. The whole set comes back at once, and there are no pages to walk. The list holds only the changes you made. Use checkEntitlement to see the value a customer really gets.
| Field | Type | Meaning |
|---|---|---|
idrequired | string (uuid) |
{
"overrides": [
{
"id": "0192f5a4-7c31-7b8e-9a2d-4f6c8e1b3a73",
"subscription_id": "0192f5a4-7c31-7b8e-9a2d-4f6c8e1b3a21",
"billable_metric_id": "0192f5a4-7c31-7b8e-9a2d-4f6c8e1b3a64",
"billable_metric_key": "seats",
"value": {
"cap": 25
},
"expires_at": null,
"reason": "Enterprise trial, agreed with sales",
"created_at": "2026-07-28T09:00:00Z",
"updated_at": "2026-07-28T09:00:00Z"
}
]
} | Field | Type | Meaning |
|---|---|---|
overridesoptional | array | |
overrides.subscription_idrequired | string (uuid) | Which subscription this change belongs to. One override covers one subscription, and no other. |
overrides.billable_metric_idrequired | string (uuid) | QuotaStack's own ID for that metric. Match on |
overrides.billable_metric_keyoptional | string | Which billable metric this change is about. |
overrides.valuerequired | object | The new value, shaped to match the metric type. A boolean metric takes |
overrides.expires_atoptional | string (date-time) | When this change stops applying. The plan value takes over again after that. If you leave it out: The change lasts until you delete it. |
overrides.reasonoptional | string | Why you made this change, in your own words. QuotaStack stores it and shows it back to you. If you leave it out: QuotaStack stores an empty string. |
Errors
401— Missing or invalid authentication.404— No subscription here has thisid. You get the same reply when the subscription belongs to the other environment. A sandbox key asking about a live subscription is told it does not exist. not-found
See also
Create an override
/v1/subscriptions/{id}/overrides | Idempotency-Key | Required. Returns 422 without it. |
|---|---|
| Environment | Sandbox and Live |
| Auth | Tenant API key |
| Writes | One override row, and a fresh entitlement cache for that customer. The customer sees the new value on their very next check. |
| Fires | No webhooks. |
This call changes one entitlement for one subscription. The plan stays as it is, and everyone else on it keeps the old value. Boolean, gauge, and static metrics can be changed this way. A metered metric cannot. QuotaStack returns 400 for one of those. Change a metered price with a metering rule instead. One subscription can hold one override per metric. A second one for the same metric returns 409. An override that already expired is the exception. QuotaStack deletes the old one and makes the new one, and you get a new id.
| Field | Type | Meaning |
|---|---|---|
Idempotency-Keyrequired | string | A unique string you choose, up to 256 characters. It stops a retry from doing the work twice. This header is required on every POST and PATCH. Leave it out and the request fails with Send the same key twice and QuotaStack replays the first response. The second call's status and body match the first, and the response carries Derive the key from the business event rather than a random value, so a retry from anywhere reuses it — for example |
| Field | Type | Meaning |
|---|---|---|
idrequired | string (uuid) |
| Field | Type | Meaning |
|---|---|---|
billable_metric_keyrequired | string | Which billable metric this change is about. If you leave it out: QuotaStack rejects the call with |
valuerequired | object | The new value, shaped to match the metric type. A boolean metric takes If you leave it out: QuotaStack rejects the call with |
expires_atoptional | string (date-time) | When this change stops applying. The plan value takes over again after that. If you leave it out: The change lasts until you delete it. |
reasonoptional | string | Why you made this change, in your own words. QuotaStack stores it and shows it back to you. If you leave it out: QuotaStack stores an empty string. |
{
"billable_metric_key": "seats",
"value": {
"cap": 25
},
"reason": "Enterprise trial, agreed with sales"
} {
"id": "0192f5a4-7c31-7b8e-9a2d-4f6c8e1b3a73",
"subscription_id": "0192f5a4-7c31-7b8e-9a2d-4f6c8e1b3a21",
"billable_metric_id": "0192f5a4-7c31-7b8e-9a2d-4f6c8e1b3a64",
"billable_metric_key": "seats",
"value": {
"cap": 25
},
"expires_at": null,
"reason": "Enterprise trial, agreed with sales",
"created_at": "2026-07-28T09:00:00Z",
"updated_at": "2026-07-28T09:00:00Z"
} | Field | Type | Meaning |
|---|---|---|
idrequired | string (uuid) | |
tenant_idoptional | string (uuid) | |
subscription_idrequired | string (uuid) | Which subscription this change belongs to. One override covers one subscription, and no other. |
billable_metric_idrequired | string (uuid) | QuotaStack's own ID for that metric. Match on |
billable_metric_keyoptional | string | Which billable metric this change is about. |
valuerequired | object | The new value, shaped to match the metric type. A boolean metric takes |
expires_atoptional | string (date-time) | When this change stops applying. The plan value takes over again after that. If you leave it out: The change lasts until you delete it. |
reasonoptional | string | Why you made this change, in your own words. QuotaStack stores it and shows it back to you. If you leave it out: QuotaStack stores an empty string. |
created_atrequired | string (date-time) | |
updated_atrequired | string (date-time) |
Errors
400— The metric is metered, which this call cannot change. Orvaluedoes not match the metric type. A gauge needscap, and a boolean needsenabled. bad-request401— Missing or invalid authentication.404— No subscription here has thisid. You get the same reply when the subscription belongs to the other environment. A sandbox key asking about a live subscription is told it does not exist. not-found409— This subscription already has a live override for that metric. Update it, or delete it first. conflict
See also
Update an override
/v1/subscriptions/{id}/overrides/{billable_metric_key} | Idempotency-Key | Required. Returns 422 without it. |
|---|---|
| Environment | Sandbox and Live |
| Auth | Tenant API key |
| Writes | The override row, and a fresh entitlement cache for that customer. |
| Fires | No webhooks. |
This call changes an override you already made. The path takes the metric key, not the override id. Send only the fields you want changed. The rest stay as they are. expires_at works in a way the other fields do not. Send null for it and the override becomes permanent. Leave the field out and the old expiry stays. A new value is checked against the metric type, the same as on create.
| Field | Type | Meaning |
|---|---|---|
Idempotency-Keyrequired | string | A unique string you choose, up to 256 characters. It stops a retry from doing the work twice. This header is required on every POST and PATCH. Leave it out and the request fails with Send the same key twice and QuotaStack replays the first response. The second call's status and body match the first, and the response carries Derive the key from the business event rather than a random value, so a retry from anywhere reuses it — for example |
| Field | Type | Meaning |
|---|---|---|
idrequired | string (uuid) | |
billable_metric_keyrequired | string | The billable metric’s own key. Not a QuotaStack id. |
| Field | Type | Meaning |
|---|---|---|
valueoptional | object | The new value, shaped to match the metric type. A boolean metric takes If you leave it out: The value stays as it was. |
expires_atoptional | string (date-time) | A new end date for this change. If you leave it out: The old expiry stays. Send |
reasonoptional | string | Why you made this change, in your own words. QuotaStack stores it and shows it back to you. If you leave it out: The old reason stays. |
{
"value": {
"cap": 50
}
} {
"id": "0192f5a4-7c31-7b8e-9a2d-4f6c8e1b3a73",
"subscription_id": "0192f5a4-7c31-7b8e-9a2d-4f6c8e1b3a21",
"billable_metric_id": "0192f5a4-7c31-7b8e-9a2d-4f6c8e1b3a64",
"billable_metric_key": "seats",
"value": {
"cap": 50
},
"expires_at": null,
"reason": "Enterprise trial, agreed with sales",
"created_at": "2026-07-28T09:00:00Z",
"updated_at": "2026-07-28T11:00:00Z"
} | Field | Type | Meaning |
|---|---|---|
idrequired | string (uuid) | |
tenant_idoptional | string (uuid) | |
subscription_idrequired | string (uuid) | Which subscription this change belongs to. One override covers one subscription, and no other. |
billable_metric_idrequired | string (uuid) | QuotaStack's own ID for that metric. Match on |
billable_metric_keyoptional | string | Which billable metric this change is about. |
valuerequired | object | The new value, shaped to match the metric type. A boolean metric takes |
expires_atoptional | string (date-time) | When this change stops applying. The plan value takes over again after that. If you leave it out: The change lasts until you delete it. |
reasonoptional | string | Why you made this change, in your own words. QuotaStack stores it and shows it back to you. If you leave it out: QuotaStack stores an empty string. |
created_atrequired | string (date-time) | |
updated_atrequired | string (date-time) |
Errors
400—valuedoes not match the metric type. A gauge needscap, and a boolean needsenabled. bad-request401— Missing or invalid authentication.404— No override here covers that metric on that subscription. The subscription may be missing too, or set up in the other environment. not-found
See also
Delete an override
/v1/subscriptions/{id}/overrides/{billable_metric_key} | Idempotency-Key | Required. Returns 422 without it. |
|---|---|
| Environment | Sandbox and Live |
| Auth | Tenant API key |
| Writes | Marks the override deleted, and clears that customer entitlement cache. No credits move, and the subscription itself is untouched. |
| Fires | No webhooks. |
This call ends the special treatment. The customer goes back to the plan value right away. QuotaStack keeps the row and marks it deleted, so the history stays. The reply carries no body. A success is 204 and nothing else. You can make a new override for the same metric afterwards.
| Field | Type | Meaning |
|---|---|---|
Idempotency-Keyrequired | string | A unique string you choose, up to 256 characters. It stops a retry from doing the work twice. This header is required on every POST and PATCH. Leave it out and the request fails with Send the same key twice and QuotaStack replays the first response. The second call's status and body match the first, and the response carries Derive the key from the business event rather than a random value, so a retry from anywhere reuses it — for example |
| Field | Type | Meaning |
|---|---|---|
idrequired | string (uuid) | |
billable_metric_keyrequired | string | The billable metric’s own key. Not a QuotaStack id. |
Errors
401— Missing or invalid authentication.404— No override here covers that metric on that subscription. The subscription may sit in the other environment. not-found
See also
Loading…