> ## 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.

# Place stop-BBO order

> Place a spot stop order that becomes a BBO order on trigger, with order_stop_bbo_place.

export const exOrderStopBboPlaceResponse = {
  "id": 500009,
  "result": {
    "id": 2423735880229,
    "market": "ETH_USDT",
    "type": 3,
    "side": 1,
    "post_only": true,
    "ioc": false,
    "ctime": 1786452691.362412,
    "mtime": 1786452691.362412,
    "activation_price": "1859.73",
    "activation_condition": "lte",
    "activated": 0,
    "price": "0",
    "amount": "0.00108",
    "left": "0.00108",
    "deal_stock": "0",
    "deal_money": "0",
    "deal_fee": "0",
    "client_order_id": "",
    "stp": "no",
    "status": "OPEN"
  },
  "error": null
};

export const exOrderStopBboPlaceRequest = {
  "id": 500009,
  "method": "order_stop_bbo_place",
  "params": [{
    "market": "ETH_USDT",
    "side": "sell",
    "amount": "0.00108",
    "activation_price": "1859.73",
    "bbo_role": 1,
    "stp": "no"
  }]
};

export const orderStopBboPlaceParams = [{
  name: "market",
  type: "string",
  required: true,
  description: "Spot market name. A futures market is rejected with error `1`."
}, {
  name: "side",
  type: "string",
  required: true,
  enum: ["buy", "sell"],
  description: "Order side. The response reports the side numerically: `1` for sell, `2` for buy."
}, {
  name: "amount",
  type: "string",
  required: true,
  description: "Order size in stock, at the market stock precision."
}, {
  name: "activation_price",
  type: "string",
  required: true,
  description: "Trigger price, validated against the market price bands. Outside them the call returns error `251`."
}, {
  name: "bbo_role",
  type: "integer",
  required: true,
  enum: [1, 2],
  description: "Pricing role applied at activation. `1` maker — price at the own-side best and set `post_only`. `2` taker — price at the opposite-side best."
}, {
  name: "client_order_id",
  type: "string",
  description: "Custom client order id, echoed on the response. Must be unique among active orders — a collision returns error `43`."
}, {
  name: "stp",
  type: "string",
  enum: ["no", "co", "cn", "cb"],
  description: "Self-trade prevention mode applied to the order created on activation. Defaults to `no` when omitted."
}];

export const channelMeta = {
  "authRequired": true,
  "rateLimits": {
    "connectionsPerMinute": 1000,
    "requestsPerMinute": 200
  },
  "errorCodes": [{
    "code": 1,
    "message": "bbo role must be an integer in range 1..2",
    "description": "The `bbo_role` value is outside `1`–`2`, or is not an integer."
  }, {
    "code": 101,
    "message": "activation price should not be equal to the last price",
    "description": "The activation price equals the current last price. Move the trigger to either side of it."
  }, {
    "code": 251,
    "message": "activation price is out of bands",
    "description": "The activation price falls outside the market price bands."
  }, {
    "code": 12,
    "message": "not enough traders",
    "description": "The order book has no quote on the required side at activation, so the order cannot be priced and is dropped."
  }, {
    "code": 51,
    "message": "trading in the market is not allowed",
    "description": "Trading is suspended, or the market runs in post-only mode — a stop method is rejected there."
  }]
};

export const channelOperations = [{
  name: "Place stop-BBO order",
  send: "order_stop_bbo_place",
  receive: "Accepted conditional order, price resolved on activation",
  push: null
}];

export const WsErrorCodes = ({errorCodes}) => {
  if (Array.isArray(errorCodes)) {
    return <div>
        <table>
          <thead>
            <tr>
              <th>Code</th>
              <th>Message</th>
              <th>Description</th>
            </tr>
          </thead>
          <tbody>
            {errorCodes.map((err, i) => <tr key={i}>
                <td><code>{err.code}</code></td>
                <td>{err.message}</td>
                <td>{err.description}</td>
              </tr>)}
          </tbody>
        </table>
        <p>
          Standard WebSocket error codes apply. See <a href="/websocket/overview">WebSocket overview</a> for error code reference.
        </p>
      </div>;
  }
  return <p>
      Standard WebSocket error codes apply. See <a href="/websocket/overview">WebSocket overview</a> for error code reference.
    </p>;
};

