Payments API v1
Charge from your own storefront.
JuzePOS merchants can take card payments on a custom website or shopping cart. Redirect shoppers to a hosted pay page, or charge a card token you collected yourself. Catalog prices and stock stay in sync with the counter.
1. Get an API key
There is no separate developer signup. Use your existing JuzePOS merchant account (owner or manager):
- Sign in to the dashboard
- Open Settings → Developer
- Create a key. The secret (
jz_live_…) is shown once — copy it. - Optionally add a webhook URL to get paid / failed / refunded events.
Default scopes are payments:read, payments:write, and catalog:read.
2. Authentication
Send the secret on every /api/v1/* request:
Authorization: Bearer jz_live_…- or
X-Api-Key: jz_live_…
Base URL in production: https://juzepos.com/api. Rate limit is 300 requests / minute per key.
3. Hosted checkout
POST /v1/checkouts opens an unpaid order and returns checkoutUrl. Send the customer there. After they pay, we redirect to your returnUrl with checkout_id. Cancel uses cancelUrl.
curl -X POST https://juzepos.com/api/v1/checkouts \
-H "Authorization: Bearer jz_live_..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-1001" \
-d '{
"amount": 42.00,
"returnUrl": "https://your-shop.com/success",
"cancelUrl": "https://your-shop.com/cart",
"reference": "order-1001"
}'Poll status with GET /v1/checkouts/:id (payments:read). Hosted checkout is card-only. Tax on API checkouts is $0.00 — send a tax-inclusive amount if you calculate tax on your site.
4. Direct charge
Collect the card on your domain using the publishable config from GET /v1/payments/config, thenPOST /v1/payments with the resulting paymentToken.
Publishable config: GET /v1/payments/config. Refunds: POST /v1/payments/:id/refunds (omit amount for a full refund).
curl -X POST https://juzepos.com/api/v1/payments \
-H "Authorization: Bearer jz_live_..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-1001" \
-d '{ "amount": 42.00, "paymentToken": "pm_...", "reference": "order-1001" }'5. Catalog and stock
GET /v1/products and GET /v1/categories return live prices and on-hand stock. Query params: page, limit (max 100), search, categoryId.
Prefer product-backed line items so JuzePOS owns the price and decrements the same inventory as in-store:
curl -X POST https://juzepos.com/api/v1/checkouts \
-H "Authorization: Bearer jz_live_..." \
-H "Content-Type: application/json" \
-d '{
"lineItems": [{ "productId": "<id>", "variantId": "<id?>", "quantity": 1 }],
"returnUrl": "https://your-shop.com/success",
"cancelUrl": "https://your-shop.com/cart"
}'6. Webhooks
Register HTTPS endpoints in Settings → Developer. Events: payment.succeeded, payment.failed, refund.completed.
We POST JSON with:
X-Juze-Signature—t=<unix>,v1=<hex>X-Juze-Event— event typeX-Juze-Event-Id
HMAC-SHA256 of `${t}.${rawBody}` using the endpoint signing secret (shown once). Verify the raw body, not a re-serialized object. Failed deliveries retry for about 8 hours.
const crypto = require('crypto');
function verify(rawBody, header, secret) {
const parts = Object.fromEntries(
header.split(',').map((p) => p.split('=').map((s) => s.trim())),
);
const signed = `${parts.t}.${rawBody}`;
const expected = crypto.createHmac('sha256', secret).update(signed).digest('hex');
return crypto.timingSafeEqual(Buffer.from(parts.v1, 'hex'), Buffer.from(expected, 'hex'));
}7. Errors and idempotency
Send Idempotency-Key on checkout and charge. The same key within 24 hours returns the original order — it will not double-charge.
Typical HTTP codes: 400 validation / declined card, 401 missing or revoked key, 403 missing scope or suspended merchant, 404 unknown id, 429 rate limit.
8. OpenAPI reference
Interactive schema (including dashboard JWT routes) lives at /api/docs. Use the api_key scheme or X-Api-Key for /v1/* routes.
Questions: support@juzepos.com
