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

# On/Off-Ramp FAQ

> Common questions on the WhiteBIT on/off-ramp integration: endpoint activation, SEPA deposit matching, withdrawal fee semantics, reconciliation, identifier casing, and EEA compliance.

export const RegionBaseUrl = ({className = "", showBaseUrl = true, protocol = "https"}) => {
  const {useState, useEffect, useRef} = React;
  const EU_ENABLED = false;
  const [region, setRegionState] = useState(() => {
    if (!EU_ENABLED) return "com";
    if (typeof window !== 'undefined') {
      return localStorage.getItem("api-region-preference") || "com";
    }
    return "com";
  });
  const [mounted, setMounted] = useState(false);
  const observerRef = useRef(null);
  const isSyncingRef = useRef(false);
  const updateAllContentOnPage = targetRegion => {
    try {
      const domainFrom = targetRegion === "eu" ? "whitebit.com" : "whitebit.eu";
      const domainTo = targetRegion === "eu" ? "whitebit.eu" : "whitebit.com";
      const links = document.querySelectorAll('a');
      links.forEach(link => {
        let href = link.getAttribute('href');
        if (href && href.includes(domainFrom)) {
          link.setAttribute('href', href.replace(domainFrom, domainTo));
        }
      });
      const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, {
        acceptNode: node => {
          if (node.parentElement?.closest('.region-toggle-component')) {
            return NodeFilter.FILTER_REJECT;
          }
          return node.textContent.includes(domainFrom) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT;
        }
      });
      let currentNode;
      while (currentNode = walker.nextNode()) {
        currentNode.textContent = currentNode.textContent.replace(new RegExp(domainFrom, 'g'), domainTo);
      }
      console.log(`[RegionSync] Global content updated to ${domainTo}`);
    } catch (e) {
      console.error("[RegionSync] Error updating content:", e);
    }
  };
  const updateRegion = (newRegion, source) => {
    if (region === newRegion) return;
    console.log(`[RegionBaseUrl] Updating to "${newRegion}" (Source: ${source})`);
    if (source === 'observer') {
      isSyncingRef.current = true;
      setTimeout(() => isSyncingRef.current = false, 1000);
    }
    setRegionState(newRegion);
    localStorage.setItem("api-region-preference", newRegion);
    updateAllContentOnPage(newRegion);
    if (source === 'user-click') {
      window.dispatchEvent(new CustomEvent("regionChange", {
        detail: newRegion
      }));
      attemptToUpdateNativeDropdown(newRegion, 0);
      setTimeout(() => attemptToUpdateNativeDropdown(newRegion, 1), 500);
      setTimeout(() => attemptToUpdateNativeDropdown(newRegion, 2), 1500);
    }
  };
  const attemptToUpdateNativeDropdown = (targetRegion, attempt) => {
    if (isSyncingRef.current) return;
    try {
      const targetUrl = targetRegion === "eu" ? "https://whitebit.eu" : "https://whitebit.com";
      const targetDesc = targetRegion === "eu" ? "EU Server" : "Production Server";
      const selects = document.querySelectorAll('select');
      for (const select of selects) {
        if (select.innerHTML.includes('whitebit.com') || select.innerHTML.includes('whitebit.eu')) {
          select.value = targetUrl;
          select.dispatchEvent(new Event('change', {
            bubbles: true
          }));
          return;
        }
      }
      const buttons = Array.from(document.querySelectorAll('button, [role="combobox"]'));
      const serverSelector = buttons.find(btn => {
        if (btn.closest('a') || btn.closest('[class*="card"]') || btn.closest('nav')) {
          return false;
        }
        const txt = btn.textContent || "";
        const isServerDropdown = (txt.includes('Production Server') || txt.includes('EU Server') || txt.includes('WhiteBIT Global Server') || txt.includes('WhiteBIT EU Server')) && !txt.includes('Run') && !txt.includes('Send') || btn.getAttribute('role') === 'combobox';
        return isServerDropdown;
      });
      if (serverSelector) {
        const currentText = serverSelector.textContent || "";
        if (currentText.includes(targetDesc)) return;
        serverSelector.click();
        setTimeout(() => {
          const options = document.querySelectorAll('[role="option"], li, button');
          for (const opt of options) {
            const optText = opt.textContent || "";
            if (optText.includes(targetDesc) || optText.includes(targetUrl)) {
              opt.click();
              return;
            }
          }
        }, 100);
      }
    } catch (e) {
      console.error("[Sync] Error:", e);
    }
  };
  useEffect(() => {
    if (!EU_ENABLED) return;
    setMounted(true);
    updateAllContentOnPage(region);
    const handleStorageChange = e => {
      if (e.key === "api-region-preference" && e.newValue) {
        updateRegion(e.newValue, 'storage');
      }
    };
    const handleRegionChange = e => {
      if (e.detail !== region) {
        updateRegion(e.detail, 'event');
      }
    };
    window.addEventListener("storage", handleStorageChange);
    window.addEventListener("regionChange", handleRegionChange);
    observerRef.current = new MutationObserver(mutations => {
      if (isSyncingRef.current) return;
      updateAllContentOnPage(region);
      for (const mutation of mutations) {
        if (mutation.type !== 'childList' && mutation.type !== 'characterData') continue;
        const target = mutation.target;
        const el = target.nodeType === Node.TEXT_NODE ? target.parentElement : target;
        if (el && (el.getAttribute('role') === 'option' || el.closest('[role="listbox"]'))) continue;
        const text = target.textContent || "";
        if (text.includes('WhiteBIT EU Server') || text.includes('https://whitebit.eu') && text.includes('Server')) {
          if (el && el.tagName !== 'A' && !el.closest('.region-toggle-component')) {
            if (region !== 'eu') updateRegion('eu', 'observer');
          }
        } else if (text.includes('WhiteBIT Global Server') || text.includes('https://whitebit.com') && text.includes('Server')) {
          if (el && el.tagName !== 'A' && !el.closest('.region-toggle-component')) {
            if (region !== 'com') updateRegion('com', 'observer');
          }
        }
      }
    });
    observerRef.current.observe(document.body, {
      childList: true,
      subtree: true,
      characterData: true
    });
    if (typeof window !== 'undefined') {
      const current = localStorage.getItem("api-region-preference");
      if (current) attemptToUpdateNativeDropdown(current, 'init');
    }
    return () => {
      window.removeEventListener("storage", handleStorageChange);
      window.removeEventListener("regionChange", handleRegionChange);
      if (observerRef.current) observerRef.current.disconnect();
    };
  }, [region]);
  const apiBaseUrl = protocol === "wss" ? region === "eu" ? "wss://api.whitebit.eu/ws" : "wss://api.whitebit.com/ws" : region === "eu" ? "https://whitebit.eu" : "https://whitebit.com";
  const baseUrlLabel = protocol === "wss" ? "WebSocket URL" : "Base URL";
  if (!EU_ENABLED) {
    if (!showBaseUrl) return null;
    return <div className={`flex items-center gap-2 flex-wrap my-4 region-toggle-component ${className}`}>
                <span className="text-sm text-gray-500 dark:text-gray-400 font-mono">
                    {baseUrlLabel}
                </span>
                <span className="text-sm text-gray-400">:</span>
                {protocol === "wss" ? <code className="text-sm font-mono text-primary dark:text-primary-light">
                        {apiBaseUrl}
                    </code> : <a href={apiBaseUrl} target="_blank" rel="noopener noreferrer" className="text-sm font-mono text-primary dark:text-primary-light hover:underline">
                        {apiBaseUrl}
                    </a>}
            </div>;
  }
  if (!mounted) return null;
  return <div className={`flex items-center gap-2 flex-wrap my-4 region-toggle-component ${className}`}>
            <span className="text-sm text-gray-500 dark:text-gray-400 font-mono">
                {baseUrlLabel}
            </span>
            <span className="text-sm text-gray-400">(</span>
            <div className="inline-flex bg-gray-100 dark:bg-gray-800 rounded-lg p-0.5 border border-gray-200 dark:border-gray-700">
                <button onClick={() => updateRegion("com", "user-click")} className={`px-2 py-0.5 text-xs font-medium rounded-md transition-all ${region === "com" ? "bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 shadow-sm" : "text-gray-500 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-200"}`}>
                    .com
                </button>
                <button onClick={() => updateRegion("eu", "user-click")} className={`px-2 py-0.5 text-xs font-medium rounded-md transition-all ${region === "eu" ? "bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 shadow-sm" : "text-gray-500 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-200"}`}>
                    .eu
                </button>
            </div>
            <span className="text-sm text-gray-400">)</span>
            {showBaseUrl && <>
                    <span className="text-sm text-gray-400">:</span>
                    {protocol === "wss" ? <code className="text-sm font-mono text-primary dark:text-primary-light">
                            {apiBaseUrl}
                        </code> : <a href={apiBaseUrl} target="_blank" rel="noopener noreferrer" className="text-sm font-mono text-primary dark:text-primary-light hover:underline">
                            {apiBaseUrl}
                        </a>}
                </>}
        </div>;
};

