Skip to main content

Migrate to the /v1/cefi paths

CeFi REST v1.0.6 removes the legacy /api/v1/ path prefix. Every operation is now served only under /v1/cefi/.

This release is a path move only. Response bodies, status codes, error formats, pagination behaviour and authentication are byte-for-byte what they were — update your base path and you are done.

A second, separate change lands on November 1, 2026: schema version v2024_01_01 reaches end of life and is removed. v2026_01_23 becomes the only supported version, and it changes response shapes. Every client must be on it by that date — see Upgrading to v2026_01_23 below.

Are you affected?​

You are affected if any request you send has a path beginning /api/v1/. Those paths now return 404; there is no redirect and no grace period.

You are not affected if you were already calling /v1/cefi/ — the prefix has been available since v1.0.5 (May 2026) and is unchanged.

Step 1 — change your base path​

Productionhttps://api.truex.co/v1/cefi/
UAT (sandbox)https://api.uat.truex.co/v1/cefi/

Most clients hold this in one constant. If yours does, that is the whole change.

Step 2 — re-check your HMAC signing​

This is the step that is easy to miss. The signature covers the path:

signature = base64( HMAC_SHA256( secret, METHOD + "\n" + PATH + "\n" + TIMESTAMP + "\n" + BODY ) )

If your client builds the signature from a hard-coded path string rather than from the path it actually sends, changing the base URL alone will leave you signing /api/v1/orders while requesting /v1/cefi/orders. That fails as 401 Unauthorized, not 404, which sends people looking in the wrong place. Sign the request path you send.

JWT bearer clients (retail) have nothing to do here — there is no per-request signing.

Step 3 — map your paths​

Every removed path and its replacement:

Service​

RemovedUse instead
/api/v1/health/v1/cefi/health
/api/v1/versions/v1/cefi/versions

Assets and instruments​

RemovedUse instead
/api/v1/assets/v1/cefi/assets
/api/v1/asset/v1/cefi/assets
/api/v1/instruments/v1/cefi/instruments
/api/v1/instrument/v1/cefi/instruments

Market data​

RemovedUse instead
/api/v1/market/quote/v1/cefi/market/quote
/api/v1/markets/quote/v1/cefi/markets/quote

Clients​

RemovedUse instead
/api/v1/clients/v1/cefi/clients
/api/v1/client/v1/cefi/clients

Orders​

RemovedUse instead
/api/v1/orders/v1/cefi/orders
/api/v1/order/v1/cefi/orders
/api/v1/orders/{ref_id}/v1/cefi/orders/{ref_id}
/api/v1/order/{ref_id}/v1/cefi/orders/{ref_id}
/api/v1/orders/all/v1/cefi/orders/all
/api/v1/orders/active/v1/cefi/orders/active
/api/v1/order/active/v1/cefi/orders/active
/api/v1/orders/trade/v1/cefi/orders/trade
/api/v1/order/trade/v1/cefi/orders/trade
/api/v1/orders/activity/v1/cefi/orders/activity
/api/v1/order/activity/v1/cefi/orders/activity
/api/v1/orders/status/{ref_id}/v1/cefi/orders/status/{ref_id}
/api/v1/order/status/{ref_id}/v1/cefi/orders/status/{ref_id}

Balances​

RemovedUse instead
/api/v1/balances/v1/cefi/balances
/api/v1/balance/v1/cefi/balances
/api/v1/balances/activity/v1/cefi/balances/activity

Transfers​

RemovedUse instead
/api/v1/transfers/v1/cefi/transfers
/api/v1/transfer/v1/cefi/transfers
/api/v1/transfers/active/v1/cefi/transfers/active
/api/v1/transfer/active/v1/cefi/transfers/active

Singular forms are gone​

The singular aliases (/asset, /instrument, /client, /order, /balance, /transfer) were deprecated in v1.0.3 and are not carried over to /v1/cefi/. Use the plural form — it is the same operation with the same response.

The one exception is market quotes, where /v1/cefi/market/quote and /v1/cefi/markets/quote are both real endpoints with different behaviour. Keep whichever one you were calling.

Step 4 — verify​

curl -s https://api.truex.co/v1/cefi/health

Then grep your codebase for any remaining api/v1 — including config files, deployment health checks, monitoring probes and integration test fixtures, not just the client library.

What did not change in v1.0.6​

Worth stating explicitly, because it is the most common wrong assumption about this release:

  • The default schema version is still v2024_01_01. A request with no X-Truex-Version header gets exactly the response it got before.
  • Response bodies are unchanged. Raw arrays and objects, not envelopes.
  • Pagination is unchanged. List reads that were unpaginated stay unpaginated.
  • Error bodies are unchanged. RFC 7807 Problem Details, unwrapped.
  • Authentication is unchanged, apart from signing the new path.

