> ## Documentation Index
> Fetch the complete documentation index at: https://developer.uphold.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Interactive send walkthrough

> Navigate through a peer-to-peer asset send. Click each step to see the matching API call and visual representation side by side.

export const SEND_FLOW = {
  phases: [{
    name: "Quote",
    accent: "#3b82f6",
    badge: "bg-blue-500/20 text-blue-300"
  }, {
    name: "Settle",
    accent: "#35B13D",
    badge: "bg-[#35B13D]/20 text-[#35B13D]"
  }],
  steps: [{
    id: "send-form",
    phase: "Quote",
    title: "Configure send",
    screen: ({dark, onBack, onNext}) => <SendDetailsPickerScreen dark={dark} fromSelected={false} amount="50.00" recipientId="jane.smith@uphold.com" onBack={onBack} onFromClick={onNext} />
  }, {
    id: "list-accounts",
    phase: "Quote",
    title: "List accounts",
    screen: ({dark, onBack, onNext, setWizardState}) => <AccountListScreen dark={dark} onBack={onBack} onSelectAccount={account => {
      setWizardState(prev => ({
        ...prev,
        fromAccount: account
      }));
      onNext();
    }} />
  }, {
    id: "select-send-details",
    phase: "Quote",
    title: "Select amount and recipient",
    screen: ({dark, onBack, onNext, wizardState}) => {
      const account = wizardState?.fromAccount;
      return <SendDetailsPickerScreen dark={dark} fromAsset={account?.asset ?? "USD"} fromLabel={account?.label ?? "My USD account"} fromBalance={account?.balance ?? "250.00 USD"} amount="50.00" recipientId="jane.smith@uphold.com" onBack={onBack} onNext={onNext} />;
    }
  }, {
    id: "create-quote",
    phase: "Quote",
    title: "Create quote",
    screen: ({dark, onBack, onNext, wizardState}) => {
      const account = wizardState?.fromAccount;
      const asset = account?.asset ?? "USD";
      const label = account?.label ?? "My USD account";
      return <TradeQuoteReviewScreen dark={dark} fromAsset={asset} fromAmount="50.00" toAsset={asset} toAmount="50.00" rate={`1 ${asset} = 1 ${asset}`} sendLabel={`From ${label}`} receiveLabel="To jane.smith@uphold.com" screenTitle="Transaction preview" buttonLabel="Confirm send" liveQuote={false} onBack={onBack} onNext={onNext} />;
    }
  }, {
    id: "commit-transaction",
    phase: "Settle",
    title: "Commit transaction",
    autoAdvanceMs: 3000,
    screen: ({dark}) => <TradeProcessingScreen dark={dark} mode="send" />
  }, {
    id: "send-completed",
    phase: "Settle",
    title: "Send settled",
    screen: ({dark}) => <SendCompletedScreen dark={dark} recipientName="Jane Smith" asset="USD" amount="50.00" />
  }]
};

export const SendCompletedScreen = ({dark = true, recipientName = "Alice Martin", asset = "USD", amount = "50.00", webhookBadge = null, assetColors = {
  USD: "#35B13D"
}, completionHeading = "Send completed!", sentToLabel = "Sent to"}) => {
  const accent = dark ? "#ffffff" : "#0E1116";
  const bg = dark ? "#0B0D10" : "#FAFAF7";
  const textPrimary = dark ? "#ffffff" : "#0E1525";
  const textMuted = dark ? "rgba(255,255,255,0.5)" : "rgba(14,21,37,0.5)";
  const rowBg = dark ? "rgba(255,255,255,0.06)" : "rgba(0,0,0,0.05)";
  return <div className="flex-1 flex flex-col min-h-0" style={{
    backgroundColor: bg
  }}>
      <div className="flex-1 flex flex-col items-center justify-center px-6 text-center gap-5">
        <div className="w-20 h-20 rounded-full flex items-center justify-center" style={{
    background: dark ? "rgba(255,255,255,0.07)" : "rgba(0,0,0,0.06)",
    color: "#35B13D"
  }}>
          <IcoCheck />
        </div>
        <div className="text-2xl font-extrabold tracking-tight" style={{
    color: textPrimary
  }}>
          {completionHeading}
        </div>
        <div className="w-full rounded-2xl p-4 flex flex-col gap-3" style={{
    background: rowBg
  }}>
          <div className="flex justify-between text-sm">
            <span style={{
    color: textMuted
  }}>{sentToLabel}</span>
            <span className="font-semibold" style={{
    color: textPrimary
  }}>
              {recipientName}
            </span>
          </div>
          <div className="flex justify-between text-sm">
            <span style={{
    color: textMuted
  }}>Amount</span>
            <span className="font-semibold" style={{
    color: "#35B13D"
  }}>
              {amount} {asset}
            </span>
          </div>
        </div>
      </div>
      {webhookBadge && <div className="px-5 pb-2">{webhookBadge}</div>}
    </div>;
};