export const WsRateLimits = ({connectionsPerMinute, requestsPerMinute}) => {
  return <p>
      Standard connection-level rate limits apply. See{' '}
      <a href="/websocket/rate-limits">WebSocket Rate Limits</a> for details.
    </p>;
};

export const WsAuthBadge = ({required}) => {
  if (!required) {
    return <p><strong>Authentication:</strong> None. No authentication required.</p>;
  }
  return <Warning>
      This is a private channel.{' '}
      <a href="/websocket/authentication">Authorize</a> the WebSocket
      connection before subscribing.
    </Warning>;
};

export const WsMessageExample = ({data, title}) => {
  const [isDark, setIsDark] = useState(typeof document !== 'undefined' ? document.documentElement.classList.contains('dark') : true);
  useEffect(() => {
    const check = () => setIsDark(document.documentElement.classList.contains('dark'));
    check();
    const observer = new MutationObserver(check);
    observer.observe(document.documentElement, {
      attributes: true,
      attributeFilter: ['class']
    });
    return () => observer.disconnect();
  }, []);
  const COLORS = isDark ? {
    key: '#79c0ff',
    string: '#a5d6ff',
    number: '#e3b341',
    boolean: '#ff7b72',
    null: '#8b949e',
    punctuation: '#c9d1d9',
    ws: '#c9d1d9'
  } : {
    key: '#0550ae',
    string: '#0a3069',
    number: '#953800',
    boolean: '#cf222e',
    null: '#6e7781',
    punctuation: '#24292f',
    ws: '#24292f'
  };
  const tokenize = json => {
    const tokens = [];
    let i = 0;
    while (i < json.length) {
      if ((/\s/).test(json[i])) {
        let ws = '';
        while (i < json.length && (/\s/).test(json[i])) ws += json[i++];
        tokens.push({
          type: 'ws',
          value: ws
        });
        continue;
      }
      if (json[i] === '"') {
        let str = '"';
        i++;
        while (i < json.length) {
          if (json[i] === '\\') {
            str += json[i] + json[i + 1];
            i += 2;
          } else if (json[i] === '"') {
            str += '"';
            i++;
            break;
          } else {
            str += json[i++];
          }
        }
        let j = i;
        while (j < json.length && (/[ \t]/).test(json[j])) j++;
        const isKey = json[j] === ':';
        tokens.push({
          type: isKey ? 'key' : 'string',
          value: str
        });
        continue;
      }
      if (json[i] === '-' || (/\d/).test(json[i])) {
        let num = '';
        if (json[i] === '-') num += json[i++];
        while (i < json.length && (/[\d.eE+\-]/).test(json[i])) num += json[i++];
        tokens.push({
          type: 'number',
          value: num
        });
        continue;
      }
      if (json.slice(i, i + 4) === 'true') {
        tokens.push({
          type: 'boolean',
          value: 'true'
        });
        i += 4;
        continue;
      }
      if (json.slice(i, i + 5) === 'false') {
        tokens.push({
          type: 'boolean',
          value: 'false'
        });
        i += 5;
        continue;
      }
      if (json.slice(i, i + 4) === 'null') {
        tokens.push({
          type: 'null',
          value: 'null'
        });
        i += 4;
        continue;
      }
      tokens.push({
        type: 'punctuation',
        value: json[i++]
      });
    }
    return tokens;
  };
  const json = JSON.stringify(data, null, 2);
  const tokens = tokenize(json);
  return <div style={{
    marginBottom: '1rem'
  }}>
      {title && <p style={{
    fontWeight: 600,
    fontSize: '0.875rem',
    marginTop: '1rem',
    marginBottom: '0.5rem'
  }}>
          {title}
        </p>}
      <div className="border border-gray-200 dark:border-[#30363d]" style={{
    position: 'relative',
    borderRadius: '0.5rem',
    overflow: 'hidden'
  }}>
        <div className="bg-gray-50 dark:bg-[#161b22] border-b border-gray-200 dark:border-[#30363d]" style={{
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'space-between',
    padding: '0.375rem 1rem'
  }}>
          <span className="text-gray-500 dark:text-[#8b949e]" style={{
    fontSize: '0.75rem',
    fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace'
  }}>
            json
          </span>
        </div>
        <div className="bg-white dark:bg-[#0d1117]" style={{
    margin: 0,
    padding: '1rem 1.25rem',
    overflowX: 'auto',
    fontSize: '0.8125rem',
    lineHeight: '1.7',
    fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace',
    whiteSpace: 'pre'
  }}>
          {tokens.map((t, idx) => <span key={idx} style={{
    color: COLORS[t.type]
  }}>{t.value}</span>)}
        </div>
      </div>
    </div>;
};

