Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.crypto-cash.world/llms.txt

Use this file to discover all available pages before exploring further.

Fiat Module

Note: all numeric values, amounts, rates, and identifiers in the examples are illustrative and provided for demonstration purposes only. Real values depend on market conditions, account configuration, and the parameters of a specific transaction.

Overview

Fiat Module is a subsystem of the CryptoCash platform that allows a merchant to accept fiat payments from end users and receive cryptocurrency to their wallet. Integration is performed through signed API requests. Payments are processed via a payment provider (Mercuryo). The end user completes the payment in the CryptoCash widget, where they select a payment method. After the payment is processed, the merchant receives a webhook with the final status. Supported features:
  • Payment by card, Apple Pay, Google Pay, SEPA, and other payment methods
  • Signed requests (ED25519 or LEGACY/SHA256) for merchant authentication
  • Webhooks to the merchant on every transaction status change
  • Automatic calculation of the merchant’s earnings based on partner_fee

High-level flow

1. Merchant sends a signed API request → receives a payment URL
2. User opens the URL → sees the CryptoCash widget
3. User selects a payment method
4. Payment provider processes the payment
5. Merchant receives a webhook on every status change
6. After successful payment, the merchant’s earnings are calculated automatically
Two payment flows in the widget:
Payment methodFlow
Apple Pay (native)The user pays directly in the widget — without being redirected to an external page
Card / other methodsThe user is redirected to the payment provider’s page to complete the payment
For a detailed description of the native Apple Pay flow, see the Apple Native Pay section.

Merchant setup and Fiat API Key

What the merchant configures

After the administrator has prepared the account, the merchant generates a Fiat API Key in the dashboard. When creating the key, the merchant sets parameters that apply to all payments associated with this key:
ParameterDescription
keyTypeSignature algorithm: ED25519 (recommended) or LEGACY (SHA256)
keyNameCustom key name
partnerFeeShare of the provider fee that goes to the merchant; configured by the administrator on the provider account
paymentMethodsPayment methods available in the widget, for example ["card", "apple_pay"]
webhookUrlURL for receiving payment status webhooks
logoUrlMerchant logo displayed in the widget
ipRestrictionEnabledWhether to restrict API access by IP address
allowedIpAddressesList of allowed IP addresses or CIDR ranges
expiresAtSpecific key expiration date
neverExpiresIf true, the key does not expire (expiresAt = null); by default, the key validity period is 1 year
The response returns a publicKey / privateKey pair. The private key is stored on the platform in encrypted form and is shown to the merchant only once — during creation. Save it immediately.
If two-factor authentication is enabled on the merchant account, 2FA confirmation is required to generate the key.

Fiat API Key fields

FieldTypeDescription
publicKeystringKey identifier, passed in every request
privateKeystringSecret for signing requests; stored encrypted on the platform
keyTypeED25519LEGACYSignature algorithm
isActivebooleanWhether the key is active
expiresAtdatetimenullExpiration time (null — no expiration)
paymentMethodsstring[]Allowed payment methods
webhookUrlstringnullURL for webhook delivery
logoUrlstringnullLogo URL
ipRestrictionEnabledbooleanWhether IP restriction is enabled
allowedIpAddressesstring[]Allowed IP addresses

ED25519 vs LEGACY

ED25519LEGACY
AlgorithmAsymmetric cryptography (Ed25519)SHA256-based signature
Key relationpublicKey is mathematically derived from privateKeypublicKey is an identifier; privateKey is a shared secret used for signing
VerificationSignature is verified using publicKey without knowing privateKeyThe platform uses the stored privateKey to verify the signature
RecommendedYesOnly for compatibility with legacy integrations

What is checked on each request

When receiving a signed request, the platform checks:
  • The key is active
  • The key has not expired
  • The IP of the API caller (merchant server) is included in the allowed list if IP restriction is enabled
  • The signature is valid for the selected algorithm
Important: IP restriction applies to the address of the server making the API request, not to the end user’s IP in the payment payload ip field.

Signed requests

All merchant API requests must be signed. The signature algorithm is defined by the keyType value selected when creating the key.

Request structure

{
  "data": "<base64-encoded JSON payload>",
  "signature": "<base64-encoded signature>"
}
publicKey is passed either in the x-public-key header or inside the data object. If both are present, the header takes priority.
1. payload    → JSON.stringify(payload)
2. json       → Buffer.from(json, 'utf8').toString('base64')  → data
3. sign       → Ed25519.sign(Buffer.from(data), privateKeyBytes) → signatureBytes
4. signature  → signatureBytes.toString('base64')

LEGACY (SHA256)

1. payload    → JSON.stringify(payload)
2. json       → Buffer.from(json, 'utf8').toString('base64')  → data
3. hash       → SHA256(privateKey + data) → hashHex
4. signature  → Buffer.from(hashHex, 'utf8').toString('base64')

Full example

Payload for form/retrieve:
{
  "publicKey": "a1b2c3d4...",
  "fiatCurrency": "SGD",
  "fiatAmount": "100",
  "currency": "USDT",
  "network": "TRC20",
  "address": "TXxxx...",
  "ip": "203.0.113.5"
}
Final body of the signed request:
{
  "data": "eyJwdWJsaWNLZXkiOiJhMWIyYzNkNC4uLiIsImZpYXRDdXJyZW5jeSI6IlNHRCIsImZpYXRBbW91bnQiOiIxMDAiLCJjdXJyZW5jeSI6IlVTRFQiLCJuZXR3b3JrIjoiVFJDMjAiLCJhZGRyZXNzIjoiVFh4eHguLi4iLCJpcCI6IjIwMy4wLjExMy41In0=",
  "signature": "base64-encoded-signature"
}

