Quotes & rounding
Every payment intent is denominated in fiat (EUR, USD, BRL or GBP). Before the customer pays, that amount
has to become an exact amount of a crypto asset.
Live payments: the processor’s rate
Section titled “Live payments: the processor’s rate”Live payments are processed through the platform’s Bitcart account. When the checkout opens the Bitcart invoice
(POST /v1/public/checkout-sessions/{id}/processor-invoice), Bitcart prices the intent’s fiat amount in every
accepted asset. Each entry of the session’s processor.methods carries:
amount— the exact decimal amount to send in that asset;rate— the exchange rate Bitcart used (invoice currency per unit of the asset);addressandpayment_url— where to pay, and a wallet URI for QR codes;divisibilityand, for tokens,contract.
The checkout labels the rate as Bitcart’s exchange rate. GRYPHEM PAY does not set it, does not add a spread to it and does not offer it as a price reference. The invoice expires with the intent’s payment window.
Quotes in watch-only processing
Section titled “Quotes in watch-only processing”In watch-only processing (see Wallets; this platform does not use it for payments), the gateway itself issues a quote when the customer chooses a network and asset: an immutable, versioned conversion from your fiat amount to an exact asset amount, locked for a limited time.
{ "id": "qt_01J…", "object": "quote", "network_id": "bitcoin:mainnet", "asset_id": "btc", "asset_symbol": "BTC", "decimals": 8, "fiat_amount": "59.90", "fiat_currency": "EUR", "asset_amount": "0.00099834", "asset_amount_base_units": "99834", "rate": "60000.00", "spread_bps": 0, "rounding_policy": "ceil_to_asset_base_unit", "required_confirmations": 3, "status": "active", "network_fee_paid_by": "customer", "platform_fee_billed_separately": true}(Abridged; the values above are illustrative and are not a price.)
Rounding policy: ceil_to_asset_base_unit
Section titled “Rounding policy: ceil_to_asset_base_unit”The asset amount is computed with exact rational arithmetic and rounded up to the next base unit (satoshi, token unit), so the merchant never receives less than the invoiced value because of rounding:
units = ceil( fiat_amount / rate × 10^decimals × (1 + spread_bps / 10 000) )59.90 / 60000 × 10^8 = 99833.33… → 99834 satsNo step uses binary floating point. If the division is exact, nothing is added.
Sources, staleness and failure
Section titled “Sources, staleness and failure”The design requires a primary market feed plus a secondary sanity source, rejects stale prices and prices that
deviate beyond a limit, and fails closed: if no trustworthy rate is available, no quote is issued. The quote
records rate_source, secondary_source and deviation_bps as evidence.
Expiry and refresh
Section titled “Expiry and refresh”Each quote has locked_at and expires_at. A transfer first seen before expires_at counts as on time even if
it confirms later. After expiry the checkout offers Refresh quote (POST /v1/public/checkout-sessions/{id}/refresh-quote),
which supersedes the old quote with a new one on the same network and address. The intent’s own expires_at
still bounds how long the customer can keep paying.
Who pays what
Section titled “Who pays what”- The asset amount is what the customer must send.
- Network fees are paid by the sender on top.
- Platform fees are billed to the merchant separately — never deducted from the payment.