export const WsSchemaTable = ({title, fields}) => {
  const [isDark, setIsDark] = useState(typeof document !== 'undefined' ? document.documentElement.classList.contains('dark') : true);
  useEffect(() => {
    const check = () => setIsDark(document.documentElement.classList.contains('dark'));
    check();
    const observer = new MutationObserver(check);
    observer.observe(document.documentElement, {
      attributes: true,
      attributeFilter: ['class']
    });
    return () => observer.disconnect();
  }, []);
  const T = isDark ? {
    border: '#374151',
    borderSubtle: '#1f2937',
    headerBg: '#1f2937',
    headerText: '#9ca3af',
    titleBg: '#1f2937',
    titleText: '#d1d5db',
    fieldBg: '#374151',
    fieldText: '#e5e7eb',
    reqYes: '#f3f4f6',
    reqNo: '#4b5563',
    descText: '#9ca3af',
    emptyText: '#4b5563',
    enumBg: 'rgb(120 53 15 / 0.3)',
    enumText: '#fbbf24'
  } : {
    border: '#e5e7eb',
    borderSubtle: '#f3f4f6',
    headerBg: '#f9fafb',
    headerText: '#6b7280',
    titleBg: '#f9fafb',
    titleText: '#374151',
    fieldBg: '#f3f4f6',
    fieldText: '#1f2937',
    reqYes: '#111827',
    reqNo: '#d1d5db',
    descText: '#6b7280',
    emptyText: '#d1d5db',
    enumBg: '#fffbeb',
    enumText: '#92400e'
  };
  const TYPE_STYLE = isDark ? {
    string: {
      backgroundColor: 'rgb(88 28 135 / 0.25)',
      color: '#c084fc'
    },
    integer: {
      backgroundColor: 'rgb(154 52 18 / 0.25)',
      color: '#fb923c'
    },
    number: {
      backgroundColor: 'rgb(154 52 18 / 0.25)',
      color: '#fb923c'
    },
    boolean: {
      backgroundColor: 'rgb(30 64 175 / 0.25)',
      color: '#60a5fa'
    },
    array: {
      backgroundColor: 'rgb(17 94 89 / 0.25)',
      color: '#2dd4bf'
    },
    object: {
      backgroundColor: 'rgb(55 65 81 / 0.4)',
      color: '#9ca3af'
    },
    null: {
      backgroundColor: 'rgb(55 65 81 / 0.4)',
      color: '#9ca3af'
    }
  } : {
    string: {
      backgroundColor: '#faf5ff',
      color: '#6b21a8'
    },
    integer: {
      backgroundColor: '#fff7ed',
      color: '#9a3412'
    },
    number: {
      backgroundColor: '#fff7ed',
      color: '#9a3412'
    },
    boolean: {
      backgroundColor: '#eff6ff',
      color: '#1e40af'
    },
    array: {
      backgroundColor: '#f0fdfa',
      color: '#115e59'
    },
    object: {
      backgroundColor: '#f3f4f6',
      color: '#374151'
    },
    null: {
      backgroundColor: '#f3f4f6',
      color: '#374151'
    }
  };
  const MONO = 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace';
  const HEADER = {
    padding: '0.5rem 1rem',
    fontSize: '0.6875rem',
    fontWeight: 600,
    textTransform: 'uppercase',
    letterSpacing: '0.05em',
    whiteSpace: 'nowrap',
    color: T.headerText,
    backgroundColor: T.headerBg,
    borderBottom: `1px solid ${T.border}`
  };
  const CELL = {
    padding: '0.625rem 1rem',
    fontSize: '0.8125rem',
    display: 'flex',
    alignItems: 'center',
    minWidth: 0
  };
  const hasRequired = fields.some(f => f.required === true);
  const hasEnum = fields.some(f => f.enum && f.enum.length > 0);
  const gridTemplateColumns = ['minmax(120px, auto)', 'minmax(70px, auto)', ...hasRequired ? ['minmax(70px, auto)'] : [], ...hasEnum ? ['minmax(120px, auto)'] : [], '1fr'].join(' ');
  return <div style={{
    margin: '1.25rem 0',
    borderRadius: '0.5rem',
    border: `1px solid ${T.border}`,
    overflow: 'hidden',
    fontSize: '0.8125rem'
  }}>
      {title && <div style={{
    padding: '0.5rem 1rem',
    fontSize: '0.75rem',
    fontWeight: 600,
    letterSpacing: '0.02em',
    backgroundColor: T.titleBg,
    borderBottom: `1px solid ${T.border}`,
    color: T.titleText
  }}>
          {title}
        </div>}
      <div style={{
    display: 'grid',
    gridTemplateColumns,
    width: '100%',
    overflowX: 'auto'
  }}>

        <div style={HEADER}>Field</div>
        <div style={HEADER}>Type</div>
        {hasRequired && <div style={HEADER}>Required</div>}
        {hasEnum && <div style={HEADER}>Values</div>}
        <div style={HEADER}>Description</div>

        {fields.map((f, i) => {
    const borderTop = `1px solid ${i === 0 ? T.border : T.borderSubtle}`;
    const typeStyle = TYPE_STYLE[f.type] || TYPE_STYLE.object;
    return [<div key={`${i}-n`} style={{
      ...CELL,
      whiteSpace: 'nowrap',
      borderTop
    }}>
              <span style={{
      padding: '0.125rem 0.375rem',
      borderRadius: '0.25rem',
      fontSize: '0.75rem',
      fontFamily: MONO,
      backgroundColor: T.fieldBg,
      color: T.fieldText
    }}>
                {f.name}
              </span>
            </div>, <div key={`${i}-t`} style={{
      ...CELL,
      whiteSpace: 'nowrap',
      borderTop
    }}>
              <span style={{
      padding: '0.125rem 0.375rem',
      borderRadius: '0.25rem',
      fontSize: '0.75rem',
      whiteSpace: 'nowrap',
      fontFamily: MONO,
      ...typeStyle
    }}>
                {f.type}
              </span>
            </div>, ...hasRequired ? [<div key={`${i}-r`} style={{
      ...CELL,
      borderTop,
      fontWeight: f.required ? 500 : 400,
      color: f.required ? T.reqYes : T.reqNo
    }}>
                {f.required ? 'Yes' : '—'}
              </div>] : [], ...hasEnum ? [<div key={`${i}-e`} style={{
      ...CELL,
      borderTop,
      flexWrap: 'wrap',
      gap: '0.25rem'
    }}>
                {f.enum && f.enum.length > 0 ? f.enum.map((v, j) => <span key={j} style={{
      padding: '0.125rem 0.375rem',
      borderRadius: '0.25rem',
      fontSize: '0.75rem',
      whiteSpace: 'nowrap',
      fontFamily: MONO,
      backgroundColor: T.enumBg,
      color: T.enumText
    }}>
                        {String(v)}
                      </span>) : <span style={{
      color: T.emptyText
    }}>—</span>}
              </div>] : [], <div key={`${i}-d`} style={{
      ...CELL,
      borderTop,
      color: T.descText
    }}>
              {f.description}
            </div>];
  })}

      </div>
    </div>;
};