export const SendDetailsPickerScreen = ({dark = true, fromAsset = "USD", fromLabel = "My USD account", fromBalance = "250.00 USD", fromSelected = true, amount = "50.00", recipientId = "d9f7a3c1…5e6f", onBack, onNext, onFromClick, assetColors = {
  USD: "#35B13D",
  BTC: "#F7931A",
  ETH: "#627EEA",
  EUROC: "#2775CA"
}, screenTitle = "Send"}) => {
  const bg = dark ? "#0E1116" : "#F4F5F7";
  const accent = dark ? "#ffffff" : "#0E1116";
  const textPrimary = dark ? "rgba(255,255,255,0.9)" : "rgba(14,21,37,0.9)";
  const textMuted = dark ? "rgba(255,255,255,0.5)" : "rgba(14,21,37,0.5)";
  const rowBg = dark ? "rgba(255,255,255,0.05)" : "rgba(0,0,0,0.05)";
  const color = assetColors[fromAsset] || accent;
  return <div className="flex-1 flex flex-col min-h-0" style={{
    backgroundColor: bg
  }}>
      <RampWTopBar dark={dark} title={screenTitle} onBack={onBack} />
      <div className="flex-1 px-5 pt-2 flex flex-col gap-3 overflow-hidden">
        <div className="rounded-2xl p-4 flex items-center gap-3" style={{
    background: rowBg,
    cursor: onFromClick ? "pointer" : "default"
  }} onClick={onFromClick || undefined}>
          <div className="w-10 h-10 rounded-full flex-shrink-0 flex items-center justify-center" style={{
    background: fromSelected ? `${color}22` : dark ? "rgba(255,255,255,0.08)" : "rgba(0,0,0,0.08)",
    position: "relative"
  }}>
            {fromSelected ? <>
                <span style={{
    position: "absolute",
    fontSize: 10,
    fontWeight: "bold",
    color
  }}>
                  {fromAsset}
                </span>
                <img src={`https://cdn.uphold.com/assets/${fromAsset}.svg`} alt={fromAsset} width={24} height={24} onError={e => {
    e.currentTarget.style.display = "none";
  }} style={{
    display: "block",
    position: "relative",
    zIndex: 1
  }} />
              </> : <svg className="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke={dark ? "rgba(255,255,255,0.3)" : "rgba(0,0,0,0.3)"} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
                <circle cx="12" cy="8" r="4" />
                <path d="M4 20c0-4 3.6-7 8-7s8 3 8 7" />
              </svg>}
          </div>
          <div className="flex-1 min-w-0">
            <div className="text-xs mb-0.5" style={{
    color: textMuted
  }}>
              From
            </div>
            {fromSelected ? <>
                <div className="text-sm font-medium" style={{
    color: textPrimary
  }}>{fromLabel}</div>
                <div className="text-xs mt-0.5" style={{
    color: textMuted
  }}>{fromBalance}</div>
              </> : <div className="text-sm" style={{
    color: textMuted
  }}>Select an account</div>}
          </div>
          <svg className="w-4 h-4 flex-shrink-0" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{
    color: textMuted
  }}>
            <polyline points="9 18 15 12 9 6" />
          </svg>
        </div>
        <div className="rounded-2xl p-4 flex items-center gap-3" style={{
    background: rowBg
  }}>
          <div className="w-10 h-10 rounded-full flex-shrink-0 flex items-center justify-center" style={{
    background: `${color}22`
  }}>
            <svg className="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
              <circle cx="12" cy="8" r="4" />
              <path d="M4 20c0-4 3.6-7 8-7s8 3 8 7" />
            </svg>
          </div>
          <div className="flex-1 min-w-0">
            <div className="text-xs mb-0.5" style={{
    color: textMuted
  }}>
              To (recipient account)
            </div>
            <div className="text-sm font-mono truncate" style={{
    color: textMuted
  }}>
              {recipientId}
            </div>
          </div>
          <span style={{
    fontSize: 11,
    fontWeight: 700,
    padding: "2px 7px",
    borderRadius: 999,
    background: `${color}22`,
    color
  }}>
            {fromAsset}
          </span>
        </div>
        <div className="rounded-2xl p-4 flex flex-col gap-1" style={{
    background: rowBg
  }}>
          <div className="text-xs" style={{
    color: textMuted
  }}>
            Amount
          </div>
          <div className="text-2xl font-semibold" style={{
    color: textPrimary
  }}>
            {amount}{" "}
            <span className="text-base font-normal" style={{
    color: textMuted
  }}>
              {fromAsset}
            </span>
          </div>
        </div>
        {onNext && <button onClick={onNext} className="w-full py-4 rounded-2xl text-sm font-semibold mt-auto mb-4" style={{
    backgroundColor: "#35B13D",
    color: "#fff",
    animation: "pulse-ring 2s ease-in-out infinite"
  }}>
            Get quote
          </button>}
      </div>
      <RampWFooter dark={dark} />
    </div>;
};

export const RampWFooter = ({dark}) => <div className={`flex items-center justify-center gap-2.5 px-5 pt-4 pb-5 flex-shrink-0 text-sm ${dark ? "text-white/55" : "text-[#0E1525]/50"}`}>
    <RampLeafLogo />
    <div className={`w-px h-3.5 ${dark ? "bg-white/20" : "bg-[#0E1525]/15"}`} />
    <span>
      Powered by{" "}
      <strong style={{
  color: dark ? "#ffffff" : "#0E1525"
}}>Uphold</strong>
    </span>
  </div>;

export const RampWTopBar = ({onBack, title, dark}) => <div className="flex items-center gap-3 px-5 pt-4 pb-3">
    <button onClick={onBack} className={`w-10 h-10 rounded-full border-0 flex items-center justify-center cursor-pointer ${dark ? "bg-white/10 text-white" : "bg-black/5 text-[#0E1525]"}`}>
      <svg className="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
        <polyline points="15 18 9 12 15 6" />
      </svg>
    </button>
    {title && <div className={`flex-1 text-center pr-10 text-[17px] font-semibold ${dark ? "text-white" : "text-[#0E1525]"}`}>
        {title}
      </div>}
  </div>;

export const RampLeafLogo = () => <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 18" className="w-3.5 h-[18px]">
    <path fill="#35B13D" fillRule="evenodd" clipRule="evenodd" d="M11.622 9.986a9.52 9.52 0 0 1-1.536 2.343c.427-1.588.221-3.64-.702-5.631a9.941 9.941 0 0 0-1.866-2.741c1.163-.89 2.373-1.181 3.308-.771.6.262 1.062.8 1.337 1.555.521 1.43.319 3.39-.541 5.245Zm-9.744 0C1.018 8.131.815 6.17 1.337 4.741c.275-.755.737-1.293 1.337-1.555.935-.41 2.145-.12 3.308.77a9.924 9.924 0 0 0-1.866 2.742c-.924 1.992-1.13 4.043-.703 5.631a9.506 9.506 0 0 1-1.535-2.343Zm5.744 4.02c-.269.117-.562.178-.872.182a2.224 2.224 0 0 1-.872-.183c-1.801-.789-2.165-3.95-.796-6.905A8.948 8.948 0 0 1 6.75 4.642 8.926 8.926 0 0 1 8.417 7.1c1.37 2.953 1.006 6.115-.795 6.904Zm2.445-11.999C9 1.965 7.837 2.397 6.75 3.261 5.663 2.398 4.5 1.964 3.433 2.006a5.903 5.903 0 0 1 3.316-1.005c1.226 0 2.377.367 3.318 1.006Zm3.098 2.42v-.003l-.003-.006a.02.02 0 0 1-.001-.005l-.004-.01C12.255 1.77 9.684 0 6.749 0 3.807 0 1.23 1.778.334 4.424c-.001.004-.001.009-.003.013-.595 1.66-.38 3.882.58 5.952C2.226 13.223 4.61 15.19 6.72 15.19h.06c2.11 0 4.495-1.968 5.808-4.8.962-2.075 1.177-4.302.577-5.963Zm-4.61 12.321a6.517 6.517 0 0 1-1.757.25h-.084a6.53 6.53 0 0 1-1.768-.253.533.533 0 0 0-.657.337.497.497 0 0 0 .356.623 7.64 7.64 0 0 0 2.07.295h.083c.674 0 1.367-.098 2.056-.291a.497.497 0 0 0 .357-.623.533.533 0 0 0-.656-.338Z" />
  </svg>;

