Most AI tutorials start with a setup checklist. Pick a model provider. Create an account. Wire up a vector database for memory. Stand up a server to hold conversation state. Glue it all together. Then, finally, you send a message.
Backboard skips all of that. One API call sends your first message. A thread, an assistant, memory, and routing across thousands of models are already running behind that single call. You do not assemble the stack. It is the stack.
Here is the whole thing.
Step 1: Get a key
Sign up at app.backboard.io, go to Settings then API Keys, and copy your key. New accounts get $5 in free credits for 30 days. No credit card.
That is the only setup. Keep your key server-side, never in frontend or mobile code.
Step 2: Send the message
Pick your language. Same call in all three.
Python
pip install backboard-sdk
import asyncio
from backboard import BackboardClient
async def main():
client = BackboardClient(api_key="YOUR_API_KEY")
response = await client.send_message(
"Hello! Tell me a fun fact about space."
)
print("Reply:", response.content)
print("Thread ID:", response.thread_id)
print("Assistant ID:", response.assistant_id)
asyncio.run(main())
JavaScript (Node 18+)
No install needed. Just fetch.
const response = await fetch("https://app.backboard.io/api/threads/messages", {
method: "POST",
headers: {
"X-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
content: "Hello! Tell me a fun fact about space.",
}),
});
const result = await response.json();
console.log("Reply:", result.content);
console.log("Thread ID:", result.thread_id);
console.log("Assistant ID:", result.assistant_id);
cURL
curl -X POST "https://app.backboard.io/api/threads/messages" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"content": "Hello! Tell me a fun fact about space."}'
Run it. You get a reply. That is your first AI message.
What just happened
You sent one string. Backboard did the rest:
-
Created a thread. The
thread_idin the response is a live conversation. Send the next message with it and the model remembers what was said. -
Created an assistant. The
assistant_idis a reusable profile. Attach memory, documents, and tools to it later without changing your call. -
Picked a model. No provider config required. It defaulted to
openai/gpt-4o. You can change that with two parameters, shown below.
No vector DB. No state server. No provider SDK. One call.
Continue the conversation
Pass the thread_id back. The model now has context.
follow_up = await client.send_message(
"Make it shorter.",
thread_id=response.thread_id,
)
print(follow_up.content) # knows you mean the space fact
That is stateful conversation with zero extra infrastructure.
Swap the model with two parameters
One key gives you thousands of models. Change the provider and model per message. Same thread, same code.
response = await client.send_message(
"Explain quantum computing simply.",
llm_provider="anthropic",
model_name="claude-sonnet-4-20250514",
)
Want a different model next turn? Change two strings. You are never locked to one provider.
Turn on memory
Add memory="Auto" and the assistant remembers facts across conversations, not just within one thread.
# Thread 1: tell it something
await client.send_message(
"My name is Sarah and I prefer dark mode.",
assistant_id="your-assistant-id",
memory="Auto",
)
# Thread 2, same assistant: it remembers
reply = await client.send_message(
"What do you remember about me?",
assistant_id="your-assistant-id",
memory="Auto",
)
print(reply.content) # "Your name is Sarah and you prefer dark mode."
Persistent memory, one parameter. No database to provision.
The point
The first call is one line because the platform is full-stack. Memory, model routing, RAG, and stateful threads sit behind a single key. You start with a working AI message, then turn on capabilities as you need them by adding parameters, not services.
Sign up, grab a key, and send your first message: app.backboard.io
Full docs: docs.backboard.io
Top comments (9)
Took you up on the suggestion from the Standard Model thread — went and read the docs and the API properly.
The one-call DX is genuinely clean. The fact that thread state, model routing, and memory are provisioned automatically behind a single endpoint removes the scaffolding problem that kills most AI tutorials before anyone gets to the interesting part. That's real value.
The limitation I was curious about after our exchange: the write-side. memory="Auto" handles persistence, but the question from the Standard Model thread is about what gets written and how causality gets encoded — not just whether the memory call succeeds. The sequencing problem the article describes (failure at T1, resolution at T2, causal link only visible in retrospect) lives at the ingestion layer, not the retrieval layer. Managed memory handles the second problem well. The first one requires hooks the managed layer probably doesn't expose by design.
That's not a criticism of the product. The abstraction is the point. It's just where the trade-off lives for anyone coming from a production agent architecture who wants to control the write path. For the audience this tutorial is aimed at, none of that matters yet. For the audience reading the Standard Model thread, it's the question
The single-call onboarding is very approachable. Once the abstraction hides provider/model setup, the next question teams usually ask is “how do I see and control spend by assistant/thread/user?”
Do you expose usage metadata or budget controls per thread/assistant/provider? That kind of attribution becomes important when the platform is choosing or routing models behind one simple API.
Good question, and the right one to ask the moment the abstraction hides routing.
Yes on both, and it's a full dashboard, not raw metadata you assemble yourself. You get spend and token economics per model and per provider (deepseek on openrouter, opus on bedrock, gpt on openai, side by side), a spend breakdown across token usage, vector reads, and memory writes, an input versus output split, subscription versus usage credits, biggest-usage days, and a filterable per-event log down to the individual call and its cost.
On control: you set pre-pay and usage limits, and budget tracks per assistant. The part I like most is what happens at the cap. Instead of erroring out, the assistant falls back to open-source free models until you add budget, so spend is bounded but the app keeps running. Building for multiple companies? Split it into separate organizations and attribution stays isolated per project.
Native grouping is by model and provider. To slice by thread or user, you pivot on the per-call metadata: every response carries model_provider, model_name, and total_tokens, and you hold thread_id and assistant_id, so those axes roll up cleanly.
That's the point of routing behind one API. You should be able to see and cap the spend, not just inherit it.

Thanks, this is exactly the level of detail I was hoping for. The fallback-at-cap behavior is a nice product decision too — bounded spend without turning a user-facing app into a hard failure path.
The per-call log + assistant/org boundaries answer most of the attribution question. For thread/user rollups, it sounds like the main requirement is keeping your own IDs consistently attached on the app side, then joining against the response metadata. That feels like the right trade-off for a one-call abstraction: dashboard for the common views, metadata for product-specific accounting.
This is Extremely easy to understand!!
Omg! You guys are dev.to. I am so happy to see an Ottawa company here :). I follow you guys on my LinkedIn account.
Daniel's write-side observation is the right frame. The abstraction this article is
selling — one call, managed memory, no infrastructure — is genuinely valuable for the
audience it's aimed at. But the trade-off he's naming is real: managed memory handles
the retrieval layer cleanly and leaves the ingestion layer mostly opaque.
The failure mode I've seen documented in production agent work is specific: the item
that gets written carries a metadata claim about its own authority — what it governs,
what actions it permits — and the system later reads that claim and acts on it. If the
claim was wrong at write-time (wrong resource class, wrong scope), retrieval works
perfectly, the execution gate reads a clean record, and the action fires on bad
information. The system never errors. It just does the wrong thing with confidence.
A managed write path doesn't solve that. It actually makes it harder to inspect,
because the ingestion hook isn't exposed by design. For anyone building agents where
the write-path needs to carry verified authority metadata — not just content — that's
where the abstraction runs out. Not a criticism of this product. Just where the
boundary is.
Step-by-step is underrated. Most 'first API call' articles skip over the 401 / rate-limit edge case that actually costs the first hour. Walking through it saves people from a 'why is this not working' tail.
Some comments may only be visible to logged-in visitors. Sign in to view all comments.