Kaching Subscriptions API Documentation
Create rich subscription flows and streamline store operations on Shopify using our full-featured, enterprise-ready REST APIs.
Prerequisites
Section titled “Prerequisites”- A Shopify store with the Kaching Subscriptions app installed
- A Kaching Subscriptions API key (generated from the app admin)
Base URL
Section titled “Base URL”https://subscriptions.kachingappz.app/shop-apiAll responses are JSON.
Authentication
Section titled “Authentication”Every request must include a Bearer token in the Authorization header:
Authorization: Bearer <your-api-token>If the header is missing, malformed, or the token is unknown, the API responds with 401 Unauthorized:
{ "error": "Unauthorized", "message": "Invalid token"}Rate limiting
Section titled “Rate limiting”The API allows 60 requests per 60 seconds per shop. Requests over the limit receive 429 Too Many Requests:
{ "isError": true, "message": "Too many requests, please try again later."}List responses also include a throttle field reflecting the remaining Shopify GraphQL budget. When that budget drops below 1000, the API automatically delays the response by ~3 seconds to avoid tripping Shopify-side limits — design your integration to tolerate that latency.
Endpoints
Section titled “Endpoints”List contracts
Section titled “List contracts”GET /shop-api/contractsReturns a paginated list of subscription contracts for the authenticated shop.
Query parameters
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
cursor | string | No | — | Opaque pagination cursor from the previous response’s cursor field. |
query | string | No | status:ACTIVE OR status:PAUSED OR status:FAILED OR status:CANCELLED | Shopify GraphQL query syntax, e.g. status:ACTIVE, status:PAUSED. |
email | string | No | — | Customer email (case-insensitive exact match). Narrows the result to that customer’s contracts. Combines with query via AND. Unknown email returns an empty data array. |
customerId | string | No | — | Shopify customer ID — either a numeric ID (e.g. 258369147) or a full GID (gid://shopify/Customer/258369147). Narrows the result to that customer’s contracts. Combines with query via AND. Unknown customer returns an empty data array. Takes precedence over email if both are supplied. |
orderId | string | No | — | Shopify order ID — either a numeric ID (e.g. 369147258) or a full GID (gid://shopify/Order/369147258). Narrows the result to the contract(s) attached to that order. Combines with query via AND. Unknown or non-subscription orders return an empty data array. Takes precedence over customerId and email if multiple are supplied. |
Each page returns up to 50 contracts.
Example — fetch all active contracts
curl -G "https://subscriptions.kachingappz.app/shop-api/contracts" \ -H "Authorization: Bearer <your-api-token>" \ --data-urlencode "query=status:ACTIVE"Example — paginate
curl -G "https://subscriptions.kachingappz.app/shop-api/contracts" \ -H "Authorization: Bearer <your-api-token>" \ --data-urlencode "query=status:ACTIVE" \ --data-urlencode "cursor=eyJsYXN0X2lkIjoi..."Loop until hasNextPage is false, passing the previous response’s cursor on each iteration.
Example — fetch a single contract by ID
curl -G "https://subscriptions.kachingappz.app/shop-api/contracts" \ -H "Authorization: Bearer <your-api-token>" \ --data-urlencode "query=id:123456789"Example — fetch a specific customer’s contracts by email
curl -G "https://subscriptions.kachingappz.app/shop-api/contracts" \ -H "Authorization: Bearer <your-api-token>" \ --data-urlencode "email=sarah@example.com"Combine with query to narrow further, e.g. only that customer’s cancelled contracts:
curl -G "https://subscriptions.kachingappz.app/shop-api/contracts" \ -H "Authorization: Bearer <your-api-token>" \ --data-urlencode "email=sarah@example.com" \ --data-urlencode "query=status:CANCELLED"Example — fetch a specific customer’s contracts by customer ID
Customer ID is preferred over email when available — it’s stable across email changes. Accepts either the numeric ID or the full Shopify GID.
curl -G "https://subscriptions.kachingappz.app/shop-api/contracts" \ -H "Authorization: Bearer <your-api-token>" \ --data-urlencode "customerId=258369147"curl -G "https://subscriptions.kachingappz.app/shop-api/contracts" \ -H "Authorization: Bearer <your-api-token>" \ --data-urlencode "customerId=gid://shopify/Customer/258369147"Example — fetch a contract by orderId
Use orderId when you have a Shopify order in hand and want to find the subscription contract(s) it was generated by. Accepts either the numeric ID or the full Shopify GID.
curl -G "https://subscriptions.kachingappz.app/shop-api/contracts" \ -H "Authorization: Bearer <your-api-token>" \ --data-urlencode "orderId=369147258"curl -G "https://subscriptions.kachingappz.app/shop-api/contracts" \ -H "Authorization: Bearer <your-api-token>" \ --data-urlencode "orderId=gid://shopify/Order/369147258"If multiple of orderId, customerId, and email are provided, priority is orderId > customerId > email; the lower-priority parameters are ignored.
Response (200)
{ "data": [ { "node": { "id": "gid://shopify/SubscriptionContract/123456789", "status": "ACTIVE", "currencyCode": "USD", "lastPaymentStatus": "SUCCEEDED", "revisionId": "gid://shopify/SubscriptionContractRevision/987654321", "createdAt": "2024-01-15T10:30:00Z", "updatedAt": "2024-02-10T14:22:00Z", "deliveryPolicy": { "interval": "MONTH", "intervalCount": 1 }, "billingPolicy": { "interval": "MONTH", "intervalCount": 1, "maxCycles": null, "minCycles": null }, "deliveryPrice": { "amount": "5.99", "currencyCode": "USD" }, "deliveryMethod": { "__typename": "SubscriptionDeliveryMethodShipping", "address": { "countryCodeV2": "US", "city": "San Francisco" } }, "linesCount": { "count": 2 }, "lines": { "edges": [ { "node": { "id": "gid://shopify/SubscriptionLine/111222333", "title": "Product Title", "variantTitle": "Variant Title", "productId": "gid://shopify/Product/444555666", "variantId": "gid://shopify/ProductVariant/777888999", "quantity": 2, "lineDiscountedPrice": { "amount": "47.98", "currencyCode": "USD" }, "pricingPolicy": { "basePrice": { "amount": "25.99", "currencyCode": "USD" }, "cycleDiscounts": [ { "adjustmentType": "PERCENTAGE", "afterCycle": 0, "computedPrice": { "amount": "23.99", "currencyCode": "USD" }, "adjustmentValue": { "percentage": 8.0 } } ] }, "discountAllocations": [] } } ], "pageInfo": { "hasNextPage": false, "hasPreviousPage": false, "endCursor": null, "startCursor": null } }, "discounts": { "edges": [] }, "customer": { "id": "gid://shopify/Customer/258369147", "displayName": "Sarah Johnson", "defaultEmailAddress": { "emailAddress": "sarah@example.com" } }, "orders": { "edges": [{ "node": { "id": "gid://shopify/Order/369147258" } }], "pageInfo": { "hasNextPage": false, "hasPreviousPage": false, "endCursor": null, "startCursor": null } } } } ], "hasNextPage": true, "cursor": "eyJsYXN0X2lkIjoiZ2lkOi8vc2hvcGlmeS...", "throttle": 1850}See the Contract object reference below for field details.
Pause a contract
Section titled “Pause a contract”POST /shop-api/contracts/pauseTransitions an ACTIVE contract to PAUSED. No further billing cycles run until the contract is resumed.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
contractId | string | Yes | Either a Shopify GID (gid://shopify/SubscriptionContract/123) or the bare numeric ID. |
Example
curl -X POST "https://subscriptions.kachingappz.app/shop-api/contracts/pause" \ -H "Authorization: Bearer <your-api-token>" \ -H "Content-Type: application/json" \ -d '{"contractId":"gid://shopify/SubscriptionContract/123456789"}'Response (200)
{ "success": true }Resume a contract
Section titled “Resume a contract”POST /shop-api/contracts/resumeTransitions a PAUSED contract back to ACTIVE. Billing resumes on the contract’s configured schedule.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
contractId | string | Yes | Shopify GID or numeric ID of the contract. |
Example
curl -X POST "https://subscriptions.kachingappz.app/shop-api/contracts/resume" \ -H "Authorization: Bearer <your-api-token>" \ -H "Content-Type: application/json" \ -d '{"contractId":"gid://shopify/SubscriptionContract/123456789"}'Response (200)
{ "success": true }Cancel a contract
Section titled “Cancel a contract”POST /shop-api/contracts/cancelTransitions a contract to CANCELLED.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
contractId | string | Yes | Shopify GID or numeric ID of the contract. |
Example
curl -X POST "https://subscriptions.kachingappz.app/shop-api/contracts/cancel" \ -H "Authorization: Bearer <your-api-token>" \ -H "Content-Type: application/json" \ -d '{"contractId":"gid://shopify/SubscriptionContract/123456789"}'Response (200)
{ "success": true }Contract object reference
Section titled “Contract object reference”Top-level contract fields
Section titled “Top-level contract fields”| Field | Type | Description |
|---|---|---|
id | string | Shopify GID for the contract. |
status | string | One of ACTIVE, PAUSED, FAILED, EXPIRED, CANCELLED, STALE. |
currencyCode | string | ISO currency code for the contract. |
lastPaymentStatus | string | SUCCEEDED or FAILED. |
revisionId | string | Opaque identifier for the current revision. Use to detect contract changes. |
createdAt | string | ISO-8601 timestamp. |
updatedAt | string | ISO-8601 timestamp. |
deliveryPolicy | object | { interval, intervalCount } — how often deliveries happen. |
billingPolicy | object | { interval, intervalCount, maxCycles, minCycles } — billing cadence and limits. |
deliveryPrice | object | { amount, currencyCode } — shipping/delivery charge per cycle. |
deliveryMethod | object | Delivery method, e.g. SubscriptionDeliveryMethodShipping with an address. |
linesCount | object | { count } — total number of line items on the contract. |
lines | object | Connection of line items — see below. |
discounts | object | Connection of contract-level discount allocations. |
customer | object | { id, displayName, defaultEmailAddress.emailAddress }. |
orders | object | Connection of orders generated by this contract. |
interval values: DAY, WEEK, MONTH, YEAR.
Line item fields (lines.edges[].node)
Section titled “Line item fields (lines.edges[].node)”| Field | Type | Description |
|---|---|---|
id | string | Shopify GID for the line. |
title | string | Product title. |
variantTitle | string | Variant title. |
productId | string | Shopify product GID. |
variantId | string | Shopify variant GID. |
quantity | number | Number of units per delivery. |
lineDiscountedPrice | object | { amount, currencyCode } — final per-line price after discounts. |
pricingPolicy | object | { basePrice, cycleDiscounts[] } — base price and per-cycle adjustments. |
discountAllocations | array | Line-level discount allocations. |
Cycle discount fields (pricingPolicy.cycleDiscounts[])
Section titled “Cycle discount fields (pricingPolicy.cycleDiscounts[])”| Field | Type | Description |
|---|---|---|
adjustmentType | string | PERCENTAGE, FIXED_AMOUNT, or PRICE. |
afterCycle | number | Cycle index after which the discount applies (0 = starting with cycle 1). |
computedPrice | object | { amount, currencyCode } — resolved price once the discount applies. |
adjustmentValue | object | Either { percentage } or { amount, currencyCode }, depending on type. |
Pagination (pageInfo)
Section titled “Pagination (pageInfo)”Connections (lines, orders, top-level list) return pageInfo:
| Field | Type | Description |
|---|---|---|
hasNextPage | boolean | true if more pages exist. |
hasPreviousPage | boolean | true if previous pages exist. |
endCursor | string | Cursor for the last item in the current page. |
startCursor | string | Cursor for the first item in the current page. |
Errors
Section titled “Errors”| Status | When | Example body |
|---|---|---|
| 400 | Missing or malformed request body (e.g. no contractId) or invalid query parameter (e.g. email is not a valid address) | { "error": "Missing contractId" } |
| 401 | Missing, malformed, or unknown Bearer token | { "error": "Unauthorized", "message": "Invalid token" } |
| 429 | Rate limit exceeded (60 requests / 60 seconds per shop) | { "isError": true, "message": "Too many requests, please try again later." } |
| 500 | Upstream Shopify error or mutation failure | { "error": "Failed to pause subscription contract" } |
Mutation endpoints (pause, resume, cancel) surface Shopify-side validation messages in the error field when Shopify returns userErrors, so prefer showing the raw message to operators rather than masking it.