Appearance
Session (React)
A Swapped Connect session is one payment run identified by sessionId. Load it once, run Wallets, Exchange Pay, or Coinbase while it is active, then call restartSession() before another payment.
For UI, prefer useSessionView() over reading raw session.status. The view classifies API status, maintenance, and runtime rejection into screens you can switch on.
| Hook | Use for |
|---|---|
useSessionView() | Which screen to render |
useSession() | Session payload, isLoading, isRestarting, error |
useRestartSession() | restartSession() + isRestarting / error for buttons |
useMaintenance() | Maintenance enabled / message (when you need the message) |
Do not dig into client.getState() for internal fields. Public state is limited to session id, session payload, load/restart flags, error, and maintenance.
Status vs view
| Layer | Type | Use for |
|---|---|---|
| API status | SessionStatus on session.status | Debugging / logging |
| UI view | SessionView from useSessionView() | Which screen to render |
Only initiated sessions can start a new payment (isSessionActiveForPayments). After completion (or most other terminal views), call restartSession() or the next Wallets / Coinbase / Exchange Pay call hits SESSION_NOT_ACTIVE.
API statuses (SessionStatus)
| Status | Meaning |
|---|---|
initiated | Ready for payment — maps to view active |
awaitingConfirmation | Payment in progress — waiting screen, or completed if transactionData is already present |
awaitingEmailConfirmation | User must confirm email |
completed | Payment finished — success / restart |
failed | Payment failed |
cancelled | Session cancelled — treat as expired in UI |
rejected | Region / geo rejection (view.country, view.rejectReason) |
UI views (SessionViewType)
Returned by useSessionView() (and client.getSessionView()).
| View | When | Suggested UI |
|---|---|---|
active | No session yet, or status initiated | Your normal app (payment methods, Wallets, Coinbase, Exchange Pay) |
completed | Status completed, or awaitingConfirmation with transactionData | Success summary + Start new session (restartSession) |
awaitingConfirmation | Status awaitingConfirmation without transaction data yet | Waiting / “payment processing” |
awaitingEmailConfirmation | Status awaitingEmailConfirmation | Ask the user to confirm email |
expired | Status cancelled | Session expired + restart |
failed | Status failed | Failure message + restart |
rejectedRegion | Status rejected | Region not supported — prefer view.rejectReason (may contain \n; use white-space: pre-line), fall back to view.country |
rejectedCompliance | Runtime session:rejected (compliance) | Compliance blocked — no restart of the same session |
maintenance | Maintenance flag enabled (wins over status) | Maintenance / try later |
completed may include optional view.transaction when the SDK can show a completed-transaction screen. For success details, also use useWalletCompletedTransactionSummary, useCoinbaseCompletedTransactionSummary, or useExchangePayCompletedTransactionSummary.
This is the Swapped session. Coinbase OAuth JWT expiry is separate (COINBASE_SESSION_EXPIRED / useOnCoinbaseSessionExpired) — reconnect Coinbase, do not confuse it with expired above.
Render by view
Wrap your payment routes in a gate that switches on view.type:
tsx
import { SessionViewType } from '@swapped/connect-sdk'
import {
useCoinbaseCompletedTransactionSummary,
useExchangePayCompletedTransactionSummary,
useSessionView,
useSwappedConnectClient,
useWalletCompletedTransactionSummary,
} from '@swapped/connect-sdk/react'
import type { ReactNode } from 'react'
function SessionViewGate({ children }: { children: ReactNode }) {
const view = useSessionView()
const client = useSwappedConnectClient()
const { summary: walletsSummary } = useWalletCompletedTransactionSummary()
const coinbaseSummary = useCoinbaseCompletedTransactionSummary()
const exchangePaySummary = useExchangePayCompletedTransactionSummary()
const restart = () => {
void client.restartSession()
}
switch (view.type) {
case SessionViewType.Active:
return children
case SessionViewType.Completed:
if (walletsSummary) {
return (
<div>
<p>
{walletsSummary.receive.formatted.amount}{' '}
{walletsSummary.receive.currency}
</p>
<button type="button" onClick={restart}>
Start new session
</button>
</div>
)
}
if (coinbaseSummary) {
return (
<div>
<p>
Sent {coinbaseSummary.amount.amount}{' '}
{coinbaseSummary.amount.currency}
</p>
<button type="button" onClick={restart}>
Start new session
</button>
</div>
)
}
if (exchangePaySummary) {
return (
<div>
<p>
Paid {exchangePaySummary.amount.amount}{' '}
{exchangePaySummary.amount.currency}
</p>
<button type="button" onClick={restart}>
Start new session
</button>
</div>
)
}
return (
<div>
<p>Transaction completed</p>
<button type="button" onClick={restart}>
Start new session
</button>
</div>
)
case SessionViewType.RejectedRegion:
return (
<p style={{ whiteSpace: 'pre-line' }}>
{view.rejectReason ||
`Not available in ${view.country || 'your region'}`}
</p>
)
case SessionViewType.RejectedCompliance:
return <p>This payment cannot continue (compliance).</p>
case SessionViewType.Expired:
return (
<div>
<p>Session expired</p>
<button type="button" onClick={restart}>
Start new session
</button>
</div>
)
case SessionViewType.Failed:
return (
<div>
<p>Transaction failed</p>
<button type="button" onClick={restart}>
Start new session
</button>
</div>
)
case SessionViewType.AwaitingConfirmation:
return <p>Waiting for confirmation…</p>
case SessionViewType.AwaitingEmailConfirmation:
return <p>Confirm your email to continue</p>
case SessionViewType.Maintenance:
return <p>Temporarily unavailable. Try again later.</p>
default:
return children
}
}Use useSessionView() for this branching. Use event hooks (useOnSessionViewChanged, useOnSessionRejected, useOnMaintenanceChanged) only for side effects (analytics, toast, navigate).
Lifecycle
createSwappedConnectClient({ sessionId })→loadSession()→ wrap withSwappedConnectProvider- While view is
active, show payment methods and run Wallets, Exchange Pay, or Coinbase - When the view leaves
active, show the matching screen above restartSession()before another payment (new active session)destroy()when tearing down the client
tsx
import { useRestartSession } from '@swapped/connect-sdk/react'
function RestartButton() {
const { restartSession, isRestarting, error } = useRestartSession()
return (
<div>
<button
type="button"
disabled={isRestarting}
onClick={() => void restartSession()}
>
{isRestarting ? 'Starting…' : 'Start new session'}
</button>
{error ? <p>{error.message}</p> : null}
</div>
)
}Errors
| Code | When | What to do |
|---|---|---|
SESSION_NOT_ACTIVE | Start payment when status ≠ initiated | Show completed / terminal UI; restartSession() |
SESSION_REQUIRED | Action needs a loaded session (connect, withdraw, create order, …) | loadSession() first |
SESSION_ID_REQUIRED | Missing id on load / restart | Pass a valid sessionId |
Wallets / Coinbase / Exchange Pay guides call out SESSION_NOT_ACTIVE on their start APIs — same rule: only active / initiated can pay.
Session data and maintenance
tsx
import { useMaintenance, useSession } from '@swapped/connect-sdk/react'
function SessionHeader() {
const { session, isLoading, error } = useSession()
const maintenance = useMaintenance()
if (isLoading) return <p>Loading…</p>
if (error) return <p>{error}</p>
if (!session) return null
return (
<div>
<p>{session.merchant.name}</p>
{maintenance.enabled ? <p>{maintenance.message}</p> : null}
</div>
)
}Related
- Getting started
- Events
- Concepts
- Core track: Session