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
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"
  }'
TypeScript
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.