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

Draft Orders API
On this page

Draft Orders

Draft orders are merchant-initiated orders that haven’t been finalized. The merchant builds them incrementally — adding items, setting a customer, adjusting pricing — then completes the draft, which creates a real order with inventory deduction and order number assignment.

Draft orders support both variant-based items (resolved from your product catalog) and custom items (freeform title and price with no variant reference).

Base URL: https://api.hydrajs.dev

Endpoints

Method Path Auth Description
GET /v1/draft-orders Secret List draft orders
POST /v1/draft-orders Secret Create a draft order
GET /v1/draft-orders/{id} Secret Get a draft order
PATCH /v1/draft-orders/{id} Secret Update a draft order
DELETE /v1/draft-orders/{id} Secret Delete a draft order
POST /v1/draft-orders/{id}/items Secret Add line items
PATCH /v1/draft-orders/{id}/items/{item_id} Secret Update a line item
DELETE /v1/draft-orders/{id}/items/{item_id} Secret Remove a line item
POST /v1/draft-orders/{id}/complete Secret Complete draft into a real order
POST /v1/draft-orders/{id}/send Secret Send payment request to customer

List draft orders

GET /v1/draft-orders

Returns a paginated list of draft orders. Supports filtering by status and customer email.

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 string desc Sort direction: asc, desc
status string Filter by status: open, sent, completed
customer_email string Filter by customer email
expand string Comma-separated: items
fields string Comma-separated fields to return

Request

curl https://api.hydrajs.dev/v1/draft-orders?status=open&limit=10 \
  -H "Authorization: Bearer sk_live_YOUR_KEY"

Response 200

{
	"data": [
		{
			"id": "dord_abc123",
			"status": "open",
			"customer_id": null,
			"customer_email": null,
			"subtotal": 5998,
			"tax": 0,
			"tax_data": null,
			"tax_inclusive": false,
			"shipping_cost": 0,
			"discount": 0,
			"total": 5998,
			"currency": "USD",
			"order_id": null,
			"completed_at": null,
			"item_count": 2,
			"notes": null,
			"metadata": {},
			"created_at": "2026-08-20T10:00:00Z",
			"updated_at": "2026-08-20T10:05:00Z"
		}
	],
	"pagination": {
		"cursor": "eyJ0IjoiMjAyNi...",
		"has_more": false,
		"total": 1
	}
}

Create a draft order

POST /v1/draft-orders

Creates a new empty draft order. Line items are added separately via the add-items endpoint.

Request body

Field Type Required Description
currency string Yes 3-letter ISO currency code
customer_id string No Link to an existing customer
customer_email string No Customer email address
shipping_address object No Shipping address
billing_address object No Billing address
notes string No Internal notes (max 5,000 chars)
metadata object No Arbitrary key-value pairs (max 50 keys)

Request

curl -X POST https://api.hydrajs.dev/v1/draft-orders \
  -H "Authorization: Bearer sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "currency": "USD",
    "customer_email": "jane@example.com"
  }'

Response 201

{
	"data": {
		"id": "dord_abc123",
		"draft_number": 1,
		"status": "open",
		"customer_id": null,
		"customer_email": "jane@example.com",
		"subtotal": 0,
		"tax": 0,
		"tax_data": null,
		"tax_inclusive": false,
		"shipping_cost": 0,
		"discount": 0,
		"total": 0,
		"currency": "USD",
		"shipping_address": null,
		"billing_address": null,
		"notes": null,
		"payment_terms": "due_on_receipt",
		"payment_due_date": null,
		"order_id": null,
		"completed_at": null,
		"item_count": 0,
		"metadata": {},
		"created_at": "2026-08-20T10:00:00Z",
		"updated_at": "2026-08-20T10:00:00Z"
	}
}

Get a draft order

GET /v1/draft-orders/{id}

Returns a single draft order. Use ?expand=items to include line items inline.

Query parameters

Parameter Type Description
expand string Comma-separated: items
fields string Comma-separated fields to return

Request

curl https://api.hydrajs.dev/v1/draft-orders/dord_abc123?expand=items \
  -H "Authorization: Bearer sk_live_YOUR_KEY"

Response 200

