Quickstart
Agents don’t need memory. They need a Brain. This quickstart gets you a cited answer in three HTTP calls: create a Brain, put something in it, ask it a question. No schema to design, no policy to configure, no ids to write down.
1. Get a key
Section titled “1. Get a key”Sign in at app.nicia.ai, open Settings → API keys, and mint an organization key under “Organization keys”. The secret is shown once — copy it now.
export NICIA_KEY="…"export API="https://api.nicia.ai"An organization key can do anything inside the organization you minted it from:
create Brains, read and write them, and mint narrower keys to hand out later.
That is why it is the right key for a quickstart and the wrong key to ship
inside a client app. It is bound to that organization at mint time, so every
call below sends it alone, in authorization: Bearer — there is no second id
to copy or send. See Authentication.
Every response is { "data": … } on success and
{ "error": { "kind", "message" } } on failure. See Errors.
2. Create a Brain
Section titled “2. Create a Brain”A Brain is addressed by a handle you choose: a customer id, an employee id, a project slug — anything stable that you already have. The handle is public and appears in every URL. A key is always a secret credential; the two are never the same thing.
curl -X PUT "$API/v1/brains/tenant:acme" \ -H "authorization: Bearer $NICIA_KEY" \ -H "content-type: application/json" \ -d '{ "name": "Acme", "purpose": "Everything we know about Acme." }'{ "data": { "brain": { "id": "brain_3a91c7", "handle": "tenant:acme", "name": "Acme", "purpose": "Everything we know about Acme.", "schema": "nicia-base", "mode": "open", "createdAt": "2026-08-14T09:12:04.221Z", "updatedAt": "2026-08-14T09:12:04.221Z" } }}PUT is create-or-update on your handle, so it is safe to call on every
request, in every worker, after every crash. The first call returns 201, every
identical call after it returns 200, and there is no “does it exist yet” query
to race against.
Three defaults worth knowing:
schema: "nicia-base"— a deterministic starter vocabulary (people, companies, deals, concepts, notes). You did not have to design anything, and you can change it later — including to the domain-neutralnicia-corevocabulary by naming it explicitly. See Schemas.mode: "open"— writes land immediately. Switch to"reviewed"when you want a human to approve what agents write. See Review.- The Brain is addressed by
tenant:acmefrom here on. Nicia’s ownidcomes back in the response and works in the same slot, but nothing on this site asks for it — every path below takes the handle. Store it only if you call one of the older id-addressed paths.
3. Put something in
Section titled “3. Put something in”Documents and structured records are peer on-ramps. Use whichever you have.
# A document — text, markdown, a transcript, a PDFcurl -X POST "$API/v1/brains/tenant:acme/documents" \ -H "authorization: Bearer $NICIA_KEY" \ -H "content-type: application/json" \ -d '{ "id": "hubspot:deal:412", "text": "Renewal call 2026-03-14. Acme renewed at $120k for 24 months. Bob Smith (Head of Platform) pushed for SSO before Q3.", "metadata": { "source": "hubspot", "type": "call-note" } }'{ "data": { "document": { "id": "hubspot:deal:412", "status": "queued" } }}id is yours. Sending the same id again replaces that document, so a nightly
sync is a loop of POSTs and nothing else.
If what you have is already structured, send it as a record instead — same Brain, no schema step:
curl -X PATCH "$API/v1/brains/tenant:acme/records/bob-smith" \ -H "authorization: Bearer $NICIA_KEY" \ -H "content-type: application/json" \ -d '{ "fields": { "name": "Bob Smith", "role": "Head of Platform" } }'4. Ask it something
Section titled “4. Ask it something”curl -X POST "$API/v1/brains/tenant:acme/context" \ -H "authorization: Bearer $NICIA_KEY" \ -H "content-type: application/json" \ -d '{ "prompt": "What should I know before the renewal call?", "maxTokens": 2000 }'{ "data": { "text": "Renewal call 2026-03-14. Acme renewed at $120k for 24 months. Bob Smith (Head of Platform) pushed for SSO before Q3.\n\nbob-smith\nname: Bob Smith\nrole: Head of Platform", "citations": [ { "source": "hubspot:deal:412", "slug": "brain-evidence-0dd3e2449851d9ba41924c42bd7a61375a8b78050bfe2ca7192eb918d626236a", "quote": "Renewal call 2026-03-14. Acme renewed at $120k for 24 months. Bob Smith (Head of Platform) pushed for SSO before Q3.", "recordedAt": "2026-08-14T09:13:10.882Z" }, { "slug": "bob-smith", "quote": "bob-smith\nname: Bob Smith\nrole: Head of Platform", "recordedAt": "2026-08-14T09:13:44.117Z" } ], "staged": 0, "warnings": [], "receipt": "rcp_019ffefe", "truncated": false }}Paste text straight into your prompt. Show citations to your user. Keep
receipt in your logs — it is how you reconstruct months later exactly what the
model was shown. See Receipts.
text is one block per source, blank-line separated: a document contributes its
prose — plus a name line and its frontmatter keys, when it carries any — and a
record its label, its kind, and its values. A record with no label is headed by
its id, which is why Bob’s block starts bob-smith. Each block is the matching
citations[].quote, verbatim — so text is never more than the sum of what you
can show a user, and never less. See
what text is.
staged is the count of changes waiting for review. It is usually 0 on an
open Brain, whose writes are admitted as they arrive; a non-zero value tells
you an empty answer means “waiting”, not “nothing there”. See
Context.
That is the whole product. Everything below is the same three calls in different proportions.
The same three calls at three scales
Section titled “The same three calls at three scales”One Brain, many clients
Section titled “One Brain, many clients”Keep one Brain and give each tool its own key, so revocation and attribution stay precise:
# A read-only key for your web appcurl -X POST "$API/v1/brains/tenant:acme/keys" \ -H "authorization: Bearer $NICIA_KEY" \ -H "content-type: application/json" \ -d '{ "name": "web app", "capabilities": ["read"] }'{ "data": { "key": { "id": "key_7f3a1c", "name": "web app", "capabilities": ["read"], "status": "active", "createdAt": "2026-08-14T09:15:41Z" }, "secret": "nbk_9f2c…" }}secret is shown once. See Handing out keys.
A team
Section titled “A team”One Brain per project or account, all on the same schema so a query written once
works against every one of them. nicia-core is the neutral vocabulary —
people, organizations, topics, events, notes — which is enough for a query to
mean the same thing everywhere without anyone authoring an ontology first:
curl -X PUT "$API/v1/brains/project:atlas" \ -H "authorization: Bearer $NICIA_KEY" \ -H "content-type: application/json" \ -d '{ "name": "Atlas", "schema": "nicia-core", "mode": "reviewed" }'mode: "reviewed" is what turns “my agents write to my notes” into “my agents
propose, I accept.” Your review queue is the diff.
An AI company: one Brain per customer
Section titled “An AI company: one Brain per customer”// Provisioning is a pure function of your own tenant id.async function brainFor(tenantId: string): Promise<string> { const handle = `tenant:${tenantId}`; await fetch(`${API}/v1/brains/${encodeURIComponent(handle)}`, { method: "PUT", headers: { authorization: `Bearer ${process.env.NICIA_KEY ?? ""}`, "content-type": "application/json", }, body: JSON.stringify({ name: tenantId }), }); return handle; // your handle is the address — nothing to store, nothing to map}Because your handle is the address and PUT is idempotent, there is no
id-mapping table, no create/get branch, and no duplicate Brain to reconcile. See
One Brain per customer.