On this page
- Endpoints
- List orders
- Query parameters
- Request
- Response 200
- Create a manual order
- Request body
- Request
- Response 201
- Get an order
- Query parameters
- Request
- Response 200
- Update order status
- Request body
- Request
- Response 200
- Error 400 – invalid transition
- Download invoice PDF
- Example request
- Webhooks
- The order object
- The tax line object
Orders
Orders represent completed or in-progress purchases. They are created automatically when a Stripe checkout session completes, or manually via the API. Each order has an auto-incrementing order number, status tracking for fulfillment and payment, and immutable line items that snapshot pricing at the time of purchase.
Base URL: https://api.hydrajs.dev
Endpoints
| Method | Path | Auth | Description |
|---|---|---|---|
GET |
/v1/orders |
Secret | List orders |
POST |
/v1/orders |
Secret | Create a manual order |
GET |
/v1/orders/{id} |
Publishable | Get an order |
PATCH |
/v1/orders/{id} |
Secret | Update order status |
GET |
/v1/orders/{id}/invoice |
Secret | Download invoice PDF |
List orders
GET /v1/orders
Returns a paginated list of orders. Supports filtering by status, financial status, fulfillment status, customer, and date range.
Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
limit |
integer | 25 |
Results per page (1–100) |
cursor |
string | – | Pagination cursor from a previous response |
sort |
string | created_at |
Sort field: created_at, updated_at, order_number |
order |
string | desc |
Sort direction: asc, desc |
status |
string | – | Filter by status: open, closed, cancelled |
financial_status |
string | – | Filter by payment status: pending, paid, refunded, partially_refunded |
fulfillment_status |
string | – | Filter by fulfillment: unfulfilled, partial, fulfilled |
customer_id |
string | – | Filter by customer ID |
customer_email |
string | – | Filter by customer email |
created_after |
ISO 8601 | – | Filter: created after this date |
created_before |
ISO 8601 | – | Filter: created before this date |
fields |
string | – | Comma-separated fields to return |
Request
curl https://api.hydrajs.dev/v1/orders?status=open&financial_status=paid&limit=10 \
-H "Authorization: Bearer sk_live_YOUR_KEY"
Response 200
{
"data": [
{
"id": "ord_abc123",
"order_number": 1042,
"status": "open",
"financial_status": "paid",
"fulfillment_status": "unfulfilled",
"customer_id": "cus_xyz789",
"customer_email": "jane@example.com",
"subtotal": 5998,
"tax": 480,
"tax_inclusive": false,
"shipping_cost": 599,
"discount": 0,
"total": 7077,
"currency": "USD",
"shipping_address": {
"first_name": "Jane",
"last_name": "Doe",
"line1": "123 Main St",
"city": "Austin",
"state": "TX",
"postal_code": "78701",
"country": "US"
},
"notes": null,
"metadata": {},
"created_at": "2026-08-15T14:30:00Z",
"updated_at": "2026-08-15T14:30:00Z"
}
],
"pagination": {
"cursor": "eyJ0IjoiMjAyNi...",
"has_more": true,
"total": 156
}
}
ℹPagination
All list endpoints use cursor-based pagination. Pass the cursor value from the response to fetch
the next page.
Create a manual order
POST /v1/orders
Creates an order directly without going through the checkout flow. Useful for phone orders, imports, or custom integrations. Inventory is deducted atomically – if any variant has insufficient stock, the entire order is rejected.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
customer_email |
string | Yes | Customer email address |
customer_id |
string | No | Link to an existing customer record |
line_items |
object[] | Yes | Array of items (1–100) |
line_items[].variant_id |
string | Yes | Variant ID to order |
line_items[].quantity |
integer | Yes | Quantity (1–999) |
line_items[].unit_price |
integer | No | Override price in cents. Uses variant price if omitted |
shipping_address |
object | No | Shipping address (see address fields) |
billing_address |
object | No | Billing address |
tax |
integer | No | Tax amount in cents (default: 0) |
shipping_cost |
integer | No | Shipping cost in cents (default: 0) |
discount |
integer | No | Discount amount in cents (default: 0) |
notes |
string | No | Internal notes (max 5,000 chars) |
metadata |
object | No | Arbitrary key-value pairs (max 50 keys) |
⚠Inventory deduction
Creating an order immediately deducts inventory from each variant. If any variant has insufficient
stock, the request fails with a 409 Conflict and no inventory is modified.
Request
curl -X POST https://api.hydrajs.dev/v1/orders \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"customer_email": "jane@example.com",
"customer_id": "cus_xyz789",
"line_items": [
{
"variant_id": "var_def456",
"quantity": 2
},
{
"variant_id": "var_ghi012",
"quantity": 1,
"unit_price": 1999
}
],
"shipping_address": {
"first_name": "Jane",
"last_name": "Doe",
"line1": "123 Main St",
"city": "Austin",
"state": "TX",
"postal_code": "78701",
"country": "US"
},
"tax": 480,
"tax_inclusive": false,
"shipping_cost": 599
}'
Response 201
{
"data": {
"id": "ord_abc123",
"order_number": 1042,
"status": "open",
"financial_status": "pending",
"fulfillment_status": "unfulfilled",
"customer_id": "cus_xyz789",
"customer_email": "jane@example.com",
"subtotal": 7997,
"tax": 480,
"tax_inclusive": false,
"shipping_cost": 599,
"discount": 0,
"total": 9076,
"currency": "USD",
"shipping_address": {
"first_name": "Jane",
"last_name": "Doe",
"line1": "123 Main St",
"city": "Austin",
"state": "TX",
"postal_code": "78701",
"country": "US"
},
"billing_address": null,
"notes": null,
"metadata": {},
"stripe_payment_intent_id": null,
"platform_fee": 40,
"platform_fee_percent": 0.5,
"line_items": [
{
"id": "li_aaa111",
"order_id": "ord_abc123",
"product_id": "prod_abc123",
"variant_id": "var_def456",
"title": "Classic T-Shirt",
"variant_title": "Medium / Black",
"sku": "TS-MD-BLK",
"quantity": 2,
"unit_price": 2999,
"total": 5998,
"created_at": "2026-08-15T14:30:00Z"
},
{
"id": "li_bbb222",
"order_id": "ord_abc123",
"product_id": "prod_xyz789",
"variant_id": "var_ghi012",
"title": "Slim Jeans",
"variant_title": "32W / Indigo",
"sku": "JN-32-IND",
"quantity": 1,
"unit_price": 1999,
"total": 1999,
"created_at": "2026-08-15T14:30:00Z"
}
],
"created_at": "2026-08-15T14:30:00Z",
"updated_at": "2026-08-15T14:30:00Z"
}
}
Get an order
GET /v1/orders/{id}
Returns a single order by ID. Use expand to include related resources inline.
Query parameters
| Parameter | Type | Description |
|---|---|---|
expand |
string | Comma-separated: line_items, tax_lines |
fields |
string | Comma-separated fields to return |
Request
curl https://api.hydrajs.dev/v1/orders/ord_abc123?expand=line_items \
-H "Authorization: Bearer pk_live_YOUR_KEY"
Response 200
{
"data": {
"id": "ord_abc123",
"order_number": 1042,
"status": "open",
"financial_status": "paid",
"fulfillment_status": "unfulfilled",
"customer_id": "cus_xyz789",
"customer_email": "jane@example.com",
"subtotal": 5998,
"tax": 480,
"tax_inclusive": false,
"shipping_cost": 599,
"discount": 0,
"total": 7077,
"currency": "USD",
"base_currency": null,
"exchange_rate": null,
"shipping_address": {
"first_name": "Jane",
"last_name": "Doe",
"line1": "123 Main St",
"city": "Austin",
"state": "TX",
"postal_code": "78701",
"country": "US"
},
"billing_address": null,
"notes": null,
"metadata": {},
"stripe_payment_intent_id": "pi_3abc123",
"platform_fee": 30,
"platform_fee_percent": 0.5,
"line_items": [
{
"id": "li_aaa111",
"order_id": "ord_abc123",
"product_id": "prod_abc123",
"variant_id": "var_def456",
"title": "Classic T-Shirt",
"variant_title": "Medium / Black",
"sku": "TS-MD-BLK",
"quantity": 2,
"unit_price": 2999,
"total": 5998,
"created_at": "2026-08-15T14:30:00Z"
}
],
"created_at": "2026-08-15T14:30:00Z",
"updated_at": "2026-08-15T14:35:00Z"
}
}
ℹPublic access
The get order endpoint accepts publishable keys, allowing storefront clients to display order confirmation pages after checkout. Line items must be explicitly expanded.
Update order status
PATCH /v1/orders/{id}
Updates an order’s status, financial status, or fulfillment status. State transitions are validated – invalid transitions return 400.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
status |
string | No | open, closed, cancelled |
financial_status |
string | No | pending, paid, partially_refunded, refunded |
fulfillment_status |
string | No | unfulfilled, partial, fulfilled |
notes |
string | No | Internal notes (max 5,000 chars) |
metadata |
object | No | Arbitrary key-value pairs (max 50 keys) |
⚠State machine
Status transitions are enforced. For example, financial_status can go from pending to paid,
or from paid to refunded, but not from refunded back to pending. Invalid transitions
return a 400 error with a descriptive message.
Valid transitions:
| Field | From | Allowed |
|---|---|---|
status |
open |
closed, cancelled |
status |
closed |
open |
status |
cancelled |
(none) |
financial_status |
pending |
paid |
financial_status |
paid |
partially_refunded, refunded |
financial_status |
partially_refunded |
refunded |
financial_status |
refunded |
(none) |
fulfillment_status |
unfulfilled |
partial, fulfilled |
fulfillment_status |
partial |
fulfilled |
fulfillment_status |
fulfilled |
(none) |
Request
curl -X PATCH https://api.hydrajs.dev/v1/orders/ord_abc123 \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"fulfillment_status": "fulfilled",
"notes": "Shipped via USPS Priority Mail, tracking #9400111899223456789012"
}'
Response 200
{
"data": {
"id": "ord_abc123",
"order_number": 1042,
"status": "open",
"financial_status": "paid",
"fulfillment_status": "fulfilled",
"customer_id": "cus_xyz789",
"customer_email": "jane@example.com",
"subtotal": 5998,
"tax": 480,
"tax_inclusive": false,
"shipping_cost": 599,
"discount": 0,
"total": 7077,
"currency": "USD",
"notes": "Shipped via USPS Priority Mail, tracking #9400111899223456789012",
"metadata": {},
"created_at": "2026-08-15T14:30:00Z",
"updated_at": "2026-08-17T09:15:00Z"
}
}
Error 400 – invalid transition
{
"error": {
"code": "invalid_request",
"message": "Cannot transition fulfillment_status from \"fulfilled\" to \"unfulfilled\"."
}
}
Download invoice PDF
GET /v1/orders/{id}/invoice
Generates and returns a PDF invoice for the order. The invoice number is permanently assigned on first access and returned in subsequent GET /v1/orders/{id} responses as invoice_number.
Auth: Secret key required
Response: application/pdf binary with Content-Disposition: inline
Example request
curl https://api.hydrajs.dev/v1/orders/ord_abc123/invoice \
-H "Authorization: Bearer sk_live_..." \
-o invoice.pdf
The generated PDF includes:
- Store business info (name, address, tax ID) from project settings
- Invoice number (auto-incrementing, customizable prefix via
invoice_prefixon store settings) - Order line items with quantities and prices
- Tax breakdown by rate
- Discount and shipping totals
- Payment status
- Brand logo (if configured)
Test mode orders produce a watermarked “DRAFT” invoice.
Webhooks
Order changes fire the following webhook events:
| Event | Trigger |
|---|---|
order.created |
Order created (manual or via checkout) |
order.paid |
financial_status changed to paid |
order.fulfilled |
fulfillment_status changed to fulfilled |
order.cancelled |
status changed to cancelled |
order.refunded |
financial_status changed to refunded |
See Webhooks for subscription setup.
The order object
| Field | Type | Description |
|---|---|---|
id |
string | Unique ID (prefix: ord_) |
order_number |
integer | Auto-incrementing order number, unique per project |
status |
string | open, closed, cancelled |
financial_status |
string | pending, paid, partially_refunded, refunded |
fulfillment_status |
string | unfulfilled, partial, fulfilled |
customer_id |
string | null | Linked customer ID |
customer_email |
string | Customer email address |
subtotal |
integer | Sum of line item totals, in cents |
tax |
integer | Tax amount in cents |
tax_inclusive |
boolean | Whether prices include tax (true = tax is included in the total, false = tax is added on top) |
shipping_cost |
integer | Shipping cost in cents |
discount |
integer | Discount amount in cents |
total |
integer | Grand total in cents (subtotal + tax + shipping - discount) |
currency |
string | 3-letter ISO currency code |
base_currency |
string | null | Store’s base currency (set for multi-currency orders) |
exchange_rate |
number | null | FX rate applied at checkout |
fx_quote_id |
string | null | Stripe FX quote ID for rate locking |
shipping_address |
object | null | Shipping address with first_name, last_name, line1, line2, city, state, postal_code, country |
billing_address |
object | null | Billing address (same shape as shipping) |
notes |
string | null | Internal notes |
metadata |
object | Arbitrary key-value pairs |
invoice_number |
string | null | Assigned when invoice is first generated (e.g. INV-0001). null until GET /v1/orders/{id}/invoice is called. |
stripe_payment_intent_id |
string | null | Stripe PaymentIntent ID (set for checkout orders) |
platform_fee |
integer | Platform fee in cents, calculated as subtotal × platform_fee_percent |
platform_fee_percent |
number | Platform fee rate applied to this order (e.g. 0.5 for Pro, 2 for Free) |
line_items |
object[] | Expanded with ?expand=line_items. Each: id, order_id, product_id, variant_id, title, variant_title, sku, quantity, unit_price, total, created_at |
tax_lines |
object[] | Expanded with ?expand=tax_lines. Per-jurisdiction tax breakdown (see The tax line object) |
created_at |
string | ISO 8601 timestamp |
updated_at |
string | ISO 8601 timestamp |
The tax line object
| Field | Type | Description |
|---|---|---|
id |
string | Unique ID (prefix: otl_) |
name |
string | Tax name (e.g. “CA State Tax”) |
rate |
number | Tax rate percentage (e.g. 7.25) |
amount |
integer | Tax amount in cents |
country |
string | 2-letter ISO country code |
state |
string | null | State/province code |
tax_group_id |
string | null | Tax group ID if a group-specific rate was applied |
type |
string | line_item or shipping |
source |
string | automatic or manual |