CryptoNow is an infrastructure for accepting USDC payments on the Solana network directly to your own wallet. There is no “balance inside the service” and no concept of “we hold your funds”. You create a payment session via the API, the customer pays, funds are sent directly to your Solana address, and your server receives a webhook and completes the logic on your side.
In this article, we will show how vending integration works — step by step, with a clear understanding of the full mechanics.
CryptoNow: https://cryptnow.io/
Documentation: https://cryptnow.io/docs
Before writing any code, it is important to understand one simple rule: the vending machine, terminal, or any client device must not communicate directly with CryptoNow. All API requests are signed with your private key, and the private key must live only on your server.
The vending flow looks like this: the customer scans a QR → your server receives a scan event → you approve it → the customer selects a product → your backend creates a payment → the customer pays → the webhook payment.success arrives → you dispense the product.
Preparation
- First, register on the registration page, confirm your email, and log in to the dashboard. Then create a merchant — this is your API-facing profile through which all operations will run. The merchant stores your Solana wallet, webhook URL, and API keys.
- Set your Solana wallet address — payments are sent directly to this address. Configure your webhook URL so your server receives payment and session events.
- Choose the commission mode. Each payment is split into the CryptoNow fee and the amount you receive. If Merchant is selected, the customer pays exactly the amount, and the fee is deducted from it. If Customer is selected, the fee is added on top, the customer pays amount + fee, and you receive the exact amount. The final amount requested from the customer is always shown in the total_amount field.
- After creating the merchant, create Vending QR codes in Merchants > Actions > View. Each QR has its own qr_id — this identifies a specific vending machine or terminal. All further logic will be tied to this qr_id.
- Save your public and private API keys. The public key identifies your merchant. The private key is used to sign requests and verify webhooks. The private key must be stored only on your server.
This is the minimum setup required for integration. See https://cryptnow.io/docs in the sections “Start here”, “Basic information”, and “Website / Vending” for details.
Preparation is complete. Now we move to the vending integration itself.
Integration
In vending, everything starts not with an order, but with scanning the QR code that you placed on your machine.
Step 1. Handle the vending.scan_pending event
- When a customer scans the QR on the machine, CryptoNow sends a webhook vending.scan_pending to your server. It contains qr_id and scan_id. This is not a payment and not an order — it is a request to start a session.
- Your server accepts the POST request, verifies the X-Signature, and decides whether this scan can be processed. Typically, you check whether the machine exists, whether it is free, whether it is under maintenance, and so on.
- If the signature is valid, you process the request and return 200 OK after handling it. If your server does not return a 2xx status, CryptoNow will retry the webhook according to the retry schedule.
Step 2. Approve or reject the scan
- After receiving vending.scan_pending, you must make a decision.
- If the machine is ready, your backend calls Vending Approve with scan_id and qr_id. The request must be signed with your private key using X-Public-Key and X-Signature.
- If the machine is busy or unavailable, you call Vending Reject. You may optionally pass a reason, which will be shown in Webhook Logs.
- After Vending Approve, a vending session is created and the customer sees the waiting screen. This means the connection is established, the machine is considered busy, but the amount is not defined yet — the customer selects a product.
See https://cryptnow.io/docs in the sections Vending Approve / Vending Reject and Signature for details.
Step 3. Create an order in your system after product selection
- After approval, the customer selects a product on the machine — from this point, the logic is fully on your side.
- When the product is selected, you create an order in your system. This is a regular purchase record with order_id, amount, and status. The order is created in your system first, and only after that you send Create Payment.
- order_id must be unique within one merchant. CryptoNow will not accept a duplicate order_id, and you will use it to match webhooks with your orders. You can use UUID or a simple incremental numbering. If you use numbering, store the counter in a database so it does not reset on restart.
- While a vending session is active for a specific qr_id, we recommend treating the machine as busy. That means not accepting card or cash payments for the same product during this session. The current session must finish (payment or timeout) before the machine becomes available again.
Step 4. Create a payment with Create Payment and qr_id
- After the order is created in your system, your backend sends a Create Payment request to CryptoNow. This request must be signed with your private key — otherwise it will be rejected. You send X-Public-Key and X-Signature in the headers.
- In the request body, you send order_id, amount in USD, currency (always USD), and qr_id. When qr_id is used, return_url and success_url must not be sent — they apply only to the website scenario.
- In the response, you receive payment_id, session_key, and url. Immediately after this, the waiting screen switches to the payment screen, where the customer confirms the payment in their wallet.
- You store the mapping order_id → session_key / payment_id and set the order status to pending or processing. Then you wait for webhooks.
See Create Payment: https://cryptnow.io/docs#create-payment
See Signature: https://cryptnow.io/docs#signature
Step 5. Handle webhooks and dispense the product
- The main events are: vending.scan_pending — the customer scanned the QR and you received scan_id; vending.scan_resolved — the scan was processed and the status is approved, rejected, or timeout; session.active — the session was created and became active; payment.created — the payment was created but not yet confirmed; payment.success — the payment was confirmed on-chain, this is the main event and only after this you consider the payment completed and dispense the product; session.closed — the session was closed due to timeout or user disconnect.
- When payment.success arrives, you follow a simple sequence: verify the X-Signature, find the order by order_id, if it is not yet in paid status — update it to paid, optionally store txid and payer_wallet, and send a command to the machine to dispense the product.
- Processing must be idempotent. If the same webhook arrives again and the order is already in paid status — you do nothing and simply return 200 OK.
- If your server does not return a 2xx status, CryptoNow will retry the webhook according to the retry schedule, so always return 200 OK after successful processing.
- If session.closed arrives and no payment was made, you set the order to expired or unpaid in your system and unlock the machine so it is ready for the next customer.
See Webhooks: https://cryptnow.io/docs#webhooks
Step 6. Handle vending timing
- Vending session timers are configured in the Merchant Dashboard under Session timers so you can control each step. The default values are described below.
- After vending.scan_pending, you have 30 seconds to send Vending Approve or Vending Reject (by default). If you do not approve the scan within this time, the request expires and no session is created.
- After Vending Approve, a vending session is created and remains active for 3 minutes for product selection (by default). During this time, the machine is considered busy and the customer is standing at it choosing a product.
- When you send Create Payment with the amount, the 3-minute timer starts again — now it becomes the payment window (by default). The customer confirms the transaction in their wallet, and you wait for payment.success.
- If the customer does not pay in time, the session becomes inactive and you receive session.closed. In your system, you set the order to expired or unpaid and free the machine.
- If the customer confirms the transaction after the timer and the payment is confirmed on-chain, the status will update to paid and you will receive the corresponding webhook. Late payment is technically possible, but your vending logic must follow the timer: once the time is over, the order is marked expired or unpaid and the machine is free.
See timing details: https://cryptnow.io/docs#website-vending
Summary
In vending, the integration looks like this: the customer scans the QR → you approve the scan → the customer selects a product → you create a payment via API → the customer pays → payment.success arrives → you dispense the product.
In this article, we explained the mechanics on a logical level: how the scan is handled, when the payment is created, when the payment is considered confirmed, and how timing works. All exact request parameters, response formats, signatures, and error codes are available in the documentation: https://cryptnow.io/docs
CryptoNow: https://cryptnow.io/
If you have questions or issues, contact us on Telegram https://t.me/CryptoNow_support or by email support@cryptnow.io
For business inquiries: business@cryptnow.io

Top comments (1)
Got scammed in p2p transaction which i lost over $14k. All thanks to (hack4net8@ gmail .com) for his assistance in recovering all my lost crypto usdt coin