CryptPays

Integration path

One merchant flow across every chain

Use https://api.cryptpays.com/api as the production API base. Chain-specific behavior changes finality, priority, and transaction identity—not the overall flow.

  1. 1DiscoverCatalog and info
  2. 2CreatePayment address
  3. 3PresentNetwork + address
  4. 4VerifySigned callback
  5. 5FulfillIdempotently
  6. 6HTTP 200Acknowledge

Server integration

PHP

Discover current metadata, create an amount-independent address, persist its configuration, and route only a verified confirmed callback into transactional fulfillment.

Discover and create

This runnable PHP example requests current metadata, then explicitly selects JSON POST callbacks. Omitting post keeps the API’s GET callback default.

PHP
<?php

function cryptPayJson(string $method, string $url, ?array $body = null): array
{
    $curl = curl_init($url);
    $options = [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => 15,
        CURLOPT_HTTPHEADER => ['Accept: application/json'],
    ];

    if ($method === 'POST') {
        $options[CURLOPT_POST] = true;
        $options[CURLOPT_HTTPHEADER][] = 'Content-Type: application/json';
        $options[CURLOPT_POSTFIELDS] = json_encode($body, JSON_THROW_ON_ERROR);
    }

    curl_setopt_array($curl, $options);
    $responseBody = curl_exec($curl);
    $status = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);

    if (!is_string($responseBody) || $status !== 200) {
        throw new RuntimeException('CryptPays request failed with HTTP ' . $status);
    }

    return json_decode($responseBody, true, 512, JSON_THROW_ON_ERROR);
}

$apiBase = 'https://api.cryptpays.com/api';
$ticker = 'bep20_usdt';
$callbackUrl = 'https://merchant.example/payments/callback?order_id=123';
$addressOut = '0x1111111111111111111111111111111111111111';

$info = cryptPayJson('GET', "$apiBase/$ticker/info");
$payment = cryptPayJson('POST', "$apiBase/$ticker/create", [
    'callback_url' => $callbackUrl,
    'address_out' => $addressOut,
    'post' => 1,
    'json' => 1,
]);

// Persist the order reference, ticker, exact callback URL, address_in,
// address_out, and minimum_transaction_coin snapshot as decimal strings.
printf("Send %s to %s on %s\n", $ticker, $payment['address_in'], $info['ticker']);

Verify, transition, fulfill

Use the copy-ready PHP verifier to read the raw request, enforce the 300-second window, and verify RSA-SHA256 before parsing. Then apply this production flow transactionally:

Conceptual lifecycle logic

Verified pendingRecord uuid at pending stage; never fulfill.
Verified confirmedRequire result="sent" and pending=0.
Merchant transactionValidate order and coin; advance pending → sent; set fulfilled_at once.
Successful commitReturn exactly HTTP 200.

Persist this state in shared durable storage. A process-local array is not safe, and seeing a UUID during pending must not suppress its later confirmed event.

Server integration

Node.js

Use the built-in fetch API for discovery and creation. On the callback route, raw-body middleware must run before JSON or form parsing.

Discover and create

JavaScript · ESM
const apiBase = 'https://api.cryptpays.com/api';
const ticker = 'bep20_usdt';
const callbackUrl = 'https://merchant.example/payments/callback?order_id=123';

const infoResponse = await fetch(`${apiBase}/${ticker}/info`);
if (!infoResponse.ok) throw new Error(`Info failed: HTTP ${infoResponse.status}`);
const info = await infoResponse.json();

const createResponse = await fetch(`${apiBase}/${ticker}/create`, {
  method: 'POST',
  headers: { 'content-type': 'application/json', accept: 'application/json' },
  body: JSON.stringify({
    callback_url: callbackUrl,
    address_out: '0x1111111111111111111111111111111111111111',
    post: 1,
    json: 1,
  }),
});

if (!createResponse.ok) throw new Error(`Create failed: HTTP ${createResponse.status}`);
const payment = await createResponse.json();

// Persist callbackUrl, info.ticker, payment.address_in, payment.address_out,
// and payment.minimum_transaction_coin using decimal-safe string handling.
console.log({ ticker: info.ticker, addressIn: payment.address_in });

Preserve callback bytes

The validated Express verifier provides the complete canonicalization and node:crypto code. Its middleware order is essential:

JavaScript · integration skeleton
// Register this route before express.json() or express.urlencoded().
app.all('/payments/callback', express.raw({ type: () => true }), async (req, res) => {
  // Verify timestamp + signature over method, host, req.originalUrl,
  // and the exact req.body Buffer. Parse only after verification passes.
  const payload = await verifyAndParseCryptPaysCallback(req);

  if (payload.result === 'sent' && Number(payload.pending) === 0) {
    // In one durable DB transaction: validate order + coin, allow pending → sent,
    // and fulfill this confirmed UUID only if fulfilled_at is still empty.
    await processConfirmedPaymentIdempotently(payload);
  }

  return res.sendStatus(200);
});

Integration skeleton: use the complete verifier linked above for verifyAndParseCryptPaysCallback and implement the durable merchant transaction in your own storage layer. Do not replace it with an in-memory Set.

Chain guide

EVM networks and tokens

Prefer canonical tickers returned by the live catalog. Verified formats include erc20_eth, erc20_usdt, bep20_bnb, bep20_usdt, polygon_pol, and polygon_usdt; runtime enablement may differ.

