Structured Note Reference Data

Explorer
More ▾

Pricing Data: API

The price feed is also available as an HTTP API. You give us an ISIN — or a CUSIP, or a list of either — and we hand back the latest price we have, the raw bid/mid/ask sides behind it, and enough reference and lifecycle context to know what you're looking at. It spans everything in our security master: structured notes, municipal and corporate bonds, treasuries, CDs, ETFs/ETNs, UITs, and more. We route the lookup to the right product's price table for you; you don't have to know which one a given ISIN lives in.

The API lives at https://api.sqxnotes.com/v1/. Authentication is by API key in the x-api-key header. We'll get you a key.

Unlike the reference-data API, pricing is synchronous. There's no analysis pipeline to wait on — every call returns its answer on the connection. No jobs, no polling.


The five-second version

If you have an ISIN, ask for it:

curl -H "x-api-key: $API_KEY" \
    "https://api.sqxnotes.com/v1/price/byIsin?isin=US06370EDU91"

You get back 200 with the price right away, or 404 if we've never heard of the ISIN. That's the whole flow.


What you get back on success

Every response — success or error — comes in the same envelope: a data object, an errors array (empty on success), and a meta block with a request id and the server's as_of timestamp. On a 200, data carries three things: the pricing record, a reference block identifying the security, and a lifecycle_status.

{
    "data": {
        "reference": {
            "isin": "US06370EDU91",
            "cusip": "06370EDU9",
            "description": "Bank of Montreal Senior Medium-Term Notes",
            "type": "structured_note",
            "issuer": "Bank of Montreal",
            "currency": "USD",
            "ticker": null,
            "maturity_date": "2029-05-30"
        },
        "pricing": {
            "pricing_date": "2026-06-03",
            "price": 98.42,
            "bid_price": 98.17,
            "mid_price": 98.42,
            "ask_price": 98.67,
            "currency": null,
            "source": "icevpdt"
        },
        "lifecycle_status": "active"
    },
    "errors": [],
    "meta": {
        "request_id": "3f1c8a2e-9b04-4e77-bd1a-0c2f5e6a7d10",
        "as_of": "2026-06-04T20:00:00+00:00",
        "page": null
    }
}

The pricing object always has the same seven keys, whatever the product. Anything we don't have for a given security comes back as JSON null — never an empty string or an "N/A" sentinel.

Alongside the price we return lifecycle_statusactive, inactive, or null. It's computed from the security master: a security past maturity or flagged matured/called/redeemed reads inactive; one that's still live and recently priced reads active; anything we can't place stays null.

> The authoritative, field-by-field contract — every key, enum, and status code, including the response envelope — is the OpenAPI 3.1 spec (openapi.yaml). This page is the narrative guide; the spec is the source of truth.


A CUSIP works just as well

If you hold CUSIPs rather than ISINs, use byCusip. We resolve it to the ISIN through the security master and answer with the identical envelope — your CUSIP echoes back in reference.cusip.

curl -H "x-api-key: $API_KEY" \
    "https://api.sqxnotes.com/v1/price/byCusip?cusip=06370EDU9"

A price on a particular date

For a historical look-up, add a date:

curl -H "x-api-key: $API_KEY" \
    "https://api.sqxnotes.com/v1/price/byIsinHistorical?isin=US06370EDU91&date=2025-09-15"

Markets don't price every security every day, so we don't make you guess whether a given date has a row. The pricing object grows three extra fields that tell you exactly what we returned relative to what you asked for:

{
    "requested_date": "2025-09-15",
    "effective_date": "2025-09-12",
    "match": "prior",
    "price": 97.10,
    "bid_price": 96.85,
    "mid_price": 97.10,
    "ask_price": 97.35,
    "currency": null,
    "source": "icevpdt",
    "pricing_date": "2025-09-12"
}

match is one of exact (we had a row on your date), prior (we fell back to the most recent earlier date), next (nothing on or before your date, so we reached forward to the first later one), or none (we have no price for this security at all). When match is none you still get 200effective_date and the price fields are simply null. It isn't an error, so there's nothing in errors; the enum tells the whole story.


Looking up a lot of them at once

To price a list, POST it to the bulk endpoint instead of firing one request per ISIN:

curl -H "x-api-key: $API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"isin_list": ["US06370EDU91", "US912828YL83", "NOTANISIN"]}' \
    https://api.sqxnotes.com/v1/price/bulk/byIsin

The response sorts every ISIN you sent into one of three buckets, all three always present even when empty:

{
    "data": {
        "success": [
            { "reference": { "...": "..." }, "pricing": { "...": "..." }, "lifecycle_status": "active" }
        ],
        "unprocessed": [
            { "isin": "NOTANISIN", "reason": "invalid_isin: ISIN must be 12 characters, got 9" }
        ],
        "not_found": ["US912828YL83"]
    },
    "errors": [],
    "meta": { "...": "..." }
}

Duplicates in your input are de-duped, and the cap is 1000 ISINs per request. Send more and you get 429 with a QUOTA_LIMIT_EXCEEDED error telling you the limit and what you sent.


When we have the security but no price

A 404 means we don't recognize the identifier at all. It does not mean "no price" — those are different answers. If the security is in our master but we simply don't carry a price for it (its product type has no price table, or nothing's been captured yet), you still get 200 with the full reference block and lifecycle_status, and the pricing fields come back null. You can tell an unpriced-but-known security from a stale one by reading lifecycle_status alongside the null price.


When you get input wrong

Bad input returns 400 with a structured error in the errors array. Each one has a numeric messageCode, a category, a machine-readable type, and a human message:

{
    "data": null,
    "errors": [
        {
            "category": "VALIDATION_ERROR",
            "type": "INVALID_INPUT",
            "messageCode": 1010,
            "message": "Invalid ISIN: checksum invalid",
            "messageValues": { "isin": "US06370EDU90" }
        }
    ],
    "meta": { "...": "..." }
}

The codes you'll see on these endpoints:

messageCodeWhen
1010ISIN is malformed or fails its check digit.
1011CUSIP is malformed or fails its check digit.
1012date isn't a valid YYYY-MM-DD.
1040The identifier is well-formed but we have no such security (404).
1050Bulk request exceeded the 1000-ISIN cap (429).

Lowercase identifiers are silently uppercased — copy-paste from a spreadsheet just works.


Endpoint reference

MethodPathPurpose
GET/price/byIsin?isin={ISIN}Latest price by ISIN. 200 with the record, 404 if the ISIN is unknown.
GET/price/byCusip?cusip={CUSIP}Latest price by CUSIP. Resolves to ISIN first; same payload as byIsin.
GET/price/byIsinHistorical?isin={ISIN}&date={YYYY-MM-DD}Price as of a date, with a match of exact, prior, next, or none.
POST/v1/price/bulk/byIsinPrice up to 1000 ISINs in one call. Body {"isin_list": [...]}; returns success / unprocessed / not_found.
GET/versionReport API version. No auth required.

Authentication & versioning

Every request except /version needs a valid API key in x-api-key. Keys are scoped per client — pricing access and historical-pricing access are separate grants — and a key can carry an expiry or a call quota. A key that has lapsed answers 403 (messageCode 1033); one that's over its quota answers 429 (messageCode 1050).

The v1 base path is stable. Field additions are non-breaking and ship in-place. Breaking changes — renames, removals, semantic shifts — land at a new major version on a new stage. Minor and patch updates are reported at /version.