{
	"data": {
		"id": "dord_abc123",
		"status": "open",
		"customer_id": "cus_xyz789",
		"customer_email": "jane@example.com",
		"subtotal": 5998,
		"tax": 480,
		"tax_data": null,
		"tax_inclusive": false,
		"shipping_cost": 599,
		"discount": 0,
		"total": 7077,
		"currency": "USD",
		"shipping_address": null,
		"billing_address": null,
		"order_id": null,
		"completed_at": null,
		"item_count": 2,
		"notes": "Phone order for Jane",
		"metadata": {},
		"items": [
			{
				"id": "doli_aaa111",
				"draft_order_id": "dord_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,
				"is_custom": false,
				"note": null,
				"created_at": "2026-08-20T10:01:00Z"
			}
		],
		"created_at": "2026-08-20T10:00:00Z",
		"updated_at": "2026-08-20T10:05:00Z"
	}
}

Update a draft order

PATCH /v1/draft-orders/{id}

Updates draft order fields. Recalculates the total when tax, shipping, or discount change.

Request body

Field Type Required Description
customer_id string | null No Customer ID (null to clear)
customer_email string | null No Customer email (null to clear)
currency string No 3-letter ISO currency code (only changeable when item_count=0)
shipping_address object | null No Shipping address (null to clear)
billing_address object | null No Billing address (null to clear)
tax integer No Tax amount in cents (ignored when tax calculation is enabled)
shipping_cost integer No Shipping cost in cents
discount integer No Discount amount in cents
notes string | null No Internal notes (null to clear)
metadata object No Arbitrary key-value pairs

Request

curl -X PATCH https://api.hydrajs.dev/v1/draft-orders/dord_abc123 \
  -H "Authorization: Bearer sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "tax": 480,
    "shipping_cost": 599,
    "notes": "Phone order for Jane"
  }'

Response 200

Returns the updated draft order object.


Delete a draft order

DELETE /v1/draft-orders/{id}

Permanently deletes a draft order and its line items. Completed drafts cannot be deleted.

Request

curl -X DELETE https://api.hydrajs.dev/v1/draft-orders/dord_abc123 \
  -H "Authorization: Bearer sk_live_YOUR_KEY"

Response 204

No response body.


Add items to a draft order

POST /v1/draft-orders/{id}/items

Adds one or more line items. Supports two types: variant-based items (price resolved from the variant) and custom items (freeform title and price).

Request body

Field Type Required Description
items object[] Yes Array of items (1–100)

Each item is one of:

Variant-based item:

Field Type Required Description
variant_id string Yes Variant to add
quantity integer Yes Quantity (1–999)

Custom item:

Field Type Required Description
title string Yes Custom item name
unit_price integer Yes Price in cents
quantity integer Yes Quantity (1–999)

Request

curl -X POST https://api.hydrajs.dev/v1/draft-orders/dord_abc123/items \
  -H "Authorization: Bearer sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "items": [
      { "variant_id": "var_def456", "quantity": 2 },
      { "title": "Gift wrapping", "unit_price": 500, "quantity": 1 }
    ]
  }'

Response 201

{
	"data": [
		{
			"id": "doli_aaa111",
			"draft_order_id": "dord_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,
			"is_custom": false,
			"note": null,
			"created_at": "2026-08-20T10:01:00Z"
		},
		{
			"id": "doli_bbb222",
			"draft_order_id": "dord_abc123",
			"product_id": null,
			"variant_id": null,
			"title": "Gift wrapping",
			"variant_title": "",
			"sku": null,
			"quantity": 1,
			"unit_price": 500,
			"total": 500,
			"is_custom": true,
			"note": null,
			"created_at": "2026-08-20T10:01:00Z"
		}
	]
}

Subtotal recalculation

Adding items automatically recalculates the draft order’s subtotal and total. You don’t need to update these values manually.


Update a line item

PATCH /v1/draft-orders/{id}/items/{item_id}

Updates a line item’s quantity, note, and (for custom items only) price and title. Variant-based items only allow quantity and note changes — use the order-level discount field for price adjustments.

Request body

Field Type Required Description
quantity integer No New quantity (1–999)
unit_price integer No New price in cents (custom items only)
title string No New title (custom items only)
note string | null No Per-item note (max 1,000 chars)

Request

curl -X PATCH https://api.hydrajs.dev/v1/draft-orders/dord_abc123/items/doli_aaa111 \
  -H "Authorization: Bearer sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "quantity": 3 }'