export const IcoArrowDownTT = () => <svg className="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
    <line x1="12" y1="5" x2="12" y2="19" />
    <polyline points="5 12 12 19 19 12" />
  </svg>;

export const IcoCheck = () => <svg className="w-7 h-7" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
    <polyline points="20 6 9 17 4 12" />
  </svg>;

export const TradeProcessingScreen = ({dark = true, mode = "trade", webhookBadge = null, processingMessage = "We are processing your transaction", sendingMessage = "Sending..."}) => {
  const accent = dark ? "#ffffff" : "#0E1116";
  const bg = dark ? "#0E1116" : "#FAFAF7";
  const textPrimary = dark ? "#ffffff" : "#0E1525";
  const textMuted = dark ? "rgba(255,255,255,0.5)" : "rgba(14,21,37,0.5)";
  const label = mode === "send" ? sendingMessage : processingMessage;
  const sub = mode === "send" ? "Crediting recipient…" : "Waiting for confirmation…";
  return <div className="flex-1 flex flex-col min-h-0 items-center justify-center" style={{
    backgroundColor: bg
  }}>
      <div className="flex flex-col items-center gap-4 px-8 text-center">
        <div className="w-12 h-12 rounded-full border-2 animate-spin" style={{
    borderColor: dark ? "rgba(255,255,255,0.1)" : "rgba(0,0,0,0.1)",
    borderTopColor: accent
  }} />
        <div className="text-lg font-semibold" style={{
    color: textPrimary
  }}>
          {label}
        </div>
        <div className="text-sm" style={{
    color: textMuted
  }}>
          {sub}
        </div>
        {webhookBadge && <div className="mt-2">{webhookBadge}</div>}
      </div>
    </div>;
};

export const TradeQuoteReviewScreen = ({dark = true, fromAsset = "USD", fromAmount = "100.00", toAsset = "BTC", toAmount = "0.00154883", rate = "1 USD = 0.0000155 BTC", onBack, onNext, assetColors = {
  BTC: "#F7931A",
  ETH: "#627EEA",
  EUROC: "#2775CA",
  USDC: "#2775CA",
  USD: "#35B13D"
}, sendLabel = "You send", receiveLabel = "You receive", expiresLabel = "Expires in", screenTitle = "Transaction preview", buttonLabel = "Confirm", liveQuote = true}) => {
  const assetColor = a => assetColors[a] ?? "#888";
  const badge = a => <span style={{
    display: "inline-flex",
    alignItems: "center",
    gap: 4,
    fontSize: 13,
    fontWeight: 700,
    padding: "2px 10px 2px 6px",
    borderRadius: 999,
    background: `${assetColor(a)}22`,
    color: assetColor(a)
  }}>
      <img src={`https://cdn.uphold.com/assets/${a}.svg`} alt={a} width={16} height={16} onError={e => {
    e.currentTarget.style.display = "none";
  }} style={{
    display: "block",
    borderRadius: "50%"
  }} />
      {a}
    </span>;
  const bg = dark ? "#0E1116" : "#FAFAF7";
  const textPrimary = dark ? "#ffffff" : "#0E1525";
  const textMuted = dark ? "rgba(255,255,255,0.5)" : "rgba(14,21,37,0.5)";
  const rowBg = dark ? "rgba(255,255,255,0.05)" : "rgba(0,0,0,0.05)";
  const dividerColor = dark ? "rgba(255,255,255,0.1)" : "rgba(14,21,37,0.1)";
  const [countdown, setCountdown] = useState(15);
  const [displayToAmount, setDisplayToAmount] = useState(toAmount);
  const [justRefreshed, setJustRefreshed] = useState(false);
  useEffect(() => {
    if (!liveQuote) return;
    const dec = toAmount.includes(".") ? toAmount.split(".")[1].length : 0;
    const unit = Math.pow(10, -dec);
    const steps = [3, -5, 7, -2, 4, -8, 6, -3, 5, -7, 2, -4, 8, -6, 3];
    let tick = 0;
    let cd = 15;
    let cur = parseFloat(toAmount);
    const id = setInterval(() => {
      cd -= 1;
      if (cd <= 0) {
        const delta = steps[tick % steps.length] * unit;
        cur = Math.max(0, cur + delta);
        setDisplayToAmount(cur.toFixed(dec));
        setJustRefreshed(true);
        setTimeout(() => setJustRefreshed(false), 1200);
        tick += 1;
        cd = 15;
      }
      setCountdown(cd);
    }, 1000);
    return () => clearInterval(id);
  }, []);
  return <div className="flex-1 flex flex-col min-h-0" style={{
    backgroundColor: bg
  }}>
      <RampWTopBar dark={dark} title={screenTitle} onBack={onBack} />
      <div className="flex-1 px-5 pt-2 flex flex-col gap-3 overflow-hidden">
        <div className="rounded-2xl p-4 flex flex-col gap-1" style={{
    background: rowBg
  }}>
          <div className="text-xs" style={{
    color: textMuted
  }}>
            {sendLabel}
          </div>
          <div className="flex items-baseline justify-between">
            <span className="text-3xl font-bold" style={{
    color: textPrimary
  }}>
              {fromAmount}
            </span>
            {badge(fromAsset)}
          </div>
        </div>
        <div className="flex items-center justify-center" style={{
    color: textMuted
  }}>
          <IcoArrowDownTT />
        </div>
        <div className="rounded-2xl p-4 flex flex-col gap-1" style={{
    background: rowBg
  }}>
          <div className="text-xs" style={{
    color: textMuted
  }}>
            {receiveLabel}
          </div>
          <div className="flex items-baseline justify-between">
            <span className="text-3xl font-bold" style={{
    color: textPrimary
  }}>
              {liveQuote ? displayToAmount : toAmount}
            </span>
            {badge(toAsset)}
          </div>
        </div>
        <div style={{
    borderTop: `1px solid ${dividerColor}`
  }} />
        <div className="flex flex-col gap-2">
          <div className="flex justify-between text-xs" style={{
    color: textMuted
  }}>
            <span>Rate</span>
            <span style={{
    color: textPrimary
  }}>{rate}</span>
          </div>
          {liveQuote && <div className="flex items-center justify-between text-xs" style={{
    color: textMuted
  }}>
              <span className="flex items-center gap-1.5">
                <svg style={{
    width: 12,
    height: 12,
    animation: "spin 1.2s linear infinite",
    flexShrink: 0
  }} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round">
                  <path d="M21 12a9 9 0 1 1-6.219-8.56" />
                </svg>
                {justRefreshed ? <span style={{
    color: "#35B13D",
    fontWeight: 600
  }}>
                    Rate updated
                  </span> : <span>Refreshes in {countdown}s</span>}
              </span>
              <span style={{
    color: textPrimary
  }}>Live quote</span>
            </div>}
        </div>
        <button onClick={onNext} className="w-full py-4 rounded-2xl text-sm font-semibold mt-auto mb-4" style={{
    backgroundColor: "#35B13D",
    color: "#fff",
    animation: "pulse-ring 2s ease-in-out infinite"
  }}>
          {buttonLabel}
        </button>
      </div>
      <RampWFooter dark={dark} />
    </div>;
};

