Get going in 30 seconds
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(
model="claude-sonnet-4-6-t4",
api_key="ni_live_YOUR_KEY_HERE",
base_url="https://northerninference.ca/v1",
)
resp = llm.invoke("What model are you?")
print(resp.content)
Replace claude-sonnet-4-6-t4 with any route ID from northerninference.ca/portal (Models page).
LangChain (Python)
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(
model="claude-sonnet-4-6-t4",
api_key="ni_live_YOUR_KEY_HERE",
base_url="https://northerninference.ca/v1",
)
resp = llm.invoke("What model are you?")
print(resp.content)
LangChain (JS/TS)
import { ChatOpenAI } from "@langchain/openai";
const llm = new ChatOpenAI({
model: "claude-sonnet-4-6-t4",
apiKey: process.env.NI_API_KEY,
configuration: {
baseURL: "https://northerninference.ca/v1",
},
});
const resp = await llm.invoke("What model are you?");
console.log(resp.content);
LlamaIndex
from llama_index.llms.openai import OpenAI
llm = OpenAI(
model="claude-sonnet-4-6-t4",
api_key="ni_live_YOUR_KEY_HERE",
api_base="https://northerninference.ca/v1",
)
print(llm.complete("What model are you?"))
Capturing the custody chain in your app
Every NI response carries custody headers. LangChain doesn't surface these through invoke(), but you can subclass ChatOpenAI or use .ainvoke_with_config() with a callback handler to capture them:
import httpx
from langchain_openai import ChatOpenAI
class NICustodyCapturingChatOpenAI(ChatOpenAI):
last_custody_path: str = ""
last_request_id: str = ""
last_jurisdiction: str = ""
def _get_http_client(self):
transport = httpx.HTTPTransport()
def log_response(response: httpx.Response):
self.last_custody_path = response.headers.get("x-ni-custody-path", "")
self.last_request_id = response.headers.get("x-ni-request-id", "")
self.last_jurisdiction = response.headers.get("x-ni-resolved-jurisdiction", "")
return httpx.Client(event_hooks={"response": [log_response]})
Or, simpler: use GET /api/usage/custody/{request_id} after each call to pull the full chain. The request_id is available on any failure via the x-ni-request-id header in the 4xx/5xx response too.
To attribute spend to a case file, contract or WBS code, send your own opaque reference on every call and it is recorded, shown in the portal and bound into the signed custody record. ChatOpenAI takes it as a default header:
llm = ChatOpenAI(
model="claude-haiku-4-5-20251001-t4",
api_key=NI_API_KEY,
base_url="https://northerninference.ca/v1",
default_headers={"X-NI-Reference": reference_for(case_id)},
)
Keep the value opaque (a keyed HMAC of your identifier, never the identifier itself); the full rules are in the curl guide under "Tag a request with your own reference".