Documentation

Start here

1. Register an account

Register your CryptoNow account.

2. Create a merchant

Open Dashboard and add a merchant.

  • Name - your site / store name.
  • Webhook URL - server-to-server notifications about payment events come here. If you do not set it, check payment status through View Session.
  • Default return URL - your store, where the customer can return.
  • Solana Wallet - the wallet where payments go by default.
  • Commission mode - the fee is either added to the payment amount or deducted from it (Read here).
  • Session timers - configure timing for sessions (Read here).
3. Add a wallet

Payments go directly to your wallet, so we recommend a non-custodial Solana wallet: Solflare, Trust Wallet, MetaMask.

Use a wallet with Solana support.

4. Save your API keys

After you create a merchant, you will see a public key and a private key in Dashboard. Public key identifies your merchant. Private key signs API requests.

// Keep the API private key and seed phrase in a safe place and protect them carefully.

How it works

To get a payment link, you need to first create a session.

With API
  1. Create a session using API request.
  2. The response returns "url" (payment link) and you direct the customer to it.
  3. When the customer opens "url", they see the payment page, the amount and details, and can pay right away.
  4. When the customer has paid, funds go directly to your Solana wallet and the customer moves to the success page, where they see the txid link in Solscan, as well as "success_url" and "return_url", if you passed them (Read here). By following "success_url", the customer gets access to the service they paid for.
With Dashboard

If you want to create a payment manually without API, go to Dashboard > Create Session.

You receive a link that you send to the customer, and after that receive the payment.

// Set "return_url" manually, because it is not taken from merchant settings by default.

Timing
  1. After creating a payment in Dashboard or API, you receive "url" (payment link) and the customer has time equal to "Wait for open" to open it. If the link is not opened in time, the session becomes inactive and can no longer be paid.
  2. If the customer opens "url" (payment link) before "Wait for open" expires, the session becomes active and the customer has time equal to "Session duration" to pay. After that time, the session becomes inactive and can no longer be paid. After successful payment, the session also becomes inactive.

// "Wait for open" and "Session duration" can be configured in Dashboard.

Statuses in dashboard:
Session History
  1. Processing - session is created and can be paid.
  2. Paid - session is paid.
  3. Inactive - session became inactive and can no longer be paid: wait-for-open timeout, session-duration timeout, or successful payment.
Payment History
  1. Processing - payment is not confirmed yet.
  2. Paid - payment confirmed successfully.
  3. Not Paid - no payment received before the session became inactive.

Basic information

Core concepts
  • Merchant - your store created in Dashboard. It stores your wallet address, other data, API keys, and the history of payments and sessions.
  • Merchant Edit - If you edit any parameters such as wallet, webhook URL, Default return URL, commission mode, or Session timers in your merchant, the changes apply only to new sessions. Existing sessions keep the data that was saved when the session was created.
  • Customer - The person who pays for your product or service.
  • Session link (payment link) - you receive it when the session is created and direct the customer to it. When they open "url", they can pay.
  • Fee - each payment is split into "merchant_receives" (your net amount) and "fee" (CryptoNow commission). For payments from $0.10 to $1.99 the fee is always $0.01. From $2.00 and above it increases by $0.01 per whole dollar.
    Example:
    $0.10 -> $0.01
    $1.99 -> $0.01
    $2.00 -> $0.02
    $10.00 -> $0.10
    $100.00 -> $1.00
  • Commission mode - you choose whether the service fee is paid by Merchant or by Customer. If set to Merchant, the customer pays the exact "amount" you passed, and you receive "amount - fee" to your wallet. If set to Customer, the fee is added on top, the customer pays "amount + fee" and you receive the exact "amount" to your wallet. The final amount the customer pays is "total_amount".
  • For USDC, the amount stays the same - 1:1 equivalent to USD. If the customer pays in SOL, the SOL amount is calculated at our rate, locked once when the customer moves to the payment step and stays unchanged for the rest of that session.
Time
All timestamps in API responses are returned in UTC and use ISO 8601 format (for example, 2026-01-18T16:45:14.000Z). The frontend displays time in the user's local timezone.
Limits
  • You can create a payment with an amount from $0.10 to $100,000.
  • Max merchants per user: 20.
  • Merchant API v1 rate limit: 500 requests per minute, plus a short burst limit of 200 requests per 10 seconds.

You can activate or deactivate merchant in the Dashboard. Deactivating a merchant blocks API requests, dashboard session creation, and merchant edits. You can turn it back on again at any time.

