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

# Create limit order

> Place a spot limit order to buy or sell at a specified price via the WhiteBIT V4 API.

export const RegionalRestrictionNote = () => <Note>
    Available order types and execution flags depend on your region. A request
    for an order type or flag not available in your region is rejected with HTTP
    status <code>453</code>. See all details in{' '}
    <a href="/concepts/order-types#regional-restrictions">
      Order types — Regional restrictions
    </a>
    .
  </Note>;

export const signerFields = [{
  "name": "market",
  "type": "string",
  "required": true,
  "description": "Trading pair. Format: BASE_QUOTE (e.g., BTC_USDT). Query GET /api/v4/public/markets for available markets.",
  "example": "BTC_USDT"
}, {
  "name": "side",
  "type": "string",
  "required": true,
  "description": "Order side. Allowed values: buy, sell.",
  "example": "buy",
  "enum": ["buy", "sell"]
}, {
  "name": "amount",
  "type": "string",
  "required": true,
  "description": "Order quantity in base (stock) currency. Minimum and maximum values are market-dependent. Query GET /api/v4/public/markets for minAmount, minTotal, maxTotal. Precision: stockPrec.",
  "example": "0.001"
}, {
  "name": "price",
  "type": "string",
  "required": false,
  "description": "Limit price per unit in quote (money) currency. Required unless bboRole is set — the BBO execution method replaces the explicit price. Minimum and maximum values are market-depe…",
  "example": "9800"
}, {
  "name": "clientOrderId",
  "type": "string",
  "required": false,
  "description": "Custom client order identifier. Uniqueness is enforced only among the account's open (pending) orders on the same market — once a previous order is filled or canceled, the same …",
  "example": "order1987111"
}, {
  "name": "postOnly",
  "type": "boolean",
  "required": false,
  "description": "Post-only flag. When true, the order executes only as a maker order and the system rejects the order if it would match immediately. Allowed only when bboRole is not set. Do not …",
  "example": "false",
  "default": false
}, {
  "name": "ioc",
  "type": "boolean",
  "required": false,
  "description": "Immediate-or-cancel (IOC) flag. When true, the matching engine executes all or part of the order immediately and cancels any unfilled portion. Default: false. IOC does not suppo…",
  "example": "false",
  "default": false
}, {
  "name": "bboRole",
  "type": "integer",
  "required": false,
  "description": "Best Bid/Offer (BBO) execution method. The system selects the best market price for execution. 1 = Queue method, 2 = Counterparty method. When bboRole is set, price is not requi…",
  "enum": ["1", "2"]
}, {
  "name": "stp",
  "type": "string",
  "required": false,
  "description": "Self-trade prevention mode. Allowed values: no (self-trades allowed), cb (cancel both the new and the existing order), cn (cancel the new order, keep the existing), co (cancel t…",
  "example": "no",
  "enum": ["no", "cb", "cn", "co"],
  "default": "no"
}, {
  "name": "rpi",
  "type": "boolean",
  "required": false,
  "description": "Enables Retail Price Improvement (RPI) mode. Default: false. RPI orders apply post-only behavior automatically — do not also send an explicit postOnly=true: a request combining …",
  "example": "true",
  "default": false
}, {
  "name": "retail",
  "type": "boolean",
  "required": false,
  "description": "Retail-source taker flag. When true, the order is eligible to match against orders submitted by RPI makers and may receive price improvement at execution. Default: false. The Re…",
  "example": "false",
  "default": false
}];

