Seqlense docs

Order Book

Import your own exchange order flow (orders and their lifecycle events) so it can be browsed, tied to identities and scanned for order-book market abuse.

GET
/v1/orderbook/books

The books (venue + instrument pairs) the workspace holds, most active first, up to 200. Same item shape as instruments in the summary.

Authorization

ApiKeyAuth
AuthorizationBearer <token>

Send your API key as a bearer token: Authorization: Bearer sq_YOUR_API_KEY.

In: header

Response Body

application/json

application/json

curl -X GET "https://example.com/v1/orderbook/books"
{  "books": [    {      "venue": "WHITEBIT",      "instrument": "BTC/USDC",      "events": 820,      "orders": 410,      "clients": 31,      "cancels": 96,      "last_event": "2026-04-20T09:44:17+00:00"    }  ]}
GET
/v1/orderbook/clients

The distinct client ids found in your events, busiest (most events) first, each with its linked identity (or null) and its tags. The roster is read from the events: there is no separate client list to maintain.

linked and total describe this page only, not the whole workspace (use GET /v1/orderbook/summary for workspace coverage).

status=matched|unmatched cannot be applied when the workspace has more than 20,000 links. The list is then returned unfiltered with filter_applied: false.

Authorization

ApiKeyAuth
AuthorizationBearer <token>

Send your API key as a bearer token: Authorization: Bearer sq_YOUR_API_KEY.

In: header

Query Parameters

q?string

Case-insensitive substring of the client id. Ignored when longer than 190 characters.

Lengthlength <= 190
status?string

matched keeps linked clients, unmatched keeps the ones still to link, anything else means all.

Default"all"

Value in

  • "all"
  • "matched"
  • "unmatched"
limit?integer

Page size. Clamped to 1..500. Defaults to 100.

Range1 <= value <= 500
Default100

Response Body

application/json

application/json

curl -X GET "https://example.com/v1/orderbook/clients"
{  "clients": [    {      "client_id": "POSTG0000114",      "events": 212,      "orders": 106,      "venues": 1,      "instruments": 3,      "first_event": "2026-03-20T08:00:00+00:00",      "last_event": "2026-04-20T09:44:17+00:00",      "identity": {        "id": "8a1d2c3b-4e5f-4a6b-9c7d-0e1f2a3b4c5d",        "type": "PERSON",        "display_name": "Jane Doe",        "country": "FR"      },      "tags": [        {          "id": "1c2d3e4f-5a6b-4c7d-8e9f-a0b1c2d3e4f5",          "name": "VIP",          "color": "#f59e0b"        }      ]    },    {      "client_id": "POSTG0000127",      "events": 40,      "orders": 20,      "venues": 1,      "instruments": 1,      "first_event": "2026-03-21T08:00:00+00:00",      "last_event": "2026-03-21T09:00:00+00:00",      "identity": null,      "tags": []    }  ],  "linked": 1,  "total": 2,  "status": "all",  "filter_applied": true}
GET
/v1/orderbook/events

One page of the workspace's events, newest first (ts_event descending, ties broken by order_id then event_id), with the total count behind the filters. Every filter is optional and they are combined with AND.

Amounts are returned as strings so no precision is lost. identities maps each client id on the page that is linked to an identity; unlinked client ids are absent from it.

A filter value that fails its format check (for example a venue with spaces, or an unknown event_type) is ignored rather than rejected.

Authorization

ApiKeyAuth
AuthorizationBearer <token>

Send your API key as a bearer token: Authorization: Bearer sq_YOUR_API_KEY.

In: header

Query Parameters

venue?string

Venue, case-insensitive. Letters, digits and / _ - ., up to 60 characters.

instrument?string

Instrument as BASE/QUOTE, case-insensitive.

client_id?string

Exact client id (up to 190 characters).

order_id?string

Exact order id (up to 190 characters).

event_type?string

Event type, case-insensitive.