export const WsChannelOverview = ({operations}) => {
  const hasPush = operations.some(op => op.push);
  const Th = ({children}) => <th className="text-left text-gray-500 dark:text-gray-400 border-b border-gray-200 dark:border-gray-700" style={{
    padding: "0.5rem 1rem",
    fontSize: "0.6875rem",
    fontWeight: 600,
    textTransform: "uppercase",
    letterSpacing: "0.05em",
    whiteSpace: "nowrap"
  }}>
      {children}
    </th>;
  const PushBadge = ({value}) => {
    const dashIdx = value.indexOf(" — ");
    const method = dashIdx !== -1 ? value.slice(0, dashIdx) : value;
    const desc = dashIdx !== -1 ? value.slice(dashIdx + 3) : null;
    return <span style={{
      display: "inline-flex",
      alignItems: "center",
      gap: "0.375rem",
      flexWrap: "wrap"
    }}>
        <code className="bg-blue-50 dark:bg-blue-900/20 text-blue-800 dark:text-blue-400" style={{
      padding: "0.125rem 0.375rem",
      borderRadius: "0.25rem",
      fontSize: "0.75rem",
      whiteSpace: "nowrap"
    }}>
          {method}
        </code>
        {desc && <span className="text-gray-500 dark:text-gray-400" style={{
      fontSize: "0.75rem"
    }}>
            — {desc}
          </span>}
      </span>;
  };
  return <div style={{
    margin: "1.25rem 0",
    borderRadius: "0.5rem",
    border: "1px solid",
    overflow: "hidden",
    fontSize: "0.8125rem"
  }} className="border-gray-200 dark:border-gray-700">
      <table className="w-full" style={{
    margin: 0,
    borderCollapse: "collapse",
    tableLayout: "auto"
  }}>
        <thead>
          <tr className="bg-gray-50 dark:bg-gray-800/60 border-b border-gray-200 dark:border-gray-700">
            {Th({
    children: "Operation"
  })}
            {Th({
    children: <span><span style={{
      color: "#16a34a"
    }}>→</span> You send</span>
  })}
            {Th({
    children: "← Server responds"
  })}
            {hasPush && Th({
    children: <span><span style={{
      color: "#2563eb"
    }}>⟵</span> Server pushes</span>
  })}
          </tr>
        </thead>
        <tbody>
          {operations.map((op, i) => <tr key={i} className="border-b border-gray-100 dark:border-gray-800" style={{
    borderBottom: i === operations.length - 1 ? "none" : undefined
  }}>
              {}
              <td className="text-gray-900 dark:text-gray-100" style={{
    padding: "0.625rem 1rem",
    fontWeight: 500,
    whiteSpace: "nowrap"
  }}>
                {op.name}
              </td>

              {}
              <td style={{
    padding: "0.625rem 1rem",
    whiteSpace: "nowrap"
  }}>
                <code className="bg-green-50 dark:bg-green-900/20 text-green-800 dark:text-green-400" style={{
    padding: "0.125rem 0.375rem",
    borderRadius: "0.25rem",
    fontSize: "0.75rem"
  }}>
                  {op.send}
                </code>
              </td>

              {}
              <td className="text-gray-500 dark:text-gray-400" style={{
    padding: "0.625rem 1rem"
  }}>
                {op.receive}
              </td>

              {}
              {hasPush && <td style={{
    padding: "0.625rem 1rem"
  }}>
                  {op.push ? PushBadge({
    value: op.push
  }) : <span className="text-gray-300 dark:text-gray-600">—</span>}
                </td>}
            </tr>)}
        </tbody>
      </table>
    </div>;
};

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 protocol="wss" />

