{"openapi":"3.1.0","info":{"title":"OpenStock Public API","version":"1.0.0","description":"Store-scoped checkout sessions, cryptocurrency withdrawals, and customer balances. This specification describes the supported public API; dashboard session endpoints are not public API-key endpoints."},"servers":[{"url":"https://openstock.dev"}],"tags":[{"name":"Checkout sessions"},{"name":"Withdrawals"},{"name":"Customer balance"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"Store API key","description":"A secret sk_ key with the permission required by the endpoint. Keep it on your server."}}},"paths":{"/api/checkout-api/sessions":{"post":{"operationId":"api_checkout_create_session","tags":["Checkout sessions"],"summary":"Create session","description":"Creates a hosted checkout session and returns the URL to redirect your customer to. Pass either `line_items` (custom priced items) or `product_ids` (products from your store, delivered automatically) — not both.\n\nKeys with no permissions at all are accepted by the Checkout API for backwards compatibility.","security":[{"bearerAuth":[]}],"x-required-permission":"checkout_api","x-rate-limit":"100 requests / hour","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"line_items":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"Item name shown at checkout."},"price":{"type":"number","description":"Unit price in the store currency."},"quantity":{"type":"integer","description":"Positive integer.","default":1},"description":{"type":"string","description":"Optional line description."},"image_url":{"type":"string","description":"Optional image shown next to the item."}},"required":["name","price"]},"description":"Custom items with their own name and price. Required unless `product_ids` is set."},"product_ids":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Product ID."},"quantity":{"type":"integer","description":"Positive integer, limited by available stock.","default":1},"variant_id":{"type":"string","description":"Variant ID for products with variants."},"variant_name_or_id":{"type":"string","description":"Alternative to `variant_id`: matches a variant by ID or case-insensitive name."}},"required":["id"]},"description":"Products from your store. Stock is checked and delivery is handled for you. Required unless `line_items` is set."},"customer_email":{"type":"string","description":"Prefills the email field at checkout."},"customer_name":{"type":"string","description":"Prefills the customer name."},"success_url":{"type":"string","description":"Where the customer lands after paying."},"cancel_url":{"type":"string","description":"Where the customer lands if they abandon checkout."},"expired_url":{"type":"string","description":"Where the customer is sent if the session has expired."},"webhook_url":{"type":"string","description":"Receives `checkout.session.*` events for this session."},"expires_in_seconds":{"type":"number","description":"Session lifetime in seconds. Takes precedence over `expires_in_hours`."},"expires_in_hours":{"type":"number","description":"Session lifetime in hours.","default":24},"metadata":{"type":"object","description":"Key/value pairs echoed back in webhooks."},"client_reference_id":{"type":"string","description":"Your own identifier for this checkout, echoed back in webhooks."},"hide_navbar":{"type":"boolean","description":"Hide the store navbar on the checkout page.","default":false},"hide_footer":{"type":"boolean","description":"Hide the store footer on the checkout page.","default":false},"disable_coupons":{"type":"boolean","description":"Prevent coupon codes for this session.","default":false},"disable_gift_cards":{"type":"boolean","description":"Prevent gift card redemption for this session.","default":false}}},"example":{"line_items":[{"name":"Premium License","price":29.99,"quantity":1}],"customer_email":"jane@example.com","success_url":"https://example.com/success","cancel_url":"https://example.com/cancel","webhook_url":"https://example.com/webhooks/checkout","expires_in_seconds":1800,"metadata":{"orderNumber":"ORD-4821"}}}}},"responses":{"201":{"description":"Session created.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"},"status":{"type":"string"},"total_amount":{"type":"number"},"currency":{"type":"string"},"expires_at":{"type":"string"},"line_items":{"type":"number"}}},"example":{"id":"cs_9f2c4e1a7b3d4c5e8f90a1b2c3d4e5f6","url":"https://your-store.openstock.dev/checkout?session=cs_9f2c4e1a7b3d4c5e8f90a1b2c3d4e5f6","status":"pending","total_amount":29.99,"currency":"USD","expires_at":"2026-03-04T18:50:00.000Z","line_items":1}}}},"400":{"description":"Invalid body, unknown product, unavailable product or insufficient stock.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}},"example":{"error":"invalid_request","message":"Either line_items or product_ids is required (as a non-empty array)"}}}},"401":{"description":"Missing, malformed, disabled or expired API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}},"example":{"error":"unauthorized","message":"Missing or invalid Authorization header. Use: Bearer sk_..."}}}},"429":{"description":"The hourly limit for this key was reached.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"},"retry_after":{"type":"number"}}},"example":{"error":"rate_limit_exceeded","message":"Rate limit exceeded. Maximum 100 requests per hour.","retry_after":1260}}}}}},"get":{"operationId":"api_checkout_list_sessions","tags":["Checkout sessions"],"summary":"List sessions","description":"Returns checkout sessions for the store, newest first.","security":[{"bearerAuth":[]}],"x-required-permission":"checkout_api","parameters":[{"name":"limit","in":"query","required":false,"description":"Number of results to return, between 1 and 100.","schema":{"type":"integer","description":"Number of results to return, between 1 and 100.","default":20}},{"name":"offset","in":"query","required":false,"description":"Number of results to skip.","schema":{"type":"integer","description":"Number of results to skip.","default":0}},{"name":"status","in":"query","required":false,"description":"Filter by status: `pending`, `completed`, `cancelled` or `expired`.","schema":{"type":"string","description":"Filter by status: `pending`, `completed`, `cancelled` or `expired`."}}],"responses":{"200":{"description":"A page of sessions.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string"},"total_amount":{"type":"number"},"currency":{"type":"string"},"customer_email":{"type":["string","null"]},"payment_method":{"type":["string","null"]},"created_at":{"type":"string"},"completed_at":{"type":["string","null"]}}}},"total":{"type":"number"},"limit":{"type":"number"},"offset":{"type":"number"}}},"example":{"data":[{"id":"cs_9f2c4e1a7b3d4c5e8f90a1b2c3d4e5f6","status":"pending","total_amount":49.98,"currency":"USD","customer_email":"jane@example.com","payment_method":null,"created_at":"2026-03-04T18:20:00.000Z","completed_at":null}],"total":1,"limit":20,"offset":0}}}},"401":{"description":"Missing, malformed, disabled or expired API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}},"example":{"error":"unauthorized","message":"Missing or invalid Authorization header. Use: Bearer sk_..."}}}}}}},"/api/checkout-api/sessions/{session_id}":{"get":{"operationId":"api_checkout_get_session","tags":["Checkout sessions"],"summary":"Retrieve session","description":"Fetches a single session. Pending sessions past their expiry are marked `expired` when read.","security":[{"bearerAuth":[]}],"x-required-permission":"checkout_api","parameters":[{"name":"session_id","in":"path","required":true,"description":"The `cs_…` ID returned when the session was created.","schema":{"type":"string","description":"The `cs_…` ID returned when the session was created."}}],"responses":{"200":{"description":"The session.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"},"status":{"type":"string"},"total_amount":{"type":"number"},"currency":{"type":"string"},"customer_email":{"type":["string","null"]},"customer_name":{"type":["string","null"]},"payment_method":{"type":["string","null"]},"metadata":{"type":"object","properties":{"orderNumber":{"type":"string"}}},"client_reference_id":{},"line_items":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"price":{"type":"number"},"quantity":{"type":"number"},"image":{},"metadata":{"type":"object","properties":{}}}}},"expires_at":{"type":"string"},"created_at":{"type":"string"}}},"example":{"id":"cs_9f2c4e1a7b3d4c5e8f90a1b2c3d4e5f6","url":"https://your-store.openstock.dev/checkout?session=cs_9f2c4e1a7b3d4c5e8f90a1b2c3d4e5f6","status":"pending","total_amount":29.99,"currency":"USD","customer_email":"jane@example.com","customer_name":null,"payment_method":null,"metadata":{"orderNumber":"ORD-4821"},"client_reference_id":null,"line_items":[{"name":"Premium License","description":"","price":29.99,"quantity":1,"image":null,"metadata":{}}],"expires_at":"2026-03-04T18:50:00.000Z","created_at":"2026-03-04T18:20:00.000Z"}}}},"401":{"description":"Missing, malformed, disabled or expired API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}},"example":{"error":"unauthorized","message":"Missing or invalid Authorization header. Use: Bearer sk_..."}}}},"404":{"description":"No session with that ID belongs to this store.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}},"example":{"error":"session_not_found","message":"Checkout session not found"}}}}}}},"/api/checkout-api/sessions/{session_id}/cancel":{"post":{"operationId":"api_checkout_cancel_session","tags":["Checkout sessions"],"summary":"Cancel session","description":"Cancels a session that has not been paid. Completed sessions cannot be cancelled.","security":[{"bearerAuth":[]}],"x-required-permission":"checkout_api","parameters":[{"name":"session_id","in":"path","required":true,"description":"The session to cancel.","schema":{"type":"string","description":"The session to cancel."}}],"responses":{"200":{"description":"Session cancelled.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string"}}},"example":{"id":"cs_9f2c4e1a7b3d4c5e8f90a1b2c3d4e5f6","status":"cancelled"}}}},"400":{"description":"The session is already completed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}},"example":{"error":"session_completed","message":"Cannot cancel a completed session"}}}},"401":{"description":"Missing, malformed, disabled or expired API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}},"example":{"error":"unauthorized","message":"Missing or invalid Authorization header. Use: Bearer sk_..."}}}},"404":{"description":"Unknown session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}},"example":{"error":"session_not_found","message":"Checkout session not found"}}}}}}},"/api/withdrawal-api/wallets":{"get":{"operationId":"api_withdrawals_list_wallets","tags":["Withdrawals"],"summary":"List wallets","description":"Lists the store’s active crypto wallets with their balances and minimum withdrawal amounts.","security":[{"bearerAuth":[]}],"x-required-permission":"withdrawal_api","parameters":[],"responses":{"200":{"description":"Active wallets.","content":{"application/json":{"schema":{"type":"object","properties":{"wallets":{"type":"array","items":{"type":"object","properties":{"currency":{"type":"string"},"address":{"type":"string"},"balance":{"type":"number"},"pending_balance":{"type":"number"},"min_withdrawal":{"type":"number"}}}}}},"example":{"wallets":[{"currency":"BTC","address":"bc1qexampleaddressxxxxxxxxxxxxxxxxxxxxxx","balance":0.0123,"pending_balance":0,"min_withdrawal":0.0001},{"currency":"LTC","address":"ltc1qexampleaddressxxxxxxxxxxxxxxxxxxxxx","balance":1.5,"pending_balance":0.2,"min_withdrawal":0.001}]}}}},"401":{"description":"Missing, malformed, disabled or expired API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}},"example":{"error":"unauthorized","message":"Missing or invalid Authorization header. Use: Bearer sk_..."}}}},"403":{"description":"The key lacks the `withdrawal_api` permission.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}},"example":{"error":"permission_denied","message":"API key does not have withdrawal_api permission. Create a new key with this permission."}}}}}}},"/api/withdrawal-api/withdrawals":{"post":{"operationId":"api_withdrawals_create_withdrawal","tags":["Withdrawals"],"summary":"Create withdrawal","description":"Requests a withdrawal from one of the store’s wallets. The request is accepted as `pending` and processed in the background; subscribe with `webhook_url` to learn the outcome.\n\nCrypto transfers cannot be reversed. Validate destination addresses on your side before calling this endpoint.","security":[{"bearerAuth":[]}],"x-required-permission":"withdrawal_api","x-rate-limit":"50 withdrawal requests / hour","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"currency":{"type":"string","description":"`BTC`, `LTC` or `ETH`."},"amount":{"type":"number","description":"Amount to withdraw. Minimums: BTC 0.0001, LTC 0.001, ETH 0.001."},"to_address":{"type":"string","description":"Destination address. Must be valid for the currency and differ from the store wallet."},"webhook_url":{"type":"string","description":"Receives `withdrawal.completed` or `withdrawal.failed`."},"metadata":{"type":"object","description":"Key/value pairs echoed back in webhooks."}},"required":["currency","amount","to_address"]},"example":{"currency":"LTC","amount":0.05,"to_address":"ltc1qexampleaddressxxxxxxxxxxxxxxxxxxxxxx","webhook_url":"https://example.com/webhooks/withdrawals"}}}},"responses":{"201":{"description":"Withdrawal accepted for processing.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string"},"amount":{"type":"number"},"fee_amount":{"type":"number"},"net_amount":{"type":"number"},"currency":{"type":"string"},"to_address":{"type":"string"},"created_at":{"type":"string"}}},"example":{"id":"wd_4b8e2f0c9a1d","status":"pending","amount":0.05,"fee_amount":0.002,"net_amount":0.048,"currency":"LTC","to_address":"ltc1qexampleaddressxxxxxxxxxxxxxxxxxxxxxx","created_at":"2026-03-04T18:30:00.000Z"}}}},"400":{"description":"Invalid currency, amount below minimum, bad address or insufficient balance.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}},"example":{"error":"amount_too_small","message":"Minimum withdrawal for LTC is 0.001"}}}},"401":{"description":"Missing, malformed, disabled or expired API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}},"example":{"error":"unauthorized","message":"Missing or invalid Authorization header. Use: Bearer sk_..."}}}},"404":{"description":"The store has no active wallet for that currency.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}},"example":{"error":"wallet_not_found","message":"No active LTC wallet found for this store. Create one in the dashboard first."}}}},"429":{"description":"The hourly limit for this key was reached.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"},"retry_after":{"type":"number"}}},"example":{"error":"rate_limit_exceeded","message":"Rate limit exceeded. Maximum 50 withdrawal requests per hour.","retry_after":1260}}}}}},"get":{"operationId":"api_withdrawals_list_withdrawals","tags":["Withdrawals"],"summary":"List withdrawals","description":"Returns withdrawals requested through the API, newest first.","security":[{"bearerAuth":[]}],"x-required-permission":"withdrawal_api","parameters":[{"name":"limit","in":"query","required":false,"description":"Number of results to return, between 1 and 100.","schema":{"type":"integer","description":"Number of results to return, between 1 and 100.","default":20}},{"name":"offset","in":"query","required":false,"description":"Number of results to skip.","schema":{"type":"integer","description":"Number of results to skip.","default":0}},{"name":"status","in":"query","required":false,"description":"Filter by status: `pending`, `completed` or `failed`.","schema":{"type":"string","description":"Filter by status: `pending`, `completed` or `failed`."}}],"responses":{"200":{"description":"A page of withdrawals.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string"},"amount":{"type":"number"},"fee_amount":{"type":"number"},"net_amount":{"type":"number"},"currency":{"type":"string"},"to_address":{"type":"string"},"tx_hash":{"type":["string","null"]},"created_at":{"type":"string"},"completed_at":{"type":["string","null"]}}}},"total":{"type":"number"},"limit":{"type":"number"},"offset":{"type":"number"}}},"example":{"data":[{"id":"wd_4b8e2f0c9a1d","status":"completed","amount":0.05,"fee_amount":0.002,"net_amount":0.048,"currency":"LTC","to_address":"ltc1qexampleaddressxxxxxxxxxxxxxxxxxxxxxx","tx_hash":"3f6c…e91a","created_at":"2026-03-04T18:30:00.000Z","completed_at":"2026-03-04T18:31:12.000Z"}],"total":1,"limit":20,"offset":0}}}},"401":{"description":"Missing, malformed, disabled or expired API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}},"example":{"error":"unauthorized","message":"Missing or invalid Authorization header. Use: Bearer sk_..."}}}}}}},"/api/withdrawal-api/withdrawals/{withdrawal_id}":{"get":{"operationId":"api_withdrawals_get_withdrawal","tags":["Withdrawals"],"summary":"Retrieve withdrawal","description":"Fetches a single withdrawal, including the transaction hash once it is broadcast.","security":[{"bearerAuth":[]}],"x-required-permission":"withdrawal_api","parameters":[{"name":"withdrawal_id","in":"path","required":true,"description":"The ID returned when the withdrawal was created.","schema":{"type":"string","description":"The ID returned when the withdrawal was created."}}],"responses":{"200":{"description":"The withdrawal.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string"},"amount":{"type":"number"},"fee_amount":{"type":"number"},"net_amount":{"type":"number"},"currency":{"type":"string"},"to_address":{"type":"string"},"tx_hash":{"type":["string","null"]},"created_at":{"type":"string"},"completed_at":{"type":["string","null"]}}},"example":{"id":"wd_4b8e2f0c9a1d","status":"completed","amount":0.05,"fee_amount":0.002,"net_amount":0.048,"currency":"LTC","to_address":"ltc1qexampleaddressxxxxxxxxxxxxxxxxxxxxxx","tx_hash":"3f6c…e91a","created_at":"2026-03-04T18:30:00.000Z","completed_at":"2026-03-04T18:31:12.000Z"}}}},"401":{"description":"Missing, malformed, disabled or expired API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}},"example":{"error":"unauthorized","message":"Missing or invalid Authorization header. Use: Bearer sk_..."}}}},"404":{"description":"Unknown withdrawal.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}},"example":{"error":"withdrawal_not_found","message":"Withdrawal not found"}}}}}}},"/api/customer-balance-api/customers":{"get":{"operationId":"api_customer_balance_list_customers","tags":["Customer balance"],"summary":"List customers","description":"Lists the store’s customers with their balances, newest first.","security":[{"bearerAuth":[]}],"x-required-permission":"customer_balance_api","parameters":[{"name":"limit","in":"query","required":false,"description":"Number of results to return, between 1 and 100.","schema":{"type":"integer","description":"Number of results to return, between 1 and 100.","default":20}},{"name":"offset","in":"query","required":false,"description":"Number of results to skip.","schema":{"type":"integer","description":"Number of results to skip.","default":0}},{"name":"min_balance","in":"query","required":false,"description":"Only customers with at least this balance.","schema":{"type":"number","description":"Only customers with at least this balance."}},{"name":"search","in":"query","required":false,"description":"Case-insensitive match on email or name.","schema":{"type":"string","description":"Case-insensitive match on email or name."}}],"responses":{"200":{"description":"A page of customers.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"email":{"type":"string"},"name":{"type":"string"},"balance":{"type":"number"},"total_spent":{"type":"number"},"order_count":{"type":"number"},"created_at":{"type":"string"},"updated_at":{"type":"string"}}}},"total":{"type":"number"},"limit":{"type":"number"},"offset":{"type":"number"}}},"example":{"data":[{"id":"6f1d3c2a-0b4e-4c8d-9a7f-2e5b1c0d9a8e","email":"jane@example.com","name":"Jane Doe","balance":25,"total_spent":189.5,"order_count":7,"created_at":"2026-01-12T09:30:00.000Z","updated_at":"2026-03-04T18:30:00.000Z"}],"total":1,"limit":20,"offset":0}}}},"401":{"description":"Missing, malformed, disabled or expired API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}},"example":{"error":"unauthorized","message":"Missing or invalid Authorization header. Use: Bearer sk_..."}}}},"403":{"description":"The key lacks the `customer_balance_api` permission.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}},"example":{"error":"permission_denied","message":"API key does not have customer_balance_api permission. Create a new key with this permission."}}}}}}},"/api/customer-balance-api/customers/info":{"post":{"operationId":"api_customer_balance_get_customer","tags":["Customer balance"],"summary":"Retrieve customer","description":"Looks up one customer by email. The email goes in the JSON body, never in the URL.\n\nEmails in URL paths (for example `/customers/{email}`) are rejected with `deprecated_endpoint`. Always send the email in the body.","security":[{"bearerAuth":[]}],"x-required-permission":"customer_balance_api","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"Customer email address."}},"required":["email"]},"example":{"email":"jane@example.com"}}}},"responses":{"200":{"description":"The customer.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"email":{"type":"string"},"name":{"type":"string"},"balance":{"type":"number"},"total_spent":{"type":"number"},"order_count":{"type":"number"},"created_at":{"type":"string"},"updated_at":{"type":"string"}}},"example":{"id":"6f1d3c2a-0b4e-4c8d-9a7f-2e5b1c0d9a8e","email":"jane@example.com","name":"Jane Doe","balance":25,"total_spent":189.5,"order_count":7,"created_at":"2026-01-12T09:30:00.000Z","updated_at":"2026-03-04T18:30:00.000Z"}}}},"401":{"description":"Missing, malformed, disabled or expired API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}},"example":{"error":"unauthorized","message":"Missing or invalid Authorization header. Use: Bearer sk_..."}}}},"404":{"description":"No customer with that email in this store.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}},"example":{"error":"customer_not_found","message":"Customer with email jane@example.com not found"}}}}}}},"/api/customer-balance-api/customers/add-balance":{"post":{"operationId":"api_customer_balance_add_balance","tags":["Customer balance"],"summary":"Add balance","description":"Credits a customer’s store balance. Customers that do not exist yet are created.","security":[{"bearerAuth":[]}],"x-required-permission":"customer_balance_api","x-rate-limit":"100 requests / hour","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"Customer email address."},"amount":{"type":"number","description":"Positive amount to add."},"reason":{"type":"string","description":"Shown in the customer’s transaction history.","default":"API balance addition"},"metadata":{"type":"object","description":"Stored with the transaction."}},"required":["email","amount"]},"example":{"email":"jane@example.com","amount":10,"reason":"Referral reward"}}}},"responses":{"200":{"description":"Balance updated.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"customer":{"type":"object","properties":{"id":{"type":"string"},"email":{"type":"string"},"balance":{"type":"number"}}},"transaction":{"type":"object","properties":{"type":{"type":"string"},"amount":{"type":"number"},"reason":{"type":"string"}}}}},"example":{"success":true,"customer":{"id":"6f1d3c2a-0b4e-4c8d-9a7f-2e5b1c0d9a8e","email":"jane@example.com","balance":35},"transaction":{"type":"credit","amount":10,"reason":"Referral reward"}}}}},"400":{"description":"Invalid email or amount.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}},"example":{"error":"invalid_amount","message":"Amount must be a positive number"}}}},"401":{"description":"Missing, malformed, disabled or expired API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}},"example":{"error":"unauthorized","message":"Missing or invalid Authorization header. Use: Bearer sk_..."}}}},"409":{"description":"The balance changed while updating. Retry the request.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}},"example":{"error":"conflict","message":"Balance changed concurrently. Please retry."}}}},"429":{"description":"The hourly limit for this key was reached.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"},"retry_after":{"type":"number"}}},"example":{"error":"rate_limit_exceeded","message":"Rate limit exceeded. Maximum 100 requests per hour.","retry_after":1260}}}}}}},"/api/customer-balance-api/customers/deduct-balance":{"post":{"operationId":"api_customer_balance_deduct_balance","tags":["Customer balance"],"summary":"Deduct balance","description":"Debits a customer’s store balance. Fails if the customer does not exist or has insufficient balance.","security":[{"bearerAuth":[]}],"x-required-permission":"customer_balance_api","x-rate-limit":"100 requests / hour","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"Customer email address."},"amount":{"type":"number","description":"Positive amount to deduct."},"reason":{"type":"string","description":"Shown in the customer’s transaction history.","default":"API balance deduction"},"metadata":{"type":"object","description":"Stored with the transaction."}},"required":["email","amount"]},"example":{"email":"jane@example.com","amount":5,"reason":"Manual adjustment"}}}},"responses":{"200":{"description":"Balance updated.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"customer":{"type":"object","properties":{"id":{"type":"string"},"email":{"type":"string"},"balance":{"type":"number"}}},"transaction":{"type":"object","properties":{"type":{"type":"string"},"amount":{"type":"number"},"reason":{"type":"string"}}}}},"example":{"success":true,"customer":{"id":"6f1d3c2a-0b4e-4c8d-9a7f-2e5b1c0d9a8e","email":"jane@example.com","balance":20},"transaction":{"type":"debit","amount":5,"reason":"Manual adjustment"}}}}},"400":{"description":"Insufficient balance or invalid input.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}},"example":{"error":"insufficient_balance","message":"Insufficient balance. Available: $2, Requested: $5"}}}},"401":{"description":"Missing, malformed, disabled or expired API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}},"example":{"error":"unauthorized","message":"Missing or invalid Authorization header. Use: Bearer sk_..."}}}},"404":{"description":"Unknown customer.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}},"example":{"error":"customer_not_found","message":"Customer with email jane@example.com not found"}}}}}}},"/api/customer-balance-api/customers/transactions":{"post":{"operationId":"api_customer_balance_list_transactions","tags":["Customer balance"],"summary":"List transactions","description":"Returns a customer’s balance history. Pagination parameters go in the body for this endpoint.","security":[{"bearerAuth":[]}],"x-required-permission":"customer_balance_api","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"Customer email address."},"type":{"type":"string","description":"Filter by `credit` or `debit`."},"limit":{"type":"integer","description":"Between 1 and 100.","default":20},"offset":{"type":"integer","description":"Number of results to skip.","default":0}},"required":["email"]},"example":{"email":"jane@example.com","limit":20}}}},"responses":{"200":{"description":"A page of transactions.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string"},"amount":{"type":"number"},"reason":{"type":"string"},"metadata":{"type":"object","properties":{}},"created_at":{"type":"string"}}}},"total":{"type":"number"},"limit":{"type":"number"},"offset":{"type":"number"}}},"example":{"data":[{"id":"b1e0c9d8-7a6f-4e5d-8c3b-2a1f0e9d8c7b","type":"credit","amount":10,"reason":"Referral reward","metadata":{},"created_at":"2026-03-04T18:30:00.000Z"}],"total":1,"limit":20,"offset":0}}}},"401":{"description":"Missing, malformed, disabled or expired API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}},"example":{"error":"unauthorized","message":"Missing or invalid Authorization header. Use: Bearer sk_..."}}}},"404":{"description":"Unknown customer.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}},"example":{"error":"customer_not_found","message":"Customer with email jane@example.com not found"}}}}}}}}}