Value in

  • "NEW"
  • "REPLACE"
  • "PARTIAL_FILL"
  • "FILL"
  • "CANCEL"
  • "EXPIRE"
  • "REJECT"
side?string

Side, case-insensitive.

Value in

  • "BUY"
  • "SELL"
from?string

Inclusive lower bound on ts_event. RFC 3339, or YYYY-MM-DD HH:MM:SS read as UTC.

to?string

Exclusive upper bound on ts_event, same formats. Must be after from.

limit?integer

Page size. Clamped to 1..200. Defaults to 50.

Range1 <= value <= 200
Default50
offset?integer

Rows to skip. Capped at 100000. Defaults to 0.

Range0 <= value <= 100000
Default0
include_raw?string

1 or true adds raw, the row exactly as it was posted, to each event.

Value in

  • "1"
  • "true"

Response Body

application/json

application/json

application/json

curl -X GET "https://example.com/v1/orderbook/events"
{  "events": [    {      "event_id": "3f5a0c9b7e1d2f4a6c8e0b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a1c3e5b7d9f1a",      "ts_event": "2026-04-20T09:44:17+00:00",      "organization": "acme",      "venue": "WHITEBIT",      "instrument": "BTC/USDC",      "base": "BTC",      "quote": "USDC",      "client_id": "POSTG0000114",      "account_id": "",      "order_id": "1776678242178",      "event_type": "FILL",      "order_type": "LIMIT",      "side": "SELL",      "status": "FILLED",      "price": "75235.92",      "quantity": "0.0001",      "filled_qty": "0.0001",      "notional": "7.523592",      "notional_usd": null,      "fee": null,      "fee_currency": "",      "cancel_origin": "",      "time_in_force": "",      "order_origin": "",      "liquidity_flag": "",      "best_bid": null,      "best_ask": null    }  ],  "identities": {    "POSTG0000114": {      "id": "8a1d2c3b-4e5f-4a6b-9c7d-0e1f2a3b4c5d",      "type": "PERSON",      "display_name": "Jane Doe"    }  },  "total": 1,  "limit": 50,  "offset": 0}
POST
/v1/orderbook/import/batch

Validates and stores one batch of up to 1000 rows into a RUNNING import. The whole request must stay under 2 MB; a larger body arrives empty and is answered with a 400 telling you to send fewer rows.

Rows that fail validation are skipped and reported in errors; the others are written. A partial batch is a normal outcome and still returns 200. Only the first 50 rejection messages of a run are kept on the import record; each batch response carries all of its own.

record_shape must match the shape the import was opened with, and the parsing options (timezone, decimal_separator) must be sent on every batch, since the server does not remember them between requests. Set first_row to the file line of the batch's first row so error messages point at the original file.

Re-sending a batch (after a timeout, for example) is safe: event ids are derived from the event content, so duplicates collapse in storage.

Authorization

ApiKeyAuth
AuthorizationBearer <token>

Send your API key as a bearer token: Authorization: Bearer sq_YOUR_API_KEY.

In: header

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Rows plus the parsing options that apply to all of them.

Response Body

application/json

application/json

application/json

curl -X POST "https://example.com/v1/orderbook/import/batch" \  -H "Content-Type: application/json" \  -d '{    "import_id": "0b8f7a52-6a0e-4a8f-9d5e-3c1f0e2b7a41",    "record_shape": "ORDER_SNAPSHOT",    "timezone": "UTC",    "decimal_separator": ".",    "first_row": 2,    "rows": [      {        "client_id": "POSTG0000113",        "order_id": "1767011739000",        "venue": "BYBIT",        "base": "ETH",        "quote": "USDC",        "side": "SELL",        "order_type": "LIMIT",        "price": "3000",        "quantity": "0.003",        "status": "CANCELED",        "cancel_origin": "EXCHANGE",        "ts_submitted": "2025-12-29 12:35:39",        "ts_finished": "2025-12-29 12:51:00"      }    ]  }'
{  "import_id": "0b8f7a52-6a0e-4a8f-9d5e-3c1f0e2b7a41",  "rows_seen": 1,  "rows_accepted": 1,  "rows_rejected": 0,  "events_written": 2,  "errors": []}
POST
/v1/orderbook/import/finish