export const AccountListScreen = ({dark = true, onBack, onNext, onSelectAccount, title = "Accounts", accounts = [{
  asset: "USD",
  label: "My USD account",
  balance: "250.00 USD"
}, {
  asset: "BTC",
  label: "My BTC account",
  balance: "0.0015 BTC"
}, {
  asset: "XRP",
  label: "My XRP account",
  balance: "120.50 XRP"
}], buttonLabel = "Continue", assetColors = {
  USD: "#35B13D",
  BTC: "#F7931A",
  XRP: "#346AA9"
}}) => {
  const bg = dark ? "#0E1116" : "#F4F5F7";
  const accent = dark ? "#ffffff" : "#0E1116";
  const textPrimary = dark ? "rgba(255,255,255,0.9)" : "rgba(14,21,37,0.9)";
  const textMuted = dark ? "rgba(255,255,255,0.5)" : "rgba(14,21,37,0.5)";
  const rowBg = dark ? "rgba(255,255,255,0.05)" : "rgba(0,0,0,0.05)";
  return <div className="flex-1 flex flex-col min-h-0" style={{
    backgroundColor: bg
  }}>
      <RampWTopBar dark={dark} title={title} onBack={onBack} />
      <div className="flex-1 px-5 pt-2 flex flex-col gap-2 overflow-hidden">
        {accounts.map(account => {
    const {asset, label, balance} = account;
    const color = assetColors[asset] || accent;
    const balanceDisplay = typeof balance === 'number' ? `${balance} ${asset}` : balance;
    return <div key={asset} className="rounded-2xl px-4 py-3 flex items-center gap-3" style={{
      background: rowBg,
      cursor: onSelectAccount ? 'pointer' : 'default'
    }} onClick={onSelectAccount ? () => onSelectAccount(account) : undefined}>
              <div className="w-10 h-10 rounded-full flex-shrink-0" style={{
      background: `${color}22`,
      position: "relative",
      display: "flex",
      alignItems: "center",
      justifyContent: "center"
    }}>
                <span style={{
      position: "absolute",
      fontSize: 10,
      fontWeight: "bold",
      color
    }}>
                  {asset}
                </span>
                <img src={`https://cdn.uphold.com/assets/${asset}.svg`} alt={asset} width={24} height={24} onError={e => {
      e.currentTarget.style.display = "none";
    }} style={{
      display: "block",
      position: "relative",
      zIndex: 1
    }} />
              </div>
              <div className="flex-1 min-w-0">
                <div className="text-sm font-medium" style={{
      color: textPrimary
    }}>
                  {label}
                </div>
                <div className="text-xs mt-0.5" style={{
      color: textMuted
    }}>
                  {balanceDisplay}
                </div>
              </div>
            </div>;
  })}
        {!onSelectAccount && <button onClick={onNext} className="w-full py-4 rounded-2xl text-sm font-semibold mt-auto mb-4" style={{
    backgroundColor: "#35B13D",
    color: "#fff",
    animation: "pulse-ring 2s ease-in-out infinite"
  }}>
            {buttonLabel}
          </button>}
      </div>
      <RampWFooter dark={dark} />
    </div>;
};

export const WizardCopyButton = ({text}) => {
  const [copied, setCopied] = useState(false);
  useEffect(() => {
    if (!copied) return;
    const t = setTimeout(() => setCopied(false), 1400);
    return () => clearTimeout(t);
  }, [copied]);
  const handleClick = async () => {
    if (!navigator?.clipboard?.writeText) return;
    try {
      await navigator.clipboard.writeText(text);
      setCopied(true);
    } catch (_) {}
  };
  return <button onClick={handleClick} className="p-1.5 rounded hover:bg-zinc-100 dark:hover:bg-white/10 transition-colors text-zinc-500 dark:text-white/50 hover:text-zinc-800 dark:hover:text-white/90 border-0 cursor-pointer bg-transparent">
      {copied ? <svg className="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
          <polyline points="20 6 9 17 4 12" />
        </svg> : <svg className="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
          <rect x="9" y="9" width="11" height="11" rx="2" />
          <path d="M5 15V5a2 2 0 0 1 2-2h10" />
        </svg>}
    </button>;
};