Upgrading to v2026_01_23​

On November 1, 2026, schema version v2024_01_01 is removed. From that date:

  • v2026_01_23 becomes the default, so a request sending no X-Truex-Version header gets the new response shapes.
  • A request that explicitly sends X-Truex-Version: v2024_01_01 is rejected.

This is a hard cutoff, not a default change you can sit out. v2024_01_01 is already past its August 5, 2026 sunset.

There is no opt-out

Pinning X-Truex-Version: v2024_01_01 does not extend your deadline. Today it holds the old format; on November 1 that same header starts failing your requests outright.

If you pin it as a stopgap, set a reminder to remove it — a pinned v2024_01_01 is the one configuration that turns this migration into an outage rather than a change in response shape.

The work below is independent of the path move above, and you can start it today. Budget for it now: every client must be reading the envelope, following the cursor, and unwrapping errors before November 1.

Step 1 — adopt the new version​

X-Truex-Version: v2026_01_23

Send this header and you get the new format immediately, on whatever date suits you, regardless of what the current default is. That is the whole opt-in — the rest of this section is the client-side work it requires.

The version may also be supplied as a query parameter if a header is inconvenient.

tip

Pin v2026_01_23 explicitly rather than waiting to inherit it as the default on November 1. An explicit header means you choose the date you absorb the change, you can roll it out one environment at a time, and nothing about your client changes when the default moves underneath it.

Step 2 — unwrap the envelope​

Every response body is wrapped in data:

// v2024_01_01
[ { "...": "..." }, { "...": "..." } ]

// v2026_01_23
{
"data": [ { "...": "..." }, { "...": "..." } ],
"pagination": { "size": 10, "next_cursor": "1761955200000000000" }
}

If you want a decoder that works on both versions during the transition, unwrap only when both keys are present — that is a no-op on v2024_01_01:

def unwrap(body):
if isinstance(body, dict) and "data" in body and "pagination" in body:
return body["data"]
return body

Step 3 — follow the cursor​

This is the step that silently loses data if you skip it. Under v2024_01_01 a list read returned everything. Under v2026_01_23 it returns at most size records, and size defaults to 10.

A client that issues one request and treats the result as the complete set will read 10 orders and believe that is all of them. No error is raised.

Page size parameter?size=
Default10
Maximum100 (larger values are clamped, not rejected)
Cursor returned aspagination.next_cursor
Cursor sent back as?timestamp=
End of resultsnext_cursor is null

Note the asymmetry: the cursor comes back to you as next_cursor but goes out as timestamp. It is a nanosecond-precision timestamp, and paging walks backwards from it, so passing it through as an opaque string is correct — do not parse, round, or reformat it.

def get_all(session, path, page_size=100):
results, cursor = [], None
while True:
params = {"size": page_size}
if cursor:
params["timestamp"] = cursor
body = session.get(path, params=params).json()
page = body["data"]
results.extend(page)
cursor = body["pagination"]["next_cursor"]
# An empty page alongside a cursor would loop forever — treat it as the end.
if not cursor or not page:
break
return results
warning

Keep the not page guard. An empty page returned together with a non-null cursor is the one shape that turns this loop into an infinite one.

Step 4 — unwrap errors​

The RFC 7807 Problem Details body is nested under an error key. The fields inside it are unchanged.

// v2024_01_01
{ "type": "...", "title": "...", "status": 400, "detail": "..." }

// v2026_01_23
{ "error": { "type": "...", "title": "...", "status": 400, "detail": "..." } }

Check your error handling for code that reads body["title"] or body["detail"] directly — those move to body["error"]["title"] and body["error"]["detail"]. HTTP status codes are unchanged, so any handling keyed on the status code alone keeps working.

Your HMAC signature is not affected​

Pagination adds query parameters, which raises a reasonable worry after Step 2 of the path migration. It is not a problem: the signature covers the path only, not the query string. Adding ?size=100&timestamp=... does not change what you sign.

Sign /v1/cefi/orders whether you request /v1/cefi/orders or /v1/cefi/orders?size=100&timestamp=1761955200000000000.

Step 5 — verify​

GET /v1/cefi/versions reports the supported versions and the current default, so you can assert on it from a test instead of tracking this page.

A good end-to-end check: create more than 10 of something, then read the list back and confirm you get all of them. That single test catches the pagination mistake, which is the one that fails quietly.

Responses for a deprecated version carry RFC 8594 Deprecation and Sunset headers — worth logging so an expiring version shows up in your own telemetry before it starts failing requests.

Reference​