Hosted checkout
What buyers see on /pay/{invoiceId} and how payment links differ from API invoices.
API invoice checkout
After POST /api/v1/invoices, redirect to checkout_url:
https://ulasend.com/pay/{invoice_id}For crypto payments, the page shows the source coin, exact amount, network, QR and deposit address from payment_instructions, plus any required memo and live status updates. Bank payments show USD transfer instructions instead. Choose an available source under Settings → Payment methods before creating the invoice. An issued checkout keeps its original payment source.
Buy with card is available for new checkouts whose source is USDC on Base, when configured. Other payment sources do not offer card purchase. Details: Buy with card.
The payment provider converts the source payment to USDC on Base. The invoice's financial fields use USDC, and its received amount reflects the actual verified settlement. A detected source transfer remains processing until delivery is verified. Before fulfilling, verify the signed webhook, current invoice status, and received amount against your saved order.
A verified payment that arrived after invoice expiry enters review. When the provider supplies a source receipt time, Ulasend uses that time; otherwise it uses the first verified delivery time. Payments already sent continue to be monitored. Test invoices offer a simulation flow without real payment controls.
ACH and domestic wire payments
Eligible live accounts can create bank invoices using USD_ACH or USD_WIRE. ACH requires your individual merchant receiving wallet and bank-payment eligibility; shared receiving wallets do not support ACH. Domestic wire is available only for accounts enabled for that method. The methods offered in your dashboard reflect your account's eligibility.
Bank payments are customer-initiated transfers. Ulasend does not debit the customer's bank account. Checkout displays the exact USD amount, bank and beneficiary details, routing and account numbers, and a required payment reference. The customer should:
- Send the exact amount in one transfer using the specified ACH or domestic wire method. Do not send an international SWIFT transfer.
- Include the payment reference exactly as shown. If their bank cannot include it, contact the merchant before sending.
- Pay bank sending fees separately so the full requested amount arrives, and initiate the transfer before the checkout's send-by deadline.
Bank amounts use whole USD cents, with a minimum of 1 USD. The default payment window is seven days; an explicit expires_in_minutes must be between 10080 and 20160 (seven to fourteen days). Bank invoices always require the full amount, even if your crypto underpayment tolerance is positive.
Bank processing can take several business days. A bank confirmation or a Processingmessage is not a completed order. Wait for Ulasend's verified invoice result and signed webhook before fulfillment. Settlement is recorded in USDC on Base. A later bank return or review can require attention even after an earlier paid receipt; check the current payment state when resolving an order.
Once a transfer is processing, complete, returned, expired or cancelled, saved bank details are for records only. Do not reuse them or send a second transfer to cover a shortfall without contacting the merchant. If checkout says ACH is unavailable, request another payment method. Transfers already sent continue to be checked.
Require exact payment
With zero underpayment tolerance, an invoice can become paid only when verified funds received cover its full final requested amount. Compare against amount_atomic returned by the invoice API. This includes any processing fee passed to the buyer and any upward rounding in the final quote. The required amount is never rounded down to accept a short payment.
For a 100 USDC invoice, 99.999999 USDC remains partially_paid; 100 USDC covers the amount requirement. More than 100 USDC also covers it, with the excess handled under the invoice's overpayment policy. Other review holds still apply. Accepting a manual review may release verified funds to your balance, but cannot waive a shortfall on an exact-payment invoice.
The tolerance setting is saved when the invoice is issued. Changing the setting applies to future invoices. Historical invoices already marked paid keep their recorded status; integrations that require full payment should always check the actual received amount.
Accepting slightly short payments
For crypto payments, a positive tolerance lets an invoice become paid when the verified amount delivered is within the percentage saved on that invoice. For a final 100 USDC requirement with a 1% allowance, 99 USDC meets the amount requirement; 98.999999 USDC stays partially_paid. Other review holds still apply. Manual review cannot accept less than the saved minimum.
New eligible provider-routed checkouts use flexible amount matching when the tolerance is positive. This lets us record the actual payment and then apply your saved rule. Existing payment instructions retain their original provider matching rules. A completed short payment does not guarantee that the same address will accept a second transfer.
You receive credit only for funds actually delivered, less applicable fees. Accepting a shortfall does not add the missing amount to your balance. For a provider-routed payment, the comparison uses final USDC after conversion and network costs, even if the payer sent another coin.
For USDC on Base, use six-decimal integer units: 1 USDC is 1000000atomic units. The settlement gross is the verified USDC delivered before Ulasend's fees; the net is your credited amount after fees and any retained excess. Compare the gross to the required amount, not the net. See the webhook fulfillment checks.
Return to your order after payment
Your server can set success_url in POST /api/v1/invoices for each order, whether the invoice uses usd_amount, a coin amount, or product_id:
{
"usd_amount": "49.99",
"asset": "USDC_BASE",
"external_reference": "order-12345",
"success_url": "https://merchant.example/orders/order-12345/confirmation"
}Replace the example domain with your own. success_url is optional and must be a complete HTTPS URL, at most 2,048 characters, with no embedded username or password. Ulasend trims surrounding whitespace and normalizes the URL with new URL(value).toString(). It does not append invoice or order IDs; include your order reference in the URL and use external_reference to match the webhook to the same order.
The destination is saved when the invoice is created and cannot be changed on an issued invoice. The authenticated invoice API returns success_url, or nullif it was omitted. A payment link's Redirect After Payment setting applies to invoices created through that link; for a separate API-created invoice, pass success_url explicitly.
Checkout redirects after three seconds once Ulasend confirms paid or overpaid, provided that browser tab has previously seen the invoice awaiting payment. Checkout remembers that state in the tab's session storage, including across a refresh. A manual Continue link is also available. Opening an already-paid receipt without that checkout history offers the manual link without an automatic redirect. Live and test invoices use the same behavior. Incomplete or unsuccessful payments, and invoices without a success_url, do not redirect.
Use the verified payment webhook to mark your order paid and fulfill it. A browser return is not proof of payment. The buyer may return before the webhook arrives, so your confirmation page should show a pending state until your backend has confirmed payment.
Payment links
Dashboard / API payment links (/l/pl_…) are reusable. For an order-specific cart total and reference, your server issues a signed checkout URL from the link's checkout-sessions endpoint. See Dynamic payment links.