For the complete documentation index, see llms.txt. This page is also available as Markdown.

/v3/limit - Place and manage limit orders

Offer your users price-contingent swaps that execute asynchronously when the market reaches their target.

The SwapKit Limit Order API lets integrators offer their users price-contingent swaps: the order rests until the market reaches the target price, then settles asynchronously. All endpoints sit under /v3/limit/*, every request must carry an x-api-key header, and all payloads are JSON.

Integrators do not choose the provider. SwapKit routes the pair server-side and returns the chosen provider on the quote. The wallet-signing shape differs per provider, and the service surfaces that difference on the /v3/limit/build response.


Signing models

Every provider fits one of two signing models. /v3/limit/build tells you which one applies to a given order by populating exactly one set of fields:

Model
Build response
What the wallet does

Signed intent

typedData populated, tx and txMeta null

Signs an off-chain payload. Nothing goes on-chain at build time — the provider holds the signed order until a filler matches it.

Deposit

tx and txMeta populated, typedData null

Signs and broadcasts a transaction. The deposit is the order: its parameters are encoded into the transaction, and the resulting tx hash is the receipt.

Branch on the artifact, not the provider. Check typedData !== null instead of switching on provider — every provider maps onto one of these two models, including ones not yet live.

Providers

Provider
Signing model
Coverage
Chains
Status

1inch

Signed intent

Same-chain EVM swaps

ETH, ARB, AVAX, BASE, BSC

Available — more EVM chains rolling out

Harbor

Deposit

Cross-chain between BTC, ETH and USDT

BTC, ETH (+ USDT)

Available — BTC ↔ ETH.ETH and BTC ↔ ETH.USDT pairs

THORChain

Confirmed at launch

Native cross-chain across 11 chains

BTC, ETH, LTC, ATOM, DOGE, AVAX, BSC, SOL, BASE, TRX, XRP

Coming soon — broadens BTC, LTC, Cosmos, Doge, TRX, XRP

Jupiter

Confirmed at launch

Solana native assets

SOL

Coming soon — Solana spot liquidity

New providers are added without a breaking change: the endpoints, the order object, and the status lifecycle stay identical, and the only per-provider variation is which signing model the /build response uses.


Endpoint index

Method
Endpoint
Description

GET

/v3/limit/tokens

Supported assets and pairs per provider.

POST

/v3/limit/quote

Price the pair, reserve a routeId. See below.

POST

/v3/limit/build

Persist the order and produce the signing artifact. See below.

POST

/v3/limit/submit

Relay the wallet signature or deposit tx hash. See below.

GET

/v3/limit/orders/:orderId

Single order detail, refreshed from the provider. See below.

GET

/v3/limit/orders

Paginated list scoped to the API key. See below.

POST

/v3/limit/cancel/build

Pre-build a cancel transaction. See below.

POST

/v3/limit/cancel/submit

Record the broadcast cancel tx or signature. See below.


1. Price the pair

Method: POST URL: https://api.swapkit.dev/v3/limit/quote

Returns a market price for the pair, computes the user's limitPrice deviation from spot, and caches a routeId for the subsequent /v3/limit/build call.

Request schema

Parameter
Type
Required
Description

sellAsset

string

Yes

The asset being sold (e.g. "ETH.ETH")

buyAsset

string

Yes

The asset being bought (e.g. "BTC.BTC").

sellAmount

decimal string

No

Provide any two of sellAmount / buyAmount / limitPrice; the third is derived. Human-readable decimal, not base units — selling 10 USDT is "10", not "10000000".

buyAmount

decimal string

No

Derived from the other two if omitted. Same human-readable decimal convention as sellAmount.

limitPrice

decimal string

No

buyAsset per 1 sellAsset, in human-readable decimal.

sourceAddress

string

No

Screened for AML at quote time and pre-filled into the /v3/limit/build hint.

destinationAddress

string

No

Same treatment as sourceAddress.

affiliateFee

int (0–1000 bps)

No

Overrides the API key default.

expiresAt

int (unix seconds)

No

Defaults to now + 3 days.

providers

enum[]

No

Restrict routing to these providers. Omit to consider every provider that supports the pair.

Asset identifiers follow the same nomenclature as the rest of the API — Chain.Asset ("BTC.BTC") or Chain.Asset-ContractAddress ("ETH.USDC-0xA0b8…"). See /tokens.

Response schema

Top level

Field
Type
Description

quoteId

string

UUID for this quote response

routes

LimitRoute[]

A single-entry array.

Per route

Field
Type
Description

routeId

string

UUID of this specific swap response. Pass this to /v3/limit/build.

provider

enum

Provider used, chosen server-side.

sellAmount, buyAmount, limitPrice

decimal string

Resolved values, including the leg you didn't provide.

spotPrice

decimal string

Current market reference price.

effectiveFillPrice

decimal string

The price the market must reach for the order to fill: spotPrice × (1 + feeGapBps / 10_000). The gap is takerFeeBps + integratorFeeBps on 1inch, where the integrator fee is charged on the taker side; on Harbor it's takerFeeBps alone, since the integrator fee is settled out of proceeds and doesn't affect the fill threshold. Equals spotPrice when the gap is zero.

takerFeeBps

number

Protocol-side taker fee in bps a whitelisted filler pays on top of the taking amount. Excludes the integrator fee, which is reported separately as integratorFeeBps.

spotPriceDeviationBps

number

Signed bps delta of limitPrice vs effectiveFillPrice — not vs raw spotPrice. Positive: the limit sits above the fill threshold, so the order waits for the market to move. Negative: it's at or below the threshold and would fill immediately at a worse rate than a market swap.

minExpirationSeconds, maxExpirationSeconds

number

Bounds for the expiresAt you may pass to /v3/limit/build.

integratorFeeBps

number

Affiliate fee applied to this route.

warnings

Warning[]

Structured warning objects — see below.

nextActions

object[]

Data needed for the next request in the flow (/v3/limit/build call).

Compare against effectiveFillPrice, not spotPrice — it's the threshold that triggers a fill, and spotPriceDeviationBps is measured from it.

expiresAt is an absolute unix timestamp, but the bounds are durations: expiresAt − now must fall within [minExpirationSeconds, maxExpirationSeconds]. Outside that, /build returns limitOrderExpirationOutOfBounds (400).

Warnings

Each entry in warnings[] is a structured object — the same shape swap quotes already use — so you can render a short display label with a longer tooltip behind it. tooltip is optional; null-check it. The array is always present and may be empty, and the cached route carries its warnings through to the /v3/limit/build response as well.

At most one price warning fires per quote. Both are measured against effectiveFillPrice, not spotPrice:

  • limitPriceBelowSpotspotPriceDeviationBps ≤ -100. The limit sits 1% or more below the effective fill price, so the order fills immediately at a clearly worse rate than a market swap.

  • limitPriceWithinFeeGap-100 < spotPriceDeviationBps ≤ 0, and the fee gap is non-zero. The limit sits inside the fee gap: it still fills immediately, but only modestly off-market. Raising the limit by |spotPriceDeviationBps| bps or more puts it above the threshold, where it rests as a genuine limit order.

Both mean the order fills on submission rather than resting — surface either to the user before they sign. Render the display string with tooltip behind it rather than switching on code, and treat code as an open enum: new values ship with new providers.

Errors

Status
Error code
Scenario

400

insufficientLiquidity

The provider could not return a market rate for the pair, or the market rate / requested amount evaluated to zero. Surfaced as "Insufficient liquidity for trade".

400

invalidSourceAddress

sourceAddress was provided but doesn't match the sell-chain address format. Per-chain validation fires at /quote rather than waiting for /build.

400

invalidDestinationAddress

destinationAddress was provided but doesn't match the buy-chain address format. Same early-validation behaviour.

400

limitOrderAmountAmbiguous

Not exactly two of sellAmount / buyAmount / limitPrice were supplied.

400

limitOrderUnsupportedPair

No limit-order provider implements this pair at all.

400

limitOrderUnsupportedChain

Limit orders aren't offered on that chain.

400

limitOrderChainMismatch

The pair spans two chains on a path that requires both assets on one.

401

apiKeyInvalid

Missing or unrecognized x-api-key header.

502

limitOrderProviderError

The upstream provider rate-limited, returned a 5xx, or failed in transport while pricing. Deliberately generic. Worth retrying.

503

limitOrderActionUnavailable

A provider supports the pair, but the action is currently disabled for one of its chains. Ops-controlled, so it can clear without a change on your side.


2. Build the signing artifact

Method: POST URL: https://api.swapkit.dev/v3/limit/build

Validates and screens both addresses per-chain, resolves the token spender where the chain needs one, and runs the provider build, deep address screens, and approval check in parallel. Persists the order with status = PENDING.

Request schema

Parameter
Type
Required
Description

routeId

string

Yes

The ID of the route to build the order from. Obtained from a previous /v3/limit/quote response

sourceAddress

string

Yes

Blockchain address to send the asset from. Must be a valid address for the sell asset's chain. Becomes the order's maker.

destinationAddress

string

Yes

Recipient blockchain address to send the asset to. Must be a valid address for the buy asset's chain. Becomes the order's receiver.

expiresAt

int (unix seconds)

Yes

Must fall inside [minExpirationSeconds, maxExpirationSeconds] from /v3/limit/quote.

allowPartialFill

bool

No

1inch only, and must be true (the default). Disabling either flag forces LOP v6 bit-invalidator mode, which the orderbook accepts only for RFQ orders, so /build returns limitOrderUnsupportedFillFlags (400). Harbor ignores both.

allowMultipleFills

bool

No

Same constraint as allowPartialFill

usePermit2

bool

No

Currently ignored server-side — a placeholder for an upcoming Permit2 two-phase build flow on EVM. Until it ships, EVM token orders use the approvalTx path. Default false.

Build response schema

Field
Type
Description

orderId

string

UUID of this specific order. Pass it to /v3/limit/submit and every later call.

orderHash

string

Canonical on-chain identifier of the order, 0x-prefixed.

typedData

object (optional)

Off-chain payload for the wallet to sign. Signed-intent orders onlynull on deposit orders. See below.

tx

varies (optional)

Ready-to-sign deposit transaction. Deposit orders onlynull on signed-intent orders. See below.

txMeta

object (optional)

Broadcast hints for tx. Deposit orders onlynull on signed-intent orders. See below.

isApproved

boolean (optional)

Whether the sell-side token allowance is already in place. Omitted when no approval is part of the flow — See below.

approvalTx

object (optional)

Present when a token approval transaction must be submitted before the order can be signed or broadcast. See below.

warnings

Warning[]

Potential warnings about this order, carried over from /v3/limit/quote. Warnings never block the response.

nextActions

object[]

Data needed for the next request in the flow (/v3/limit/submit call).

Response — the two signing models

You always get exactly one of the two shapes below, never both and never a mix — see signing models.

1inch today.

The wallet signs typedData, then you post the resulting signature to /v3/limit/submit as { orderId, signature }.

Harbor today.

The wallet signs and broadcasts tx, then you post the on-chain hash to /v3/limit/submit as { orderId, depositTxHash }.

Why the two models exist. They reflect two kinds of venue. An off-chain orderbook can hold a signed order until a filler matches it, so a signature is all it needs from the user. A deposit venue has no off-chain book to hold anything — the order doesn't exist until it's on-chain — so the deposit transaction has to carry the order parameters itself. 1inch is the first venue of the former kind, Harbor of the latter.

The typedData object

Returned for signed-intent orders only. A structured payload the wallet signs without broadcasting — today an EIP-712 document with domain, types, primaryType, and message. Pass it to the wallet unmodified and post the resulting signature to /v3/limit/submit; don't reconstruct or reorder it, since the signature is taken over the exact payload.

The tx field

Returned for deposit orders only. Its shape depends on the sell chain, and txMeta tells you how to handle it — the same pattern /v3/swap uses:

Field
Type
Description

txMeta.txType

string

How to sign and broadcast tx. "evm"tx is an object with { from, to, value, data }. "psbt"tx is a base64 PSBT string. More values ship with new chains.

txMeta.chainId

number (optional)

EVM chain the deposit is broadcast on, as a number (1, 42161) — not a string. Present only when txMeta.txType is "evm"; omitted entirely on the psbt path, where the chain is implied by the PSBT. Read the chain from txType rather than expecting this field.

txMeta.memo

string

The order memo encoded into the deposit, exposed so you can verify it before signing. Present for providers that encode order parameters in a memo.

The approvalTx object

Present when the sell asset is a token on a chain that requires an allowance to a spender contract, and the maker's current allowance is below the order amount. Same shape as the approvalTx returned by /v3/swap — broadcast it and wait for confirmation before signing or broadcasting the order.

Field
Type
Description

approvalTx.to

string

Token contract address to send the approval

approvalTx.from

string

User wallet address.

approvalTx.value

string

ETH value — always "0" for approvals.

approvalTx.data

string

Encoded approve() call data.

approvalTx.gasLimit

string

Optional. Estimated max gas units for the approval transaction, as a hex quantity string

approvalTx.gasPrice

string

Optional. Gas price in wei per gas unit, as a hex quantity string. Legacy (type-0) gas pricing.

The isApproved field

isApproved is only populated when a separate token approve() is part of the flow. Treat it as a tri-state:

Value
Meaning

isApproved: true

Nothing extra to broadcast — though not a guarantee that the allowance was verified. See below.

isApproved: false

An approval is required and the wallet must broadcast the accompanying approvalTx before signing the order.

Field omitted

No approval is required — the sell asset is a native asset, or the chain has no allowance model (UTXO chains, for instance).

Whether the field appears is a property of the sell asset and its chain, not of the provider.

How the allowance check is evaluated

isApproved is not a general "is this token approved" flag. It reports whether this order can be pulled, on the same amount-scoped and spender-scoped terms /v3/swap uses — see How the allowance is read for the mechanics and the staleness caveat.

So a token the wallet already shows as approved can still come back false: approving 1 USDT and then building a 2 USDT order returns false, and an allowance granted for an earlier order on a different provider does not carry over, because each provider pulls through its own contract.

The check is advisory as well — if the read fails outright, the build returns isApproved: true rather than failing with it, so true is not proof the allowance exists.

Errors

Status
Error code
Scenario

404

limitOrderQuoteNotFound

The quoteId is unknown or has expired. Re-price with /v3/limit/quote.

404

limitOrderRouteNotFound

The routeId isn't one of the routes that quote returned.

400

limitOrderExpirationOutOfBounds

expiresAt sits outside the quote's expiration bounds. The message carries both.

500

limitOrderBuildFailed

The provider accepted the pair but failed to build the order.


3. Submit the signed artifact

Method: POST URL: https://api.swapkit.dev/v3/limit/submit

Attaches the wallet signature (signed-intent orders) or the on-chain deposit tx hash (deposit orders) to the order, advancing it from PENDING to SUBMITTED. The poller then watches for provider acknowledgement and flips SUBMITTEDOPEN.

Request schema

Send signature or depositTxHash, depending on which artifact /v3/limit/build returned.

Parameter
Type
Required for
Description

orderId

string

All orders

The ID of the order to submit. Obtained from a previous /v3/limit/build response

signature

string

Signed intent

Wallet signature over the typedData returned by /v3/limit/build. Relayed to the provider's orderbook.

depositTxHash

string

Deposit

Hash of the broadcast deposit transaction. Accepted case-insensitively and stored lowercase — it surfaces back as depositHash on /v3/limit/orders/:orderId.

Submit response schema

Field
Type
Description

orderId

string

UUID of this specific order.

orderHash

string

Canonical on-chain identifier of the order, 0x-prefixed.

status

enum

Always SUBMITTED on success. See the order status lifecycle.

createdAt

ISO 8601 string

When the order was created.

Submit errors

The orderbook rejects most bad submissions for a client-side reason. Those are reported as 4xx and are not worth retrying — only a genuine upstream fault is a 502.

Status
Error code
Scenario

451

limitOrderMakerBlacklisted

The orderbook refuses orders from this maker address — a compliance decision made upstream, not by SwapKit's screening. Permanent for the address; the order can never be submitted by retrying.

400

limitOrderInsufficientAllowance

The maker hasn't approved enough of the sell token for the limit-order router. Recoverable: re-run /v3/limit/build and broadcast the returned approvalTx, then submit again.

400

limitOrderMaxOrdersExceeded

The maker already holds the orderbook's maximum of simultaneously valid orders (1inch: 100). Recoverable: cancel an existing order first. The message carries the cap.

409

limitOrderInvalidState

The order is already in the book, or has advanced past PENDING. Same code as the re-submit guard above.

400

limitOrderRejected

Any other client-side rejection SwapKit doesn't model individually — bad signature, expired, insufficient balance. Carries the orderbook's own description.

502

limitOrderSubmissionFailed

A genuine upstream fault: the orderbook returned a 5xx, or the call failed in transport with no status. This one is worth retrying.


4. Single-order detail

Method: GET URL: https://api.swapkit.dev/v3/limit/orders/:orderId

Returns one order. Syncs with the upstream provider on every call before returning, so the response always reflects post-sync state.

Order object

Field
Type
Description

orderId

UUID string

UUID of this specific order. Stable across the order's lifetime.

orderHash

string

Canonical order identifier, 0x-prefixed, stable for the order's whole lifetime. Signed-intent orders: the digest of the signed payload. Deposit orders: a deterministic hash over the order parameters — it is not replaced by the deposit tx hash after /submit; that hash surfaces separately as depositHash.

chainId

string enum

ChainId of the sell asset. Numeric-string for EVM ("1", "42161", "8453", …); slug for non-EVM ("bitcoin", "solana", "thorchain-1", …).

provider

enum

Provider that routed this order.

maker

string

Blockchain address to send the asset from — the address that owns the order on the sell chain. Format varies per chain (EVM hex, BTC bech32, etc.).

receiver

string or null

Recipient blockchain address to send the asset to on the buy chain. Nullable only for legacy orders created without one.

sellAsset

string

The asset being sold (e.g. "ETH.ETH")

buyAsset

string

The asset being bought (e.g. "BTC.BTC").

sellAmount

decimal string

Amount of the sell asset. Human-readable decimal, not smallest units — unlike /v3/quote and /v3/swap.

buyAmount

decimal string

Amount of the buy asset the order is resting for. Same human-readable decimal convention as sellAmount.

limitPrice

decimal string

buyAsset per 1 sellAsset, in human-readable decimal.

filledSellAmount, filledBuyAmount

decimal string

"0" before any fill. On providers that settle all-or-nothing they jump straight to the full amounts; on providers that support partial fills they climb incrementally.

txHashes

TxHash[]

On-chain transactions in the order's lifecycle, chronological. Always present; [] before anything lands. Populated by provider sync or backfill.

usdValueOpen

string or null

Sell-side notional in USD at build time. Approximate (cached price); null if the lookup missed.

usdValueClose

string or null

Realized buy-side notional in USD at the terminal transition. Same approximation; null until the order is terminal.

status

enum

PENDING, SUBMITTED, OPEN, PARTIAL, FILLED, CANCELLED, EXPIRED, FAILED. See the order status lifecycle.

fees

Fee[]

List of fees applied to the order (liquidity, affiliate, service, network) — see below. Pre-fill: projected amounts. Post-fill: actual settled values where the provider reports them.

depositHash

string?

L1 tx hash of the deposit, lowercased. Chain-native format (0x-prefixed on EVM, raw 64-hex on Bitcoin). Populated by the provider sync once the deposit lands; omitted until then, and on models with no deposit leg.

withdrawHash

string?

L1 tx hash of the settlement (withdraw), lowercase 0x-prefixed. Populated after the order fills; omitted before.

expiresAt

ISO 8601 string

TTL. SwapKit flips the order to EXPIRED locally once expiresAt is in the past; providers that escrow funds refund them at this point.

createdAt, updatedAt

ISO 8601 string

Server timestamps. updatedAt moves every time sync writes new state.

Fees breakdown

Fees are categorized into different types based on their role in the order's lifecycle. Not every provider charges every type.

Fee Type
Description

Liquidity

Fee applied by the liquidity provider to facilitate the swap.

Affiliate

Fee paid to the specified affiliate, projected from the API key config.

Service

SwapKit's service fee. Currently 0.

Network

Blockchain transaction fee for processing the order — destination-chain gas / outbound fee.

Each entry in fees[] has the following shape:

Field
Type
Description

type

enum

liquidity, affiliate, service or network.

amount

string

Fee amount in human-readable decimal.

amountBps

number

Fee in basis points (100 bps = 1%).

asset

string

SwapKit asset identifier the fee is denominated in.

chain

string

Chain where the fee is paid or extracted.

protocol

enum

Provider that charges the fee.

Projected vs settled fees. Before a fill, fees[] is a build-time projection priced on the sell chain. Once the order fills, providers that report settlement figures — Harbor today — replace their liquidity and network entries with actual values, and each replaced entry's chain becomes the fee asset's chain ("ETH" for a USDT fee). affiliate and service stay projected. So don't assume an entry's chain holds steady across the order's lifetime, and keep projected and settled entries apart when totalling per chain.

Multi-affiliate encoding. When an API key carries both a SwapKit fee and an integrator fee, providers that support two recipients encode both — Harbor's o: memo lists SwapKit first: …:sk/<integrator>:<skBps>/<integratorBps>. Where the orderbook takes only one recipient (1inch today), the SwapKit slot is fixed at 0.

Errors

Status
Error code
Scenario

404

limitOrderNotFound

Unknown orderId, or the order belongs to a different API key. Ownership is enforced — the response does not leak existence across keys.

401

apiKeyInvalid

Missing or unrecognized x-api-key header.


5. Paginated order list

Method: GET URL: https://api.swapkit.dev/v3/limit/orders

Returns a paginated list of orders owned by the requesting API key, newest first. It does not re-sync with the provider on each call — use /v3/limit/orders/:orderId when freshness matters.

Query parameters

All optional. Unknown query keys are silently ignored. API-key scoping is always applied — you cannot see another partner's orders even by querying a known address.

Parameter
Type
Description

sourceAddress

string

Filter by the blockchain address the asset is sold from (Order.maker). EVM addresses match case-insensitively, so checksummed and lowercase forms return the same orders. Non-EVM addresses (base58, bech32) match exactly, since their casing is significant.

destinationAddress

string

Filter by the recipient blockchain address (Order.receiver). Same casing rules as sourceAddress.

sourceChain

string enum

Filter by the sell-asset chain. Stringified EVM ids ("1", "42161", "8453", …) or a non-EVM slug ("bitcoin", "solana", "thorchain-1").

destinationChain

string enum

Filter by the buy-asset chain. Same value space as sourceChain. Matches only orders whose destination chain was recorded when the order was created. Orders predating that column aren't backfilled, so an older order won't match this filter even when its buy asset is on the chain you asked for.

joinType

enum

How each filter pair combines internally — fullOuter (default) is OR, inner is AND. Applies to the address pair and the chain pair alike, and only matters when both halves of a pair are set.

status

enum or enum[]

Any of PENDING, SUBMITTED, OPEN, PARTIAL, FILLED, CANCELLED, EXPIRED, FAILED — see the order status lifecycle. Accepts a single value (?status=FILLED), a repeated key (?status=PENDING&status=FILLED), or a comma-separated list (?status=PENDING,FILLED).

cursor

ISO 8601 string

Opaque pagination cursor — echo back the nextCursor from the previous page. Don't parse or manufacture values; the server compares strictly (createdAt < cursor).

limit

int (1–100)

Default 50. Values outside the range return 400.

There is no provider filter — filter by sourceChain / destinationChain instead.

List response schema

Field
Type
Description

orders

Order[]

Orders owned by the API key, sorted by createdAt descending. Order schema is explained above.

nextCursor

string (optional)

Pagination cursor for the next page. Present iff the page is full (orders.length === limit); its absence means the last page was reached.

To iterate: start with no cursor, then keep passing nextCursor until the response omits it.

Examples

Errors

Status
Error code
Scenario

400

validation_error

Bad limit (<1 or >100), unparseable cursor, or an invalid value in sourceChain / destinationChain / status / joinType. The body lists the accepted enum values.

401

apiKeyInvalid

Missing or unrecognized x-api-key header.


6. Cancel an order

Method: POST URL: https://api.swapkit.dev/v3/limit/cancel/build

Force-syncs the order with the provider and returns the appropriate signing artifact for cancellation. One request shape; the artifact you get back depends on how the order's venue and sell chain expect a cancellation to be authorised.

Request schema

Parameter
Type
Required
Description

orderId

string

Yes

The ID of the order to cancel. Obtained from /v3/limit/build or a /v3/limit/orders response

Cancel build response schema

Exactly one of the three artifacts is non-null. Branch on which field is populated, not on the provider.

Field
Type
Description

orderId

string

UUID of the order being cancelled.

cancelTx

object (optional)

Ready-to-broadcast cancel transaction, for venues that cancel on-chain. null otherwise. 1inch today.

typedData

object (optional)

Off-chain cancel payload for the wallet to sign, for venues that accept a signed cancellation. null otherwise. Harbor EVM today.

btcSignaturePreimage

string (optional)

Canonical-JSON string to sign as a Bitcoin Signed Message, for Bitcoin-side orders. null otherwise. Harbor BTC today.

nextActions

object[]

Data needed for the next request in the flow (/v3/limit/cancel/submit call).

The wallet broadcasts a cancel transaction to the venue's contract. Any existing token allowance is unaffected — only the specific order is invalidated. On 1inch this is a cancelOrder(makerTraits, orderHash) call on the aggregation router.

The wallet broadcasts it; you then post the resulting txHash to /v3/limit/cancel/submit.

The wallet signs an EIP-712 cancellation message. Nothing goes on-chain from your side. Harbor's EVM payload uses CancelAndWithdraw:

Sign the payload exactly as returned. Note that payload.orderId is the provider's internal order id, not the SwapKit orderId or orderHash — on Harbor it's the clientOrderId (trd-…). nonce and expiry are JSON numbers (uint256 wire-encoded as JS numbers; values stay below Number.MAX_SAFE_INTEGER).

The wallet signs the canonical-JSON string as a Bitcoin Signed Message (BIP-137).

Submit the base64-encoded compact secp256k1 signature.


7. Submit the cancellation

Method: POST URL: https://api.swapkit.dev/v3/limit/cancel/submit

Records the broadcast cancel transaction or the wallet's cancellation signature, depending on which artifact /v3/limit/cancel/build returned.

Request schema

Parameter
Type
Required for
Description

orderId

string

All cancellations

The ID of the order being cancelled. Obtained from a previous /v3/limit/cancel/build response

txHash

string

cancelTx

Hash of the broadcast cancel transaction.

signature

string

typedData, btcSignaturePreimage

Wallet's cancellation signature — 0x-hex for an EIP-712 signature, base64 for a BIP-137 one. The provider verifies the format server-side.

Cancel submit response schema

Field
Type
Description

orderId

string

UUID of the cancelled order.

status

enum

CANCELLED on success. See the order status lifecycle.

txHash

string (optional)

Hash of the broadcast cancel transaction. Returned only for the cancelTx path; omitted for signatures.

Errors

Status
Error code
Scenario

409

limitOrderInvalidState

The order is in a state that doesn't allow cancellation: a terminal state, the provider hasn't acknowledged it yet, the payload is past its expiry, or it's already cancelled. The body carries a descriptive message.

400

limitOrderCancelFailed

The provider rejected the cancellation.

404

limitOrderNotFound

Unknown orderId, or it belongs to a different API key.


Order status lifecycle

PENDINGSUBMITTEDOPENPARTIALFILLED / CANCELLED / EXPIRED / FAILED

Everything past SUBMITTED is driven by a poller that reconciles SUBMITTED / OPEN / PARTIAL orders against the provider every 30 minutes, publishing each transition to the webhook deliverer. GET /v3/limit/orders/:orderId force-syncs on every call — use it when you need state fresher than the poller interval.

Status
Description

PENDING

The order has been built but /v3/limit/submit hasn't been called yet. No signature or deposit hash on file.

SUBMITTED

/v3/limit/submit has attached the wallet signature or the deposit tx hash, but the provider hasn't acknowledged the order as resting yet (still in the mempool, or not yet indexed).

OPEN

Emitted by the poller once the provider confirms the order is resting. Not monotonic — if a provider temporarily has no record of an order, sync can regress it OPENSUBMITTED until visibility returns.

PARTIAL

The order has been partly filled. Only emitted by providers that support partial fills; all-or-nothing paths go straight to FILLED.

FILLED, CANCELLED, EXPIRED, FAILED

Terminal.


Webhooks

Configure apiKey.settings.LIMIT_ORDER_WEBHOOK_URL (under ApiKeySettingsSchema, alongside NOTIFICATION and VAULT_SWAPS; apiKey.config is reserved strictly for fee configuration). The webhook deliverer POSTs every status transition over HTTP, for orders on any provider.

Verify authenticity via the x-swapkit-signature header, which carries an HMAC-SHA256 of the raw body keyed to the webhook secret.

Headers

Header
Description

x-swapkit-signature

Hex HMAC-SHA256 of the raw body, keyed to the webhook secret.

content-type

Always application/json.

x-swapkit-event-id

Matches eventId in the body. Dedupe on it.

x-swapkit-delivery-attempt

1-based delivery attempt number for this event.

Body schema

Field
Type
Description

type

string

Always "limitOrder.statusChanged".

eventId

string

Unique id for this delivery event. Use it to dedupe redeliveries.

orderId

string

UUID of this specific order.

orderHash

string

Canonical on-chain identifier of the order, 0x-prefixed.

apiKeyId

number

Numeric id of the API key that owns the order.

provider

string

Provider that routed the order.

chainId

string

ChainId of the sell asset.

maker

string

Sell-side address that owns the order.

sellAsset, buyAsset

string

SwapKit asset identifiers.

sellAmount, buyAmount

decimal string

Order amounts, human-readable decimal.

limitPrice

decimal string

buyAsset per 1 sellAsset

previousStatus

enum

The status the order transitioned from.

status

enum

The new status. See the order status lifecycle.

previousFilledSellAmount, previousFilledBuyAmount

decimal string

Filled amounts before this transition.

filledSellAmount, filledBuyAmount

decimal string

Filled amounts after this transition.

integratorFeeBps

number or null

Integrator fee encoded on the order.

createdAt

ISO 8601 string

When the transition was recorded.


Integrator checklist

  1. Obtain an API key configured for limit orders. The affiliate fee and integrator recipient live on the key's config — see Monetization.

  2. Call /v3/limit/quote. Pass the pair plus any two of sellAmount / buyAmount / limitPrice. Optionally pre-send sourceAddress / destinationAddress for early screening.

  3. Inspect the route. spotPriceDeviationBps shows the user how far their limit is from spot; minExpirationSeconds / maxExpirationSeconds bound the expiresAt you can pass to /v3/limit/build.

  4. Call /v3/limit/build with routeId, sourceAddress, destinationAddress, and expiresAt.

  5. Handle the token approval. Check isApproved and broadcast the accompanying approvalTx first if it's false.

  6. Sign per the signing model. If typedData is non-null, the wallet signs it and you post { orderId, signature } to /v3/limit/submit. If tx is non-null, the wallet signs and broadcasts it — using txMeta.txType to pick the right codec — and you post { orderId, depositTxHash }.

  7. Track state. Poll GET /v3/limit/orders/:orderId (which also refreshes from the provider) or paginate via GET /v3/limit/orders. Treat OPEN as non-monotonic.

  8. Cancel when needed. POST /v3/limit/cancel/build → the wallet signs or broadcasts whichever artifact came back → POST /v3/limit/cancel/submit.

  9. Optional: webhooks. Configure apiKey.settings.LIMIT_ORDER_WEBHOOK_URL to receive PENDINGSUBMITTEDOPENPARTIALFILLED / CANCELLED / EXPIRED transitions over HTTP.

Staying forward-compatible. Switch on txMeta.txType rather than on the chain, so an unrecognised value fails loudly instead of being signed with the wrong codec — and treat it, provider, warnings[].code and fees[].type as open enums with an explicit fallback. Read minExpirationSeconds / maxExpirationSeconds and fees[] off each quote rather than hard-coding today's values.

Last updated