Response 200

Returns the updated line item object.

Variant item restrictions

Attempting to update unit_price or title on a variant-based line item returns a 400 error. Variant prices are resolved from the product catalog and cannot be overridden on individual items.


Remove a line item

DELETE /v1/draft-orders/{id}/items/{item_id}

Removes a line item and recalculates the draft order’s subtotal and total.

Request

curl -X DELETE https://api.hydrajs.dev/v1/draft-orders/dord_abc123/items/doli_aaa111 \
  -H "Authorization: Bearer sk_live_YOUR_KEY"

Response 204

No response body.


Complete a draft order

POST /v1/draft-orders/{id}/complete

Completes a draft order by creating a real order. This is the key operation — it:

  1. Validates the draft has a customer email and at least one line item
  2. Creates a real order via the order creation pipeline (advisory-locked order numbering, platform fee)
  3. Deducts inventory for variant-based items (custom items have no inventory impact)
  4. Sets the draft’s status to completed and links it to the new order
  5. Dispatches draft_order.completed and order.created webhook events

Irreversible

Completing a draft order cannot be undone. Inventory is deducted and an order number is assigned permanently.

Request

curl -X POST https://api.hydrajs.dev/v1/draft-orders/dord_abc123/complete \
  -H "Authorization: Bearer sk_live_YOUR_KEY"

Response 201

Returns the created order object (same shape as POST /v1/orders).

Error 400 – validation failure

{
	"error": {
		"code": "invalid_request",
		"message": "Draft order must have a customer email before completing."
	}
}

Send payment request

POST /v1/draft-orders/{id}/send

Sends a payment request email to the customer and marks the draft order’s status as sent. The email includes the full order details (line items, totals, addresses) and a “Pay now” button linking to checkout if the store has a verified domain.

The draft must be open with a customer email and at least one line item.

Request body (optional)

Field Type Description
subject string Override the default email subject line. Max 200 characters.
message string Custom message displayed above the order summary. Max 5,000 characters.
cc string[] CC recipients (up to 5 email addresses). Visible to all recipients.
bcc string[] BCC recipients (up to 5 email addresses). Hidden from other recipients.

All fields are optional. If omitted, the default subject (“Order #{draft_number} from {store}”) and body are used.

Request

curl -X POST https://api.hydrajs.dev/v1/draft-orders/dord_abc123/send \
  -H "Authorization: Bearer sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "subject": "Your order from My Store",
    "message": "Here are the details of the order we discussed.",
    "cc": ["sales@example.com"]
  }'

Response 200

Returns the updated draft order with status: "sent".


Webhooks

Draft order changes fire the following webhook events:

Event Trigger
draft_order.created Draft order created
draft_order.updated Draft order fields or line items changed
draft_order.completed Draft completed into a real order
draft_order.deleted Draft order deleted

Completing a draft also fires order.created and potentially inventory.low for the resulting order.

See Webhooks for subscription setup.


The draft order object

Field Type Description
id string Unique ID (prefix: dord_)
status string open, sent, completed
customer_id string | null Linked customer ID
customer_email string | null Customer email (required before completion)
subtotal integer Sum of line item totals, in cents
tax integer Tax amount in cents (auto-calculated when tax calculation is enabled)
tax_data object | null Tax breakdown (total_tax, tax_inclusive, source, tax_lines[])
tax_inclusive boolean Whether tax is included in item prices
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
shipping_address object | null Shipping address
billing_address object | null Billing address
order_id string | null Linked order ID (set when completed)
completed_at string | null ISO 8601 timestamp of completion
item_count integer Number of line items
notes string | null Internal notes
metadata object Arbitrary key-value pairs
items object[] Expanded with ?expand=items
created_at string ISO 8601 timestamp
updated_at string ISO 8601 timestamp

The draft order line item object

Field Type Description
id string Unique ID (prefix: doli_)
draft_order_id string Parent draft order ID
product_id string | null Product ID (null for custom items)
variant_id string | null Variant ID (null for custom items)
title string Product or custom item title
variant_title string Variant title (empty string for custom items)
sku string | null SKU at time of addition
quantity integer Item quantity
unit_price integer Price per unit in cents
total integer quantity x unit_price
is_custom boolean true for freeform items with no variant
note string | null Per-item note
created_at string ISO 8601 timestamp