Closes a RUNNING import as DONE (default) or FAILED, and returns the import record. events_written is then replaced by the number of distinct events the table actually holds for this import, which is lower than the running tally when rows were re-sent or duplicated.

Finishing an import that is no longer RUNNING changes nothing and returns its current record.

Authorization

ApiKeyAuth
AuthorizationBearer <token>

Send your API key as a bearer token: Authorization: Bearer sq_YOUR_API_KEY.

In: header

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

application/json

application/json

curl -X POST "https://example.com/v1/orderbook/import/finish" \  -H "Content-Type: application/json" \  -d '{    "import_id": "0b8f7a52-6a0e-4a8f-9d5e-3c1f0e2b7a41"  }'
{  "id": "0b8f7a52-6a0e-4a8f-9d5e-3c1f0e2b7a41",  "venue": "WHITEBIT",  "filename": "whitebit-2026-04.csv",  "record_shape": "ORDER_SNAPSHOT",  "status": "DONE",  "rows_received": 127,  "rows_accepted": 126,  "rows_rejected": 1,  "events_written": 252,  "errors": [    "row 88: ts_finished: required because status is FILLED (a terminal state)"  ],  "created_at": "2026-04-21 10:02:11",  "finished_at": "2026-04-21 10:02:19",  "rolled_back_at": "",  "events_removed": 0}
POST
/v1/orderbook/import/start

Opens an import run and returns its import_id. Every batch refers to that id, and the run's record_shape is fixed here: batches declaring another shape are refused.

All fields are optional, but the body must be a JSON object (send {} for the defaults). venue is stored uppercased and is only a label on the run; each row still carries its own venue. profile_id, when given, must be a mapping profile of your workspace and is recorded as the provenance of the mapping.

Authorization

ApiKeyAuth
AuthorizationBearer <token>

Send your API key as a bearer token: Authorization: Bearer sq_YOUR_API_KEY.

In: header

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

application/json

curl -X POST "https://example.com/v1/orderbook/import/start" \  -H "Content-Type: application/json" \  -d '{    "record_shape": "ORDER_SNAPSHOT",    "filename": "whitebit-2026-04.csv",    "venue": "WHITEBIT"  }'
{  "import_id": "0b8f7a52-6a0e-4a8f-9d5e-3c1f0e2b7a41",  "record_shape": "ORDER_SNAPSHOT"}
GET
/v1/orderbook/imports

Lists the workspace's import runs, newest first, including rolled-back ones. A run still RUNNING long after its created_at is an upload that was never finished.

Authorization

ApiKeyAuth
AuthorizationBearer <token>

Send your API key as a bearer token: Authorization: Bearer sq_YOUR_API_KEY.

In: header

Query Parameters

limit?integer

Maximum number of imports. Clamped to 1..200. Defaults to 25.

Range1 <= value <= 200
Default25

Response Body

application/json

application/json

curl -X GET "https://example.com/v1/orderbook/imports"
{  "imports": [    {      "id": "0b8f7a52-6a0e-4a8f-9d5e-3c1f0e2b7a41",      "venue": "WHITEBIT",      "filename": "whitebit-2026-04.csv",      "record_shape": "ORDER_SNAPSHOT",      "status": "ROLLED_BACK",      "rows_received": 127,      "rows_accepted": 127,      "rows_rejected": 0,      "events_written": 254,      "errors": [],      "created_at": "2026-04-21 10:02:11",      "finished_at": "2026-04-21 10:02:19",      "rolled_back_at": "2026-04-21 11:30:00",      "events_removed": 254    }  ]}
POST
/v1/orderbook/imports/rollback

