Skip to main content

Crypto payments via API

With Crypto, you create and confirm a Payment Intent from your server, then redirect the buyer to an ONVO-hosted form. The buyer selects an available asset and network and sends payment from their wallet. ONVO updates the intent asynchronously, even if the buyer closes the page.

Before you start​

  • Crypto via API must be enabled for your account and the mode you plan to use. Contact ONVO to enable it; availability in Checkout does not mean it is enabled for API payments.
  • It is available for Costa Rican accounts and Payment Intents in USD or CRC.
  • Amounts use the currency's smallest denomination, not crypto units: 1000 in USD means USD 10.00.
  • Use your Secret API Key on your server and configure webhooks.
  • This flow supports one-time payments with automatic capture. Manual capture, subscriptions, and refunds through the Refunds API are not supported.

1. Create the Payment Intent​

Create one intent per order and save its id on your server as PAYMENT_INTENT_ID.

curl https://api.onvopay.com/v1/payment-intents \
-X POST \
-H "Authorization: Bearer $ONVO_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"amount": 1000,
"currency": "USD",
"description": "Order #1001"
}'

2. Create the Payment Method​

Send type: "crypto" and a crypto object containing fullName and email. The full name must be a non-empty string and the email must be valid; ONVO trims leading and trailing whitespace from both values.

Real buyer details

Send the buyer's real full name and a valid email address they can access. This email is used for communications about their Crypto payment, including notices about any applicable automatic refund. Using fictitious details, the merchant's email, or an address the buyer cannot access may prevent them from receiving important payment information.

The example details are illustrative: replace them with the buyer's real details when processing a real payment.

curl https://api.onvopay.com/v1/payment-methods \
-X POST \
-H "Authorization: Bearer $ONVO_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "crypto",
"crypto": {
"fullName": "María Rodríguez",
"email": "maria@example.com"
}
}'

Save the returned id to confirm the intent. You may associate a customer using customerId or customer, but that does not replace the required crypto fields. These details populate the buyer information in the form; the buyer may still need to accept terms or complete verification.

Do not send cryptoPaymentId or the detail objects for other payment method types. The payment session starts when you confirm the intent. Each Crypto method is bound to one intent and cannot be reused for another order.

3. Confirm and redirect​

Replace PAYMENT_METHOD_ID with the created method's id. For Crypto, returnUrl is required and must be an absolute https:// or http:// URL for your application.

curl "https://api.onvopay.com/v1/payment-intents/$PAYMENT_INTENT_ID/confirm" \
-X POST \
-H "Authorization: Bearer $ONVO_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"paymentMethodId": "PAYMENT_METHOD_ID",
"returnUrl": "https://shop.example.com/orders/1001/return"
}'

A new session returns requires_action and nextAction. This response is abbreviated and uses illustrative identifiers:

{
"id": "PAYMENT_INTENT_ID",
"status": "requires_action",
"amount": 1000,
"receivedAmount": 0,
"currency": "USD",
"nextAction": {
"type": "redirect_to_url",
"redirectToUrl": {
"url": "https://checkout.onvopay.com/crypto/CRYPTO_SESSION_ID",
"returnUrl": "https://shop.example.com/orders/1001/return"
}
}
}

Redirect the browser to nextAction.redirectToUrl.url exactly as returned by the API. Do not construct this URL or substitute paymentMethod.crypto.hostedUrl. The ONVO form offers English and Spanish and starts in English.

Confirmation also creates a pending charge to record the attempt. Creating that charge or receiving a URL does not mean the payment is complete.

4. Verify the result on your server​

Listen for payment-intent.succeeded using the authentication mechanism described in Webhooks. You can also retrieve the intent from your server:

curl "https://api.onvopay.com/v1/payment-intents/$PAYMENT_INTENT_ID" \
-H "Authorization: Bearer $ONVO_SECRET_KEY"

Use the ID saved for your order and verify its amount, currency, and status: "succeeded" before fulfillment. Complete each order only once, even if you query the API and receive a webhook for the same payment.

