Skip to content

useExchangePayOrder

Create a deposit order, read checkout fields, track status, and close when supported.

When to use

Amount form submit → checkout screen → pending payment. Session must be active. Pair with expiry & countdown on the checkout step.

Must be used under ExchangePayContextProvider. createOrder() builds the request from the current selection.

Example — create

tsx
import {
  useExchangePayAmount,
  useExchangePayOrder,
  useExchangePaySelection,
} from '@swapped/connect-sdk/react'

function DepositForm() {
  const { canSubmit } = useExchangePaySelection()
  const { error: amountError, setTouched } = useExchangePayAmount()
  const { createOrder, isCreating, error, order } = useExchangePayOrder()

  async function onSubmit() {
    setTouched(true)
    if (!canSubmit) return
    await createOrder()
  }

  return (
    <div>
      {(amountError || error) && (
        <p>{(amountError?.message ?? error?.message)}</p>
      )}
      <button
        type="button"
        disabled={isCreating || !canSubmit}
        onClick={() => void onSubmit()}
      >
        {isCreating ? 'Creating…' : 'Continue'}
      </button>
      {order && <p>Order {order.id} created</p>}
    </div>
  )
}

Example — checkout

tsx
import {
  useExchangePayOrder,
  useOnExchangePayOrderExpired,
} from '@swapped/connect-sdk/react'

function Checkout({ onExpired }: { onExpired: () => void }) {
  const { order, closeOrder, status, isCompleted } = useExchangePayOrder()

  useOnExchangePayOrderExpired(() => {
    // e.g. toast.info('Order expired, please try again')
    onExpired() // navigate back to deposit
  })

  if (!order) return null
  if (isCompleted) return <p>Payment received</p>

  const { qr, url, mobileUrl } = order.checkout

  return (
    <div>
      <p>Status: {status}</p>
      {/* 'PENDING' | 'PAY_SUCCESS' | 'AWAITING_PROVIDER_FUNDS' | null */}

      {qr?.type === 'image' && <img src={qr.value} alt="Pay QR" />}
      {qr?.type === 'url' && <QrCode value={qr.value} /> /* e.g. qrcode.react */}

      {url && (
        <a href={url} target="_blank" rel="noreferrer">
          Open checkout
        </a>
      )}
      {mobileUrl && mobileUrl !== url && (
        <a href={mobileUrl}>Open in app</a>
      )}

      {order.canClose && (
        <button type="button" onClick={() => void closeOrder()}>
          Cancel order
        </button>
      )}
    </div>
  )
}

On expiry, order is cleared. Handle toast / navigate with useOnExchangePayOrderExpired. expiredOrder is available if you still need the last order payload.

Checkout fields

FieldUse for
order.checkout.qr{ type: 'image' | 'url', value }
order.checkout.urlDesktop link (may be null)
order.checkout.mobileUrlMobile / deep link (may be null)
order.expiresAtCountdown — see Expiry
order.canCloseWhether to show cancel (closeOrder)

Closing: If canClose is true, call closeOrder() when the user leaves checkout. If false (Bybit, OKX), skip cancel UI; create a new order when needed. Starting a new order also clears the previous active order.

Returns

FieldPurpose
orderActive ExchangePayOrder or null (cleared on expiry)
expiredOrderLast expired order, or null (cleared on create / close / reset)
statusLatest status string or null
transactionFull ExchangePayOrderStatus or null
isCompleted / isExpiredConvenience flags
createOrder / closeOrder / getOrderActions
isCreating / isClosing / isFetchingStatusIn-flight flags
errorLast action failure

Errors

CodeWhenWhat to do
REACT_EXCHANGE_PAY_PROVIDER_REQUIREDUsed outside ExchangePayContextProviderWrap with the provider
EXCHANGE_PAY_SELECTION_INCOMPLETEMissing provider / currency / amountComplete selection first
SESSION_NOT_ACTIVESession cannot pay againrestartSession()
SESSION_REQUIREDSession not loadedloadSession()
NO_ACTIVE_ORDERStatus/close without an orderBack to form / create
CLOSE_ACTIVE_ORDER_FAILEDClose API failedRetry or create again
API_ERRORCreate / status / close failureRetry

See Errors.