Causes of payment interruptions
Crypto deposits require orchestration of several independent protocols like bridges, DEXs, blockchains, onramp providers and more. Mid-workflow, an asset’s price could change significantly, a fee could increase beyond the bounds of the quote, an onramp could experience an unexpected delay or other unforseen setbacks. Halliday Payments was built to be robust under all of these conditions within the ever-growing ecosystem of onchain protocols. The Halliday payments OTWs are self-custodial. Users are always the sole controllers of these addresses through their wallet.Recoveries
Halliday Payments provides two options for recovering assets within an interrupted payment.Retry a payment
An interrupted payment can be retried with a new quote. The new output amount may differ from the original quote based on asset price changes. If a payment expires, and has not been funded, it is safe to abandon it and create a whole new payment. Effectively, a new payment is created and then funded using the interrupted payment by transferring tokens from the old deposit address to the new deposit address using an EIP-712 signature. An example of this signature request is shown below. Retry a payment using the API- A funded payment is not completing.
- Query the balances API endpoint (
POST /payments/balances) and pass the incomplete payment ID which we will call failedpayment_id. This returns the deposit address (address) and the balance. Check that the balance is greater than zero. If so, a recovery can be performed. - Get new quotes using
POST /payments/quotes. Provide the failedpayment_idasparent_payment_idin the request body. - Once the user selects a quote, confirm the new quote using
POST /payments/confirm. To do this, pass the new quote’s payment ID, which we will call newpayment_id, to the confirm endpoint. - Next call the withdraw endpoint (
POST /payments/withdraw) with the parameters:payment_id: The failed payment’s ID.token_amount: The returned amount of token from the priorPOST /payments/balancesendpoint call.recipient_address: The address of the new payment’s deposit address.
- The owner wallet of the failed payment must sign an EIP-712 withdrawal transaction. This is returned from the
POST /payments/withdrawcall response object as thewithdraw_authorizationproperty. - Next call the confirm withdraw endpoint (
POST /payments/withdraw/confirm) with the same parameters passed to the prior API call along with the newly createdowner_signature. The withdrawal will be executed onchain automatically and transfer the assets from the old deposit address to the new one.
Withdrawals
Assets lingering in a deposit address can be withdrawn to any address specified in a withdrawal signature created by the owner wallet. In some situations, this may result in the asset being moved to a user-controlled wallet on a different chain than the intended destination. Withdrawal steps using the API- A funded payment is not completing.
- Query the balances API endpoint (
POST /payments/balances) and pass the incomplete payment ID which we will call failedpayment_id. This returns the deposit address (address) and the balance. Check that the balance is greater than zero. If so, a recovery can be performed. - Next call the withdraw endpoint (
POST /payments/withdraw) with the parameters:payment_id: The failed payment’s ID.token_amount: The returned amount of token from the priorPOST /payments/balancesendpoint call.recipient_address: The address to withdraw the tokens to, usually the owner’s wallet.
- The owner wallet of the failed payment must sign an EIP-712 withdrawal transaction. This is returned from the
POST /payments/withdrawcall response object as thewithdraw_authorizationproperty. - Next call the confirm withdraw endpoint (
POST /payments/withdraw/confirm) with the same parameters passed to the prior API call along with the newly createdowner_signature. This signature will be executed onchain automatically and transfer the assets.
Example Withdrawal Signature Request
The following is an example withdrawal signature request on EVM chains using EIP-712 which is returned from thePOST /payments/withdraw API endpoint.
The owner of the payment will generate a signature using their private key in order to confirm a withdrawal.
API Errors
The REST API returns formatted errors with a corresponding error code, such as 400 for bad request and 401 for unauthorized. Example 401 responseGET /assets/available-inputs and GET /assets/available-outputs endpoints will return bad request errors in the scenario that an unsupported asset address is passed as a parameter.
