Order status lifecycle
Every AnySpend order moves through these states:
enum OrderStatus {
// Waiting
SCANNING_DEPOSIT_TRANSACTION = "scanning_deposit_transaction",
WAITING_STRIPE_PAYMENT = "waiting_stripe_payment",
EXPIRED = "expired",
// Processing
SENDING_TOKEN_FROM_VAULT = "sending_token_from_vault",
RELAY = "relay",
// Done
EXECUTED = "executed",
// Failed
REFUNDING = "refunding",
REFUNDED = "refunded",
FAILURE = "failure",
}
| Status | What’s happening | User action |
|---|
scanning_deposit_transaction | Waiting for blockchain confirmation | None — wait |
waiting_stripe_payment | Processing card payment | May need to complete 3D Secure |
sending_token_from_vault | Sending tokens for swap | None — automatic |
relay | Cross-chain transaction in progress | None — wait |
executed | Done | None |
expired | Order expired before payment arrived | Create a new order |
refunding | Automatic refund in progress | None — wait |
refunded | Refund sent | Check wallet for refunded tokens |
failure | Transaction failed | Review error details, retry |
Error codes
Payment errors
User doesn’t have enough tokens. Prompt them to add funds or switch to a different token.if (error.message === "INSUFFICIENT_BALANCE") {
toast.error("Not enough funds. Add tokens or choose a different payment method.");
}
Token contract isn’t supported on the target chain. Show the user which tokens are available.if (error.message === "INVALID_TOKEN_ADDRESS") {
toast.error("This token isn't supported. Please choose another.");
}
Transaction amount is below the minimum threshold.if (error.message === "MINIMUM_AMOUNT_NOT_MET") {
toast.error(`Minimum amount is $${minimumAmount}.`);
}
Transaction amount exceeds the limit. Split into multiple transactions or reduce the amount.if (error.message === "MAXIMUM_AMOUNT_EXCEEDED") {
toast.error(`Maximum amount is $${maximumAmount}.`);
}
Network errors
Price moved beyond tolerance during execution. Retry or wait for the market to settle.if (error.message === "SLIPPAGE") {
toast.warning("Price moved. Retrying...");
retryWithHigherSlippage();
}
RPC connection issue or chain congestion. Retry after a short delay.if (error.message === "NETWORK_ERROR") {
toast.error("Network issue. Check your connection and try again.");
}
Price quote is stale. Fetch a new one.if (error.message === "QUOTE_EXPIRED") {
toast.info("Quote expired. Getting a fresh one...");
refreshQuoteAndRetry();
}
Requested chain isn’t supported. Show the user which chains are available.if (error.message === "CHAIN_NOT_SUPPORTED") {
toast.error("This chain isn't supported.");
showSupportedChains();
}
Contract errors
Smart contract execution failed. Double-check the contract parameters and state.
Gas limit was too low. Retry with a higher limit.
Nonce conflict from a pending transaction. Wait for the pending tx to confirm, then retry.
The contract reverted. Usually means a precondition wasn’t met (e.g., sale ended, not enough allowance).
Error handling patterns
Per-component error handling
Payment with error handling
import { useAnyspendCreateOrder } from "@b3dotfun/sdk/anyspend";
function PaymentComponent() {
const [error, setError] = useState<string | null>(null);
const [retryCount, setRetryCount] = useState(0);
const { createOrder, isCreatingOrder } = useAnyspendCreateOrder({
onError: (error) => {
switch (error.message) {
case "INSUFFICIENT_BALANCE":
setError("Not enough funds. Add tokens or try a different payment method.");
break;
case "SLIPPAGE":
if (retryCount < 3) {
setError("Price moved. Retrying...");
setTimeout(() => {
setRetryCount((prev) => prev + 1);
retryPayment();
}, 2000);
} else {
setError("Price too volatile right now. Try again later.");
}
break;
case "QUOTE_EXPIRED":
setError("Quote expired. Getting a fresh one...");
refreshQuote();
break;
default:
setError("Payment failed. Try again or contact support.");
}
},
onSuccess: () => {
setError(null);
setRetryCount(0);
},
});
return (
<div>
{error && (
<div className="error-banner">
<span>{error}</span>
<button onClick={() => setError(null)}>Dismiss</button>
</div>
)}
<button onClick={handlePayment} disabled={isCreatingOrder}>
{isCreatingOrder ? "Processing..." : "Pay Now"}
</button>
</div>
);
}
Order status monitoring
import { useAnyspendOrderAndTransactions } from "@b3dotfun/sdk/anyspend";
function OrderTracker({ orderId }: { orderId: string }) {
const { orderAndTransactions, isLoadingOrderAndTransactions, getOrderAndTransactionsError } =
useAnyspendOrderAndTransactions(orderId);
if (getOrderAndTransactionsError) {
return (
<div>
<p>Couldn't load order status. Check your connection and try again.</p>
<button onClick={() => window.location.reload()}>Retry</button>
</div>
);
}
if (!orderAndTransactions) return <div>Loading order status...</div>;
const { order, executeTx, refundTxs } = orderAndTransactions.data;
switch (order.status) {
case "scanning_deposit_transaction":
return <p>Waiting for payment confirmation (1-2 minutes)...</p>;
case "relay":
return <p>Processing cross-chain transaction...</p>;
case "executed":
return (
<div>
<p>Done!</p>
{executeTx && (
<a href={`https://basescan.org/tx/${executeTx.txHash}`} target="_blank">
View transaction
</a>
)}
</div>
);
case "failure":
case "obtain_failed":
return (
<div>
<p>Transaction failed: {order.errorDetails || "Unknown error"}</p>
<button onClick={() => createNewOrder()}>Try again</button>
</div>
);
case "refunded":
return <p>Refund processed. Check your wallet.</p>;
case "expired":
return (
<div>
<p>Order expired before payment arrived.</p>
<button onClick={() => createNewOrder()}>Create new order</button>
</div>
);
default:
return <p>Processing... (status: {order.status})</p>;
}
}
Error boundary
Wrap AnySpend components in an error boundary to catch rendering crashes:
import React, { Component, ErrorInfo } from "react";
class AnySpendErrorBoundary extends Component<
{ children: React.ReactNode },
{ hasError: boolean; error?: Error }
> {
state = { hasError: false, error: undefined as Error | undefined };
static getDerivedStateFromError(error: Error) {
return { hasError: true, error };
}
componentDidCatch(error: Error, errorInfo: ErrorInfo) {
console.error("AnySpend error:", error, errorInfo);
// Report to your error tracking service (Sentry, etc.)
}
render() {
if (this.state.hasError) {
return (
<div>
<h3>Something went wrong</h3>
<p>{this.state.error?.message}</p>
<button onClick={() => this.setState({ hasError: false })}>Try again</button>
</div>
);
}
return this.props.children;
}
}
// Usage
function App() {
return (
<AnySpendErrorBoundary>
<AnyspendProvider>
<YourApp />
</AnyspendProvider>
</AnySpendErrorBoundary>
);
}
User-friendly error messages
A helper that maps error codes to messages your users can actually understand:
function getErrorMessage(error: Error) {
const map: Record<string, { title: string; message: string; action?: string }> = {
INSUFFICIENT_BALANCE: {
title: "Insufficient balance",
message: "You don't have enough funds for this transaction.",
action: "Add funds or choose a different payment method.",
},
SLIPPAGE: {
title: "Price changed",
message: "The price moved while processing your transaction.",
action: "We'll retry with updated pricing.",
},
NETWORK_ERROR: {
title: "Connection issue",
message: "Can't reach the blockchain network.",
action: "Check your internet connection and try again.",
},
QUOTE_EXPIRED: {
title: "Quote expired",
message: "The price quote is no longer valid.",
action: "Getting a fresh quote...",
},
};
return map[error.message] ?? {
title: "Transaction failed",
message: "Something went wrong.",
action: "Try again or contact support.",
};
}
Tips
- Keep users informed during long operations. Cross-chain transactions can take a few minutes — show progress, not just a spinner.
- Retry transient errors (slippage, network, quote expired) with exponential backoff. Many resolve on the second try.
- Log errors with context (order ID, user address, timestamp) so you can debug issues after the fact.
- Offer fallbacks when possible. If cross-chain fails, suggest same-chain. If crypto fails, suggest fiat onramp.
Getting help
Discord
Get help from the community and support team
GitHub
Report bugs and request features
When reporting issues, include: error message/code, steps to reproduce, browser/device info, and order ID if applicable.