<Note>
  Coming soon: order placement over WebSocket becomes available on September 2, 2026, on the global platform only. The EU platform is not yet supported.
</Note>

Park an order that turns into a BBO order when the market reaches `activation_price`. The price is resolved from the order book at activation time rather than at placement, which is why `price` stays `"0"` while the order waits.

<WsChannelOverview operations={channelOperations} />

<WsAuthBadge required={channelMeta.authRequired} />

## Rate limits

<WsRateLimits {...channelMeta.rateLimits} />

## Place stop-BBO order

### Request parameters

<WsSchemaTable fields={orderStopBboPlaceParams} />

The `bbo_role` semantics match [`order_bbo_place`](/websocket/order-management/order-bbo-place), with one difference: the role is applied at activation, against the order book as it stands then. Role `1` sets `post_only` on the resulting order.

<WsMessageExample data={exOrderStopBboPlaceRequest} />

### Response

<WsMessageExample data={exOrderStopBboPlaceResponse} />

The `result` object adds the conditional fields to the standard order object and reports `type` `3` with `price` `"0"`. See the [order object reference](/websocket/order-management/overview#order-object).

<Warning>An empty order book at activation drops the order. With no quote on the required side there is nothing to peg to, so the order cannot be priced and is discarded rather than retried. Use [`order_stop_limit_place`](/websocket/order-management/order-stop-limit-place) where a guaranteed price matters more than a book-relative one.</Warning>

## Error codes

<WsErrorCodes errorCodes={channelMeta.errorCodes} />

Standard transport errors and the shared account, rate-limit, and region codes are listed in [Order Management](/websocket/order-management/overview#error-codes).