export const WizardJsonBlock = ({label, data, dark = true}) => {
  const [copied, setCopied] = useState(false);
  useEffect(() => {
    if (!copied) return;
    const t = setTimeout(() => setCopied(false), 1400);
    return () => clearTimeout(t);
  }, [copied]);
  const handleCopy = async text => {
    if (!navigator?.clipboard?.writeText) return;
    try {
      await navigator.clipboard.writeText(text);
      setCopied(true);
    } catch (_) {}
  };
  const tokenizeJson = str => {
    const tokens = [];
    let cursor = 0;
    while (cursor < str.length) {
      const slice = str.slice(cursor);
      const wsMatch = slice.match(/^\s+/);
      if (wsMatch) {
        tokens.push({
          type: "whitespace",
          text: wsMatch[0]
        });
        cursor += wsMatch[0].length;
        continue;
      }
      const stringMatch = slice.match(/^"(?:[^"\\]|\\.)*"/);
      if (stringMatch) {
        const text = stringMatch[0];
        const after = str.slice(cursor + text.length).replace(/^\s*/, "");
        tokens.push({
          type: after.startsWith(":") ? "key" : "string",
          text
        });
        cursor += text.length;
        continue;
      }
      const numberMatch = slice.match(/^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?/);
      if (numberMatch) {
        tokens.push({
          type: "number",
          text: numberMatch[0]
        });
        cursor += numberMatch[0].length;
        continue;
      }
      const boolMatch = slice.match(/^(true|false)/);
      if (boolMatch) {
        tokens.push({
          type: "boolean",
          text: boolMatch[0]
        });
        cursor += boolMatch[0].length;
        continue;
      }
      if (slice.startsWith("null")) {
        tokens.push({
          type: "null",
          text: "null"
        });
        cursor += 4;
        continue;
      }
      if (("{[]:,}").includes(str[cursor])) {
        tokens.push({
          type: "punctuation",
          text: str[cursor]
        });
        cursor += 1;
        continue;
      }
      tokens.push({
        type: "unknown",
        text: str[cursor]
      });
      cursor += 1;
    }
    return tokens;
  };
  const TOKEN_COLORS = dark ? {
    key: "#79c0ff",
    string: "#f78c6c",
    number: "#79c0ff",
    boolean: "#ffd700",
    null: "rgba(255,255,255,0.5)",
    punctuation: "rgba(255,255,255,0.7)",
    whitespace: null
  } : {
    key: "#0550ae",
    string: "#b56959",
    number: "#0550ae",
    boolean: "#b5890e",
    null: "rgba(0,0,0,0.4)",
    punctuation: "rgba(0,0,0,0.5)",
    whitespace: null
  };
  const json = data != null ? JSON.stringify(data, null, 2) : null;
  return <div className="not-prose flex flex-col gap-1.5">
      <div className="flex items-center justify-between px-1">
        <span style={{
    fontSize: 10,
    color: dark ? "rgba(255,255,255,0.35)" : "rgba(0,0,0,0.4)",
    fontFamily: "monospace",
    textTransform: "uppercase",
    letterSpacing: "0.12em"
  }}>
          {label}
        </span>
        {json != null && <button onClick={() => handleCopy(json)} style={{
    padding: 6,
    background: "transparent",
    border: "none",
    cursor: "pointer",
    color: dark ? "rgba(255,255,255,0.4)" : "rgba(0,0,0,0.4)",
    display: "flex",
    alignItems: "center"
  }}>
            {copied ? <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><polyline points="20 6 9 17 4 12" /></svg> : <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><rect x="9" y="9" width="11" height="11" rx="2" /><path d="M5 15V5a2 2 0 0 1 2-2h10" /></svg>}
          </button>}
      </div>
      <div className="rounded-xl p-4 max-h-[360px] overflow-auto" style={{
    backgroundColor: dark ? "#111318" : "#f5f6f8",
    border: dark ? "1px solid rgba(255,255,255,0.06)" : "1px solid rgba(0,0,0,0.08)"
  }}>
        <pre style={{
    fontSize: 13,
    fontFamily: "monospace",
    lineHeight: 1.6,
    margin: 0,
    whiteSpace: "pre"
  }}>
          {json != null ? tokenizeJson(json).map((token, i) => <span key={`${token.type}-${i}`} style={{
    color: TOKEN_COLORS[token.type] ?? (dark ? "rgba(255,255,255,0.85)" : "rgba(0,0,0,0.7)")
  }}>
                {token.text}
              </span>) : <span style={{
    color: dark ? "rgba(255,255,255,0.3)" : "rgba(0,0,0,0.3)",
    fontStyle: "italic"
  }}>
              — no payload —
            </span>}
        </pre>
      </div>
    </div>;
};

export const WizardWebhookBadge = ({event, payload, dark = true, payloadLabel = "Payload"}) => {
  const [open, setOpen] = useState(false);
  return <div className="flex flex-col gap-2">
      <span onClick={() => setOpen(o => !o)} className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full bg-purple-500/20 text-purple-300 text-xs font-mono cursor-pointer select-none hover:bg-purple-500/30">
        <svg className="w-3.5 h-3.5" viewBox="0 0 24 24" fill="currentColor">
          <path d="M13 2L4 14h7l-1 8 9-12h-7l1-8z" />
        </svg>
        {event}
      </span>
      {open && <WizardJsonBlock label={payloadLabel} data={payload} dark={dark} />}
    </div>;
};

export const WizardStatusBar = ({light}) => <div className="h-11 flex items-center justify-between px-7 flex-shrink-0 text-[15px] font-semibold" style={{
  color: light ? "#0E1525" : "white",
  backgroundColor: light ? "white" : "black"
}}>
    <span>9:41</span>
    <div className="flex items-center gap-1.5">
      <svg className="w-[18px] h-3" viewBox="0 0 18 12" fill="currentColor">
        <rect x="0" y="8" width="3" height="4" rx="0.5" />
        <rect x="5" y="5" width="3" height="7" rx="0.5" />
        <rect x="10" y="2" width="3" height="10" rx="0.5" />
        <rect x="15" y="0" width="3" height="12" rx="0.5" />
      </svg>
      <svg className="w-4 h-3" viewBox="0 0 16 12" fill="none" stroke="currentColor" strokeWidth="1.4">
        <path d="M1,5 Q8,-1 15,5" />
        <path d="M3.5,7 Q8,3 12.5,7" />
        <circle cx="8" cy="9.5" r="1" fill="currentColor" />
      </svg>
      <svg className="w-[26px] h-3" viewBox="0 0 26 12" fill="none">
        <rect x="0.5" y="0.5" width="22" height="11" rx="2.5" stroke="currentColor" strokeOpacity="0.5" />
        <rect x="2" y="2" width="19" height="8" rx="1.5" fill="currentColor" />
        <rect x="23" y="4" width="2" height="4" rx="1" fill="currentColor" fillOpacity="0.5" />
      </svg>
    </div>
  </div>;