Deletes the events written by one import and marks it ROLLED_BACK. The import record is kept (with rolled_back_at and events_removed) as an audit trail. Works on RUNNING imports too, which is how an abandoned upload is undone. Links between client ids and identities are not touched.

Events carry no import in their id: if the same file was imported twice, the stored copy of an event belongs to the later import. Rolling back the earlier one may then remove nothing, and rolling back the later one removes events both imports carried. Re-import the file if that was not intended.

Authorization

ApiKeyAuth
AuthorizationBearer <token>

Send your API key as a bearer token: Authorization: Bearer sq_YOUR_API_KEY.

In: header

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

application/json

application/json

curl -X POST "https://example.com/v1/orderbook/imports/rollback" \  -H "Content-Type: application/json" \  -d '{    "import_id": "0b8f7a52-6a0e-4a8f-9d5e-3c1f0e2b7a41"  }'
{  "rolled_back": true,  "import_id": "0b8f7a52-6a0e-4a8f-9d5e-3c1f0e2b7a41",  "events_removed": 254}
POST
/v1/orderbook/link-identity

Points one of your client ids at an identity, replacing any previous link for that client id (linking a client already held by another identity moves it). Several client ids may point at the same identity, which is how one person trading under several ids becomes visible.

The identity must be visible to your workspace (403 otherwise) and the client id must appear in your stored events (400 otherwise). The change is written to the identity's activity log.

Authorization

ApiKeyAuth
AuthorizationBearer <token>

Send your API key as a bearer token: Authorization: Bearer sq_YOUR_API_KEY.

In: header

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

application/json

application/json

curl -X POST "https://example.com/v1/orderbook/link-identity" \  -H "Content-Type: application/json" \  -d '{    "client_id": "POSTG0000114",    "identity_id": "8a1d2c3b-4e5f-4a6b-9c7d-0e1f2a3b4c5d"  }'
{  "linked": true,  "client_id": "POSTG0000114",  "identity_id": "8a1d2c3b-4e5f-4a6b-9c7d-0e1f2a3b4c5d"}
DELETE
/v1/orderbook/link-identity

Removes the link of one client id. Succeeds even when the client id was not linked.

Authorization

ApiKeyAuth
AuthorizationBearer <token>

Send your API key as a bearer token: Authorization: Bearer sq_YOUR_API_KEY.

In: header

Query Parameters

client_id*string

Client id to unlink (URL-encoded).

Lengthlength <= 190

Response Body

application/json

application/json

application/json

curl -X DELETE "https://example.com/v1/orderbook/link-identity?client_id=string"
{  "unlinked": true,  "client_id": "POSTG0000114"}
GET
/v1/orderbook/profiles

Lists the workspace's saved mapping profiles, most recently updated first. A profile stores how a feed's columns map to canonical fields so the next import of the same feed does not need to be mapped again.

Authorization

ApiKeyAuth
AuthorizationBearer <token>

Send your API key as a bearer token: Authorization: Bearer sq_YOUR_API_KEY.

In: header

Response Body

application/json

application/json

curl -X GET "https://example.com/v1/orderbook/profiles"
{  "profiles": [    {      "id": "5d7c1a3e-2f4b-4c6d-8e9f-0a1b2c3d4e5f",      "name": "Whitebit export",      "venue": "WHITEBIT",      "profile": {        "record_shape": "ORDER_SNAPSHOT",        "timezone": "Europe/Paris",        "decimal_separator": ",",        "columns": {          "ord_id": "order_id",          "ord_amount": "quantity"        }      },      "created_at": "2026-04-20 16:10:00",      "updated_at": "2026-04-21 09:58:43"    }  ]}
POST
/v1/orderbook/profiles

Creates a profile, or overwrites the one with the same name in your workspace (its venue and profile are replaced and its id kept). Returns the id of the stored profile.