Request
Base URL:

Content-Type: application/json.

Use UTF-8 for the JSON body.

POST is signed with the request body (payload). GET is signed with params and query.

Response body:

Each response returns a status flag and the result data.

  • success - true or false.
  • data - the result of the request.
  • error - message when success is false.
  • signature - response signature for { success, data }.

Successful request:

{
  "success": true,
  "data": {
    "property": "value",
    "second_property": "second_value"
  },
  "signature": "b8e4c0d13f6a9b27d5e8f104c3a6d92b7e0f5a1c8d4b63f290a7e5c1d8b4f603"
}

Request with an error:

{
  "success": false,
  "error": "error message"
}

Authentication

Every API request must be authenticated.

Required headers
  • X-Public-Key - identifies your merchant and matches the public key shown in the Dashboard.
  • X-Signature - HMAC SHA-256 signature of the request payload signed with your private key from Dashboard.
Auth:
  1. Build the payload from the request data.
  2. Generate an HMAC SHA-256 signature using your private key and the canonicalization rules.
  3. Send the signature in X-Signature together with X-Public-Key.

How to generate the signature (Read Here).

Error codes:
  • 401 - Authentication failed.
  • 429 - Too many requests (rate limit exceeded).
  • 500 - Internal server error.

Signature generation

The signature is used for API requests and webhooks. CryptoNow signs JSON payloads with HMAC SHA-256 using your private key.

Canonical payload

Build the canonical payload this way:

  1. Sort object keys alphabetically at every level.
  2. Remove fields with undefined values. Do not remove fields whose value is null.
  3. Keep the original order of items inside arrays.
  4. Serialize the result to one exact JSON string before signing.
  5. Use that final JSON string for HMAC SHA-256.
Why canonicalization is needed

It makes sure you and CryptoNow always sign the same JSON string. Without canonicalization, the same payload could produce a different signature just because keys were written in a different order.

What is signed:

For POST requests, sign the JSON from the request body. For GET requests, sign the JSON object built from params and query.

Signature formula:
signature = HMAC_SHA256(canonical_json_payload, private_key)
Ready-to-use examples:

Use one of the examples below to create signatures for Create Payment requests.

Verifying signatures:

Verification uses the same rules as signing. Rebuild the same canonical JSON string, compute HMAC SHA-256, and compare the result to the signature you received.

  1. Take the JSON you received.
  2. For API responses, sign { success, data }. For webhooks, sign { event, data }.
  3. Apply the same canonicalization rules.
  4. Compute HMAC SHA-256 with your private key.
  5. Compare the result to the signature you received.

// API responses include "signature". Webhooks use "X-Signature". The same rules apply everywhere.

Webhooks

A webhook is a server-to-server notification sent to your webhook URL you set in Dashboard when a payment or session event happens. Webhooks are optional - if you do not configure one, you can confirm payment and session status using the API request in View Session.

To mark delivery as successful, return HTTP 200 OK from your server.

Retry timeline
  • Request #1: immediately after the event.
  • Request #2: 5 seconds after the previous attempt.
  • Request #3: 10 seconds after the previous attempt.
  • Request #4: 30 seconds after the previous attempt.
  • Request #5: 2 minutes after the previous attempt.
  • Request #6: 10 minutes after the previous attempt.
  • Request #7: 1 hour after the previous attempt.
  • Request #8: 6 hours after the previous attempt.
  • Request #9: 24 hours after the previous attempt.

After the last attempt, no more retries are sent. If delivery succeeds, further notifications are not sent.

You can review webhook attempts at Dashboard > Actions > Webhook Logs.

Webhook format
MethodPOST
Content-Typeapplication/json
HeaderX-Signature
Webhook messages
payment.created - sent right after a session (payment) is created
payment.success - sent when the payment is successfully confirmed on-chain, marked as paid, and the session becomes inactive
session.active - sent when the customer opens the payment link and the session becomes active
session.inactive - sent when the session becomes inactive: successful payment, wait-for-open timeout, or session-duration timeout

// Always verify the signature on all responses and webhooks (Read here).

Create Payment

Creates a payment session and returns a payment link. Direct the customer to it so they can pay.