Intent statusMeaning and action
requires_actionThe buyer must complete the form. Use nextAction when present.
processingPayment is pending, for example while a transfer is being confirmed or the amount is incomplete. Do not fulfill the order.
succeededONVO confirmed the complete payment. You can fulfill the order.
requires_payment_methodThe attempt failed or was canceled before funds were received. Check lastPaymentError and allow another attempt.
canceledThe merchant canceled the intent. Do not reuse it to collect another payment.

Partial and pending payments​

If the buyer sends less than the required amount, the intent may remain in processing. While the session still accepts payment, the form allows the buyer to send the remaining amount. Do not close the flow or mark the order as paid just because a transfer occurred.

receivedAmount is the amount ONVO has recorded for the intent, in the same units as amount; it is not necessarily the amount the wallet just sent. A session in hold is still awaiting confirmation and may have receivedAmount: 0.

The session status, a thank-you message in the form, or nextAction: null does not replace the intent status. Even if the form is unavailable or expired, processing is still not a successful payment. Retrieve the status and wait for server confirmation; do not depend on a payment-intent.processing event.

Returning to the merchant​

When ONVO confirms succeeded, the form displays the result and automatically redirects to returnUrl after a few seconds. The return adds these parameters:

ParameterDescription
payment_intent_idThe intent ID.
statusThe intent status observed when returning.
outcomesuccess or cancel, according to the return flow's outcome.

These parameters are informational and can be modified in the browser. Returning with outcome=success is not proof of payment. Retrieve the intent from your server or process the authenticated webhook. Payment updates do not depend on the buyer returning to your site.

Cancellation, expiration, and retries​

  • If the buyer closes the form with the X before sending funds, ONVO fails the charge with crypto_payment_canceled, records the error in lastPaymentError, and returns the intent to requires_payment_method. The return has outcome=cancel and ONVO emits payment-intent.failed.
  • If funds have already arrived or a transfer is pending, closing the form does not mean payment is canceled and does not reverse the transfer. Continue checking the intent and handling its webhooks.
  • To cancel the intent from your server, use Cancel a Payment Intent. This operation sets it to canceled and emits payment-intent.canceled; it is not a refund.
  • Each session has an expiration time, available in paymentMethod.crypto.expiryDate. An expired session cannot be reused. For another attempt without pending funds, create a new Crypto method and confirm an intent that permits another attempt.
  • Reconfirming the same intent with its method and a valid session lets you recover the existing action. Do not create another order or intent just because the buyer returns from the form.

Common errors​

The API may return 400 with a validation error (statusCode, message, error) if crypto is missing, the name is blank, or the email is invalid. These errors do not guarantee a code field. For business errors, use the response's code:

CodeWhat to check
payment_methods.invalid_payment_method_payloadThe payload mixes details for different method types or does not meet the method's contract.
payment_methods.crypto_not_enabledThe account, country, or mode does not have Crypto via API enabled.
payment_methods.crypto_currency_not_supportedThe intent currency must be USD or CRC.
payment_intents.return_url_requiredConfirmation is missing returnUrl. A malformed URL may also produce a validation error.
payment_methods.crypto_already_usedThe method is bound to another intent or cannot be reused.
payment_methods.crypto_session_expiredA new attempt needs a new session.
payment_intents.crypto_session_unavailableThe form could not be started. Retrieve the intent before retrying.
payment_intents.crypto_settlement_in_progressA payment update is in progress. Wait and retrieve the status before retrying cancellation.

Testing​

Use an onvo_test_ key with Crypto via API enabled in test mode. Follow the form's instructions for the test asset and network it displays; for example, if it shows testBTC, use test funds for that network. Do not send real funds to the test flow.

Validate full payment, partial payment followed by the remaining amount, pending status, closing without funds, expiration, and invalid buyer details. For every scenario, check the intent from your server and verify that your application fulfills only on succeeded, even if the buyer closes the browser.