Get started
Quickstart
Send one signup to Qualia and read the briefing it writes, with curl, the TypeScript SDK, JavaScript, or Python.
In this quickstart you send one signup to the Qualia API, wait for Qualia to research it, and read the briefing. You need a terminal and about ten minutes.
Before you begin
- A Qualia account with briefing credits. Each briefing uses one credit. Check your balance in Settings → Billing.
- An ICP. You describe your ideal customer during onboarding, and you can refine it in Settings → ICP. Qualia needs it to score signups. Without it, you still get the briefing, but
scoreisnull. - A real work email to test with. Your own is the best choice, because you can check the briefing against what you know. The examples below use
anna@ridgeline.co, a fictional person.
1. Create an API key
- Open Settings → API Keys and select Create key.
- Name the key, for example
Quickstart, and select Create. - Copy the key. It starts with
qk_live_.
Save it as an environment variable in your terminal:
export QUALIA_API_KEY="qk_live_..."Check that the key works:
curl https://qualia.so/v1/ping \
-H "Authorization: Bearer $QUALIA_API_KEY"A working key returns 200 OK with "ok": true and the IDs of your organization and key. A 401 means the key is wrong or revoked. This check uses no credits and does not count toward your rate limit.
Keep your key on the server
Anyone with the key can send signups and read briefings for your organization. Call Qualia from your backend only. Never put the key in browser or mobile code.
2. Send a signup
Send the person's email with POST /v1/actors. Add a name if you have one, and a source label that tells you where the signup came from.
If you use the SDK, install it first with npm install @qualiaso/sdk. Put the TypeScript code from steps 2 and 3 in one file named quickstart.mts and run it with npx tsx quickstart.mts.
import { Qualia } from "@qualiaso/sdk";
const qualia = new Qualia({
auth: () => process.env.QUALIA_API_KEY!,
});
const { data, error, response } = await qualia.createActor({
body: {
email: "anna@ridgeline.co",
name: "Anna Park",
source: "quickstart",
},
});
if (error) {
throw new Error(`Qualia returned ${response.status}: ${JSON.stringify(error)}`);
}
console.log(data);Qualia replies with 201 Created and the new actor's ID:
{
"actorId": "q3ab8fnt2kzw7yx1mvd05hce",
"status": "created"
}Keep the actorId. You use it to read the result.
Sending the same email again is safe. You get the same actorId back with 200 OK and "status": "already_exists", and Qualia does not research the person twice.
3. Wait for the research to finish
Research runs in the background and can take a few minutes. Read the actor with GET /v1/actors/{actorId} and check status:
pendingorenriching: research is still running. Check again in 15 seconds.enriched: the briefing is ready.rejectedorfailed: there is no briefing. See If there is no briefing.
const { actorId } = data;
while (true) {
const result = await qualia.getActor({ path: { actorId } });
if (result.error) {
throw new Error(`Qualia returned ${result.response.status}`);
}
const actor = result.data;
if (actor.status !== "pending" && actor.status !== "enriching") {
console.log(actor);
break;
}
console.log(`Status: ${actor.status}. Checking again in 15 seconds.`);
await new Promise((resolve) => setTimeout(resolve, 15_000));
}With curl, run the command again every 15 seconds until status changes. While research runs, every research field in the response is null.
4. Read the briefing
When status is enriched, the response carries the briefing:
{
"id": "q3ab8fnt2kzw7yx1mvd05hce",
"email": "anna@ridgeline.co",
"name": "Anna Park",
"status": "enriched",
"rejectionReason": null,
"failureReason": null,
"score": 82,
"scoringStatus": "ok",
"title": "Head of Platform Engineering",
"linkedinUrl": "https://www.linkedin.com/in/annapark-ridgeline",
"location": "Denver, Colorado",
"companyName": "Ridgeline",
"companyDomain": "ridgeline.co",
"industry": "Logistics software",
"companyLocation": "Denver, Colorado",
"createdAt": "2026-09-29T14:02:11.482Z",
"enrichedAt": "2026-09-29T14:04:37.915Z",
"summary": "Anna Park leads platform engineering at Ridgeline, a logistics software company that builds route planning tools for regional freight carriers. She joined in 2024 after six years on infrastructure teams at larger SaaS companies.",
"highlights": [
"Ridgeline raised a Series A in June 2026.",
"Ridgeline lists four open backend and data engineering roles.",
"Anna spoke about moving Ridgeline's event pipeline to managed infrastructure at a DevOps meetup in 2025."
],
"bio": "Platform engineer focused on developer tooling and reliable data pipelines.",
"companyDescription": "Ridgeline builds route planning and dispatch software for regional freight carriers."
}The fields you will use most:
| Field | What it tells you |
|---|---|
summary | Who the person is and what their company does, in two or three sentences. |
highlights | Short facts worth knowing before you reach out. |
score | ICP fit from 0 to 100. Higher means a closer match to your ICP. |
title, companyName, industry | The person's role and employer. |
Any research field can be null if Qualia could not find it. Briefings and ICP fit explains every field. You can also open the signup in the dashboard to see the reasoning behind the score.
If there is no briefing
| Status | What happened | What to do |
|---|---|---|
rejected | Qualia declined the signup before researching it, for example a disposable email address. rejectionReason says why. Rejected signups use no credits. | Follow Handle rejected signups. |
failed | The research run hit an error. failureReason says why. Failed runs use no credits. | Qualia retries failed runs automatically. See Get briefing results. |
Next steps
Send signups from your backend
Add the call to your signup handler, send useful context, and backfill existing users.
Get briefing results
Poll for results in production and act on the score.
Deliver briefings to Slack
Post researched signups to a channel, filtered by score.
API reference
Authentication, limits, errors, and every endpoint.