Endpoint
MethodPOST
URLhttps://cryptnow.io/api/v1/payment/create
AuthX-Public-Key, X-Signature
Request body
FieldTypeRequiredDescription
order_idstring+Your order id. Used to track and match payments in your system (1-100 chars).
amountnumber | string+Amount in USD (up to 2 decimals). Examples: 10, 10.1, 10.10.
currencystring+Currency code. Always send "USD".
coinstringPayment method the customer will use. Set to "USDC" or "SOL" to make it the only available method for this session. If not set, the customer can choose the payment method.
return_urlstring (url)Your store the customer can return to during payment.
success_urlstring (url)URL where the customer is redirected after a successful payment (link to your service).
recipient_walletstringOverride wallet for this payment. Funds go here instead of the default merchant wallet.
Rules
  1. order_id must be unique per merchant.
  2. success_url and return_url can be HTTP or HTTPS.
Notes
  • "return_url" is used for the Back button, so the customer can return to your store at any point during payment. On small screens the button is hidden. If it is not passed, we use Default return URL from merchant settings.
  • After a successful payment, the customer can click "Get your service" to access the service they paid for. The button uses "success_url" if provided, otherwise "return_url", otherwise the default return URL. If none are set, the button is disabled.
  • "recipient_wallet" replaces the recipient wallet for this payment, and funds go to the wallet set in "recipient_wallet".
Request example
curl 'https://cryptnow.io/api/v1/payment/create' \
  -X POST \
  -H 'X-Public-Key: public_4F8x...' \
  -H 'X-Signature: 21bc4f0d2d0e...' \
  -H 'Content-Type: application/json' \
  -d '{
    "amount": "14.20",
    "currency": "USD",
    "order_id": "147",
    "success_url": "https://site.io/order/5f2c9b"
  }'
Success response
{
  "success": true,
  "data": {
    "payment_id": 456,
    "session_key": "f3a91c20-7d44-4b8f-9c2a-6e15d3b8a904",
    "session_status": "pending",
    "order_id": "147",
    "amount": "14.20",
    "total_amount": "14.20",
    "merchant_receives": "14.06",
    "fee": "0.14",
    "currency": "USD",
    "payment_method": "ALL",
    "token": null,
    "network": "Solana",
    "payment_status": null,
    "recipient_wallet": "BQLxH3Drh51hbjfR9GMeB5FTBZyCtpYLvD5eqpfXupyo",
    "payer_wallet": null,
    "txid": null,
    "created_at": "2026-02-14T10:00:00Z",
    "active_at": null,
    "paid_at": null,
    "inactive_at": "2026-02-14T10:30:00Z",
    "url": "https://cryptnow.io/payment?session=f3a91c20-7d44-4b8f-9c2a-6e15d3b8a904",
    "return_url": null,
    "success_url": "https://site.io/order/5f2c9b"
  },
  "signature": "b8e4c0d13f6a9b27d5e8f104c3a6d92b7e0f5a1c8d4b63f290a7e5c1d8b4f603"
}
Errors
{
  "success": false,
  "error": "Payment with this order_id already exists"
}
Error codes:
  • 400 - Invalid request, validation error, or unknown field(s).
  • 401 - Authentication failed.
  • 404 - Merchant not found.
  • 409 - Duplicate order_id or payment already exists.
  • 429 - Too many requests (rate limit exceeded).
  • 500 - Internal server error.

// Always verify the signature on all responses and webhooks (Read here).

View Session

Returns a payment session by session_key so you can check its status, timing, and other data at any time. Use this endpoint if you do not want to use webhooks and want to get session information using an API request.

Endpoint
MethodGET
URLhttps://cryptnow.io/api/v1/payment/session/:session_key
AuthX-Public-Key, X-Signature
Path params
FieldTypeRequiredDescription
session_keystring (uuid)+Session id from Create Payment or, if you use webhooks, from webhooks.
Request example
GEThttps://cryptnow.io/api/v1/payment/session/f3a91c20-7d44-4b8f-9c2a-6e15d3b8a904
Success response
{
  "success": true,
  "data": {
    "payment_id": 456,
    "session_key": "f3a91c20-7d44-4b8f-9c2a-6e15d3b8a904",
    "session_status": "pending",
    "order_id": "147",
    "amount": "14.20",
    "total_amount": "14.20",
    "merchant_receives": "14.06",
    "fee": "0.14",
    "currency": "USD",
    "payment_method": "ALL",
    "token": null,
    "network": "Solana",
    "payment_status": null,
    "recipient_wallet": "BQLxH3Drh51hbjfR9GMeB5FTBZyCtpYLvD5eqpfXupyo",
    "payer_wallet": null,
    "txid": null,
    "created_at": "2026-02-14T10:00:00Z",
    "active_at": "2026-02-14T10:00:15Z",
    "paid_at": null,
    "inactive_at": "2026-02-14T10:30:00Z",
    "url": "https://cryptnow.io/payment?session=f3a91c20-7d44-4b8f-9c2a-6e15d3b8a904",
    "return_url": "https://site.io",
    "success_url": "https://site.io/order/5f2c9b"
  },
  "signature": "b8e4c0d13f6a9b27d5e8f104c3a6d92b7e0f5a1c8d4b63f290a7e5c1d8b4f603"
}
Errors
{
  "success": false,
  "error": "Session not found"
}
Error codes:
  • 400 - Invalid session_key.
  • 401 - Authentication failed.
  • 404 - Session not found.
  • 429 - Too many requests (rate limit exceeded).
  • 500 - Internal server error.

