Shopify API Reference
All public store endpoints are unauthenticated — L402 payment proof serves as authorization. Admin endpoints require your Lightning Enable API key.
Base URL: https://api.lightningenable.com
Public Endpoints
These endpoints are accessible without an API key. The {slug} parameter is the URL-safe identifier you chose when creating the integration.
Get Catalog
Fetches the product catalog from your Shopify store. Results are cached.
GET /api/shopify/{slug}/catalog
Response: 200 OK
{
"storeName": "your-store.com",
"slug": "your-store",
"shipping": {
"domesticUsd": 5.99,
"domesticOnly": true,
"freeShippingEnabled": true,
"freeShippingThresholdUsd": 50.00
},
"products": [
{
"productId": 8234567890123,
"title": "Premium Coffee Beans",
"description": "Single-origin Ethiopian coffee, light roast",
"imageUrl": "https://cdn.shopify.com/s/files/...",
"variants": [
{
"variantId": 44567890123456,
"title": "12oz Bag",
"priceUsd": 18.99,
"available": true
},
{
"variantId": 44567890123457,
"title": "2lb Bag",
"priceUsd": 34.99,
"available": true
}
]
}
]
}
Error Responses:
| Status | Meaning |
|---|---|
404 | Integration not found or inactive |
Create Checkout
Creates an L402 checkout with a Lightning invoice. Returns HTTP 402 with the payment challenge.
POST /api/shopify/{slug}/checkout
Request Body:
{
"items": [
{ "variantId": 44567890123456, "quantity": 2 },
{ "variantId": 44567890123457, "quantity": 1 }
]
}
Validation Rules:
- 1–10 items per checkout
- Each item quantity: 1–10
- Total quantity across all items: max 10
- All variant IDs must exist in the catalog
- All variants must be available (in stock)
Response: 402 Payment Required
The response includes a WWW-Authenticate header with the L402 challenge:
WWW-Authenticate: L402 macaroon="...", invoice="lnbc..."
Response Body:
{
"orderId": "shpfy_a1b2c3d4e5f6",
"items": [
{
"variantId": 44567890123456,
"productTitle": "Premium Coffee Beans",
"variantTitle": "12oz Bag",
"quantity": 2,
"priceUsd": 18.99
},
{
"variantId": 44567890123457,
"productTitle": "Premium Coffee Beans",
"variantTitle": "2lb Bag",
"quantity": 1,
"priceUsd": 34.99
}
],
"subtotalUsd": 72.97,
"shippingUsd": 0.00,
"totalUsd": 72.97,
"totalSats": 72150,
"claimToken": "SC-x7k9m2p4",
"claimExpiresAt": "2026-03-05T18:30:00Z",
"invoice": "lnbc721500n1pn...",
"macaroonBase64": "AgELbGlnaHRuaW5n...",
"paymentHash": "a1b2c3d4e5f6...",
"invoiceExpiresAt": "2026-02-26T18:40:00Z"
}
Key Fields:
invoice— BOLT11 Lightning invoice to paymacaroonBase64— L402 macaroon (save this for the claim step)paymentHash— links the macaroon to the invoiceclaimToken— used to claim the order with shipping details (configurable expiry, default 30 days)totalSats— BTC amount locked at current exchange rate
Error Responses:
| Status | Meaning |
|---|---|
400 | Invalid cart (bad variant ID, unavailable item, exceeds limits) |
404 | Integration not found |
Claim Order
Claims an order after payment: verifies L402 proof, saves shipping details, and creates a Shopify order.
POST /api/shopify/{slug}/claim
Headers:
Authorization: L402 {macaroonBase64}:{preimageHex}
Content-Type: application/json
The Authorization header format is L402 <macaroon>:<preimage>:
macaroon— themacaroonBase64from the checkout responsepreimage— the 64-character hex preimage obtained after paying the invoice
Request Body:
{
"claimToken": "SC-x7k9m2p4",
"email": "customer@example.com",
"shippingAddress": {
"firstName": "Jane",
"lastName": "Doe",
"address1": "123 Main St",
"address2": "Apt 4B",
"city": "Austin",
"province": "TX",
"zip": "78701",
"country": "US",
"phone": "+15125551234"
}
}
Shipping Address Fields:
| Field | Required | Max Length |
|---|---|---|
firstName | Yes | 200 |
lastName | Yes | 200 |
address1 | Yes | 500 |
address2 | No | 500 |
city | Yes | 100 |
province | No | 100 |
zip | No | 20 |
country | Yes | 100 |
phone | No | 30 |
Response: 200 OK
{
"orderId": "shpfy_a1b2c3d4e5f6",
"status": "PaidWithDetails",
"shopifyOrderNumber": "#1042",
"message": "Order #1042 created successfully. You'll receive shipping confirmation at customer@example.com."
}
Error Responses:
| Status | Meaning |
|---|---|
400 | Invalid claim token, expired token, already claimed, invalid L402 proof |
401 | L402 verification failed |
404 | Claim token not found |
Get Order Status
Check the status of an order. Requires the claim token as a query parameter.
GET /api/shopify/{slug}/orders/{orderId}?claimToken={claimToken}
Response: 200 OK
{
"orderId": "shpfy_a1b2c3d4e5f6",
"status": "Shipped",
"totalUsd": 72.97,
"paidSats": 72150,
"shopifyOrderNumber": "#1042",
"trackingNumber": "1Z999AA10123456784",
"trackingCarrier": "UPS",
"trackingUrl": "https://www.ups.com/track?tracknum=1Z999AA10123456784",
"createdAt": "2026-02-26T18:30:00Z",
"paidAt": "2026-02-26T18:31:15Z",
"shippedAt": "2026-02-28T14:22:00Z"
}
Error Responses:
| Status | Meaning |
|---|---|
401 | Claim token doesn't match the order |
404 | Order not found |
Merchant Admin Endpoints
These endpoints require your Lightning Enable API key in the X-API-Key header.
Get Integration
GET /api/merchant/shopify
Returns your Shopify integration configuration. The Admin API token is never returned — only hasAdminApiToken: true/false.
Create Integration
POST /api/merchant/shopify
See Setup Guide for the full request schema.
Update Integration
PUT /api/merchant/shopify
Partial update — include only the fields you want to change.
{
"domesticShippingUsd": 6.99,
"freeShippingEnabled": true,
"isActive": false,
"listInRegistry": true,
"registryCategories": "[\"commerce\",\"food-and-beverage\"]",
"registryDescription": "Your store description for agent discovery."
}
Invalidate Cache
POST /api/merchant/shopify/invalidate-cache
Forces a refresh of the cached product catalog on the next request.
List Orders
GET /api/merchant/shopify/orders
GET /api/merchant/shopify/orders?status=PaidWithDetails
GET /api/merchant/shopify/orders?page=2&pageSize=10
Query Parameters:
| Parameter | Default | Description |
|---|---|---|
status | (all) | Filter by status: PendingPayment, PaidAwaitingDetails, PaidWithDetails, Fulfilled, Shipped |
page | 1 | Page number |
pageSize | 20 | Results per page |
Response:
[
{
"orderId": "shpfy_a1b2c3d4e5f6",
"status": "PaidWithDetails",
"totalUsd": 72.97,
"paidSats": 72150,
"email": "customer@example.com",
"shopifyOrderNumber": "#1042",
"createdAt": "2026-02-26T18:30:00Z"
}
]
Complete Purchase Flow Example
Here's the full flow using curl:
# 1. Browse products
CATALOG=$(curl -s https://api.lightningenable.com/api/shopify/my-store/catalog)
echo "$CATALOG" | jq '.products[0].variants[0]'
# 2. Create checkout (get variant ID from catalog)
CHECKOUT=$(curl -s -X POST https://api.lightningenable.com/api/shopify/my-store/checkout \
-H "Content-Type: application/json" \
-d '{"items": [{"variantId": 44567890123456, "quantity": 1}]}')
# Extract the invoice and macaroon
INVOICE=$(echo "$CHECKOUT" | jq -r '.invoice')
MACAROON=$(echo "$CHECKOUT" | jq -r '.macaroonBase64')
CLAIM_TOKEN=$(echo "$CHECKOUT" | jq -r '.claimToken')
# 3. Pay the invoice (using Lightning Enable MCP, lncli, or any Lightning wallet)
# This gives you the preimage (64 hex chars)
PREIMAGE="your_preimage_hex_here"
# 4. Claim the order
curl -X POST https://api.lightningenable.com/api/shopify/my-store/claim \
-H "Content-Type: application/json" \
-H "Authorization: L402 ${MACAROON}:${PREIMAGE}" \
-d "{
\"claimToken\": \"${CLAIM_TOKEN}\",
\"email\": \"customer@example.com\",
\"shippingAddress\": {
\"firstName\": \"Jane\",
\"lastName\": \"Doe\",
\"address1\": \"123 Main St\",
\"city\": \"Austin\",
\"province\": \"TX\",
\"zip\": \"78701\",
\"country\": \"US\"
}
}"
# 5. Check order status
curl "https://api.lightningenable.com/api/shopify/my-store/orders/shpfy_abc123?claimToken=${CLAIM_TOKEN}"
Edge Cases
| Scenario | What Happens |
|---|---|
| BTC price moves after checkout | The sats amount is locked in the Lightning invoice at checkout time. The invoice expires in ~10 minutes. |
| Product goes out of stock | Checked at checkout time against cached catalog. At claim time, Shopify's decrement_obeying_policy handles inventory. |
| Claim token used twice | Second claim is rejected — tokens are single-use. |
| Shopify order creation fails | Order stays in PaidAwaitingDetails. Payment is safe. Can be retried via admin. |
| Invoice expires before payment | Order stays in PendingPayment. Agent must create a new checkout. |
| Claim token expires | Contact the merchant for manual resolution. Payment is recorded. Default expiry is 30 days (configurable). |