Shared address, independent payments

1 ETH depositPayment A → UUID A → forward A → callback A
100 BSC USDT depositPayment B → UUID B → forward B → callback B

Deposits are never combined merely because they use the same address.

Reuse and priority

  • The same callback URL across compatible EVM assets returns the existing EVM address and configuration.
  • Repeated /create does not update address_out, confirmations, priority, transport, pending, or conversion settings.
  • Use a new callback URL when you need a separate configuration.
  • EVM accepts priority=default only; explicit slow or fast returns 1103 UNSUPPORTED_PRIORITY.

Chain guide

UTXO chains

BTC, LTC, BCH, DOGE, and ZEC use network-specific address families. A callback URL already associated with BTC cannot be reused to create an LTC, BCH, DOGE, or ZEC address.

txid_in

Bare transaction hash

Never parse a colon-delimited output index from this field.

vout

Output index

Use (txid_in, vout) as the incoming on-chain identity because one transaction can contain multiple outputs.

Confirmations and priority

confirmations is the incoming customer-deposit count, never the outbound-forward count. You may request a higher threshold within current operator limits; a lower request cannot reduce the network default.

UTXO priority behavior
FamilySupported prioritiesMerchant note
BTCslow, default, fastSelected tier affects forwarding network cost.
LTCslow, default, fastUses Litecoin-specific network configuration.
BCHslow, default, fastUses Bitcoin Cash-specific network rules.
DOGEslow, default, fastA Dogecoin-specific fee floor still applies.
ZECdefault onlyZIP-317 conventional fees do not expose artificial tiers.

The public minimum remains based on default/medium economics even when a wallet selects slow or fast. Consult live metadata rather than hardcoding a threshold.

Chain guide

Solana and SPL

Use sol_sol for native SOL and tickers such as sol_usdc for enabled SPL assets. The live catalog is authoritative for availability.

Finality

Pending/not final uses confirmations=0. Confirmed/final uses confirmations=1. Numeric confirmations supplied to /create do not change this model, and slot distance is not exposed.

Priority

slow, default, and fast are supported and affect the actual forwarding priority and network cost. Internal compute-unit pricing is operator-controlled and not part of the public contract.

Independent principal and costs

Every incoming SOL or SPL deposit is one independent payment with its own UUID, accounting, forward, and callback. Earlier wallet or token balances are not added to a later deposit’s principal, and quick successive deposits remain separate.

Applicable Solana network and rent-related recovery can contribute to fee_coin; fee remains the contracted CryptPays percentage. Reconcile using value_coin = value_forwarded_coin + fee_coin.

Chain guide

TRON

trc20_trx is the canonical native format. A token ticker such as trc20_usdt is usable only when that token appears in the live enabled catalog.

  • TRON follows the numeric-chain confirmation rules: the operator default is the floor, and higher merchant requests must remain within the configured maximum.
  • TRON currently accepts priority=default only. Explicit slow or fast is rejected.
  • If a TRON asset is disabled or unavailable, it does not appear in /api/cryptocurrencies.

No resource-management or delegation setting is required from merchants.

Migration

Migrating from CryptAPI

CryptPays follows a familiar keyless payment-address and callback model, but migration requires an explicit contract review. Check your existing integration against the CryptPays requirements below rather than assuming an upstream field or behavior is identical.

CryptPays migration requirements
AreaCryptPays requirementWhat to check in your existing integration
TickerUse the canonical ticker returned by CryptPays discovery.Do not assume an older ticker string is identical.
Address identityCallback URL plus address family controls compatible reuse.Use a new callback URL for an incompatible family or new configuration.
Confirmed eventFulfill on result=sent, pending=0.Do not wait for another terminal wire value.
AcknowledgementReturn exactly HTTP 200; body is ignored.Remove any dependency on a special response body.
SignatureVerify the RSA-SHA256 canonical request and timestamp first.Preserve method, host, exact path/query, and raw body.
IdempotencyTrack UUID plus lifecycle transition; fulfill confirmed once.Allow the same UUID to advance from pending to sent.
Accountingfee is percentage; fee_coin is total deduction.Reconcile with the exact callback invariant.
Price/conversionQuotes and conversion keys use USDT.Do not interpret them as fiat or multi-fiat output.
UTXO identityUse bare txid_in plus separate vout.Review the deduplication key.
TransportGET is default; explicitly set post=1, json=1 for JSON POST.Do not infer delivery method from the method used to call /create.
MinimumRead current values from discovery or /info.Remove hardcoded thresholds.

Go-live review

Production integration checklist

  • Use /api/cryptocurrencies for current supported assets.
  • Use /info for current minimum and default metadata.
  • Use a stable unique callback URL per order and address family.
  • Display both network and asset clearly to the customer.
  • Do not assume /create registers an expected amount.
  • Set post=1, json=1 explicitly when JSON POST is desired.
  • Keep pending off unless an early informational event is useful.
  • Verify timestamp and signature before trusting callback fields.
  • Preserve exact raw callback bytes for verification.
  • Fulfill only result=sent, pending=0.
  • Use persistent lifecycle-aware idempotency.
  • Return exactly HTTP 200 after successful handling.
  • Treat monetary values as decimal strings or base-unit-safe values.
  • Use txid_in plus vout for UTXO identity.
  • Use runtime minimums instead of hardcoded values.
  • Test callbacks through the real proxy, firewall, and WAF path.