v1.0 REST JSON

CUSIP Lookup API

Search Canadian fixed-income bonds by CUSIP or ISIN in real time. Designed for typeahead inputs — fast prefix matching, full bond record returned on each keystroke.

Bonds indexed
190k+
CA, US, XS issuers
CUSIP coverage
~30%
Active bonds with CUSIP
Latency target
<50 ms
Prefix queries, indexed
Update frequency
Daily
CIRO price + pipeline

Overview

The CUSIP Lookup API is a read-only REST endpoint that powers bond identifier search widgets. It accepts a partial CUSIP, ISIN, or issuer name and returns matching bonds instantly — ideal for wiring into an <input> field with a debounce of 150–300 ms.

Each result includes the full bond record (coupon, maturity, currency, issuer type) plus the most recent CIRO price if available.

💡 Typeahead behaviour
Start sending requests after the user types 2+ characters. At 9 characters you have an exact CUSIP — the response will be a single bond.

Base URL

All API requests are made over HTTPS to:

https://api-cusip.yieldexchange.ca

Authentication

Every request must include your API key in the X-API-Key HTTP header. Keys are managed on the API Keys page of the dashboard.

X-API-Key: yex_sk_360ece523dcc8d4d93aa2331e698b0c8
⚠ Keep your key secret
Never expose the key in client-side JavaScript that you ship to end users. For browser-based typeahead, proxy the request through your own backend.

Rate Limits

The lookup endpoint is optimised for typeahead usage. Standard keys allow 600 requests / minute (10 req/sec) per key. Burst of up to 30 requests is permitted. A 429 Too Many Requests response is returned when exceeded; retry after the Retry-After header value.


GET  /api/lookup Primary

GET /api/lookup?q={query}&limit={n}&status={status}

Prefix-matches the query against CUSIP and ISIN fields (indexed scan). When the query contains only letters, falls back to a partial issuer name search. Results are ordered: exact match → prefix match → alphabetical.

Query Parameters

ParameterTypeRequiredDefaultDescription
q string required CUSIP prefix (e.g. 1350), ISIN prefix (e.g. CA1350), or partial issuer name (e.g. Royal Bank). Min 1 char, max 20 chars.
limit integer optional 10 Max results to return (1–50). Use 1 for exact lookup.
status string optional "active" Filter by lifecycle: active (not yet matured), matured, or all.

Headers

HeaderRequiredDescription
X-API-Key required Your API key.

GET  /api/bonds/{id}

GET /api/bonds/{cusip_or_isin}

Fetch a single bond by exact CUSIP or ISIN. Returns the full record plus the most recent CIRO price observation.

Path Parameter

ParameterTypeDescription
id string 9-char CUSIP (e.g. 135087T53) or 12-char ISIN (e.g. CA135087T537). Case-insensitive.

Response Schema

GET /api/lookup — response envelope