Payment creation — form/retrieve

Endpoint

POST /merchant/api/v1/pay-fiat/form/retrieve
Signed request. The signature and IP are checked before the request is processed.

Request

The data field of the signed request contains the following JSON:
FieldTypeRequiredDescription
tickerstring✓*Crypto asset and network ticker, for example "USDTTRC20"
currencystring✓*Cryptocurrency code, for example "USDT"
networkstring✓*Blockchain network, for example "TRC20"
fiatCurrencystringFiat currency code, for example "SGD"
fiatAmountstringFiat amount as a string, for example "100"
addressstringWallet address for cryptocurrency crediting
ipstringEnd user’s IP address
emailstringCustomer email
redirectUrlstringURL to return the user to after payment
langstringWidget language, default "en"
externalIdstringExternal order ID on the merchant side; must be unique within the key
* To select a crypto asset, pass either ticker or the currency + network pair.

Response

{
  "code": 200,
  "data": {
    "item": {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "externalId": "order-123",
      "url": "https://buy.cryptocash.world/merchant/payment/550e8400-e29b-41d4-a716-446655440000"
    }
  }
}
FieldDescription
idInternal transaction UUID
externalIdExternal ID from the request or null
urlCryptoCash widget URL — redirect the user to this URL

What happens after the request

  1. Signature and IP are checked.
  2. externalId uniqueness is checked within the merchant key.
  3. The fiat amount is checked against the minimum allowed amount for the selected currency.
  4. The network value is normalized case-insensitively.
  5. A transaction is created with the New status.
  6. The widget URL is generated.
  7. A payment::created webhook is sent to the merchant.
  8. id and url are returned.

CryptoCash widget and provider page

CryptoCash widgetPayment provider page
URLhttps://buy.cryptocash.world/merchant/payment/{id}Generated inside the widget
BrandingMerchant logoProvider styling
PurposePayment method selection, rate preview, native Apple PayDirect payment processing
The merchant always receives the CryptoCash widget URL. The provider page URL is generated inside the widget after the payment method is selected and is not returned to the merchant.

Merchant Public API

Retrieve payment

POST /merchant/api/v1/pay-fiat/payments/retrieve
Signed request. The data field contains one of the following:
{ "internalId": "550e8400-..." }
or
{ "externalId": "order-123" }
Response:
{
  "code": 200,
  "data": {
    "item": {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "externalId": "order-123",
      "status": "Paid",
      "fiatCurrency": "SGD",
      "fiatAmount": "100",
      "cryptoCurrency": "USDT",
      "network": "TRC20",
      "cryptoAmount": "73.21",
      "address": "TXxxx...",
      "hash": "blockchain-hash",
      "widgetUrl": "https://buy.cryptocash.world/merchant/payment/550e8400-...",
      "createdAt": "2026-04-16T10:00:00.000Z",
      "updatedAt": "2026-04-16T10:07:00.000Z"
    }
  }
}

Payment list

POST /merchant/api/v1/pay-fiat/payments/list
Signed request. The data field:
FieldTypeDefaultDescription
pagenumber1Page number
pageSizenumber100Number of items per page
dateAfterdatetimeFilter: created after this date
dateBeforedatetimeFilter: created before this date
Response:
{
  "code": 200,
  "data": {
    "items": [ /* array of payments in the same structure as retrieve */ ],
    "pagination": {
      "page": 1,
      "pageSize": 100,
      "total": 42
    }
  }
}

Currency lists

POST /merchant/api/v1/fiat-currencies/list
POST /merchant/api/v1/pay-fiat/crypto-currencies/list
Both endpoints use signed requests. Minimum payload in data:
{ "publicKey": "..." }
crypto-currencies/list returns the cryptocurrencies available to the merchant together with networks and tickers. Values from tickers can be passed to form/retrieve instead of the currency + network pair.

Payment response fields

FieldTypeNullableDescription
idstringTransaction UUID
externalIdstringMerchant external ID
statusstringCurrent status
fiatCurrencystringFiat currency code
fiatAmountstringFiat amount
cryptoCurrencystringCryptocurrency code
networkstringBlockchain network
cryptoAmountstringReceived crypto amount
addressstringWallet address
hashstringBlockchain transaction hash
widgetUrlstringWidget URL
createdAtdatetimeCreation time
updatedAtdatetimeLast update time

Transaction statuses

StatusDescription
NewTransaction created, awaiting user action
WaitingPayment accepted and being processed
PaidCryptocurrency sent to the wallet address
FailPayment failed
CanceledPayment canceled
Statuses are set by the platform based on payment provider events. The merchant cannot change the status via API.

Error handling

All API errors are returned in one of two formats: Format A — coded error:
{ "code": 2020, "message": "..." }
Format B — error list used for decoding errors:
{ "errors": [2010] }

Error codes

CodeDescription
1000Bad request
1102Invalid request: unsupported network, amount below minimum, duplicate externalId
1110Request validation error
2010data decoding error
2011signature decoding error
2020Invalid signature
2021API key blocked
2030IP address forbidden
3001Order not found
3002Transaction not found

Apple Pay

The CryptoCash widget supports the native Apple Pay flow: the iOS payment sheet opens directly in the widget without redirecting to an external page. For a detailed description of native mode availability conditions, fallback behavior, and error handling, see the Apple Native Pay section.

Diagrams

General payment flow