export const WhitebitSigner = ({path: defaultPath = "/api/v4/order/market", defaultParams = "{}", fields = null}) => {
  const {useState, useMemo} = React;
  const [baseUrl, setBaseUrl] = useState("https://whitebit.com");
  const getApiHost = () => baseUrl;
  const hex = buf => Array.from(new Uint8Array(buf)).map(b => b.toString(16).padStart(2, "0")).join("");
  const b64 = s => {
    const bytes = new TextEncoder().encode(s);
    let bin = "";
    bytes.forEach(b => bin += String.fromCharCode(b));
    return btoa(bin);
  };
  const hmacSha512Hex = async (secret, msg) => {
    const key = await crypto.subtle.importKey("raw", new TextEncoder().encode(secret), {
      name: "HMAC",
      hash: "SHA-512"
    }, false, ["sign"]);
    const sig = await crypto.subtle.sign("HMAC", key, new TextEncoder().encode(msg));
    return hex(sig);
  };
  const queryFields = fields ? fields.filter(function (f) {
    return f.paramIn === "query" || f.paramIn === "path";
  }) : [];
  const bodyFields = fields ? fields.filter(function (f) {
    return !f.paramIn || f.paramIn === "body";
  }) : [];
  const [open, setOpen] = useState(false);
  const [authOpen, setAuthOpen] = useState(true);
  const [paramsOpen, setParamsOpen] = useState(true);
  const [apiKey, setApiKey] = useState("");
  const [apiSecret, setApiSecret] = useState("");
  const [showSecret, setShowSecret] = useState(false);
  const [path, setPath] = useState(defaultPath);
  const initFieldValues = fieldDefs => {
    if (!fieldDefs) return {};
    const vals = {};
    for (const f of fieldDefs) {
      vals[f.name] = f.default !== undefined ? String(f.default) : "";
    }
    return vals;
  };
  const [fieldValues, setFieldValues] = useState(function () {
    return initFieldValues(fields);
  });
  const [showRaw, setShowRaw] = useState(false);
  const [params, setParams] = useState(defaultParams === "{}" ? "" : defaultParams);
  const [computed, setComputed] = useState(null);
  const [response, setResponse] = useState(null);
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState("");
  const [urlCopied, setUrlCopied] = useState(false);
  const useFieldsMode = fields !== null && fields !== undefined && !showRaw;
  const setFieldValue = (name, value) => setFieldValues(function (prev) {
    return {
      ...prev,
      [name]: value
    };
  });
  const toggleRaw = () => {
    if (fields === null || fields === undefined) return;
    if (!showRaw) {
      const obj = {};
      for (const f of bodyFields) {
        const val = fieldValues[f.name];
        if (val !== "" && val !== null && val !== undefined) {
          obj[f.name] = f.type === "integer" || f.type === "number" ? Number(val) : val;
        }
      }
      setParams(Object.keys(obj).length ? JSON.stringify(obj, null, 2) : "");
      setShowRaw(true);
    } else {
      try {
        const parsed = JSON.parse(params.trim() || "{}");
        const next = {
          ...fieldValues
        };
        for (const f of bodyFields) {
          if (parsed[f.name] !== undefined) next[f.name] = String(parsed[f.name]);
        }
        setFieldValues(next);
      } catch (e) {}
      setShowRaw(false);
    }
  };
  const compute = async () => {
    setError("");
    setComputed(null);
    setResponse(null);
    try {
      if (!apiKey.trim()) throw new Error("API key is required");
      if (!apiSecret.trim()) throw new Error("API secret is required");
      let extraBodyParams = {};
      let queryString = "";
      if (useFieldsMode) {
        const qParams = {};
        for (const f of fields) {
          const val = fieldValues[f.name];
          const empty = val === "" || val === null || val === undefined;
          if (empty) {
            if (f.required) throw new Error('"' + f.name + '" is required');
            continue;
          }
          if (f.paramIn === "query" || f.paramIn === "path") {
            qParams[f.name] = String(val);
          } else {
            if (f.type === "integer" || f.type === "number") {
              const num = Number(val);
              if (isNaN(num)) throw new Error('"' + f.name + '" must be a number');
              extraBodyParams[f.name] = num;
            } else {
              extraBodyParams[f.name] = val;
            }
          }
        }
        if (Object.keys(qParams).length > 0) {
          queryString = "?" + Object.entries(qParams).map(function (kv) {
            return encodeURIComponent(kv[0]) + "=" + encodeURIComponent(kv[1]);
          }).join("&");
        }
      } else if (params.trim()) {
        try {
          extraBodyParams = JSON.parse(params.trim());
        } catch (e) {
          throw new Error("Body params is not valid JSON");
        }
      }
      const bodyObj = {
        request: path,
        nonce: Date.now(),
        nonceWindow: true
      };
      for (const k in extraBodyParams) bodyObj[k] = extraBodyParams[k];
      const bodyStr = JSON.stringify(bodyObj);
      const payload = b64(bodyStr);
      const signature = await hmacSha512Hex(apiSecret.trim(), payload);
      const result = {
        payload,
        signature,
        bodyStr,
        queryString
      };
      setComputed(result);
      return result;
    } catch (e) {
      setError(e && e.message ? e.message : String(e));
      return null;
    }
  };
  const send = async () => {
    setBusy(true);
    setResponse(null);
    try {
      const out = await compute();
      if (!out) return;
      const res = await fetch("/_mintlify/api/request", {
        method: "POST",
        headers: {
          "Content-Type": "application/json"
        },
        body: JSON.stringify({
          method: "post",
          url: getApiHost() + path + out.queryString,
          header: {
            "content-type": "application/json",
            "X-TXC-APIKEY": apiKey.trim(),
            "X-TXC-PAYLOAD": out.payload,
            "X-TXC-SIGNATURE": out.signature
          },
          body: JSON.parse(out.bodyStr),
          cookie: {},
          query: {}
        })
      });
      const text = await res.text();
      let status = res.status;
      let pretty = text;
      try {
        const json = JSON.parse(text);
        if (json.statusCode !== undefined) {
          status = json.statusCode;
          const raw = typeof json.body === "string" ? json.body : JSON.stringify(json.body);
          try {
            pretty = JSON.stringify(JSON.parse(raw), null, 2);
          } catch (e2) {
            pretty = raw;
          }
        } else {
          pretty = JSON.stringify(json, null, 2);
        }
      } catch (e2) {}
      setResponse({
        status,
        body: pretty
      });
    } catch (e) {
      setError(e && e.message ? e.message : String(e));
    } finally {
      setBusy(false);
    }
  };
  const copy = text => {
    if (navigator && navigator.clipboard) navigator.clipboard.writeText(text);
  };
  const headerRows = useMemo(function () {
    if (!computed) return [];
    return [{
      key: "X-TXC-APIKEY",
      value: apiKey.trim()
    }, {
      key: "X-TXC-PAYLOAD",
      value: computed.payload
    }, {
      key: "X-TXC-SIGNATURE",
      value: computed.signature
    }];
  }, [computed, apiKey]);
  const INPUT_CLS = "w-full rounded-xl border-standard px-3 py-2 text-sm font-mono bg-background-light dark:bg-background-dark outline-none focus:ring-1 focus:ring-[#3064E3]/40 text-gray-900 dark:text-gray-100 placeholder-gray-400 dark:placeholder-white/20";
  const SECTION_CLS = "rounded-2xl border border-zinc-200 dark:border-zinc-800";
  const SECTION_BTN_CLS_OPEN = "flex w-full pt-3.5 pb-3 px-3.5 items-center justify-between cursor-pointer hover:bg-gray-50 dark:hover:bg-white/5 transition-colors rounded-t-2xl";
  const SECTION_BTN_CLS_CLOSED = "flex w-full pt-3.5 pb-3 px-3.5 items-center justify-between cursor-pointer hover:bg-gray-50 dark:hover:bg-white/5 transition-colors rounded-2xl";
  const renderField = function (f) {
    return <div key={f.name}>
        <div className="flex items-center gap-1.5 mb-1 mt-2.5">
          <span className="text-xs font-mono font-medium text-gray-700 dark:text-gray-300">{f.name}</span>
          {f.required ? <span className="text-xs text-red-500 dark:text-red-400">required</span> : <span className="text-xs text-gray-400 dark:text-gray-500">optional</span>}
          <span className="text-xs text-gray-400 dark:text-gray-500 ml-auto">{f.type}{f.enum ? " · enum" : ""}</span>
        </div>
        {f.description && <div className="text-xs text-gray-400 dark:text-gray-500 mb-1">{f.description}</div>}
        {f.enum ? <select className={INPUT_CLS} value={fieldValues[f.name] || ""} onChange={function (e) {
      setFieldValue(f.name, e.target.value);
    }}>
            {!f.required && <option value="">— leave empty —</option>}
            {f.enum.map(function (v) {
      return <option key={v} value={v}>{v}</option>;
    })}
          </select> : <input type={f.type === "integer" || f.type === "number" ? "number" : "text"} className={INPUT_CLS} value={fieldValues[f.name] || ""} onChange={function (e) {
      setFieldValue(f.name, e.target.value);
    }} placeholder={f.example !== undefined ? String(f.example) : f.required ? f.name : "optional"} spellCheck={false} autoComplete="off" />}
      </div>;
  };
  return <div className="not-prose my-6 flex w-full flex-col bg-background-light dark:bg-background-dark border-standard rounded-2xl p-1.5">

      {}
      <div className="flex w-full items-center space-x-1.5 rounded-xl p-1.5 border-standard">

        {}
        <div className="flex items-center gap-1.5 flex-1 min-w-0">
          <span className="rounded-lg font-bold px-1.5 py-0.5 text-xs leading-5 shrink-0 bg-blue-400/20 text-blue-700 dark:text-blue-400">
            POST
          </span>
          <div className="flex items-center flex-1 min-w-0 text-sm font-mono overflow-hidden">
            {}
            <div className="relative shrink-0 flex items-center">
              <select value={baseUrl} onChange={function (e) {
    setBaseUrl(e.target.value);
  }} onClick={function (e) {
    e.stopPropagation();
  }} className="appearance-none bg-transparent outline-none font-mono text-sm text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-200 transition-colors cursor-pointer pr-4">
                <option value="https://whitebit.com">https://whitebit.com</option>
                <option value="https://whitebit.eu">https://whitebit.eu</option>
              </select>
              <svg className="absolute right-0 top-1/2 -translate-y-1/2 pointer-events-none text-gray-400 dark:text-gray-500" width="10" height="10" viewBox="0 0 10 10" fill="none">
                <path d="M2 3.5L5 6.5L8 3.5" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round" strokeLinejoin="round" />
              </svg>
            </div>
            {}
            <button type="button" title="Copy URL" onClick={function () {
    var url = baseUrl + path;
    if (navigator && navigator.clipboard) navigator.clipboard.writeText(url);
    setUrlCopied(true);
    setTimeout(function () {
      setUrlCopied(false);
    }, 1500);
  }} className="truncate text-left text-black dark:text-white transition-colors">
              {path}
            </button>
          </div>
        </div>

        <div className="flex items-center gap-1.5 shrink-0">
          {}
          <button type="button" title="Copy URL" onClick={function () {
    var url = getApiHost() + path;
    if (navigator && navigator.clipboard) navigator.clipboard.writeText(url);
    setUrlCopied(true);
    setTimeout(function () {
      setUrlCopied(false);
    }, 1500);
  }} className="flex items-center justify-center w-6 h-6 rounded-lg hover:bg-gray-200 dark:hover:bg-white/10 text-gray-400 dark:text-gray-500 transition-colors">
            {urlCopied ? <svg width="13" height="13" viewBox="0 0 13 13" fill="none">
                <path d="M2 7L5 10L11 3" stroke="#2AB673" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
              </svg> : <svg width="13" height="13" viewBox="0 0 13 13" fill="none">
                <rect x="4.5" y="1.5" width="7" height="8" rx="1.5" stroke="currentColor" strokeWidth="1.2" />
                <path d="M2 4.5H1.5A1 1 0 0 0 .5 5.5v6A1 1 0 0 0 1.5 12.5h6A1 1 0 0 0 8.5 11.5V11" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round" />
              </svg>}
          </button>

          {}
          <button type="button" onClick={function () {
    setOpen(function (v) {
      return !v;
    });
  }} className="text-sm font-semibold px-3 py-1.5 rounded-lg bg-[#2AB673] text-white hover:bg-[#239660] active:bg-[#1e7d52] transition-colors hidden sm:inline-flex items-center gap-1.5 cursor-pointer">
            {open ? <>
                Close
                <svg width="12" height="12" viewBox="0 0 12 12" fill="none" className="shrink-0">
                  <path d="M2 9L6 5L10 9" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
                </svg>
              </> : <>
                Try it
                <svg width="12" height="12" viewBox="0 0 12 12" fill="none" className="shrink-0">
                  <polygon points="2,1 11,6 2,11" fill="currentColor" />
                </svg>
              </>}
          </button>
        </div>
      </div>

      {}
      {open && <div className="mt-1.5 space-y-1.5">

          {}
          <div className={SECTION_CLS}>
            <button type="button" onClick={function () {
    setAuthOpen(function (v) {
      return !v;
    });
  }} className={authOpen ? SECTION_BTN_CLS_OPEN : SECTION_BTN_CLS_CLOSED}>
              <div className="flex items-center gap-x-1.5">
                <svg width="12" height="12" viewBox="0 0 12 12" fill="none" className="text-gray-400 dark:text-gray-500 transition-transform shrink-0" style={{
    transform: authOpen ? "rotate(90deg)" : "rotate(0deg)"
  }}>
                  <path d="M4 2.5L8 6L4 9.5" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
                </svg>
                <span className="text-sm font-medium text-gray-800 dark:text-gray-200 leading-6">Authentication</span>
              </div>
            </button>
            {authOpen && <div className="px-3.5 pb-3.5 pt-0 border-t border-zinc-100 dark:border-zinc-800/60">
                <div className="flex items-center gap-1.5 mb-1 mt-2.5">
                  <span className="text-xs font-mono font-medium text-gray-700 dark:text-gray-300">X-TXC-APIKEY</span>
                  <span className="text-xs text-red-500 dark:text-red-400">required</span>
                  <span className="text-xs text-gray-400 dark:text-gray-500 ml-auto">string</span>
                </div>
                <input className={INPUT_CLS} value={apiKey} onChange={function (e) {
    setApiKey(e.target.value);
  }} placeholder="your-api-key" autoComplete="off" spellCheck={false} />

                <div className="flex items-center gap-1.5 mb-1 mt-2.5">
                  <span className="text-xs font-mono font-medium text-gray-700 dark:text-gray-300">API secret</span>
                  <span className="text-xs text-red-500 dark:text-red-400">required</span>
                  <span className="text-xs text-gray-400 dark:text-gray-500 ml-auto">string</span>
                </div>
                <div className="flex gap-1.5">
                  <input type={showSecret ? "text" : "password"} className={INPUT_CLS + " flex-1"} value={apiSecret} onChange={function (e) {
    setApiSecret(e.target.value);
  }} placeholder="your-api-secret" autoComplete="off" spellCheck={false} />
                  <button type="button" onClick={function () {
    setShowSecret(function (v) {
      return !v;
    });
  }} className="text-xs px-2.5 rounded-xl border-standard bg-background-light dark:bg-background-dark hover:bg-gray-50 dark:hover:bg-white/5 text-gray-500 dark:text-gray-400 shrink-0 transition-colors">
                    {showSecret ? "hide" : "show"}
                  </button>
                </div>
                <p className="text-xs text-gray-400 dark:text-gray-500 mt-1.5">
                  Credentials stay in memory only — never written to localStorage or cookies.
                </p>
              </div>}
          </div>

          {}
          <div className={SECTION_CLS}>
            <button type="button" onClick={function () {
    setParamsOpen(function (v) {
      return !v;
    });
  }} className={paramsOpen ? SECTION_BTN_CLS_OPEN : SECTION_BTN_CLS_CLOSED}>
              <div className="flex items-center gap-x-1.5">
                <svg width="12" height="12" viewBox="0 0 12 12" fill="none" className="text-gray-400 dark:text-gray-500 transition-transform shrink-0" style={{
    transform: paramsOpen ? "rotate(90deg)" : "rotate(0deg)"
  }}>
                  <path d="M4 2.5L8 6L4 9.5" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
                </svg>
                <span className="text-sm font-medium text-gray-800 dark:text-gray-200 leading-6">Body</span>
              </div>
              {fields !== null && fields !== undefined && bodyFields.length > 0 && <button type="button" onClick={function (e) {
    e.stopPropagation();
    toggleRaw();
  }} className="text-xs text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 underline mr-1">
                  {showRaw ? "form fields" : "edit as JSON"}
                </button>}
            </button>
            {paramsOpen && <div className="px-3.5 pb-3.5 pt-0 border-t border-zinc-100 dark:border-zinc-800/60">
                {queryFields.length > 0 && <div className="mb-1">
                    <p className="text-xs font-medium text-gray-500 dark:text-gray-400 mb-1 mt-2.5">Query parameters</p>
                    {queryFields.map(renderField)}
                  </div>}

                {useFieldsMode ? bodyFields.length > 0 ? <div>
                      {bodyFields.map(renderField)}
                      <p className="text-xs text-gray-400 dark:text-gray-500 mt-2">
                        <code className="font-mono">request</code>, <code className="font-mono">nonce</code>, <code className="font-mono">nonceWindow</code> added automatically.
                      </p>
                    </div> : <p className="text-xs text-gray-400 dark:text-gray-500 mt-2.5">
                      No body parameters required.{" "}
                      <code className="font-mono">request</code>, <code className="font-mono">nonce</code>, <code className="font-mono">nonceWindow</code> added automatically.
                    </p> : <div>
                    <p className="text-xs text-gray-400 dark:text-gray-500 mt-2.5 mb-1.5">
                      <code className="font-mono">request</code>, <code className="font-mono">nonce</code>, <code className="font-mono">nonceWindow</code> added automatically.
                    </p>
                    <textarea className={INPUT_CLS + " min-h-[80px] resize-y"} rows={4} value={params} onChange={function (e) {
    setParams(e.target.value);
  }} placeholder="{ &quot;market&quot;: &quot;BTC_USDT&quot; }" spellCheck={false} />
                  </div>}
              </div>}
          </div>

          {}
          <div className="flex flex-wrap items-center gap-1.5 px-0.5">
            <button type="button" onClick={send} disabled={busy} className="flex items-center justify-center px-3 h-9 text-sm font-medium rounded-xl hover:opacity-80 gap-1.5 transition-opacity disabled:opacity-50 disabled:pointer-events-none bg-[#3064E3] text-white">
              {busy ? <svg className="animate-spin w-4 h-4" viewBox="0 0 24 24" fill="none">
                  <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
                  <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8v8z" />
                </svg> : "Send request"}
            </button>
            <button type="button" onClick={compute} disabled={busy} className="flex items-center justify-center px-3 h-9 text-sm font-medium rounded-xl border-standard hover:bg-gray-50 dark:hover:bg-white/5 transition-colors disabled:opacity-50 disabled:pointer-events-none text-gray-700 dark:text-gray-300 bg-background-light dark:bg-background-dark">
              Compute headers
            </button>
          </div>

          {}
          {error && <div className="px-3.5 py-2.5 rounded-2xl border border-red-200 dark:border-red-900/40 bg-red-50 dark:bg-red-950/20 text-sm text-red-600 dark:text-red-400 break-words">
              {error}
            </div>}

          {}
          {computed && <div className={SECTION_CLS + " overflow-hidden"}>
              <div className="flex items-center justify-between pt-3 pb-2.5 px-3.5 border-b border-zinc-100 dark:border-zinc-800/60">
                <span className="text-sm font-medium text-gray-800 dark:text-gray-200">Computed headers</span>
              </div>
              <div className="px-3.5 pb-3.5">
                {headerRows.map(function (row) {
    return <div key={row.key} className="mt-2.5">
                      <div className="flex items-center justify-between mb-1">
                        <span className="text-xs font-mono text-gray-500 dark:text-gray-400">{row.key}</span>
                        <button type="button" onClick={function () {
      copy(row.value);
    }} className="text-xs px-2 py-0.5 rounded-lg border-standard hover:bg-gray-50 dark:hover:bg-white/5 text-gray-500 dark:text-gray-400 transition-colors">
                          copy
                        </button>
                      </div>
                      <input readOnly value={row.value} className="w-full rounded-xl border-standard px-3 py-2 text-xs font-mono bg-gray-50 dark:bg-white/[0.03] text-gray-500 dark:text-gray-400 outline-none select-all cursor-default" />
                    </div>;
  })}
                <details className="mt-2.5">
                  <summary className="text-xs text-gray-400 dark:text-gray-500 cursor-pointer select-none hover:text-gray-600 dark:hover:text-gray-300 transition-colors">
                    full request body
                  </summary>
                  <pre className="text-xs font-mono whitespace-pre-wrap break-all mt-2 text-gray-600 dark:text-gray-400 m-0">
                    {(function () {
    try {
      return JSON.stringify(JSON.parse(computed.bodyStr), null, 2);
    } catch (e) {
      return computed.bodyStr;
    }
  })()}
                  </pre>
                </details>
                {computed.queryString && <p className="text-xs text-gray-400 dark:text-gray-500 font-mono mt-1">
                    query: {computed.queryString}
                  </p>}
              </div>
            </div>}

          {}
          {response && <div className={SECTION_CLS + " overflow-hidden"}>
              <div className="flex items-center gap-2 pt-3 pb-2.5 px-3.5 border-b border-zinc-100 dark:border-zinc-800/60">
                <span className="text-sm font-medium text-gray-800 dark:text-gray-200">Response</span>
                <span className={"text-xs font-mono font-medium px-1.5 py-0.5 rounded-lg " + (response.status < 400 ? "bg-[#2AB673]/10 text-[#2AB673]" : "bg-red-100/50 dark:bg-red-400/10 text-red-600 dark:text-red-300")}>
                  {response.status}
                </span>
              </div>
              <pre className="text-xs font-mono whitespace-pre-wrap overflow-auto max-h-80 m-0 px-3.5 py-3 text-gray-700 dark:text-gray-300">
                {response.body}
              </pre>
            </div>}

        </div>}

    </div>;
};

