Guide
Send cases in
Make a case in Nolmo from another system: a contact form, a returns page, a shop. It is routed, timed and assessed exactly as an email would be.
Last updated 20 October 2026
Before you start
An admin makes a key in Settings → API keys. A key has scopes, the things it may do, and the groups of cases it sees. The secret is shown once, so keep it on your server and never in a web page or an app. Every request carries it as a header:
Authorization: Bearer nolmo_live_…Every error is JSON, {"error": {"code": "…", "message": "…", "details": null}}. Branch on code. Past the limit the answer is 429 with Retry-After.
Make a case
The key needs the scope cases:write. Send the person, a subject and what they wrote. Nolmo finds the person by email, then phone, then an id of yours in external_ids, and makes them when they are new. The case arrives on the channel api, and its timeline says which key made it.
curl https://api.nolmo.no/v1/cases \
-H "Authorization: Bearer $NOLMO_KEY" \
-H "Idempotency-Key: returns-12345-first-send" \
-H "Content-Type: application/json" \
-d '{
"contact": { "name": "Kari Kunde", "email": "kari@example.no" },
"subject": "Cracked tiles in the delivery",
"message": { "body_text": "Three of the tiles in the pack were cracked. Order 12345." },
"external_ref": "order-12345",
"source": "Returns page"
}'const res = await fetch("https://api.nolmo.no/v1/cases", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.NOLMO_KEY}`,
"Idempotency-Key": `returns-${order.id}-first-send`,
"Content-Type": "application/json",
},
body: JSON.stringify({
contact: { name: order.name, email: order.email },
subject: "Cracked tiles in the delivery",
message: { body_text: order.complaint },
external_ref: `order-${order.id}`,
source: "Returns page",
}),
});
if (res.status === 409) {
// the case is already there: external_ref_taken names it
const { error } = await res.json();
console.log("already made", error.details);
} else if (!res.ok) {
throw new Error(`Nolmo said ${res.status}`);
}
const made = await res.json(); // { number: 1042, subject: "…", status: "new", version: 1, … }Send an Idempotency-Key
A request that timed out may or may not have been written. Send the same Idempotency-Key again and you get the first answer back, marked Idempotent-Replayed: true, and nothing is made twice. Use any value that is the same for the same job, such as an order id; the same key with another body is a 422. Keys are remembered for 24 hours.
Find the case again
external_ref is your own id for the case. It is unique within the source you made it under, and it finds the case later:
curl "https://api.nolmo.no/v1/cases?external_ref=order-12345&source=Returns%20page" \
-H "Authorization: Bearer $NOLMO_KEY"A second create with the same external_ref is a 409, external_ref_taken, and says which case has it. The key needs cases:read, and sees only the cases in its groups.
Attach a file
Upload the file first, then name its id in the message. A file you never use is deleted after a day.
# 1. upload the file; the answer has an id
curl https://api.nolmo.no/v1/uploads \
-H "Authorization: Bearer $NOLMO_KEY" \
-F "file=@damaged-tiles.jpg"
# { "id": "0192f3c4-…", "name": "damaged-tiles.jpg", "content_type": "image/jpeg", "size": 183204 }
# 2. name the id in the message's attachments
# "message": { "body_text": "…", "attachments": ["0192f3c4-…"] }Change a case
PATCH /v1/cases/{number} changes tags, priority, custom fields and the external_ref. Status and assignment stay with the team. Send the version you read: if the case has moved on the answer is 409 case_changed and nothing is written.
Next
Answer a customer, or look up any route in the reference.