Entitlements
All endpoints require a valid API key in the Authorization header.
Check entitlement
The fastest way to check if a customer has access to a product. Optimized for low latency.
GET /v1/entitlements/check?customer_id={customer_id}&product_id={product_id}Scope: entitlements:read
Query parameters
| Parameter | Description |
|---|---|
customer_id | Customer ID (or use shopify_customer_id) |
shopify_customer_id | Shopify customer ID (alternative to customer_id) |
product_id | Product ID (or use shopify_product_id) |
shopify_product_id | Shopify product ID (alternative to product_id) |
Response
{ "data": { "entitled": true, "entitlement": { "id": "ent_abc123", "product_id": "prod_xyz", "status": "active", "granted_at": "2026-01-15T10:00:00.000Z", "expires_at": null, "metadata": {}, "access_type": "direct" } }, "meta": { "request_id": "req_abc123", "timestamp": "2026-03-01T12:00:00.000Z" }}Returns { "entitled": false, "entitlement": null } if the customer does not have access — never a 404.
List entitlements
GET /v1/entitlementsScope: entitlements:read
Requires at least one filter parameter.
Query parameters
| Parameter | Default | Description |
|---|---|---|
customer_id | — | Filter by customer ID |
shopify_customer_id | — | Filter by Shopify customer ID |
product_id | — | Filter by product ID |
status | — | Filter by status: ACTIVE, EXPIRED, REVOKED, SUSPENDED, PENDING |
source | — | Filter by source: ORDER, MANUAL, RULE, API, BUNDLE, SUBSCRIPTION, FLOW, IMPORT |
granted_after | — | ISO 8601 timestamp |
granted_before | — | ISO 8601 timestamp |
limit | 25 | Number of results (1–100) |
cursor | — | Pagination cursor |
Response
{ "data": [ { "id": "ent_abc123", "customer_id": "cust_123", "shopify_customer_id": "7890", "product_id": "prod_xyz", "status": "active", "granted_at": "2026-01-15T10:00:00.000Z", "expires_at": null, "revoked_at": null, "revocation_reason": null, "usage_count": 0, "usage_limit": null, "source": "order", "shopify_order_id": "6001234567890", "metadata": {}, "created_at": "2026-01-15T10:00:00.000Z", "updated_at": "2026-01-15T10:00:00.000Z" } ], "meta": { "request_id": "req_abc123", "timestamp": "2026-03-01T12:00:00.000Z" }, "pagination": { "total": 1, "limit": 25, "has_more": false, "next_cursor": null }}Get entitlement
GET /v1/entitlements/{entitlement_id}Scope: entitlements:read
Response
Returns the full entitlement object (same shape as list items, plus shopify_line_item_id and parent_entitlement_id).
Create entitlement
POST /v1/entitlementsScope: entitlements:write
Request body
{ "customer_id": "cust_123", "product_id": "prod_xyz", "expires_at": "2026-06-01T00:00:00.000Z", "usage_limit": 10, "metadata": { "campaign": "spring-launch" }, "idempotency_key": "unique-key-123"}| Field | Required | Description |
|---|---|---|
customer_id | Yes* | Customer ID (*or shopify_customer_id) |
shopify_customer_id | Yes* | Shopify customer ID (*or customer_id) |
product_id | Yes* | Product ID (*or shopify_product_id) |
shopify_product_id | Yes* | Shopify product ID (*or product_id) |
expires_at | No | ISO 8601 expiration timestamp |
usage_limit | No | Maximum number of uses |
metadata | No | Arbitrary JSON object |
idempotency_key | No | Prevents duplicate creation |
Response
201 Created
{ "data": { "id": "ent_abc123", "customer_id": "cust_123", "product_id": "prod_xyz", "status": "active", "granted_at": "2026-03-01T12:00:00.000Z", "expires_at": "2026-06-01T00:00:00.000Z", "source": "api", "metadata": { "campaign": "spring-launch" }, "created_at": "2026-03-01T12:00:00.000Z" }, "meta": { "request_id": "req_abc123", "timestamp": "2026-03-01T12:00:00.000Z" }}Update entitlement
PATCH /v1/entitlements/{entitlement_id}Scope: entitlements:write
Request body
{ "expires_at": "2026-12-31T23:59:59.000Z", "metadata": { "campaign": "extended" }}Both fields are optional. Only provided fields are updated.
Revoke entitlement
POST /v1/entitlements/{entitlement_id}/revokeScope: entitlements:write
Request body
{ "reason": "Refund processed"}The reason field is optional. Publishes an entitlement.revoked webhook event.
Suspend entitlement
POST /v1/entitlements/{entitlement_id}/suspendScope: entitlements:write
Request body
{ "reason": "Payment dispute"}The reason field is optional. Publishes an entitlement.suspended webhook event. Use reactivate to restore access.
Reactivate entitlement
POST /v1/entitlements/{entitlement_id}/reactivateScope: entitlements:write
Reactivates a suspended or expired entitlement. Publishes an entitlement.reactivated webhook event.
Status transitions
Not all status transitions are valid. The API returns 409 Conflict for invalid transitions.
| From | Allowed transitions |
|---|---|
ACTIVE | suspended, revoked, expired |
SUSPENDED | active (reactivate), revoked |
EXPIRED | active (reactivate) |
REVOKED | — (terminal) |
PENDING | active, revoked |