export const RelatedResources = ({children}) => {
  const {useEffect, useRef, useState} = React;
  const ref = useRef(null);
  const [visible, setVisible] = useState(false);
  useEffect(() => {
    if (!ref.current) return;
    const el = ref.current;
    if (el.parentElement) {
      el.parentElement.appendChild(el);
    }
    setVisible(true);
  }, []);
  return <div ref={ref} className="related-resources" style={{
    marginTop: "2.5rem",
    paddingTop: "1.5rem",
    borderTop: "1px solid var(--border-color, #e5e7eb)",
    opacity: visible ? 1 : 0,
    transition: "opacity 0.15s ease-in"
  }}>
      <h2 style={{
    marginTop: 0
  }}>Related resources</h2>
      {children}
    </div>;
};

<WhitebitSigner path="/api/v4/order/new" fields={signerFields} />

<RegionalRestrictionNote />

<RelatedResources>
  * [Query unexecuted orders](/api-reference/trading/query-unexecuted-orders) — list open orders
  * [Cancel order](/api-reference/trading/cancel-order) — cancel an open order
  * [Modify order](/api-reference/trading/modify-order) — modify an existing order
  * [Bulk limit order](/api-reference/trading/bulk-limit-order) — place multiple limit orders
</RelatedResources>

## Used in these guides

