Subscriptions (Read)
Read-only endpoints for the Joy Subscription Storefront API. Use these to list a customer's subscription contracts, fetch full contract detail, preview upcoming and historical orders, preview the next charge, and resolve available shipping options.
All paths are relative to the base URL:
https://<your-app-domain>/storefront-api/v1Every endpoint on this page requires both auth layers on every request. The shopId is always derived from the session — it is never read from a header.
X-Joy-App-Id: <app-id>
X-Joy-Secret-Key: sk_live_xxx # server-side only, never expose to the browser
X-Session-Id: <session-id>Responses use a consistent envelope:
// Success
{ "success": true, "data": { /* … */ }, "meta": { /* optional */ } }
// Error
{ "success": false, "error": { "code": "NOT_FOUND", "message": "…" } }{contractId} is the numeric subscriptionContractId. Accessing a contract that does not exist, or one not owned by the authenticated customer, returns 404 NOT_FOUND (existence is never leaked).
Endpoint index
| Method | Path | Description |
|---|---|---|
| GET | /upcoming-orders | All upcoming orders across the customer's contracts. |
| GET | /subscriptions | List the customer's subscription contracts. |
| GET | /subscriptions/{contractId} | Full detail of one contract. |
| GET | /subscriptions/{contractId}/upcoming-orders | Upcoming orders of one contract. |
| GET | /subscriptions/{contractId}/history-orders | Past (billed) orders of one contract. |
| GET | /subscriptions/{contractId}/next-charge | Preview the next charge. |
| GET | /subscriptions/{contractId}/shipping-options | Available shipping options. |
GET /subscriptions
List all subscription contracts owned by the authenticated customer. Each contract is enriched with its current cycle's nextOrderDate.
- Method:
GET - Path:
/subscriptions - Auth:
X-Joy-App-Id,X-Joy-Secret-Key,X-Session-Id
Query parameters
| Name | Type | Notes |
|---|---|---|
status | string (CSV) | Filter by status, e.g. active,paused. |
direction | asc | desc | Order by createdAt. |
Pagination: none — returns the full list. No meta.
Request
curl -G "https://<your-app-domain>/storefront-api/v1/subscriptions" \
--data-urlencode "status=active,paused" \
--data-urlencode "direction=desc" \
-H "X-Joy-App-Id: <app-id>" \
-H "X-Joy-Secret-Key: sk_live_xxx" \
-H "X-Session-Id: <session-id>"Response
{
"success": true,
"data": [
{
"subscriptionContractId": 123456789,
"status": "ACTIVE",
"currentBillingCycle": 4,
"nextOrderDate": "2026-07-01T00:00:00.000Z",
"lines": [ /* … */ ]
/* …other contract fields… */
}
]
}GET /subscriptions/{contractId}
Full detail of a single contract, including the upcoming order (merged cycle line prices, discounts, shipping/delivery price, estimated tax) and the upcoming fulfillment order.
- Method:
GET - Path:
/subscriptions/{contractId} - Auth:
X-Joy-App-Id,X-Joy-Secret-Key,X-Session-Id
Path parameters
| Name | Type | Notes |
|---|---|---|
contractId | integer | Positive integer subscriptionContractId. |
Query parameters: none.
Request
curl "https://<your-app-domain>/storefront-api/v1/subscriptions/123456789" \
-H "X-Joy-App-Id: <app-id>" \
-H "X-Joy-Secret-Key: sk_live_xxx" \
-H "X-Session-Id: <session-id>"Response
{
"success": true,
"data": {
"subscriptionContractId": 123456789,
"status": "ACTIVE",
"upcomingOrder": {
"cycleIndex": 5,
"lines": [ /* merged */ ],
"discounts": [ /* … */ ],
"shippingPrice": "5.00",
"deliveryPrice": "5.00",
"estimatedTax": "1.20",
"billingAttemptExpectedDate": "2026-07-01T00:00:00.000Z"
},
"upcomingFulfillmentOrder": {
"currentOrder": { /* … */ },
"fulfillmentOrders": [ /* … */ ],
"scheduledFulfill": { /* … */ }
}
/* …other contract fields… */
}
}GET /upcoming-orders
All upcoming orders across every contract of the authenticated customer (dashboard view). The customer id is taken from the session — it is never client-controlled.
- Method:
GET - Path:
/upcoming-orders - Auth:
X-Joy-App-Id,X-Joy-Secret-Key,X-Session-Id
Query parameters
| Name | Type | Default | Notes |
|---|---|---|---|
nextCycleOnly | boolean | — | If true, only the next (current) cycle per contract. |
after | string | — | Cursor for the next page. |
limitPerPage | integer | 10 | Range 1–50. Out of range returns 400 VALIDATION_FAILED. |
Pagination: cursor. This is the only Read endpoint that returns meta.nextCursor.
"meta": { "hasNext": true, "hasPre": false, "total": 8, "nextCursor": "…" }Request
curl -G "https://<your-app-domain>/storefront-api/v1/upcoming-orders" \
--data-urlencode "nextCycleOnly=true" \
--data-urlencode "limitPerPage=10" \
-H "X-Joy-App-Id: <app-id>" \
-H "X-Joy-Secret-Key: sk_live_xxx" \
-H "X-Session-Id: <session-id>"Response
{
"success": true,
"data": [
{
"subscriptionContractId": 123456789,
"cycleIndex": 5,
"lines": [ /* … */ ],
"estimatedTax": "1.20"
}
],
"meta": { "hasNext": true, "hasPre": false, "total": 8, "nextCursor": "…" }
}GET /subscriptions/{contractId}/upcoming-orders
Upcoming orders / billing cycles for one contract, each with estimatedTax.
- Method:
GET - Path:
/subscriptions/{contractId}/upcoming-orders - Auth:
X-Joy-App-Id,X-Joy-Secret-Key,X-Session-Id
Path parameters
| Name | Type | Notes |
|---|---|---|
contractId | integer | Positive integer subscriptionContractId. |
Query parameters
| Name | Type | Default | Notes |
|---|---|---|---|
limitPerPage | integer | 10 | Range 1–50. Out of range returns 400 VALIDATION_FAILED. |
Pagination: page-style. meta is { hasNext, hasPre, total } (no nextCursor).
Request
curl -G "https://<your-app-domain>/storefront-api/v1/subscriptions/123456789/upcoming-orders" \
--data-urlencode "limitPerPage=10" \
-H "X-Joy-App-Id: <app-id>" \
-H "X-Joy-Secret-Key: sk_live_xxx" \
-H "X-Session-Id: <session-id>"Response
{
"success": true,
"data": [ { "cycleIndex": 5, "lines": [ /* … */ ], "estimatedTax": "1.20" } ],
"meta": { "hasNext": true, "hasPre": false, "total": 12 }
}GET /subscriptions/{contractId}/history-orders
Past (billed) orders for the contract, with Shopify order links (hashedOrderId, shopGraphqlId).
- Method:
GET - Path:
/subscriptions/{contractId}/history-orders - Auth:
X-Joy-App-Id,X-Joy-Secret-Key,X-Session-Id
Path parameters
| Name | Type | Notes |
|---|---|---|
contractId | integer | Positive integer subscriptionContractId. |
Query parameters
| Name | Type | Notes |
|---|---|---|
after | string | Cursor for the next page. |
Pagination: cursor (via after). meta is { hasNext, hasPre, total }. This endpoint does not return a nextCursor field — use hasNext to decide whether to keep paging, and derive the cursor from your own bookkeeping. Only the all-contracts GET /upcoming-orders endpoint returns meta.nextCursor.
Request
curl -G "https://<your-app-domain>/storefront-api/v1/subscriptions/123456789/history-orders" \
--data-urlencode "after=<cursor>" \
-H "X-Joy-App-Id: <app-id>" \
-H "X-Joy-Secret-Key: sk_live_xxx" \
-H "X-Session-Id: <session-id>"Response
{
"success": true,
"data": [
{
"orderId": 5544332211,
"billingAttemptExpectedDate": "2026-06-01T00:00:00.000Z",
"shopGraphqlId": "12345678",
"hashedOrderId": "abc123…",
"lines": [ /* … */ ]
}
],
"meta": { "hasNext": true, "hasPre": false, "total": 24 }
}GET /subscriptions/{contractId}/next-charge
Preview the next charge of a contract at a point in time — merged cycle prices, discounts, shipping/delivery price, and estimatedTax.
- Method:
GET - Path:
/subscriptions/{contractId}/next-charge - Auth:
X-Joy-App-Id,X-Joy-Secret-Key,X-Session-Id
Path parameters
| Name | Type | Notes |
|---|---|---|
contractId | integer | Positive integer subscriptionContractId. |
Query parameters
| Name | Type | Default | Notes |
|---|---|---|---|
date | string (ISO 8601) | now | Preview the cycle effective at this date. |
Request
curl -G "https://<your-app-domain>/storefront-api/v1/subscriptions/123456789/next-charge" \
--data-urlencode "date=2026-07-01T00:00:00.000Z" \
-H "X-Joy-App-Id: <app-id>" \
-H "X-Joy-Secret-Key: sk_live_xxx" \
-H "X-Session-Id: <session-id>"Response
{
"success": true,
"data": {
"cycleIndex": 5,
"lines": [ /* merged */ ],
"discounts": [ /* … */ ],
"shippingPrice": "5.00",
"deliveryPrice": "5.00",
"estimatedTax": "1.20"
}
}GET /subscriptions/{contractId}/shipping-options
Available shipping/delivery options for the contract, based on current lines plus the delivery address. contractId is taken only from the path param.
- Method:
GET - Path:
/subscriptions/{contractId}/shipping-options - Auth:
X-Joy-App-Id,X-Joy-Secret-Key,X-Session-Id
Path parameters
| Name | Type | Notes |
|---|---|---|
contractId | integer | Positive integer subscriptionContractId. |
Query parameters: none.
Request
curl "https://<your-app-domain>/storefront-api/v1/subscriptions/123456789/shipping-options" \
-H "X-Joy-App-Id: <app-id>" \
-H "X-Joy-Secret-Key: sk_live_xxx" \
-H "X-Session-Id: <session-id>"Response
{
"success": true,
"data": [
{ "handle": "…", "title": "Standard", "price": "5.00" }
]
}