{ "query": string // echo of the q param, uppercased "status": string // "active" | "matured" | "all" "count": integer // number of results returned (<= limit) "results": BondRecord[] // see below }

BondRecord object

{ "id": integer // internal row ID "cusip": string | null // 9-char CUSIP, e.g. "135087T53" "isin": string | null // 12-char ISIN, e.g. "CA135087T537" "issuer_name": string "issuer_type": string // "GOC" | "PROV" | "FIN" | "CORP" "province_code": string | null // "ON" | "QC" | "AB" … (PROV bonds only) "coupon_rate": number | null // annual coupon %, e.g. 3.25 "maturity_date": string | null // ISO 8601, e.g. "2035-12-01" "issue_date": string | null "currency": string // "CAD" | "USD" | "EUR" … "amount_outstanding_cad": number | null // par outstanding in CAD "confidence_score": number // 0.0 – 1.0 source quality score "source_name": string // originating data source "latest_price": PriceRecord | null }

PriceRecord object (nested in each result)

{ "price_date": string // "2026-04-07" "mid_price": number | null // clean mid price (% of par) "yield_mid": number | null // yield to maturity, % "g_spread_bps": number | null // G-spread in basis points }

Live Demo

Enter your API key and start typing a CUSIP, ISIN, or issuer name. Results appear as you type (150 ms debounce).

🔑 Your API key is stored only in this browser tab and never sent to any third party.
Results

Code Examples

Typeahead search — prefix query

# Search for all GoC bonds starting with "1350"
curl -s -X GET \
  "https://api-cusip.yieldexchange.ca/api/lookup?q=1350&limit=10&status=active" \
  -H "X-API-Key: yex_sk_360ece523dcc8d4d93aa2331e698b0c8"
import requests

API_KEY = "yex_sk_360ece523dcc8d4d93aa2331e698b0c8"
BASE    = "https://api-cusip.yieldexchange.ca"

def lookup(query: str, limit: int = 10, status: str = "active"):
    resp = requests.get(
        f"{BASE}/api/lookup",
        params={"q": query, "limit": limit, "status": status},
        headers={"X-API-Key": API_KEY},
        timeout=5,
    )
    resp.raise_for_status()
    return resp.json()["results"]

# Typeahead: called on each keystroke
for bond in lookup("1350"):
    print(f"{bond['cusip']}  {bond['issuer_name']}  mat={bond['maturity_date']}")
const API_KEY = "yex_sk_360ece523dcc8d4d93aa2331e698b0c8";
const BASE    = "https://api-cusip.yieldexchange.ca";

/**
 * Typeahead lookup — wire to an input's `oninput` handler with debounce.
 * @param {string} query - partial CUSIP, ISIN, or issuer name
 * @returns {Promise<BondRecord[]>}
 */
async function lookupBond(query, limit = 10, status = "active") {
  const url = new URL(`${BASE}/api/lookup`);
  url.searchParams.set("q", query);
  url.searchParams.set("limit", limit);
  url.searchParams.set("status", status);

  const res = await fetch(url, {
    headers: { "X-API-Key": API_KEY },
  });
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  const data = await res.json();
  return data.results;
}

// Debounce helper
function debounce(fn, ms) {
  let timer;
  return (...args) => { clearTimeout(timer); timer = setTimeout(() => fn(...args), ms); };
}

// Wire to input
const input = document.querySelector("#cusip-search");
input.addEventListener("input", debounce(async (e) => {
  if (e.target.value.length < 2) return;
  const results = await lookupBond(e.target.value);
  // render results …
}, 150));
interface PriceRecord {
  price_date:   string;
  mid_price:    number | null;
  yield_mid:    number | null;
  g_spread_bps: number | null;
}

interface BondRecord {
  id:                     number;
  cusip:                  string | null;
  isin:                   string | null;
  issuer_name:            string;
  issuer_type:            "GOC" | "PROV" | "FIN" | "CORP";
  province_code:          string | null;
  coupon_rate:            number | null;
  maturity_date:          string | null;
  issue_date:             string | null;
  currency:               string;
  amount_outstanding_cad: number | null;
  confidence_score:       number;
  source_name:            string;
  latest_price:           PriceRecord | null;
}

interface LookupResponse {
  query:   string;
  status:  string;
  count:   number;
  results: BondRecord[];
}

const API_KEY = "yex_sk_360ece523dcc8d4d93aa2331e698b0c8";
const BASE    = "https://api-cusip.yieldexchange.ca";

async function lookupBond(
  query:  string,
  limit:  number = 10,
  status: string = "active"
): Promise<BondRecord[]> {
  const url = new URL(`${BASE}/api/lookup`);
  url.searchParams.set("q", query);
  url.searchParams.set("limit", String(limit));
  url.searchParams.set("status", status);

  const res = await fetch(url.toString(), {
    headers: { "X-API-Key": API_KEY },
  });
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  const data: LookupResponse = await res.json();
  return data.results;
}

Exact CUSIP or ISIN lookup

# By exact CUSIP
curl -s "https://api-cusip.yieldexchange.ca/api/bonds/135087T53" \
  -H "X-API-Key: yex_sk_360ece523dcc8d4d93aa2331e698b0c8"

# By exact ISIN (same endpoint, auto-detected)
curl -s "https://api-cusip.yieldexchange.ca/api/bonds/CA135087T537" \
  -H "X-API-Key: yex_sk_360ece523dcc8d4d93aa2331e698b0c8"
def get_bond(identifier: str):
    """Fetch a single bond by CUSIP or ISIN."""
    resp = requests.get(
        f"{BASE}/api/bonds/{identifier.upper()}",
        headers={"X-API-Key": API_KEY},
    )
    if resp.status_code == 404:
        return None
    resp.raise_for_status()
    return resp.json()

bond = get_bond("CA135087T537")
print(bond["cusip"], bond["coupon_rate"], bond["maturity_date"])

Example JSON response

{
  "query":  "CA135087T",
  "status": "active",
  "count":  3,
  "results": [
    {
      "id":                     4821,
      "cusip":                  "135087T53",
      "isin":                   "CA135087T537",
      "issuer_name":            "CANADA (GOVERNMENT OF)",
      "issuer_type":            "GOC",
      "province_code":          null,
      "coupon_rate":            3.25,
      "maturity_date":          "2035-12-01",
      "issue_date":             "2025-07-03",
      "currency":               "CAD",
      "amount_outstanding_cad": 22500000000,
      "confidence_score":       0.97,
      "source_name":            "bmo_etf",
      "latest_price": {
        "price_date":   "2026-04-07",
        "mid_price":    98.14,
        "yield_mid":    3.41,
        "g_spread_bps": null
      }
    }
    // … more results
  ]
}

Errors

HTTP StatusCodeWhen it occurs
401 Unauthorized Missing or invalid X-API-Key header.
404 Not Found CUSIP/ISIN not in the database (/api/bonds/{id} only).
422 Unprocessable Entity Missing required query parameter q, or value out of range.
429 Too Many Requests Rate limit exceeded. Check Retry-After header.
500 Internal Server Error Unexpected server error. Contact support if persistent.
CUSIP Repository — Canadian Fixed Income Data Platform · Dashboard · Manage Keys · Swagger UI · ReDoc