* [Copy Trading](/guides/copy-trading) — mirror a lead trader's orders into followers' own accounts via OAuth-issued keys.


## OpenAPI

````yaml openapi/private/http-trade-v4.yaml POST /api/v4/order/new
openapi: 3.0.3
info:
  title: Private HTTP API V4 - Collateral Trading
  description: |
    WhiteBIT Private HTTP API V4 for collateral/margin trading operations.

    Base URL: https://whitebit.com

    All endpoints return time in Unix-time format.
    All endpoints return either a JSON object or array.
    For receiving responses from API calls please use http method POST.

    Authentication required for all endpoints.
  version: 4.0.0
  license:
    name: WhiteBIT Terms of Service
    url: https://whitebit.com/terms
servers:
  - url: https://whitebit.com
    description: WhiteBIT Global Server
  - url: https://whitebit.eu
    description: WhiteBIT EU Server
security:
  - ApiKeyAuth: []
    PayloadAuth: []
    SignatureAuth: []
tags:
  - name: Collateral Trading
    description: Endpoints for collateral/margin trading operations
  - name: Spot Trading
    description: Endpoints for spot trading operations
  - name: Market Fee
    description: Endpoints for querying trading fees
paths:
  /api/v4/order/new:
    post:
      tags:
        - Spot Trading
      summary: Create Limit Order
      description: >
        The endpoint creates a [limit trading order](/glossary#limit-order). The
        order remains on the order book until filled, cancelled, or expired.
        Minimum and maximum values for `amount` and `price` are market-dependent
        — query `GET /api/v4/public/markets` for per-market constraints.


        **Order validation rules** (per-market, from `GET
        /api/v4/public/markets`):

        - `amount` must have at most `stockPrec` decimal places

        - `price` must have at most `moneyPrec` decimal places

        - `amount` must be ≥ `minAmount`

        - `amount × price` must be ≥ `minTotal`

        - `amount × price` must be ≤ `maxTotal` (when `maxTotal` is not `"0"`)


        <Warning>

        Rate limit: 10000 requests/10 sec.

        </Warning>


        <Note>
          - RPI orders do not appear in public order book feeds (`depth`, `bookTicker`). RPI orders are visible only in private active orders and in the exchange UI order book (web/mobile).
          - RPI orders are post-only by design and cannot be used with the IOC flag. The API returns error code `40` when both `rpi=true` and `ioc=true` are used.
          - RPI orders apply post-only behavior automatically — do not also send `postOnly=true`: a request combining `rpi=true` with an explicit `postOnly=true` fails validation.
          - `retail=true` marks the order as a retail-source taker eligible to match RPI-maker liquidity. The Retail flag must be enabled on the account; contact the account manager to enable it.
          - `retail=true` and `rpi=true` cannot be combined. The API returns error code `41` when both flags are set.
          - `retail=true` has no effect on a `postOnly=true` order. Post-only orders are makers and cannot be retail takers.
        </Note>


        <Accordion title="Error Codes">
          - `30` - default validation error code
          - `31` - market validation failed
          - `32` - amount validation failed
          - `33` - price validation failed
          - `36` - clientOrderId validation failed
          - `37` - `ioc=true` cannot be combined with `postOnly=true`
          - `40` - `ioc=true` cannot be combined with `rpi=true`
          - `41` - `retail=true` cannot be combined with `rpi=true`
          - `42` - `retail=true` is not allowed for the account
          - `43` - `rpi=true` is not allowed for the account
        </Accordion>


        <Accordion title="Errors">

        ```json

        {
          "code": 30,
          "message": "Validation failed",
          "errors": {
            "amount": ["Amount field is required."],
            "market": ["Market field is required."],
            "price": ["Price field is required."],
            "side": ["Side field is required."]
          }
        }

        ```


        ```json

        {
          "code": 30,
          "message": "Validation failed",
          "errors": {
            "side": ["Side field should contain only 'buy' or 'sell' values."]
          }
        }

        ```


        ```json

        {
          "code": 32,
          "message": "Validation failed",
          "errors": {
            "amount": ["Amount field should be numeric string or number."]
          }
        }

        ```


        ```json

        {
          "code": 33,
          "message": "Validation failed",
          "errors": {
            "price": ["Price field should be numeric string or number."]
          }
        }

        ```


        ```json

        {
          "code": 31,
          "message": "Validation failed",
          "errors": {
            "market": ["Market is not available."]
          }
        }

        ```


        ```json

        {
          "code": 31,
          "message": "Validation failed",
          "errors": {
            "market": ["Market field should not be empty string."]
          }
        }

        ```


        ```json

        {
          "code": 32,
          "message": "Validation failed",
          "errors": {
            "amount": [
              "Given amount is less than min amount 0.001",
              "Min amount step = 0.000001"
            ]
          }
        }

        ```


        ```json

        {
          "code": 36,
          "message": "Validation failed",
          "errors": {
            "clientOrderId": ["ClientOrderId field should be a string."]
          }
        }

        ```


        ```json

        {
          "code": 36,
          "message": "Validation failed",
          "errors": {
            "clientOrderId": [
              "ClientOrderId field should contain only latin letters, numbers and dashes."
            ]
          }
        }

        ```


        ```json

        {
          "code": 36,
          "message": "Validation failed",
          "errors": {
            "clientOrderId": [
              "This client order id is already used by the current account."
            ]
          }
        }

        ```


        ```json

        {
          "code": 37,
          "message": "Validation failed",
          "errors": {
            "ioc": ["Either IOC or PostOnly flag in true state is allowed."]
          }
        }

        ```


        ```json

        {
          "code": 30,
          "message": "Validation failed",
          "errors": {
            "total": ["Total (amount * price) is less than 5.05"]
          }
        }

        ```


        ```json

        {
          "code": 32,
          "message": "Validation failed",
          "errors": {
            "amount": [
              "Min amount step = 0.01"
            ]
          }
        }

        ```


        ```json

        {
          "code": 33,
          "message": "Validation failed",
          "errors": {
            "price": ["Price field should be at least 10", "Min price step = 0.000001"]
          }
        }

        ```


        ```json

        {
          "code": 33,
          "message": "Validation failed",
          "errors": {
            "price": ["Price should be greater than 0."]
          }
        }

        ```


        ```json

        {
          "code": 35,
          "message": "Validation failed",
          "errors": {
            "maker_fee": ["Incorrect maker fee"]
          }
        }

        ```


        ```json

        {
          "code": 41,
          "message": "Validation failed",
          "errors": {
            "retail": ["api.tradeErrors.flagsCantBeCombined.rpiRetail"]
          }
        }

        ```


        ```json

        {
          "code": 42,
          "message": "Validation failed",
          "errors": {
            "retail": ["api.validation.retail.not_allowed"]
          }
        }

        ```

        </Accordion>
      operationId: createLimitOrder
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/LimitOrderRequest'
      responses:
        '200':
          description: Order created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrderResponse'
        '400':
          description: Inner validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Request validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '503':
          description: Service temporarily unavailable
      security:
        - ApiKeyAuth: []
          PayloadAuth: []
          SignatureAuth: []
components:
  schemas:
    LimitOrderRequest:
      type: object
      required:
        - market
        - side
        - amount
        - request
        - nonce
      properties:
        market:
          type: string
          description: >-
            Trading pair. Format: `BASE_QUOTE` (e.g., `BTC_USDT`). Query `GET
            /api/v4/public/markets` for available markets.
          example: BTC_USDT
        side:
          type: string
          enum:
            - buy
            - sell
          description: 'Order side. Allowed values: `buy`, `sell`.'
          example: buy
        amount:
          type: string
          description: >-
            Order quantity in base (stock) currency. Minimum and maximum values
            are market-dependent. Query `GET /api/v4/public/markets` for
            `minAmount`, `minTotal`, `maxTotal`. Precision: `stockPrec`.
          example: '0.001'
        price:
          type: string
          description: >-
            Limit price per unit in quote (money) currency. Required unless
            `bboRole` is set — the BBO execution method replaces the explicit
            price. Minimum and maximum values are market-dependent. Precision:
            `moneyPrec`.
          example: '9800'
        clientOrderId:
          type: string
          description: >-
            Custom client order identifier. Uniqueness is enforced only among
            the account's open (pending) orders on the same market — once a
            previous order is filled or canceled, the same identifier can be
            reused, including on the same market. Contains only letters,
            numbers, dashes, dots, or underscores.
          example: order1987111
        postOnly:
          type: boolean
          default: false
          description: >-
            Post-only flag. When `true`, the order executes only as a
            [maker](/glossary#maker) order and the system rejects the order if
            it would match immediately. Allowed only when `bboRole` is not set.
            Do not combine with `rpi=true` — RPI orders apply post-only behavior
            automatically, and a request setting both flags fails validation.
            Default: `false`.
          example: false
        ioc:
          type: boolean
          default: false
          description: >
            Immediate-or-cancel (IOC) flag. When `true`, the matching engine
            executes all or part of the order immediately and cancels any
            unfilled portion. Default: `false`.


            IOC does not support `rpi=true` because RPI uses post-only behavior
            by design.

            The API returns error code `40` when a request sets both `ioc=true`
            and `rpi=true`.

            IOC cannot be combined with `postOnly=true` (error code `37`), and
            with `bboRole` it is allowed only for the Counterparty method (`2`).


            Refer to [Order Parameter Rules](/guides/order-parameter-rules) for
            unsupported parameter combinations.
          example: false
        bboRole:
          type: integer
          enum:
            - 1
            - 2
          description: >
            Best Bid/Offer ([BBO](/glossary#best-bid-offer-bbo)) execution
            method. The system selects the best market price for execution. `1`
            = Queue method, `2` = Counterparty method.


            When `bboRole` is set, `price` is not required — the BBO method
            determines the execution price. `postOnly` is allowed only when
            `bboRole` is not set; `ioc` can be combined only with the
            Counterparty method (`2`). Use method `2` with the `ioc` flag.


            Refer to [Order Parameter Rules](/guides/order-parameter-rules) for
            the full interaction rules.
        stp:
          type: string
          enum:
            - 'no'
            - cb
            - cn
            - co
          default: 'no'
          description: >
            Self-trade prevention mode. Allowed values: `no` (self-trades
            allowed), `cb` (cancel both the new and the existing order), `cn`
            (cancel the new order, keep the existing), `co` (cancel the existing
            order, place the new one). Default: `no`.


            Legacy values `cancel_both`, `cancel_new`, `cancel_old` are
            deprecated: the API accepts the legacy values with identical
            behavior until a deprecation deadline is announced, then rejects the
            legacy values. Responses always return the abbreviated form,
            regardless of which variant the request used.


            See [Self-Trade Prevention](/platform/self-trade-prevention).
          example: 'no'
        rpi:
          type: boolean
          default: false
          description: >
            Enables Retail Price Improvement (RPI) mode. Default: `false`.


            RPI orders apply post-only behavior automatically — do not also send
            an explicit `postOnly=true`: a request combining the two flags fails
            validation. An RPI order does not support `ioc=true`.

            The API returns error code `40` when a request sets both `rpi=true`
            and `ioc=true`.

            RPI orders do not appear in public order book feeds (`depth`,
            `bookTicker`). RPI orders are visible only in private active orders
            and in the exchange UI order book (web/mobile).

            RPI executions may apply custom fees or rebates, especially when
            trading via sub-accounts. Use Query Market Fees to verify effective
            fees.


            Refer to [Order Parameter Rules](/guides/order-parameter-rules) for
            unsupported parameter combinations.
          example: true
        retail:
          type: boolean
          default: false
          description: >
            Retail-source taker flag. When `true`, the order is eligible to
            match against orders submitted by RPI makers and may receive price
            improvement at execution. Default: `false`.


            The Retail flag must be enabled on the account before a private-API
            request can set `retail=true`. Contact the account manager to enable
            the Retail flag.


            The Retail flag cannot be combined with `rpi`. The API returns error
            code `41` when a request sets both `retail=true` and `rpi=true`.


            The flag has no effect on a `postOnly=true` order. Post-only orders
            are [makers](/glossary#maker); only takers carry the retail
            designation.


            Refer to [Retail flag](/glossary#retail-flag) and [Order Parameter
            Rules](/guides/order-parameter-rules) for unsupported parameter
            combinations.
          example: false
        request:
          type: string
          example: '{{request}}'
        nonce:
          type: integer
          example: 1594297865000
    OrderResponse:
      type: object
      description: >-
        Shared order shape returned by the order-creation, cancel, active-orders
        list, and modify endpoints. Field presence varies by endpoint and order
        type — see the per-field notes.
      properties:
        orderId:
          type: integer
          description: Unique identifier assigned to the order by the matching engine.
          example: 4180284841
        clientOrderId:
          type: string
          description: >-
            Custom client order identifier supplied in the request. Returns an
            empty string when not specified.
          example: order1987111
        market:
          type: string
          description: 'Trading pair for the order. Format: `BASE_QUOTE` (e.g., `BTC_USDT`).'
          example: BTC_USDT
        side:
          type: string
          description: 'Order side. Possible values: `buy`, `sell`.'
          example: buy
        type:
          type: string
          description: >-
            Order type. Possible values: `limit`, `market`, `stock market`,
            `stop limit`, `stop market`.
          example: limit
        timestamp:
          type: number
          description: >-
            Unix timestamp in seconds (UTC) of order creation, with microsecond
            precision.
          example: 1595792396.165973
        dealMoney:
          type: string
          description: >-
            Filled amount in quote currency. Returns `"0"` while the order
            remains unfilled.
          example: '0'
        dealStock:
          type: string
          description: >-
            Filled amount in base currency. Returns `"0"` while the order
            remains unfilled.
          example: '0'
        amount:
          type: string
          description: >-
            Order quantity in base currency for limit and stop-limit orders, or
            in quote currency for buy market orders.
          example: '0.01'
        left:
          type: string
          description: >-
            Remaining unfilled quantity. Equals `amount` for new orders and
            `"0"` for fully filled orders.
          example: '0.001'
        dealFee:
          type: string
          description: >-
            Cumulative trading fee charged for filled portions, denominated in
            the fee asset.
          example: '0'
        feeAsset:
          type: string
          description: >-
            Currency ticker of the asset used to pay the trading fee. Omitted
            when empty.
          example: USDT
        price:
          type: string
          description: >-
            Limit price per unit in quote currency. Present for orders that
            carry a price (limit and stop-limit shapes); omitted on market and
            stop-market order shapes.
          example: '40000'
        postOnly:
          type: boolean
          description: >-
            Post-only flag. When `true`, the order executes only as a maker
            order and is rejected if it would match immediately. Omitted when
            not set.
          example: false
        ioc:
          type: boolean
          description: >-
            Immediate-or-cancel flag. When `true`, the order executes available
            quantity immediately and cancels the unfilled remainder. Default:
            `false`.
          example: false
        status:
          $ref: '#/components/schemas/OrderStatus'
        stp:
          type: string
          description: >-
            Self-trade prevention mode applied to the order. Possible values:
            `no`, `cb`, `cn`, `co`. The response always returns the abbreviated
            form, even when the request used a legacy value. Default: `no`.
          example: 'no'
        positionSide:
          type: string
          description: >-
            Position side (for collateral orders). Returned on the cancel,
            active-orders list, and modify responses; omitted when not set. Spot
            order-creation responses do not include the field.
          example: LONG
        oto:
          type: object
          description: >-
            OTO order data. Present only when the order belongs to an
            [OTO](/glossary#one-triggers-the-other-oto) group — returned on the
            cancel, active-orders list, and modify responses.
          properties:
            otoId:
              type: integer
              description: OTO order identifier
              example: 29457221
            takeProfit:
              type: string
              description: Take profit order price
              example: '50000'
            stopLoss:
              type: string
              description: Stop loss order price
              example: '30000'
        rpi:
          type: boolean
          description: Indicates Retail Price Improvement (RPI) mode for the order.
          example: true
        retail:
          type: boolean
          description: >-
            Retail-source taker flag. The field is present only when the order
            was placed with `retail=true`. See [Retail
            flag](/glossary#retail-flag).
          example: true
        reduceOnly:
          type: boolean
          description: >-
            Reduce-only flag. When `true`, the order can only reduce or close an
            existing position. Returned on the cancel, active-orders list, and
            modify responses; spot order-creation responses do not include the
            field. See [reduce-only](/glossary#reduce-only).
          example: false
        activated:
          type: integer
          description: >-
            Activation status of the stop order. 0 = not yet triggered (waiting
            for the activation_price condition to be met). 1 = triggered (the
            stop condition has been met and the order is now active). Returned
            for stop orders; omitted on other order shapes.
          example: 0
        activationCondition:
          type: string
          enum:
            - lte
            - gte
          description: >
            Trigger condition for the stop order. Response-only — not accepted
            in the request body, and cannot be overridden. Derived from `side`:


            - `side = buy` → `gte`. The order activates when the market price
            rises to or above `activation_price`.

            - `side = sell` → `lte`. The order activates when the market price
            falls to or below `activation_price`.
          example: lte
        activation_price:
          type: string
          description: >-
            The trigger price for the stop order. Always equals the
            activation_price value submitted in the request. Returned for stop
            orders; omitted on other order shapes.
          example: '40000'
    ErrorResponse:
      type: object
      properties:
        code:
          type: integer
          description: Error code
          example: 30
        message:
          type: string
          description: Error message
          example: Validation failed
        errors:
          type: object
          additionalProperties:
            type: array
            items:
              type: string
          description: Detailed error information
    OrderStatus:
      type: string
      description: >-
        Order lifecycle status. `FILLED` — fully executed. `CANCELED` — canceled
        before execution. `PARTIALLY_FILLED` — partially executed, remainder
        still active. `CANCELED_TAKER_BAND` — partially filled up to the taker
        band limit, remainder canceled to protect against excessive order book
        slippage. `AUTO_CANCELED_REDUCE_ONLY` — pending reduce-only order
        auto-canceled because the associated position was closed.
        `AUTO_CANCELED_LIQUIDATION` — pending order auto-canceled because the
        associated position was force-liquidated. `CANCELED_STP` — order
        canceled by [Self-Trade Prevention](/platform/self-trade-prevention).
        REST returns the single-`L` spelling throughout; `NEW` and
        `PARTIAL_FILLED` are not REST values (`NEW` is WebSocket-only; the
        partially-filled state is `PARTIALLY_FILLED`).
      example: FILLED
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-TXC-APIKEY
      description: The public WhiteBIT API key.
    PayloadAuth:
      type: apiKey
      in: header
      name: X-TXC-PAYLOAD
      description: Base64-encoded JSON request body.
    SignatureAuth:
      type: apiKey
      in: header
      name: X-TXC-SIGNATURE
      description: >-
        HMAC-SHA512 signature of the payload, hex-encoded. Computed as
        hex(HMAC-SHA512(payload, api_secret)).

````