Skip to main content

How to create an Invoice Payment Widget via API

Overview​

Invoice Payment Widget lets the merchant create a hosted Calypso checkout page through API.

After the widget is created, use the returned idempotencyKey as widgetKey in the payment URL:

https://pay.calypso.money/pay?widgetKey={idempotencyKey}

Widget type​

Widget typeDescription
SINGLE_FIATCreates a payment widget for one fiat-denominated payment. The customer pays in one of the allowed cryptocurrencies.

Integration flow​

Common setup​

  1. Create a SINGLE_FIAT payment widget through Payment Widget API.
  2. Save the returned idempotencyKey, widgetType, widgetState, externalId, and invoices.
  3. Build the widget URL and redirect the customer to it or embed it into the merchant website with an iframe.
  4. When Calypso sends INVOICE_CREATE_INVOICE, store the invoice identifiers from the webhook or from the widget response.
  5. Use paymentStatus from returnUrl only for customer-facing page state.

Successful payment flow​

Use this flow when the customer pays through the widget and Calypso can complete the payment without manual intervention.

  1. Optional: Calypso may send INVOICE_MEM_POOL_FOUND when the customer transaction is detected in the blockchain mempool. This webhook is not guaranteed: on fast blockchains, the mempool status may be skipped.
  2. When Calypso sends INVOICE_FUNDS_RECEIVED_FOR_INVOICE, record that funds were received on the invoice address. This webhook confirms the deposit, but it is not always the final payment result.
  3. If Calypso sends INVOICE_PAID, mark the customer-facing payment as successful.
  4. INVOICE_TRANSLATION_TO_ACCOUNT_COMPLETED is sent when funds are credited to the merchant account balance. Use it for reconciliation, not as the customer-facing payment confirmation.

If needed, verify the current invoice status by using [POST] invoice.

No payment or failed processing flow​

Use this flow when the customer does not complete the widget payment in time or invoice processing cannot be completed.

  1. INVOICE_EXPIRED is sent if the invoice created from the widget expires before a successful payment is completed. Stop accepting payment for this widget invoice and create a new widget if the customer still needs to pay.
  2. INVOICE_FAILED is sent if invoice processing fails because Calypso cannot complete the payment flow for this widget invoice. Stop the current payment flow and verify the invoice state through [POST] invoice.

Compliance corner case​

Use this flow only when the transaction is routed to compliance review.

  1. Optional: INVOICE_PENDING_COMPLIANCE is sent only if the transaction is routed to compliance review under the relevant compliance conditions. If the transaction automatically passes compliance, this webhook is not sent; continue waiting for the next invoice status webhook.
  2. If Calypso sends INVOICE_COMPLIANCE_DECLINED, treat it as a terminal negative compliance result and do not mark the widget payment as paid.

Intervention corner case​

Use this flow when funds were received, but the widget invoice requires merchant action, for example because of underpay or overpay.

  1. After INVOICE_FUNDS_RECEIVED_FOR_INVOICE, Calypso may send INVOICE_PENDING_INTERVENTION.
  2. Check the invoice details by using [POST] invoice and review state, interventionType, amount, totalDebitAmount, and isInterventionResolved.
  3. Do not mark the widget payment as paid until the intervention is resolved and the invoice reaches PAID.

Sequence​

Names of requests on the scheme indicate Payment Widget API methods and invoice webhook events.

SINGLE_FIAT Invoice Payment Widget sequence

Widget lifetime​

The widget can have an expiration date set during creation.

For each created widget, the lifetime of invoices created from the widget does not exceed one day. If the widget expiration time is less than one day, invoices created from this widget expire after the same shorter period.

Common request fields​

The Payment Widget API creation method uses the standard request wrapper.

FieldTypeRequiredDescription
accountstringYesMerchant account ID. The request will be sent for this account.
timestampnumberYesCurrent Unix UTC timestamp in milliseconds. The value must not be less than 3 minutes in the past or greater than 3 minutes in the future.
payloadobjectYesObject with payment widget creation data.

Create SINGLE_FIAT widget​

Use [POST] payment-widget/single-fiat/create.