profile is a free-form JSON object that your client replays; the server never applies it. Only two keys are checked when present: record_shape must be a valid shape and timezone a valid IANA zone. The serialized profile is limited to 64 KB.

Authorization

ApiKeyAuth
AuthorizationBearer <token>

Send your API key as a bearer token: Authorization: Bearer sq_YOUR_API_KEY.

In: header

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

application/json

curl -X POST "https://example.com/v1/orderbook/profiles" \  -H "Content-Type: application/json" \  -d '{    "name": "Whitebit export",    "venue": "whitebit",    "profile": {      "record_shape": "ORDER_SNAPSHOT",      "timezone": "Europe/Paris",      "decimal_separator": ",",      "columns": {        "ord_id": "order_id",        "ord_amount": "quantity"      }    }  }'
{  "id": "5d7c1a3e-2f4b-4c6d-8e9f-0a1b2c3d4e5f",  "name": "Whitebit export"}
DELETE
/v1/orderbook/profiles

Deletes one mapping profile of your workspace. Imports that recorded it keep their history. Answers {"deleted": true} even when no profile with this id exists.

Authorization

ApiKeyAuth
AuthorizationBearer <token>

Send your API key as a bearer token: Authorization: Bearer sq_YOUR_API_KEY.

In: header

Query Parameters

id*string

Profile id.

Formatuuid

Response Body

application/json

application/json

application/json

curl -X DELETE "https://example.com/v1/orderbook/profiles?id=497f6eca-6276-4993-bfeb-53cbbbba6f08"
{  "deleted": true}
POST
/v1/orderbook/purge

Deletes every order-book event of the workspace and its whole import history. Mapping profiles and client-identity links are kept. This cannot be undone; to undo a single file use POST /v1/orderbook/imports/rollback instead.

To confirm, confirm must equal your workspace's exact tenancy key: the organization name shown by GET /v1/hello (Hello, member of <key>!). In the development workspace that key ends in __dev, so a dev key can only purge dev data.

Admin only: a member, or a key created by a member, gets 403.

Authorization

ApiKeyAuth
AuthorizationBearer <token>

Send your API key as a bearer token: Authorization: Bearer sq_YOUR_API_KEY.

In: header

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

application/json

application/json

curl -X POST "https://example.com/v1/orderbook/purge" \  -H "Content-Type: application/json" \  -d '{    "confirm": "acme"  }'
{  "purged": true,  "events_removed": 12400,  "imports_removed": 7}
GET
/v1/orderbook/schema

Returns the canonical fields a row may carry for one record shape, with their type, whether they are required, allowed enum values, header aliases (lowercase names commonly used for the column in exchange exports) and enum synonyms (common spellings mapped to the canonical value).

Fields that only apply to the other shape are left out: ts_submitted appears only for ORDER_SNAPSHOT, ts_event and event_type only for ORDER_EVENT.

Synonyms are a hint for building your column mapping. The server does not apply them: a row must already carry the canonical value (FILLED, not COMPLETED).

Authorization

ApiKeyAuth
AuthorizationBearer <token>

Send your API key as a bearer token: Authorization: Bearer sq_YOUR_API_KEY.

In: header

Query Parameters

shape?string

Record shape to describe. Case-insensitive. Defaults to ORDER_SNAPSHOT.

Default"ORDER_SNAPSHOT"

Value in

  • "ORDER_SNAPSHOT"
  • "ORDER_EVENT"

Response Body

application/json

application/json

application/json

curl -X GET "https://example.com/v1/orderbook/schema"
{  "shape": "ORDER_SNAPSHOT",  "shapes": [    "ORDER_SNAPSHOT",    "ORDER_EVENT"  ],  "max_rows_per_batch": 1000,  "max_rows_per_validate": 500,  "fields": [    {      "name": "side",      "label": "Side",      "type": "enum",      "required": true,      "values": [        "BUY",        "SELL"      ],      "aliases": [        "side",        "direction",        "way",        "buy_sell"      ],      "unlocks": "",      "synonyms": {        "B": "BUY",        "S": "SELL",        "BID": "BUY",        "ASK": "SELL"      }    }  ]}
GET
/v1/orderbook/summary

