Skip to main content

Quickstart

You need three things to send a chat request:

  1. An API key with the chat:companion scope.
  2. A vector store (an Upstash Vector index) configured on your account.
  3. A request describing the persona and the conversation so far.

Base URL

All client endpoints live under https://api.phantomrouter.ai, with the /api/v1 prefix.

1. Authenticate

Every request carries your key as a Bearer token:

export PHANTOM_KEY="sk_your_api_key"
curl https://api.phantomrouter.ai/api/v1/me/vector-store \
-H "Authorization: Bearer $PHANTOM_KEY"

If the key is valid but no store is configured yet, you get 404 NOT_FOUND - that's expected, you'll fix it in the next step. See Authentication for how keys and scopes work.

2. Configure your vector store

Phantom writes memories to your Upstash Vector index. Point it at the index's REST URL and token (a 1536-dimension index matching the default embedding model). Prefer a UI? Connect it from the console instead - see Connect your vector store for a screenshot walkthrough.

curl -X PUT https://api.phantomrouter.ai/api/v1/me/vector-store \
-H "Authorization: Bearer $PHANTOM_KEY" \
-H "Content-Type: application/json" \
-d '{
"provider": "upstash",
"url": "https://your-index.upstash.io",
"token": "your-upstash-rest-token"
}'

Phantom test-probes the connection before saving and encrypts the token at rest. See the vector store reference for details and constraints.

3. Send a chat turn

curl -X POST https://api.phantomrouter.ai/api/v1/companion/chat \
-H "Authorization: Bearer $PHANTOM_KEY" \
-H "Content-Type: application/json" \
-d '{
"chat_id": "user-42",
"persona": {
"name": "Luna",
"bio": "A warm, witty companion who loves astronomy and late-night talks.",
"chat_style": "playful, curious"
},
"messages": [
{ "role": "user", "content": "Hey Luna! I just hiked Mount Rainier. I'm Sam, by the way." }
]
}'

A successful response:

{
"reply": "Sam! Rainier is no joke - those switchbacks earn the view. ...",
"chat_id": "user-42",
"moderation": { "inbound_prohibited": false, "outbound_filtered": false },
"memory": { "retrieved_count": 0, "profile_used": false },
"extraction_enqueued": false
}

The first turn retrieves nothing (the store is empty) and may not extract yet - memory extraction is cadence-gated (by default every 4 user turns). Keep the same chat_id across turns and Phantom builds up a memory of "Sam" and "Mount Rainier" that surfaces in later conversations.

4. See it work

Reuse the same chat_id across turns and Phantom accumulates memory about the user. A few turns later, ask a follow-up and watch memory.retrieved_count climb as earlier turns surface. The Playground is the fastest way to drive this interactively - send turns and inspect each request and response live.

Next steps