API authentication and request signing
Every call to the CasePrimus.ai API is authenticated with an API key. For integrations that need more, you can also have requests signed with your own key pair, and payloads encrypted.
API keys
An API key is a secret that identifies your integration. Create and manage keys from the Developer console in your CasePrimus.ai dashboard. A key's secret is shown once, when you create it, so store it somewhere safe, such as your secrets manager. Never put it in client-side code or a public repository.
Create a separate key for each system that connects. If one is exposed or no longer needed, you can switch off just that key without touching the others.
Send your key
Put the key in the X-CasePrimus-Api-Key header. All requests go to https://api.caseprimus.ai/api/caseprimus/v1 over HTTPS.
curl "https://api.caseprimus.ai/api/caseprimus/v1/watchlist/entities/search" \ -X POST \ -H "X-CasePrimus-Api-Key: $CASEPRIMUS_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "$skip": 0, "$limit": 10 }'
const res = await fetch("https://api.caseprimus.ai/api/caseprimus/v1/watchlist/entities/search", { method: "POST", headers: { "Content-Type": "application/json", "X-CasePrimus-Api-Key": process.env.CASEPRIMUS_API_KEY, }, body: JSON.stringify({ $skip: 0, $limit: 10 }), });
import os import requests res = requests.post( "https://api.caseprimus.ai/api/caseprimus/v1/watchlist/entities/search", headers={"X-CasePrimus-Api-Key": os.environ["CASEPRIMUS_API_KEY"]}, json={"$skip": 0, "$limit": 10}, )
Signed requests (optional)
For integrations that need to prove each request came from you and was not altered, you can turn on request signing for a key. You give CasePrimus.ai your public key; you keep the private key. Each request then carries two extra headers: X-Signature and X-Signature-Timestamp.
- Build the string
METHOD\nPATH\nTIMESTAMP\nBODY: the HTTP method, the full request path, the timestamp, and the exact raw body, separated by newlines. - Sign it with your private key using RSA with SHA-256, and send the result base64-encoded in
X-Signature. - Send the timestamp in milliseconds since the Unix epoch. Requests older than five minutes are rejected, which protects against replay.
const crypto = require("crypto"); const method = "POST"; const path = "/api/caseprimus/v1/watchlist/cases"; const body = JSON.stringify({ caseIdentifier: { cnr: "DLHC01-004821-2026" } }); const timestamp = Date.now().toString(); // Sign EXACTLY this string: method, path, timestamp and the raw body bytes, // joined by newlines, with your own RSA private key. const payload = `${method}\n${path}\n${timestamp}\n${body}`; const signature = crypto .sign("RSA-SHA256", Buffer.from(payload), YOUR_PRIVATE_KEY_PEM) .toString("base64"); const response = await fetch(`https://api.caseprimus.ai${path}`, { method, headers: { "Content-Type": "application/json", "X-CasePrimus-Api-Key": YOUR_API_KEY_SECRET, "X-Signature": signature, "X-Signature-Timestamp": timestamp, }, body, });
import time import json import base64 import requests from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import padding from cryptography.hazmat.primitives.serialization import load_pem_private_key method = "POST" path = "/api/caseprimus/v1/watchlist/cases" body = json.dumps({"caseIdentifier": {"cnr": "DLHC01-004821-2026"}}) timestamp = str(int(time.time() * 1000)) # Sign EXACTLY this string: method, path, timestamp and the raw body bytes, # joined by newlines, with your own RSA private key. payload = f"{method}\n{path}\n{timestamp}\n{body}".encode() private_key = load_pem_private_key(YOUR_PRIVATE_KEY_PEM, password=None) signature = base64.b64encode( private_key.sign(payload, padding.PKCS1v15(), hashes.SHA256()) ).decode() response = requests.post( f"https://api.caseprimus.ai{path}", headers={ "Content-Type": "application/json", "X-CasePrimus-Api-Key": YOUR_API_KEY_SECRET, "X-Signature": signature, "X-Signature-Timestamp": timestamp, }, data=body, )
Sign the exact bytes you send
Encrypted payloads (optional)
On top of HTTPS, a key can also be set up so that request and response bodies are encrypted, using a hybrid scheme that combines RSA and AES. Only the holder of your private key can read the responses. This is off by default and is turned on per key in the Developer console. The same option exists for webhook deliveries.
Permissions
Each endpoint lists the permission it needs, such as watchlist.write or case.read. A call without the right permission returns 403. Your plan also decides which products you can call, for example Watchlist, Live Case Lookup or Historical Search; calling one your plan does not include returns 403 with the code PRODUCT_NOT_IN_PLAN, and nothing is charged. See Rate limits & errors.
Frequently asked questions
How do I authenticate with the CasePrimus.ai API?
Create an API key in the Developer console of your CasePrimus.ai dashboard and send it in the X-CasePrimus-Api-Key header of every request. No other login or token exchange is needed.
Do I have to sign my requests?
No. Request signing is an optional extra layer you can turn on per API key, by giving CasePrimus.ai your public key. When it is on, every request must carry a valid signature and a timestamp no older than five minutes.
Can I use separate keys for separate systems?
Yes, and it is recommended. Keys are created per integration, so a CRM sync and an internal alerting pipeline can each have their own key and be revoked independently.
What does a 401 response mean?
The key is missing, invalid or inactive, or the request was signed incorrectly or too long ago. Check the header, that the key is active, and, if signing is on, the signature and timestamp.
Last updated 14 October 2026