Hydra is now in beta|Get started free|Follow our journey on X.com

Orders API
On this page

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_prefix on 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