Quickstart
In this tutorial you store two facts about a project’s database, months apart, and then ask Alvia which database the project uses. You see Alvia return the fact that applies now, not both facts. It takes about ten minutes.
Try it in the dashboard first
Section titled “Try it in the dashboard first”To see Alvia answer before you write code, open the dashboard, then Demo Project, then Playground. The Demo Project holds about 25 sample memories about Tidepool, a fictional habit-tracking app, including facts that changed and two that contradict each other. Choose Context and ask “Which database does Tidepool’s backend use?” or “How many habits does the free tier allow?”. The Playground shows each call as code in every REST language.
Playground calls use your normal read and write allowances. The Demo Project and its sample memories sit outside the project limit and the stored-memory limit.
Create a project and an API key
Section titled “Create a project and an API key”-
Sign in to the dashboard and create a project. A project holds its own memories, apart from every other project.
-
In the project, create an API key and copy it now: Alvia stores only a hash of it, so the dashboard shows the full key this once. The key starts with
sk-mem-. -
Save the key in an environment variable, so that it stays out of your code:
Terminal export ALVIA_API_KEY="sk-mem-..."
Store the first fact
Section titled “Store the first fact”Send the first fact with POST /v1/memories. The occurred_at field says when the fact was
true: here, March 2026. In Python, Node.js and C#, keep all the code on this page in one script.
In Node.js, name it quickstart.mjs, so that await works at the top level, and run it with
node quickstart.mjs. In Go, add the code of each later step at the end of main.
curl https://api.alvia.ai/v1/memories \ -H "Authorization: Bearer $ALVIA_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "content": "The Atlas service uses MySQL 8 as its primary database.", "occurred_at": "2026-03-02T09:00:00Z" }'import osimport requests
API_URL = "https://api.alvia.ai"HEADERS = {"Authorization": f"Bearer {os.environ['ALVIA_API_KEY']}"}
first = requests.post( f"{API_URL}/v1/memories", headers=HEADERS, json={ "content": ( "The Atlas service uses MySQL 8 as its primary database." ), "occurred_at": "2026-03-02T09:00:00Z", }, timeout=30,)first.raise_for_status() # 202 Accepted, empty bodyconst API_URL = "https://api.alvia.ai";const HEADERS = { Authorization: `Bearer ${process.env.ALVIA_API_KEY}`, "Content-Type": "application/json",};
const first = await fetch(`${API_URL}/v1/memories`, { method: "POST", headers: HEADERS, body: JSON.stringify({ content: "The Atlas service uses MySQL 8 as its primary database.", occurred_at: "2026-03-02T09:00:00Z", }),});// 202 Accepted, empty bodyif (!first.ok) { throw new Error(`${first.status}: ${await first.text()}`);}package main
import ( "bytes" "encoding/json" "fmt" "io" "log" "net/http" "os" "time")
const apiURL = "https://api.alvia.ai"
var client = &http.Client{Timeout: 30 * time.Second}
// post sends a JSON body to Alvia. It returns the status code and the// response body.func post(path string, body any) (int, []byte, error) { payload, err := json.Marshal(body) if err != nil { return 0, nil, err } req, err := http.NewRequest(http.MethodPost, apiURL+path, bytes.NewReader(payload)) if err != nil { return 0, nil, err } key := os.Getenv("ALVIA_API_KEY") req.Header.Set("Authorization", "Bearer "+key) req.Header.Set("Content-Type", "application/json") resp, err := client.Do(req) if err != nil { return 0, nil, err } defer resp.Body.Close() data, err := io.ReadAll(resp.Body) return resp.StatusCode, data, err}
func main() { fact := "The Atlas service uses MySQL 8 as its primary database." status, body, err := post("/v1/memories", map[string]string{ "content": fact, "occurred_at": "2026-03-02T09:00:00Z", }) if err != nil { log.Fatal(err) } if status != http.StatusAccepted { log.Fatalf("%d: %s", status, body) } fmt.Println("Accepted:", status)}using System.Net;using System.Net.Http.Json;using System.Text.Json;
var key = Environment.GetEnvironmentVariable("ALVIA_API_KEY");using var http = new HttpClient();http.BaseAddress = new Uri("https://api.alvia.ai");http.Timeout = TimeSpan.FromSeconds(30);http.DefaultRequestHeaders.Authorization = new("Bearer", key);
var fact = "The Atlas service uses MySQL 8 as its primary database.";var first = await http.PostAsJsonAsync("/v1/memories", new{ content = fact, occurred_at = "2026-03-02T09:00:00Z",});first.EnsureSuccessStatusCode(); // 202 Accepted, empty bodyAlvia answers 202 with an empty body. It has accepted the text and forms the memory in the
background.
Store the change
Section titled “Store the change”Six months later, the team moves Atlas to a new database. Send that fact with its own date:
curl https://api.alvia.ai/v1/memories \ -H "Authorization: Bearer $ALVIA_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "content": "The Atlas service moved its primary database from MySQL 8 to PostgreSQL 17.", "occurred_at": "2026-09-23T14:00:00Z" }'change = requests.post( f"{API_URL}/v1/memories", headers=HEADERS, json={ "content": ( "The Atlas service moved its primary database " "from MySQL 8 to PostgreSQL 17." ), "occurred_at": "2026-09-23T14:00:00Z", }, timeout=30,)change.raise_for_status() # 202 Accepted, empty bodyconst change = await fetch(`${API_URL}/v1/memories`, { method: "POST", headers: HEADERS, body: JSON.stringify({ content: "The Atlas service moved its primary database " + "from MySQL 8 to PostgreSQL 17.", occurred_at: "2026-09-23T14:00:00Z", }),});// 202 Accepted, empty bodyif (!change.ok) { throw new Error(`${change.status}: ${await change.text()}`);} fact = "The Atlas service moved its primary database " + "from MySQL 8 to PostgreSQL 17." status, body, err = post("/v1/memories", map[string]string{ "content": fact, "occurred_at": "2026-09-23T14:00:00Z", }) if err != nil { log.Fatal(err) } if status != http.StatusAccepted { log.Fatalf("%d: %s", status, body) } fmt.Println("Accepted:", status)fact = "The Atlas service moved its primary database " + "from MySQL 8 to PostgreSQL 17.";var change = await http.PostAsJsonAsync("/v1/memories", new{ content = fact, occurred_at = "2026-09-23T14:00:00Z",});change.EnsureSuccessStatusCode(); // 202 Accepted, empty bodyAlvia compares the new fact with the memories it already holds. When it finds that a new fact replaces an earlier one, it records the new fact as the next version of the same memory. The earlier version stays in the memory’s history.
Ask for context
Section titled “Ask for context”Formation finishes in less than a minute. Then ask a
question with POST /v1/memories/context:
curl https://api.alvia.ai/v1/memories/context \ -H "Authorization: Bearer $ALVIA_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "query": "Which database does the Atlas service use?" }'answer = requests.post( f"{API_URL}/v1/memories/context", headers=HEADERS, json={"query": "Which database does the Atlas service use?"}, timeout=30,)if answer.status_code == 404: print("No context yet. Try again in a minute.")else: answer.raise_for_status() print(answer.json()["context"])const answer = await fetch(`${API_URL}/v1/memories/context`, { method: "POST", headers: HEADERS, body: JSON.stringify({ query: "Which database does the Atlas service use?", }),});if (answer.status === 404) { console.log("No context yet. Try again in a minute.");} else if (!answer.ok) { throw new Error(`${answer.status}: ${await answer.text()}`);} else { console.log((await answer.json()).context);} question := "Which database does the Atlas service use?" status, body, err = post("/v1/memories/context", map[string]string{ "query": question, }) if err != nil { log.Fatal(err) } switch status { case http.StatusNotFound: fmt.Println("No context yet. Try again in a minute.") case http.StatusOK: var answer struct { Context string `json:"context"` } if err := json.Unmarshal(body, &answer); err != nil { log.Fatal(err) } fmt.Println(answer.Context) default: log.Fatalf("%d: %s", status, body) }var answer = await http.PostAsJsonAsync( "/v1/memories/context", new { query = "Which database does the Atlas service use?" });if (answer.StatusCode == HttpStatusCode.NotFound){ Console.WriteLine( "No context yet. Try again in a minute.");}else{ answer.EnsureSuccessStatusCode(); var body = await answer.Content.ReadFromJsonAsync<JsonElement>(); Console.WriteLine(body.GetProperty("context").GetString());}Alvia returns one to three sentences. Your answer reads like this one:
{ "context": "The Atlas service uses PostgreSQL 17 as its primary database. It moved from MySQL 8 on September 23, 2026."}The answer names the current database and the change, where a search over stored text would return MySQL 8 as an equal option.
See what Alvia kept
Section titled “See what Alvia kept”In the dashboard, open the project’s Memories, then the Atlas memory. Its History tab lists both versions, each with when it occurred, when it was recorded, how Alvia classified it (Supersession for a fact that replaces another) and the classifier’s explanation. Your application reads the same history through the API.
If something goes wrong
Section titled “If something goes wrong”| Error | What to do |
|---|---|
401 unauthorized |
The key is missing, mistyped, expired or revoked. Check that ALVIA_API_KEY is set without printing its value. |
400 validation_error |
The body has a mistake. The errors object names each field. |
400 invalid_argumentoccurred_at_in_future |
The occurred_at value is in the future. Use a past time, with its time zone offset. |
404 not_found |
From the context call: the memories are still forming. Try again in a minute. |
429 rate_limit_exceeded |
You sent requests too fast. Wait for the seconds in the Retry-After header. |
See Troubleshooting and Errors.
Next steps
Section titled “Next steps”- Connect a coding agent with MCP: give Claude Code, Codex or Cursor memory across sessions
- Add memory to an LLM app: fetch context before each model call and send each turn back
- Build with an AI assistant: have a coding assistant add Alvia to your app
- Filter memories: choose what real conversations contribute to memory before you connect your application
- Projects and scope: organize each user’s or agent’s memories
- Why memory for AI is hard: what this example avoided, and what else changes over time