export const WizardPhoneShell = ({children, bgClass = "bg-zinc-50 dark:bg-[#0E1116]", lightStatus = false, borderClass = "border-zinc-200 dark:border-white/10"}) => <div className={`relative w-[320px] sm:w-[360px] h-[720px] rounded-[40px] sm:rounded-[44px] overflow-hidden border-2 flex flex-col font-sans shadow-[0_48px_96px_-28px_rgba(11,15,30,0.45),0_8px_20px_-6px_rgba(11,15,30,0.18)] ${bgClass} ${borderClass}`}>
    <div className={`absolute top-2 left-1/2 -translate-x-1/2 w-[110px] h-7 rounded-full z-10 ${lightStatus ? "bg-black" : "bg-white/20"}`} />
    <WizardStatusBar light={lightStatus} />
    <div className="flex-1 flex flex-col min-h-0 relative">{children}</div>
    <div className="absolute bottom-2 left-1/2 -translate-x-1/2 w-[134px] h-[5px] rounded-full z-20" style={{
  background: lightStatus ? "rgba(14,21,37,0.2)" : "rgba(255,255,255,0.4)"
}} />
  </div>;

export const FlowWizard = ({flow = {
  phases: [],
  steps: []
}, children}) => {
  const UpholdGreen = "#35B13D";
  const phaseColors = Object.fromEntries(flow.phases.map(p => [p.name, {
    accent: p.accent,
    badge: p.badge
  }]));
  const FALLBACK_PHASE = {
    accent: UpholdGreen,
    badge: "bg-zinc-100 dark:bg-white/10 text-zinc-500 dark:text-white/50"
  };
  const steps = flow.steps;
  const [stepIndex, setStepIndex] = useState(0);
  const [isDark, setIsDark] = useState(true);
  const [wizardState, setWizardState] = useState({
    fromAccount: null,
    toAsset: null,
    amount: ''
  });
  const step = steps[stepIndex];
  const stepChildren = React.Children.toArray(children);
  const isSkipped = s => s?.skip?.(wizardState) === true;
  const findStep = (from, dir) => {
    let i = from + dir;
    while (i >= 0 && i < steps.length && isSkipped(steps[i])) i += dir;
    return i >= 0 && i < steps.length ? i : null;
  };
  const visibleSteps = steps.filter(s => !isSkipped(s));
  const visibleStepIndex = visibleSteps.indexOf(step);
  useEffect(() => {
    const update = () => setIsDark(document.documentElement.classList.contains("dark"));
    update();
    const obs = new MutationObserver(update);
    obs.observe(document.documentElement, {
      attributeFilter: ["class"]
    });
    return () => obs.disconnect();
  }, []);
  useEffect(() => {
    if (!step?.autoAdvanceMs) return;
    const next = findStep(stepIndex, 1);
    if (next == null) return;
    const t = setTimeout(() => setStepIndex(next), step.autoAdvanceMs);
    return () => clearTimeout(t);
  }, [stepIndex]);
  if (!step) return null;
  const StepScreen = step.screen;
  const {accent: phaseAccent, badge: phaseBadge} = phaseColors[step.phase] ?? FALLBACK_PHASE;
  return <div className="not-prose w-full overflow-hidden">
      <div className="flex items-center justify-between gap-3 mb-4 flex-wrap">
        <div className="flex items-center gap-2.5">
          <span className={`${phaseBadge} text-xs font-semibold px-2.5 py-0.5 rounded-full`}>
            {step.phase}
          </span>
          <span className="text-sm font-semibold text-zinc-900 dark:text-white">
            {step.title}
          </span>
        </div>
        <span className="text-xs text-zinc-400 dark:text-white/40">
          Step {visibleStepIndex + 1} of {visibleSteps.length}
        </span>
      </div>

      <div className="w-full h-1 bg-zinc-200 dark:bg-white/10 rounded-full mb-4">
        <div className="h-full rounded-full transition-all duration-300" style={{
    width: `${((visibleStepIndex + 1) / visibleSteps.length * 100).toFixed(0)}%`,
    backgroundColor: UpholdGreen
  }} />
      </div>

      <div className="flex items-center gap-1 mb-5 flex-wrap">
        {(() => {
    const seenPhases = [];
    steps.forEach(s => {
      if (!seenPhases.includes(s.phase)) seenPhases.push(s.phase);
    });
    const els = [];
    seenPhases.forEach((phase, pi) => {
      const phaseSteps = steps.map((s, idx) => ({
        ...s,
        globalIndex: idx
      })).filter(s => s.phase === phase);
      const accent = (phaseColors[phase] ?? FALLBACK_PHASE).accent;
      const isActivePhase = phaseSteps.some(s => s.globalIndex === stepIndex);
      if (pi > 0) els.push(<div key={`sep-${phase}`} style={{
        width: 1,
        height: 20,
        background: isDark ? "rgba(255,255,255,0.1)" : "rgba(0,0,0,0.1)",
        margin: "0 6px",
        flexShrink: 0
      }} />);
      els.push(<span key={`lbl-${phase}`} style={{
        fontSize: 9,
        fontWeight: 700,
        letterSpacing: "0.1em",
        textTransform: "uppercase",
        color: isActivePhase ? accent : isDark ? "rgba(255,255,255,0.2)" : "rgba(0,0,0,0.3)",
        marginRight: 4,
        flexShrink: 0
      }}>
                {phase}
              </span>);
      phaseSteps.filter(s => !isSkipped(s)).forEach(s => {
        const isDone = s.globalIndex < stepIndex;
        const isCurrent = s.globalIndex === stepIndex;
        els.push(<button key={s.id} onClick={() => setStepIndex(s.globalIndex)} title={s.title} style={{
          width: 26,
          height: 26,
          borderRadius: "50%",
          border: "none",
          cursor: "pointer",
          fontSize: 11,
          fontWeight: 700,
          flexShrink: 0,
          display: "flex",
          alignItems: "center",
          justifyContent: "center",
          transition: "all 0.15s",
          background: isCurrent ? accent : isDone ? `${accent}26` : isDark ? "rgba(255,255,255,0.06)" : "rgba(0,0,0,0.06)",
          color: isCurrent ? "white" : isDone ? accent : isDark ? "rgba(255,255,255,0.3)" : "rgba(0,0,0,0.4)",
          boxShadow: isCurrent ? `0 0 0 3px ${accent}26` : "none",
          outline: "none"
        }}>
                  {isDone ? "✓" : s.globalIndex + 1}
                </button>);
      });
    });
    return els;
  })()}
      </div>

      <div className="w-full flex flex-col lg:flex-row gap-6 items-center lg:items-start">
        <div className="flex justify-center lg:flex-shrink-0">
          <WizardPhoneShell lightStatus={!isDark}>
            <StepScreen dark={isDark} onBack={findStep(stepIndex, -1) != null ? () => setStepIndex(findStep(stepIndex, -1)) : undefined} onNext={findStep(stepIndex, 1) != null ? () => setStepIndex(findStep(stepIndex, 1)) : undefined} wizardState={wizardState} setWizardState={setWizardState} />
          </WizardPhoneShell>
        </div>
        <div className="wizard-step-pane w-full lg:sticky lg:top-6 lg:flex-1 lg:min-w-0 lg:h-[720px] lg:overflow-y-auto prose dark:prose-invert max-w-none">
          {stepChildren[stepIndex] ?? null}
        </div>
      </div>

      <div className="flex items-center justify-between mt-5">
        <button onClick={() => setStepIndex(findStep(stepIndex, -1))} disabled={findStep(stepIndex, -1) == null} className={`flex items-center gap-2 px-4 py-2 rounded-xl text-sm font-medium border-0 cursor-pointer disabled:opacity-30 disabled:cursor-not-allowed bg-[${UpholdGreen}] hover:bg-[#2d9e34] text-white transition-colors`}>
          <svg className="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
            <polyline points="15 18 9 12 15 6" />
          </svg>
          Back
        </button>
        {findStep(stepIndex, 1) != null && <button onClick={() => setStepIndex(findStep(stepIndex, 1))} className={`flex items-center gap-2 px-4 py-2 rounded-xl text-sm font-medium border-0 cursor-pointer bg-[${UpholdGreen}] hover:bg-[#2d9e34] text-white font-semibold transition-colors`}>
            Next
            <svg className="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
              <polyline points="9 18 15 12 9 6" />
            </svg>
          </button>}
      </div>
    </div>;
};