<RegionBaseUrl />

Answers to common questions on the WhiteBIT on/off-ramp integration. For the flows and code, see the [Integration guide](/guides/on-off-ramp-integration); for access, onboarding, and positioning, see the [Overview](/guides/on-off-ramp-overview).

## Access and activation

<AccordionGroup>
  <Accordion title="Fiat deposit URL permission errors">
    The `POST /api/v4/main-account/fiat-deposit-url` endpoint requires per-account activation and is not enabled by default. Contact WhiteBIT support and provide the API key to request access. Fiat operations also depend on completed Phase 2 institutional onboarding — see [How to get started](/guides/on-off-ramp-overview#how-to-get-started).
  </Accordion>

  <Accordion title="KYC requirement for fiat withdrawals">
    Fiat withdrawals require KYC verification; an account without KYC verification cannot process a fiat withdrawal. In exceptional, documented cases the institutional team can arrange a per-account override that permits fiat withdrawal without standard KYC. The override is exception-only, not a default capability — contact [institutional@whitebit.com](mailto:institutional@whitebit.com) with the documented case. See [Fiat withdrawal](/guides/payment-integration#fiat-withdrawal).
  </Accordion>
</AccordionGroup>

## Fiat deposits

<AccordionGroup>
  <Accordion title="SEPA deposit matching by payment reference">
    The `uniqueId` submitted in the `fiat-deposit-url` request must appear in the SEPA payment-reference field of the bank transfer. WhiteBIT uses that string to match the incoming settlement to the original deposit request. If the end user omits or alters the reference, the deposit may settle unmatched and require manual reconciliation through institutional support. Validate the reference field in the payment UX. See [SEPA payment reference](/guides/payment-integration#sepa-payment-reference).
  </Accordion>

  <Accordion title="Provider value for SEPA EUR deposits">
    Take the request `provider` value from the [Asset Status](/api-reference/market-data/asset-status-list) response, and confirm the enabled provider for SEPA EUR deposits on the account with the account manager.

    <Note>
      The exact provider value for SEPA EUR deposits is confirmed per account during onboarding; read the current options from the [Asset Status](/api-reference/market-data/asset-status-list) response rather than hardcoding a value.
    </Note>
  </Accordion>

  <Accordion title="VISAMASTER Referer header requirement">
    For the VISAMASTER provider, the browser must send the `Referer` header when opening the invoice link. Messengers and email clients often strip the header, and without it WhiteBIT redirects the end user to the homepage instead of the payment provider. Test the redirect in the real delivery surface — mobile app, email link, or in-app web view — before go-live. See [Card-provider flows](/guides/payment-integration#card-provider-flows).
  </Accordion>

  <Accordion title="Fiat currencies not depositable via API">
    Not every fiat ticker is depositable via API. Check `can_deposit` in the [Asset Status](/api-reference/market-data/asset-status-list) response before generating an invoice; tickers without API deposit support run through the WhiteBIT web interface.
  </Accordion>
</AccordionGroup>

## Fiat withdrawals

<AccordionGroup>
  <Accordion title="Fee handling in /withdraw and /withdraw-pay">
    Both endpoints submit a withdrawal but differ in fee handling. `POST /api/v4/main-account/withdraw` treats `amount` as **including** the fee, so the recipient receives `amount - fee`. `POST /api/v4/main-account/withdraw-pay` charges the fee **on top**, so the recipient receives the exact amount specified. Select the endpoint that matches whether the specified amount is the debit or the credit.
  </Accordion>

  <Accordion title="Partial fiat withdrawals (status 18)">
    Setting `partialEnable: true` raises the maximum limit for fiat withdrawals. The withdrawal can then complete partially, surfacing as the `Partially successful` status (18). The application must reconcile `requestAmount` against `processedAmount` in the history record and surface the remainder to operations. See the [failure and exception paths](/guides/on-off-ramp-integration#failure-and-exception-paths).
  </Accordion>
</AccordionGroup>

## Reconciliation and monitoring

<AccordionGroup>
  <Accordion title="Webhook delivery and replay behavior">
    Treat webhook delivery as best-effort. Failed deliveries are retried a small number of times spaced roughly an hour apart over a window of about one day, and there is no replay mechanism once that window closes. Pair webhooks with polling: query `POST /api/v4/main-account/history` (`transactionMethod: 1` for deposits, `2` for withdrawals) on a regular cycle, and deduplicate against received events. See [Webhooks](/platform/webhook) and the [reconciliation pattern](/guides/payment-integration#webhook-reconciliation).
  </Accordion>

  <Accordion title="Transaction identifier casing across the API">
    The identifier is named differently across the API surface:

    | Field            | Where it appears                           | Meaning                                                       |
    | ---------------- | ------------------------------------------ | ------------------------------------------------------------- |
    | `uniqueId`       | `fiat-deposit-url` and withdrawal requests | Client-side transaction identifier, up to 255 characters      |
    | `unique_id`      | History filter and records                 | The deposit/withdraw identifier in history responses          |
    | `transactionId`  | `refund-deposit` request                   | Transaction UUID, sourced from the `deposit.canceled` webhook |
    | `transaction_id` | History records                            | System-wide transaction UUID, never reused                    |

    Match on the correct casing per surface when reconciling across webhooks, history, and refunds.
  </Accordion>

  <Accordion title="Webhook source IP allowlisting">
    Configure the webhook endpoint over HTTPS and authenticate each delivery by verifying the HMAC-SHA512 signature rather than by source IP. See [Webhooks](/platform/webhook) for the verification flow.

    <Note>
      Whether the outbound delivery IP addresses are stable and publishable for allowlisting is confirmed with the account manager; the portal does not publish a fixed list.
    </Note>
  </Accordion>

  <Accordion title="Fiat settlement timing">
    Settlement windows and cutoff behavior depend on the fiat rail in use, including weekends and holidays. The account manager confirms the applicable windows for the account during onboarding.

    <Note>
      No fixed settlement time is published; the timing for the specific rails enabled on the account is confirmed by the account manager.
    </Note>
  </Accordion>
</AccordionGroup>

## Conversion

<AccordionGroup>
  <Accordion title="Convert across the fiat and crypto legs">
    In both on/off-ramp flows, fiat enters and exits through the fiat deposit and withdrawal endpoints, and conversion runs on the crypto side of the balance — request a quote with `POST /api/v4/convert/estimate`, then execute it with `POST /api/v4/convert/confirm` before the quote expires. The convert service routes balances internally; no manual Main↔Trade transfers are required. See [Convert](/platform/convert).

    <Note>
      Whether Convert accepts a fiat ticker directly as the conversion leg is confirmed per account; the conversion pairs available to the account are set with the account manager.
    </Note>
  </Accordion>
</AccordionGroup>

## Compliance

<AccordionGroup>
  <Accordion title="Travel Rule holds on inbound deposits (EEA and Turkey)">
    Inbound crypto deposits for EEA and Turkey accounts are held until Travel Rule verification completes — status 27 (awaiting originator data) and status 28 (data submitted, under review). No webhook fires for Travel Rule transitions, so the hold surfaces via history polling. Where the Travel Rule API is enabled, submit originator data through the [deposit verification endpoint](/api-reference/travel-rule/submit-deposit-verification); otherwise complete verification on the platform. See [Travel Rule](/concepts/travel-rule).
  </Accordion>

  <Accordion title="USDT alternatives for EEA accounts (MiCA)">
    Under MiCA, EEA accounts cannot deposit, withdraw, or create WhiteBIT Codes in USDT since December 30, 2024. Use USDC or EURI for the crypto leg. See [Regulatory Compliance](/institutional/compliance).
  </Accordion>
</AccordionGroup>

## What's next

<CardGroup cols={3}>
  <Card title="Overview" icon="arrow-right-arrow-left" href="/guides/on-off-ramp-overview">
    Positioning, the two-phase access model, enablement gates, and how to apply.
  </Card>

  <Card title="Integration" icon="code" href="/guides/on-off-ramp-integration">
    The on-ramp and off-ramp flows, code, reconciliation, and failure paths.
  </Card>

  <Card title="Payment Integration" icon="arrow-right-arrow-left" href="/guides/payment-integration">
    Endpoint-level lifecycle reference: statuses, fees, fiat operations, refunds.
  </Card>
</CardGroup>