// Always verify the signature on all responses and webhooks (Read here).

Export History

Returns payment history for your merchant with filters by date and status.

If you want a quick export without the API, you can use the dashboard CSV export:

  1. Open the Dashboard > Export CSV.
  2. Select the merchant and apply filters (date and status).
  3. Click Export CSV to download the filtered list.

If you need automated exports or backend processing, use the API endpoint below.

Endpoint
MethodPOST
URLhttps://cryptnow.io/api/v1/payment/export
AuthX-Public-Key, X-Signature
Request body
FieldTypeRequiredDescription
date_fromstring+Start date in DD.MM.YYYY or DD.MM.YYYY HH:MM[:SS].
date_tostring+End date in DD.MM.YYYY or DD.MM.YYYY HH:MM[:SS].
statusstring+Filter by payment status: all or paid.
Rules
  1. date_from and date_to must be valid dates (DD.MM.YYYY or DD.MM.YYYY HH:MM[:SS]). Seconds are optional.
  2. date_from must be earlier than date_to.
  3. Filters are interpreted in UTC for both Dashboard CSV export and API export.
Request example
curl 'https://cryptnow.io/api/v1/payment/export' \
  -X POST \
  -H 'X-Public-Key: public_4F8x...' \
  -H 'X-Signature: 21bc4f0d2d0e...' \
  -H 'Content-Type: application/json' \
  -d '{
    "date_from": "10.01.2026 09:00",
    "date_to": "12.01.2026 18:30:45",
    "status": "all"
  }'
Success response
{
  "success": true,
  "data": [
    {
      "payment_id": 456,
      "session_key": "f3a91c20-7d44-4b8f-9c2a-6e15d3b8a904",
      "session_status": "inactive",
      "order_id": "147",
      "amount": "14.20",
      "total_amount": "14.20",
      "merchant_receives": "14.06",
      "fee": "0.14",
      "currency": "USD",
      "payment_method": "ALL",
      "token": "USDC",
      "network": "Solana",
      "payment_status": "paid",
      "recipient_wallet": "BQLxH3Drh51hbjfR9GMeB5FTBZyCtpYLvD5eqpfXupyo",
      "payer_wallet": "5eXgehWkldzarVA3LgJFkQkZbVF1eJHGxFKpNWrR7oaj",
      "txid": "WrHzgMNZERNUVc3ojR5Z199fPDxUVqTHAhrZvZFbcG7ajPVVhjG6spwKCPWXdy38J19fKSFFtP2gL87Jr9cmyLD",
      "created_at": "2026-02-14T10:00:00Z",
      "active_at": "2026-02-14T10:00:15Z",
      "paid_at": "2026-02-14T10:01:21Z",
      "inactive_at": "2026-02-14T10:30:00Z",
      "url": "https://cryptnow.io/payment?session=f3a91c20-7d44-4b8f-9c2a-6e15d3b8a904",
      "return_url": "https://site.io",
      "success_url": "https://site.io/order/5f2c9b"
    }
  ],
  "signature": "b8e4c0d13f6a9b27d5e8f104c3a6d92b7e0f5a1c8d4b63f290a7e5c1d8b4f603"
}
Errors
{
  "success": false,
  "error": "Invalid date_from format"
}
Error codes:
  • 400 - Invalid filters, date format, or unknown field(s).
  • 401 - Authentication failed.
  • 429 - Too many requests (rate limit exceeded).
  • 500 - Internal server error.

// Always verify the signature on all responses and webhooks (Read here).