API Reference
A REST API for managing projects and running jobs. Every endpoint lives under /api/v1 and authenticates with a per-user API key.
The same operations are available to AI agents through the MCP server.
Authentication
Generate a key in Settings. Pass it as a Bearer token. Keys are shown once at creation and stored hashed — generating a new key revokes the previous one.
curl https://lanceo.daho.ai/api/v1/me \
-H "Authorization: Bearer sk_..."Requests are rate limited to 60 per minute per user. Exceeding it returns 429.
Responses
Successful responses wrap the payload in data. Errors carry a machine-readable code and a human-readable message.
{ "data": { "id": 1, "name": "My project" } }
{ "error": { "code": "NOT_FOUND", "message": "Project not found" } }| Status | Meaning |
|---|---|
401 | Missing or invalid API key |
402 | Out of credits |
404 | Not found, or not yours |
409 | Duplicate project name |
429 | Rate limit exceeded |
Account
/api/v1/meThe authenticated user's profile, project count, and remaining credits.
{
"data": {
"id": "usr_...",
"name": "Ada Lovelace",
"email": "[email protected]",
"role": "user",
"billingModel": "credits",
"usage": {
"projects": { "current": 3, "limit": null },
"credits": { "current": 27, "costs": { "market_suggest": 1 } }
}
}
}Projects
A project groups jobs and assistant sessions. The metadata object is free-form — use it for your own domain fields without a migration.
/api/v1/projectsList your projects, most recently updated first.
/api/v1/projectsCreate a project. The slug is derived from the name; a duplicate name returns 409.
curl -X POST https://lanceo.daho.ai/api/v1/projects \
-H "Authorization: Bearer sk_..." \
-H "Content-Type: application/json" \
-d '{"name": "My project", "description": "Optional"}'/api/v1/projects/:projectIdFetch one project.
/api/v1/projects/:projectIdUpdate name, description, status (active or archived), or metadata.
curl -X PATCH https://lanceo.daho.ai/api/v1/projects/1 \
-H "Authorization: Bearer sk_..." \
-H "Content-Type: application/json" \
-d '{"status": "archived", "metadata": {"tier": "pro"}}'/api/v1/projects/:projectIdDelete a project and cascade-delete its jobs. Assistant sessions are kept but unlinked.
Jobs
Jobs run asynchronously and cost credits by type. Starting a job returns immediately with an id — poll for the result. If the handler fails, the job is marked failed and the credits are refunded automatically.
/api/v1/jobsStart a job. Returns 402 if you are out of credits, or 400 for an unknown type.
curl -X POST https://lanceo.daho.ai/api/v1/jobs \
-H "Authorization: Bearer sk_..." \
-H "Content-Type: application/json" \
-d '{
"projectId": 1,
"type": "summarize",
"input": { "text": "Some text to summarize." }
}'
{ "data": { "jobId": 42, "status": "queued" } }/api/v1/jobsList your jobs, newest first. Add ?projectId= to filter to one project.
/api/v1/jobs/:jobIdFetch a job's status and result. Status is queued, running, completed, or failed.
{
"data": {
"id": 42,
"projectId": 1,
"type": "summarize",
"status": "completed",
"input": { "text": "..." },
"result": { "summary": "...", "keyPoints": ["..."] },
"error": null,
"startedAt": "2026-09-01T12:00:01Z",
"finishedAt": "2026-09-01T12:00:09Z"
}
}Job types
The template ships one job type, summarize, which takes { text: string } and returns { summary, keyPoints }. It exists to demonstrate the pipeline and is meant to be replaced.
Register your own by adding an entry to JOB_HANDLERS in lib/jobs/handlers.ts. Nothing else needs to change — the credit accounting, refund path, completion email, and this endpoint all work off the registry.
export const JOB_HANDLERS: Record<string, JobHandler> = {
summarize,
myJob: async (input) => {
const { url } = myJobInput.parse(input);
return { processed: await doTheWork(url) };
},
};