Totals for the stored order book, the 50 most active books (venue + instrument), and how many clients are linked to an identity.

coverage.matched counts linked clients that still have events; coverage.stale counts links whose client has no event left (typically after a rollback). When the workspace has more than 20,000 links the intersection is not computed: exact is false, matched is 0, and stale and pct are null.

Authorization

ApiKeyAuth
AuthorizationBearer <token>

Send your API key as a bearer token: Authorization: Bearer sq_YOUR_API_KEY.

In: header

Response Body

application/json

application/json

curl -X GET "https://example.com/v1/orderbook/summary"
{  "totals": {    "events": 12400,    "orders": 6150,    "clients": 214,    "instruments": 9,    "venues": 2,    "first_event": "2025-12-29T12:35:39+00:00",    "last_event": "2026-04-20T09:44:17+00:00"  },  "instruments": [    {      "venue": "BYBIT",      "instrument": "ETH/USDC",      "events": 5100,      "orders": 2540,      "clients": 88,      "cancels": 1210,      "last_event": "2026-04-20T09:40:02+00:00"    }  ],  "coverage": {    "exact": true,    "clients": 214,    "matched": 40,    "mapped": 42,    "stale": 2,    "pct": 19  }}
POST
/v1/orderbook/validate

Parses and validates up to 500 rows exactly as an import would, and reports what would be stored. Nothing is written. Use it on a sample of the file before opening an import: it is what catches a wrong timezone or a mis-mapped column before thousands of rows are stored.

Each rejected row produces one message in errors, prefixed with its line number (row N: ..., counted from first_row). profile is built from the rows that parsed, so it shows the distribution that would actually be stored.

A snapshot row expands into one NEW event plus, when its status is terminal, the event that ended it, which is why events_would_write can exceed rows_accepted.

Authorization

ApiKeyAuth
AuthorizationBearer <token>

Send your API key as a bearer token: Authorization: Bearer sq_YOUR_API_KEY.

In: header

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Rows plus the parsing options that apply to all of them.

Response Body

application/json

application/json

application/json

curl -X POST "https://example.com/v1/orderbook/validate" \  -H "Content-Type: application/json" \  -d '{    "record_shape": "ORDER_SNAPSHOT",    "timezone": "Europe/Paris",    "decimal_separator": ".",    "first_row": 2,    "rows": [      {        "client_id": "POSTG0000114",        "order_id": "1776678242178",        "venue": "WHITEBIT",        "base": "BTC",        "quote": "USDC",        "side": "SELL",        "order_type": "LIMIT",        "price": "75235.92",        "quantity": "0.0001",        "status": "FILLED",        "ts_submitted": "2026-04-20 09:44:02",        "ts_finished": "2026-04-20 09:44:17"      }    ]  }'
{  "rows_seen": 2,  "rows_accepted": 1,  "rows_rejected": 1,  "events_would_write": 2,  "errors": [    "row 3: status: 'COMPLETED' is not one of NEW, OPEN, PARTIALLY_FILLED, FILLED, CANCELED, EXPIRED, REJECTED - map it to one of those in the import profile"  ],  "profile": {    "events": 2,    "venues": [      {        "value": "WHITEBIT",        "count": 2      }    ],    "instruments": [      {        "value": "BTC/USDC",        "count": 2      }    ],    "statuses": [      {        "value": "FILLED",        "count": 1      },      {        "value": "NEW",        "count": 1      }    ],    "clients": [      {        "value": "POSTG0000114",        "count": 2      }    ],    "first_event": "2026-04-20T07:44:02+00:00",    "last_event": "2026-04-20T07:44:17+00:00"  }}