Payload fieldTypeRequiredDescription
fiatCurrencystringYesFiat currency of the widget amount.
fiatAmountnumberYesFiat amount used for invoices created from this widget.
descriptionstringYesPayment widget description.
cryptoCurrenciesarrayYesCryptocurrencies available for payment.
expirationstringYesWidget expiration date and time.
logoUrlstringNoMerchant logo URL shown on the widget page. PNG format is recommended.
returnUrlstringNoURL where the customer can return from the widget page.
supportUrlstringNoMerchant support URL shown on the widget page.
idempotencyKeystringNoExternal ID in UUID format.
externalIdstringNoMerchant-side widget ID. All invoices created from this widget receive the same externalId.

Request example​

{
"account": "0x0000000000000000000000000000000000000000",
"timestamp": 1761650432438,
"payload": {
"fiatCurrency": "USD",
"fiatAmount": 100,
"description": "Order #1001",
"cryptoCurrencies": [
"USDT_TRX",
"USDT_BSC"
],
"expiration": "2026-06-30T12:00:00Z",
"returnUrl": "https://merchant.com/checkout",
"supportUrl": "https://merchant.com/support",
"idempotencyKey": "123e4567-e89b-12d3-a456-426614174000",
"externalId": "order-1001"
}
}

Response fields​

FieldTypeDescription
idempotencyKeystringWidget key used to open the widget page.
cryptoCurrenciesarrayCryptocurrencies available for payment.
widgetTypestringWidget type: SINGLE_FIAT.
widgetStatestringCurrent widget status.
fiatCurrencystringFiat currency for SINGLE_FIAT widget.
fiatAmountnumberFiat amount for SINGLE_FIAT widget.
descriptionstringPayment widget description.
logoUrlstringMerchant logo URL.
returnUrlstringMerchant return URL.
supportUrlstringMerchant support URL.
expirationstringWidget expiration date and time.
externalIdstringMerchant-side widget ID.
invoicesarrayInvoices created from this widget.
createdDatestringWidget creation date and time.

Invoice object inside invoices​

FieldTypeDescription
invoiceIdstringCalypso invoice ID created from the widget.
cryptoCurrencystringCryptocurrency selected for the invoice.
invoiceIdempotencyKeystringInvoice idempotencyKey. Use it to check invoice details through Invoice API.
invoiceExternalIdstringMerchant-side invoice ID.

Widget statuses​

StatusDescription
IN_PROGRESSWidget is active and can be used for payment.
COMPLETEDWidget payment flow was completed.
ARCHIVEDWidget was archived and is no longer active.

Invoice payment status is tracked separately through invoice state and Invoice webhooks.

Widget URL​

Use the returned widget idempotencyKey as widgetKey.

https://pay.calypso.money/pay?widgetKey={idempotencyKey}

Optional URL parameters:

ParameterRequiredDescription
widgetKeyYesWidget idempotencyKey returned by Payment Widget API.
themeNoWidget color theme: light or dark. The default value is light.
logoNoShows or hides the logo on the widget page: true or false.

URL example​

https://pay.calypso.money/pay?widgetKey=123e4567-e89b-12d3-a456-426614174000&logo=true&theme=light

iframe integration​

You can embed the payment widget into the merchant website with an iframe.

Add clipboard-read and clipboard-write to the allow attribute so the widget copy buttons can copy the payment address and amount.

<iframe
src="https://pay.calypso.money/pay?widgetKey=123e4567-e89b-12d3-a456-426614174000&logo=true&theme=light"
title="Calypso payment widget"
width="100%"
height="720"
style="border: 0;"
allow="clipboard-read; clipboard-write"
></iframe>

returnUrl payment status​

When Calypso redirects the customer to returnUrl, it can append the paymentStatus query parameter.

paymentStatus valueMeaningRecommended merchant page
SUCCESSInvoice payment reached a successful final status.Success page or order confirmation.
FAILEDInvoice payment was declined, archived, or failed.Failed or expired payment page.
absentNo status-specific redirect was applied.Standard return page.

paymentStatus is a redirect parameter, not the invoice state. Use Invoice webhooks or [POST] invoice as the source of truth for backend order processing.

CaseRecommendation
Customer opens widgetShow the widget through redirect or iframe.
Customer returns to returnUrlRead paymentStatus and show a success or failed page.
Payment status changesUpdate order status through Invoice webhooks.
Intervention is requiredUse the intervention flow for INVOICE_PENDING_INTERVENTION.
Widget expires or is archivedStop showing the widget and create a new one if payment is still required.
DocumentLink
Invoice Payment Widget webhooksInvoice Payment Widget webhooks
Manage invoice interventionsHow to manage interventions via API
Payment Widget API referencePayment Widget API