<FlowWizard flow={SEND_FLOW}>
  <div />

  <div>
    <EndpointHeader method="GET" path="/core/accounts?perPage=10" />

    <CodeGroup>
      ```bash cURL theme={null}
      curl -X GET "https://api.enterprise.uphold.com/core/accounts?perPage=10" \
        -H "Authorization: Bearer <YOUR_API_KEY>"
      ```

      ```js JavaScript theme={null}
      const response = await fetch("https://api.enterprise.uphold.com/core/accounts?perPage=10", {
        method: "GET",
        headers: {
          "Authorization": "Bearer <YOUR_API_KEY>",
        },
      });

      const data = await response.json();
      ```

      ```python Python theme={null}
      import requests

      response = requests.request(
        "GET",
        "https://api.enterprise.uphold.com/core/accounts?perPage=10",
        headers={
          "Authorization": "Bearer <YOUR_API_KEY>",
        }
      )

      data = response.json()
      ```

      ```java Java theme={null}
      import java.net.http.*;
      import java.net.URI;

      var client = HttpClient.newHttpClient();
      var req = HttpRequest.newBuilder()
          .uri(URI.create("https://api.enterprise.uphold.com/core/accounts?perPage=10"))
          .header("Authorization", "Bearer <YOUR_API_KEY>")
          .method("GET", HttpRequest.BodyPublishers.noBody())
          .build();

      var response = client.send(req, HttpResponse.BodyHandlers.ofString());
      var body = response.body();
      ```
    </CodeGroup>

    ```json Response theme={null}
    {
      "accounts": [
        {
          "id": "11de2405-1f1f-4a6e-8a39-acd97dc7f3ec",
          "label": "My USD account",
          "asset": "USD",
          "balance": { "total": "250.00", "available": "250.00" }
        },
        {
          "id": "c392a0de-5fc6-49a7-96e1-e4b3f9ef5b27",
          "label": "My BTC account",
          "asset": "BTC",
          "balance": { "total": "0.0015", "available": "0.0015" }
        },
        {
          "id": "d7a1b3c2-8e4f-4d6a-b2c1-f9e8d7c6b5a4",
          "label": "My XRP account",
          "asset": "XRP",
          "balance": { "total": "120.50", "available": "120.50" }
        }
      ],
      "pagination": {
        "first": "https://api.enterprise.sandbox.uphold.com/core/accounts?page=1&perPage=10"
      }
    }
    ```
  </div>

  <div />

  <div>
    <EndpointHeader method="POST" path="/core/transactions/quote" />

    <CodeGroup>
      ```bash cURL theme={null}
      curl -X POST "https://api.enterprise.uphold.com/core/transactions/quote" \
        -H "Authorization: Bearer <YOUR_API_KEY>" \
        -H "X-On-Behalf-Of: 5feba1e3-3f14-4fd9-b00d-f386df83042f" \
        -H "Content-Type: application/json" \
        -d '{
        "origin": {
          "type": "account",
          "id": "11de2405-1f1f-4a6e-8a39-acd97dc7f3ec"
        },
        "destination": {
          "type": "account",
          "id": "d9f7a3c1-2b8e-4f5d-9c6a-1e2b3c4d5e6f"
        },
        "denomination": {
          "asset": "USD",
          "amount": "50"
        }
      }'
      ```

      ```js JavaScript theme={null}
      const response = await fetch("https://api.enterprise.uphold.com/core/transactions/quote", {
        method: "POST",
        headers: {
          "Authorization": "Bearer <YOUR_API_KEY>",
          "X-On-Behalf-Of": "5feba1e3-3f14-4fd9-b00d-f386df83042f",
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          origin: { type: "account", id: "11de2405-1f1f-4a6e-8a39-acd97dc7f3ec" },
          destination: { type: "account", id: "d9f7a3c1-2b8e-4f5d-9c6a-1e2b3c4d5e6f" },
          denomination: { asset: "USD", amount: "50" },
        }),
      });

      const data = await response.json();
      ```

      ```python Python theme={null}
      import requests

      response = requests.request(
        "POST",
        "https://api.enterprise.uphold.com/core/transactions/quote",
        headers={
          "Authorization": "Bearer <YOUR_API_KEY>",
          "X-On-Behalf-Of": "5feba1e3-3f14-4fd9-b00d-f386df83042f",
          "Content-Type": "application/json",
        },
        json={
          "origin": {"type": "account", "id": "11de2405-1f1f-4a6e-8a39-acd97dc7f3ec"},
          "destination": {"type": "account", "id": "d9f7a3c1-2b8e-4f5d-9c6a-1e2b3c4d5e6f"},
          "denomination": {"asset": "USD", "amount": "50"},
        }
      )

      data = response.json()
      ```

      ```java Java theme={null}
      import java.net.http.*;
      import java.net.URI;

      var client = HttpClient.newHttpClient();
      var req = HttpRequest.newBuilder()
          .uri(URI.create("https://api.enterprise.uphold.com/core/transactions/quote"))
          .header("Authorization", "Bearer <YOUR_API_KEY>")
          .header("X-On-Behalf-Of", "5feba1e3-3f14-4fd9-b00d-f386df83042f")
          .header("Content-Type", "application/json")
          .method("POST", HttpRequest.BodyPublishers.ofString("""
              {
                "origin": {
                  "type": "account",
                  "id": "11de2405-1f1f-4a6e-8a39-acd97dc7f3ec"
                },
                "destination": {
                  "type": "account",
                  "id": "d9f7a3c1-2b8e-4f5d-9c6a-1e2b3c4d5e6f"
                },
                "denomination": {
                  "asset": "USD",
                  "amount": "50"
                }
              }"""))
          .build();

      var response = client.send(req, HttpResponse.BodyHandlers.ofString());
      var body = response.body();
      ```
    </CodeGroup>

    ```json Response theme={null}
    {
      "quote": {
        "id": "b7e4d2c1-9f3a-4b5e-8d7c-2e1f3a4b5c6d",
        "expiresAt": "2026-05-29T14:02:00.000Z",
        "origin": { "asset": "USD", "amount": "50.00", "rate": "1.00" },
        "destination": { "asset": "USD", "amount": "50.00", "rate": "1.00" },
        "denomination": {
          "asset": "USD",
          "amount": "50.00",
          "rate": "1.00",
          "target": "origin"
        },
        "fees": []
      }
    }
    ```
  </div>

  <div>
    <EndpointHeader method="POST" path="/core/transactions" />

    <CodeGroup>
      ```bash cURL theme={null}
      curl -X POST "https://api.enterprise.uphold.com/core/transactions" \
        -H "Authorization: Bearer <YOUR_API_KEY>" \
        -H "Content-Type: application/json" \
        -H "X-On-Behalf-Of: <sender userId>" \
        -d '{
        "quoteId": "b7e4d2c1-9f3a-4b5e-8d7c-2e1f3a4b5c6d"
      }'
      ```

      ```js JavaScript theme={null}
      const response = await fetch("https://api.enterprise.uphold.com/core/transactions", {
        method: "POST",
        headers: {
          "Authorization": "Bearer <YOUR_API_KEY>",
          "Content-Type": "application/json",
          "X-On-Behalf-Of": "<sender userId>",
        },
        body: JSON.stringify({
          quoteId: "b7e4d2c1-9f3a-4b5e-8d7c-2e1f3a4b5c6d",
        }),
      });

      const data = await response.json();
      ```

      ```python Python theme={null}
      import requests

      response = requests.request(
        "POST",
        "https://api.enterprise.uphold.com/core/transactions",
        headers={
          "Authorization": "Bearer <YOUR_API_KEY>",
          "Content-Type": "application/json",
          "X-On-Behalf-Of": "<sender userId>",
        },
        json={
          "quoteId": "b7e4d2c1-9f3a-4b5e-8d7c-2e1f3a4b5c6d",
        }
      )

      data = response.json()
      ```

      ```java Java theme={null}
      import java.net.http.*;
      import java.net.URI;

      var client = HttpClient.newHttpClient();
      var req = HttpRequest.newBuilder()
          .uri(URI.create("https://api.enterprise.uphold.com/core/transactions"))
          .header("Authorization", "Bearer <YOUR_API_KEY>")
          .header("Content-Type", "application/json")
          .header("X-On-Behalf-Of", "<sender userId>")
          .method("POST", HttpRequest.BodyPublishers.ofString("""
              {
                "quoteId": "b7e4d2c1-9f3a-4b5e-8d7c-2e1f3a4b5c6d"
              }"""))
          .build();

      var response = client.send(req, HttpResponse.BodyHandlers.ofString());
      var body = response.body();
      ```
    </CodeGroup>

    ```json Response theme={null}
    {
      "transaction": {
        "id": "b7e4d2c1-9f3a-4b5e-8d7c-2e1f3a4b5c6d",
        "status": "processing",
        "origin": { "asset": "USD", "amount": "50.00" },
        "destination": { "asset": "USD", "amount": "50.00" }
      }
    }
    ```
  </div>

  <div>
    <Info>
      **Webhook event:** `core.transaction.status-changed`
    </Info>

    ```json Webhook payload theme={null}
    {
      "id": "e4f5a6b7-c8d9-4e0f-1a2b-c3d4e5f6a7b8",
      "type": "core.transaction.status-changed",
      "createdAt": "2026-05-29T14:01:55.612Z",
      "data": {
        "transaction": {
          "id": "d3e4f5a6-b7c8-4d9e-0f1a-b2c3d4e5f6a7",
          "status": "completed",
          "origin": {
            "asset": "USD",
            "amount": "50.00",
            "node": {
              "type": "account",
              "id": "11de2405-1f1f-4a6e-8a39-acd97dc7f3ec",
              "ownerId": "5feba1e3-3f14-4fd9-b00d-f386df83042f"
            }
          },
          "destination": {
            "asset": "USD",
            "amount": "50.00",
            "node": {
              "type": "account",
              "id": "d9f7a3c1-2b8e-4f5d-9c6a-1e2b3c4d5e6f",
              "ownerId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
            }
          },
          "denomination": {
            "asset": "USD",
            "amount": "50.00",
            "rate": "1.00",
            "target": "origin"
          },
          "fees": [],
          "quotedAt": "2026-05-29T14:01:50.123Z",
          "createdAt": "2026-05-29T14:01:55.000Z",
          "updatedAt": "2026-05-29T14:01:55.612Z"
        }
      }
    }
    ```
  </div>
</FlowWizard>

***

For the full prose walkthrough — capability checks, recipient resolution, and webhook handling — see the [via REST API](/developer-guides/trade-and-send/send/via-rest-api) guide.
