# API overview Source: https://docs.zenobank.io/api-reference/api-overview Quick guide to integrate crypto payments ## Authentication Send your API key in the `X-API-Key` header: ``` X-API-Key: sk_your_store_key ``` ## Integration Steps ### 1. Get your API key 1. Sign in to the [dashboard](https://dashboard.zenobank.io/) 2. Go to **[Developers](https://dashboard.zenobank.io/developer)** 3. Copy your API key (starts with `sk_`) ### 2. Set up webhooks In the [dashboard](https://dashboard.zenobank.io/), go to **[Developers](https://dashboard.zenobank.io/developer)**, create a webhook endpoint and choose the events you want to subscribe to. See [Webhooks](/api-reference/webhooks) for more details. ### 3. Create a checkout Use the [Create Checkout](/api-reference/checkouts/create-a-new-checkout) endpoint to generate a payment link for your customer. ### 4. Check checkout status You can query the current status anytime using [Get Checkout by ID](/api-reference/checkouts/get-checkout-by-id). *** # Create a checkout Source: https://docs.zenobank.io/api-reference/checkouts/create-a-new-checkout Start a new payment session for an order Create a checkout to generate a hosted payment page for your customer. ## Authentication Send your store key in the header: `X-API-Key: sk_...`. See the [API overview](/api-reference/api-overview) for where to find it. ## Request body * `orderId` (string, required): Your internal order identifier. * `priceAmount` (string, required): Decimal amount, quoted in `priceCurrency`. * `priceCurrency` (string, required): ISO 4217 currency (e.g., `USD`). * `successRedirectUrl` (string, optional): Where to send the buyer after a successful payment. ## Example request ```bash theme={null} curl -X POST https://api.zenobank.io/api/v1/checkouts \ -H "Content-Type: application/json" \ -H "X-API-Key: sk_your_store_key" \ -d '{ "orderId": "order-12345", "priceAmount": "0.01", "priceCurrency": "USD", "successRedirectUrl": "https://example.com/success" }' ``` ```javascript theme={null} const response = await fetch('https://api.zenobank.io/api/v1/checkouts', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-API-Key': 'sk_your_store_key', }, body: JSON.stringify({ orderId: 'order-12345', priceAmount: '0.01', priceCurrency: 'USD', successRedirectUrl: 'https://example.com/success', }), }); const checkout = await response.json(); ``` ```python theme={null} import requests response = requests.post( 'https://api.zenobank.io/api/v1/checkouts', headers={ 'Content-Type': 'application/json', 'X-API-Key': 'sk_your_store_key', }, json={ 'orderId': 'order-12345', 'priceAmount': '0.01', 'priceCurrency': 'USD', 'successRedirectUrl': 'https://example.com/success', }, ) checkout = response.json() ``` ```php theme={null} $ch = curl_init('https://api.zenobank.io/api/v1/checkouts'); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', 'X-API-Key: sk_your_store_key', ], CURLOPT_POSTFIELDS => json_encode([ 'orderId' => 'order-12345', 'priceAmount' => '0.01', 'priceCurrency' => 'USD', 'successRedirectUrl' => 'https://example.com/success', ]), ]); $response = curl_exec($ch); $checkout = json_decode($response, true); ``` ```go theme={null} payload := map[string]string{ "orderId": "order-12345", "priceAmount": "0.01", "priceCurrency": "USD", "successRedirectUrl": "https://example.com/success", } body, _ := json.Marshal(payload) req, _ := http.NewRequest("POST", "https://api.zenobank.io/api/v1/checkouts", bytes.NewBuffer(body)) req.Header.Set("Content-Type", "application/json") req.Header.Set("X-API-Key", "sk_your_store_key") resp, _ := http.DefaultClient.Do(req) ``` ```ruby theme={null} require 'net/http' require 'json' uri = URI('https://api.zenobank.io/api/v1/checkouts') http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true request = Net::HTTP::Post.new(uri) request['Content-Type'] = 'application/json' request['X-API-Key'] = 'sk_your_store_key' request.body = { orderId: 'order-12345', priceAmount: '0.01', priceCurrency: 'USD', successRedirectUrl: 'https://example.com/success' }.to_json response = http.request(request) checkout = JSON.parse(response.body) ``` ## Example response ```json theme={null} { "id": "ch_l0k1o87yt6", "orderId": "order-12345", "priceCurrency": "USD", "priceAmount": "0.01", "status": "OPEN", "expiresAt": "2025-10-04T10:30:00Z", "checkoutUrl": "https://pay.zenobank.io/ch_l0k1o87yt6", "createdAt": "2025-10-04T10:00:00Z", "successRedirectUrl": "https://example.com/success" } ``` # Get checkout by ID Source: https://docs.zenobank.io/api-reference/checkouts/get-checkout-by-id Retrieve the latest state of a checkout Fetch the current status and payment link for a checkout. This endpoint is public and does not require authentication. ## Path parameters * `id` (string, required): The checkout ID returned when you created the checkout. ## Example request ```bash theme={null} curl https://api.zenobank.io/api/v1/public/checkouts/ch_l0k1o87yt6 ``` ```javascript theme={null} const response = await fetch('https://api.zenobank.io/api/v1/public/checkouts/ch_l0k1o87yt6'); const checkout = await response.json(); ``` ```python theme={null} import requests response = requests.get('https://api.zenobank.io/api/v1/public/checkouts/ch_l0k1o87yt6') checkout = response.json() ``` ```php theme={null} $response = file_get_contents('https://api.zenobank.io/api/v1/public/checkouts/ch_l0k1o87yt6'); $checkout = json_decode($response, true); ``` ```go theme={null} resp, _ := http.Get("https://api.zenobank.io/api/v1/public/checkouts/ch_l0k1o87yt6") defer resp.Body.Close() var checkout map[string]interface{} json.NewDecoder(resp.Body).Decode(&checkout) ``` ```ruby theme={null} require 'net/http' require 'json' uri = URI('https://api.zenobank.io/api/v1/public/checkouts/ch_l0k1o87yt6') response = Net::HTTP.get_response(uri) checkout = JSON.parse(response.body) ``` ## Example response ```json theme={null} { "id": "ch_l0k1o87yt6", "orderId": "order-12345", "priceCurrency": "USD", "priceAmount": "0.01", "status": "OPEN", "expiresAt": "2025-10-04T10:30:00Z", "checkoutUrl": "https://pay.zenobank.io/ch_l0k1o87yt6", "createdAt": "2025-10-04T10:00:00Z", "successRedirectUrl": "https://example.com/success" } ``` # Webhooks Source: https://docs.zenobank.io/api-reference/webhooks Receive checkout lifecycle events You can manage your webhook endpoints from the **[Webhook section](https://dashboard.zenobank.io/developer)** in the dashboard. ## Setting up endpoints 1. Go to the **[Webhook section](https://dashboard.zenobank.io/developer)** in your store's dashboard. 2. Add an endpoint URL (e.g. `https://example.com/webhooks/zenobank`). 3. Select the event types you want to receive. ## Events | Event | Description | | ------------------------- | --------------------------------------------------------------------------------------- | | `checkout.completed` | The full amount has been paid successfully. | | `checkout.expired` | The checkout expired without receiving any payment. | | `checkout.partially_paid` | The checkout expired after receiving a partial payment (`paidAmount` \< `priceAmount`). | ## Payload format The customer paid the full amount. `paidAmount` is equal to or greater than `priceAmount`. ```json theme={null} { "type": "checkout.completed", "data": { "id": "ch_l0k1o87yt6", "orderId": "order-12345", "priceCurrency": "USD", "priceAmount": "100.00", "paidAmount": "100.00", "status": "COMPLETED", "expiresAt": "2025-10-05T12:00:00Z", "checkoutUrl": "https://pay.zenobank.io/ch_l0k1o87yt6", "createdAt": "2025-10-04T10:00:00Z", "successRedirectUrl": "https://example.com/success" } } ``` No payment was received before the checkout expired. `paidAmount` is `"0"`. ```json theme={null} { "type": "checkout.expired", "data": { "id": "ch_9xR3mPq2vW", "orderId": "order-67890", "priceCurrency": "USD", "priceAmount": "50.00", "paidAmount": "0", "status": "EXPIRED", "expiresAt": "2025-10-05T12:00:00Z", "checkoutUrl": "https://pay.zenobank.io/ch_9xR3mPq2vW", "createdAt": "2025-10-04T10:00:00Z", "successRedirectUrl": null } } ``` The checkout expired after receiving a partial payment. `paidAmount` is greater than `"0"` but less than `priceAmount`. The collected funds will be credited to your store balance. ```json theme={null} { "type": "checkout.partially_paid", "data": { "id": "ch_4kT7nWx8pQ", "orderId": "order-11223", "priceCurrency": "USD", "priceAmount": "100.00", "paidAmount": "45.50", "status": "PARTIALLY_PAID", "expiresAt": "2025-10-05T12:00:00Z", "checkoutUrl": "https://pay.zenobank.io/ch_4kT7nWx8pQ", "createdAt": "2025-10-04T10:00:00Z", "successRedirectUrl": null } } ``` ## Verifying webhooks Every webhook request includes three headers used for signature verification: | Header | Description | | ---------------- | ----------------------------- | | `svix-id` | Unique message identifier | | `svix-timestamp` | Unix timestamp of the message | | `svix-signature` | HMAC signature | Use the official Svix library to verify signatures. To find your signing secret, go to **[Developers](https://dashboard.zenobank.io/developer)**, click on a webhook endpoint, and copy the **Signing Secret** on the right side. It starts with `whsec_`. ### Install the Svix library `bash pnpm add svix ` `bash pip install svix ` `bash composer require svix/svix ` `bash go get github.com/svix/svix-webhooks/go ` `bash gem install svix ` ### Verify the signature You must use the **raw request body** when verifying webhooks. The cryptographic signature is sensitive to even the slightest changes. Watch out for frameworks that parse the request as JSON and then stringify it, as this will break the signature verification. ```javascript theme={null} import { Webhook } from 'svix'; const secret = process.env.ZENO_WEBHOOK_SECRET; // whsec_... const payload = rawBody; // raw request body as string const headers = { 'svix-id': request.headers.get('svix-id'), 'svix-timestamp': request.headers.get('svix-timestamp'), 'svix-signature': request.headers.get('svix-signature'), }; const wh = new Webhook(secret); try { const msg = wh.verify(payload, headers); const { type, data } = msg; switch (type) { case 'checkout.completed': // Payment successful — fulfill the order console.log(`Order ${data.orderId} completed. Paid: ${data.paidAmount} ${data.priceCurrency}`); break; case 'checkout.expired': // Checkout expired — no payment was received console.log(`Order ${data.orderId} expired`); break; case 'checkout.partially_paid': // Partial payment received — consider issuing a refund console.log(`Order ${data.orderId} partially paid: ${data.paidAmount}/${data.priceAmount} ${data.priceCurrency}`); break; } } catch (err) { // Signature verification failed console.error('Invalid webhook signature'); } ``` ```python theme={null} from svix.webhooks import Webhook, WebhookVerificationError import os secret = os.environ.get('ZENO_WEBHOOK_SECRET') # whsec_... payload = raw_body # raw request body, not parsed JSON headers = request_headers wh = Webhook(secret) try: msg = wh.verify(payload, headers) except WebhookVerificationError: # Signature verification failed raise Exception('Invalid webhook signature') event_type = msg['type'] if event_type == 'checkout.completed': # Payment successful — fulfill the order print(f"Order {msg['data']['orderId']} completed. Paid: {msg['data']['paidAmount']} {msg['data']['priceCurrency']}") elif event_type == 'checkout.expired': # Checkout expired — no payment was received print(f"Order {msg['data']['orderId']} expired") elif event_type == 'checkout.partially_paid': # Partial payment received — consider issuing a refund print(f"Order {msg['data']['orderId']} partially paid: {msg['data']['paidAmount']}/{msg['data']['priceAmount']} {msg['data']['priceCurrency']}") ``` ```php theme={null} use Svix\Webhook; use Svix\Exception\WebhookVerificationException; $secret = getenv('ZENO_WEBHOOK_SECRET'); // whsec_... $payload = file_get_contents('php://input'); // raw body $headers = array_change_key_case(getallheaders(), CASE_LOWER); try { $wh = new Webhook($secret); $msg = $wh->verify($payload, $headers); switch ($msg['type']) { case 'checkout.completed': // Payment successful — fulfill the order fulfillOrder($msg['data']['orderId']); break; case 'checkout.expired': // Checkout expired — no payment was received handleExpiredCheckout($msg['data']['orderId']); break; case 'checkout.partially_paid': // Partial payment received — consider issuing a refund handlePartialPayment($msg['data']['orderId'], $msg['data']['paidAmount']); break; } http_response_code(200); } catch (WebhookVerificationException $e) { // Signature verification failed http_response_code(400); } ``` ```go theme={null} import ( "encoding/json" "io" "net/http" "os" svix "github.com/svix/svix-webhooks/go" ) secret := os.Getenv("ZENO_WEBHOOK_SECRET") // whsec_... payload, _ := io.ReadAll(r.Body) // raw body wh, _ := svix.NewWebhook(secret) err := wh.Verify(payload, r.Header) if err != nil { // Signature verification failed w.WriteHeader(http.StatusBadRequest) return } var event struct { Type string `json:"type"` Data json.RawMessage `json:"data"` } json.Unmarshal(payload, &event) switch event.Type { case "checkout.completed": // Payment successful — fulfill the order case "checkout.expired": // Checkout expired — no payment was received case "checkout.partially_paid": // Partial payment received — consider issuing a refund } w.WriteHeader(http.StatusOK) ``` ```ruby theme={null} require 'svix' require 'json' secret = ENV['ZENO_WEBHOOK_SECRET'] # whsec_... payload = raw_body # raw request body headers = request_headers wh = Svix::Webhook.new(secret) begin msg = wh.verify(payload, headers) case msg['type'] when 'checkout.completed' # Payment successful — fulfill the order puts "Order #{msg['data']['orderId']} completed. Paid: #{msg['data']['paidAmount']} #{msg['data']['priceCurrency']}" when 'checkout.expired' # Checkout expired — no payment was received puts "Order #{msg['data']['orderId']} expired" when 'checkout.partially_paid' # Partial payment received — consider issuing a refund puts "Order #{msg['data']['orderId']} partially paid: #{msg['data']['paidAmount']}/#{msg['data']['priceAmount']} #{msg['data']['priceCurrency']}" end rescue # Signature verification failed puts 'Invalid webhook signature' end ``` Always verify the signature before processing the event. Never trust the payload without verification. You must use the **raw request body**, do not parse the JSON before verifying. For framework-specific examples (Express, Next.js, Django, Flask, Laravel, Rails, etc.), see the Svix verification docs. ## FAQ If Zeno Bank does not receive a `2xx` response from your webhook endpoint, we will retry the delivery. Each message is attempted based on the following schedule, where each period starts after the failure of the preceding attempt: * 5 seconds * 5 minutes * 30 minutes * 2 hours * 5 hours * 10 hours Respond with any `2xx` status code to acknowledge the event. You can monitor delivery attempts and manually retry from the **[Developers](https://dashboard.zenobank.io/developer)** section in the dashboard. Zeno Bank webhooks provide **at-least-once** delivery. Every event will be delivered to your endpoint at least once, but may be delivered more than once in rare cases (such as network timeouts where your server processed the event but the acknowledgement was lost). To handle duplicates, use the `svix-id` header included with every webhook request. This is a unique identifier for each event delivery. Store processed `svix-id` values and skip any duplicates. Yes. Go to **[Developers](https://dashboard.zenobank.io/developer)** in the dashboard, click on your webhook endpoint, find the event you want to retry, and click the replay button to resend it. No. If you use one of our official plugins (WooCommerce, PrestaShop, WHMCS, etc.), webhooks are configured automatically. You don't need to set up endpoints or verify signatures manually. ## IP allowlist If your firewall is blocking our webhooks, add these IP addresses to your allowlist. ``` 44.228.126.217 50.112.21.217 52.24.126.164 54.148.139.208 2600:1f24:64:8000::/56 ``` # Brand Assets Source: https://docs.zenobank.io/brand-assets Official Zeno Bank logos and brand resources for partners and integrators. ## Wordmark
Zeno wordmark black Black wordmark
Zeno wordmark white White wordmark
| Format | Light background | Dark background | | ------ | ----------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | | PNG | zenobank-text-light.png | zenobank-text-dark.png | ## Icon
Zeno icon light background Light background
Zeno icon dark background Dark background
| Format | Light background | Dark background | | ------ | ----------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | | PNG | zenobank-icon-light.png | zenobank-icon-dark.png | ## Favicon
Zeno favicon Favicon
| Format | File | | ------ | -------------------------------------- | | PNG | favicon.png | | ICO | favicon.ico | ## Typeface
Zeno typeface black Black typeface (SVG)
Zeno typeface white White typeface (SVG)
| Format | Light background | Dark background | | ------ | ----------------------------------------------------------------- | ----------------------------------------------------------------- | | SVG | typeface-black.svg | typeface-white.svg | | PNG | typeface-black.png | typeface-white.png | ## Checkout Logos If you are integrating via the API, you can use these logos to display Zeno as a payment method at checkout.
Checkout logo - USDT, USDC, Binance Pay USDT, USDC, Binance Pay
Checkout logo - USDT, USDC, BTC, LTC USDT, USDC, BTC, LTC
Checkout logo - USDC, USDT, PYUSD USDC, USDT, PYUSD
Checkout logo - Binance Pay Binance Pay
## Colors | Color | Hex | RGB | CMYK | Pantone | | ----------------- | --------- | ------------- | -------------- | ------------------ | |
**Black** | `#000000` | 0, 0, 0 | 75, 68, 67, 90 | Black 6 C / 4147 U | |
**White** | `#FFFFFF` | 255, 255, 255 | 0, 0, 0, 0 | — | # Fees Source: https://docs.zenobank.io/fees A transparent breakdown of Zeno's payment processing fees. ## Crypto Payment Fees ### Base Fee We charge a **0.1% fee** on each payment. The fee is deducted after each sweep , when funds are moved from the intermediary wallet to you, we send you 99.9% of the amount and keep 0.1%. ### Network Fees In addition to the base fee, **network fees apply when sweeping funds** from the intermediary wallet to your destination wallet. On most chains, these fees are so small they are practically imperceptible. However, on networks like Tron, fees can be notably higher. ### Binance Pay Binance Pay transactions have a **0% fee**. Funds are received directly into your Binance account with no intermediaries involved. Charging a fee here would unnecessarily complicate our fee structure, so we simply don't. ### Lightning Network Payments over the Lightning Network carry a **0.35% fee** instead of the standard 0.1%. This higher rate is necessary to cover the cost of managing Lightning Network liquidity, which requires significant operational effort. ## Withdrawals The fee for each withdrawal is **\$1 + network fees**. If you use **bring your own wallet mode**, funds are received directly in your wallet, so no withdrawal fee applies. # Quick Start Source: https://docs.zenobank.io/index Accept crypto payments with 0.1% fees, instant payouts, and no chargebacks. Zeno Bank is a payment gateway that lets you accept **crypto payments with very low fees**. We're not here to replace your existing payment gateway. We're here to **complement it**. We **abstract the complexity of crypto** so you can enjoy its benefits without worrying about the technical details. ## Why Accept Crypto? ### No More Frozen Accounts You built your business from scratch. Late nights, sacrifices, **years of hard work**. Then one morning, **your payment gateway freezes your account** for suspicious activity. Now **you can't process any more payments**, but your bills don't stop. There's nothing you can do about it but wait for a reply to your appeal ### Lower Fees Traditional gateways charge 3% on average, sometimes up to 10%. We charge just **0.1%**. That's **30x less**. Imagine reinvesting that 3% back into your business. **The compound effect over 5 years would be massive.** It's like going to the gym. You don't see results right away, but they add up. ### Reach Global Customers Millions of people in Latin America and Africa use apps like Binance to protect their savings in USDT from hyperinflation. **Most of them don't even know they're using crypto.** They just know their money holds its value because 1 USDT = 1 USD. By accepting crypto, you **unlock access to this massive market** of customers who are already spending in stablecoins every day but can't reach you through traditional payment methods. ### No More Fraud Fraudulent returns cost US retailers [**\$76.5 billion a year**](https://www.forbes.com/sites/pamdanziger/2026/02/16/fraud-is-only-the-tip-of-retails-850-billion-returns-challenge/) according to Forbes. Amazon had to cut back its return program because people kept abusing it. The same happens to you. A customer opens a PayPal dispute, and **PayPal always sides with the customer**. Too many disputes? They close your account. With crypto, **payments are final**. You're in control. You decide whether to issue a refund or not ### Get Paid Immediately No more waiting days or weeks. **You get paid in minutes.** Reinvest in ads, pay suppliers, move faster. Old payment rails no longer slow you down. ## Big Players Are Already Using Crypto **PayPal, Revolut, and many more** are already processing payments through crypto. The biggest companies in fintech are betting on it. The question is: why aren't you? ## The Future Is Already Here Stablecoin adoption is **growing rapidly year over year**. The only reason not to accept crypto is if you want to fall behind. ## Supported Platforms <> <> <> <> <> # Binance Pay Source: https://docs.zenobank.io/integrations/binance-pay Connect your Binance account to accept Binance Pay payments With the Binance Pay integration, you can let your **customers** pay using **Binance Pay** in just a few clicks. ZenoBank works as a payment processor that validates each transaction using your Binance Pay payment history via API. **Funds** sent by customers **go directly to your Binance account**. You **don't need** to have a **merchant Binance account**. You can use your regular Binance account. Binance Pay logo ## Step 1: Locate Your Binance ID 1. Log in to your Binance account at [binance.com](https://binance.com) 2. Navigate to your dashboard 3. Locate your **Binance ID** in the dashboard interface 4. Copy and securely store your Binance ID—you will need it later in the integration process Binance ID location ## Step 2: Access API Management 1. In your Binance account, click on the **Account** dropdown menu 2. Select **API Management** from the dropdown options API Management location ## Step 3: Create API Key 1. Click the **Create API** button to begin the API key creation process Create API button ## Step 4: Select API Key Type 1. You will be prompted to choose between **System generated** and **Self-generated** 2. Select **System generated** 3. Click **Next** to proceed API key type selection ## Step 5: Name Your API Key 1. Enter a name for your API key (e.g., "zeno bank") 2. This name is for identification purposes only and does not affect functionality 3. Click **Next** to continue API key naming ## Step 6: Configure API Permissions Ensure that **only the Read permission is enabled**. This restriction is critical for security. With read-only access, ZenoBank can only read your Binance Pay payment history API restrictions configuration ## Step 7: Copy Your Credentials After creating your API key, Binance will display: * **API Key** * **API Secret** Binance Api Key and Api Secret ## Step 8: Configure Integration in ZenoBank Dashboard 1. Log in to your [ZenoBank dashboard](https://dashboard.zenobank.io) 2. Navigate to **[Settings](https://dashboard.zenobank.io/settings)** in the sidebar menu 3. Click **Connect Binance Pay** ## Step 9: Enter Your Credentials 1. A modal dialog will open prompting you to enter your Binance credentials 2. Enter the following information: * **Binance ID** (from Step 1) * **API Key** (from Step 7) * **API Secret** (from Step 7) 3. Click **Save** to complete the integration # Easy Digital Downloads Source: https://docs.zenobank.io/integrations/easy-digital-downloads Accept crypto payments on your Easy Digital Downloads store