The XRAY Task Inbox API lets you create, read, update, and triage tasks programmatically. All endpoints return JSON.
Authentication
Obtaining an API Key
API keys are configured server-side via the API_KEY_MAP environment variable. Each key maps to an email address and display name:
API_KEY_MAP=your-secret-key-here:you@xray.tech:Your Name
To get an API key:
- Ask a system administrator to add an entry to the
API_KEY_MAP environment variable on the server
- The format is
key:email:name — multiple entries are comma-separated
- Your tasks will be scoped to the email address associated with your key
Using Your API Key
Include the X-API-Key header in every request:
curl -H "X-API-Key: your-secret-key-here" \
-H "Content-Type: application/json" \
https://tasks.xray.tech/api/tasks
Web Authentication
Web users authenticate via Google OAuth. Sign in at the app root (/) with your @xray.tech account. The session cookie is sent automatically with browser requests.
Auth Check
GET /auth/me
Returns the current user or 401 if not authenticated.
// 200 OK
{ "user": { "email": "mark@xray.tech", "name": "Mark Campos" } }
// 401 Unauthorized
{ "error": "Not authenticated" }
Endpoints
GET /api/tasks
List inbox tasks (Status = "Backlog", Triage Status = "New") scoped to the authenticated user.
Example
curl -H "X-API-Key: your-key" https://tasks.xray.tech/api/tasks
Response
{
"tasks": [
{
"id": "recXXXXXXXXXXXXXX",
"title": "Update onboarding docs",
"description": "The onboarding guide needs updating for new hires",
"status": "Backlog",
"priority": "Normal",
"triageStatus": "New",
"origin": "Human",
"originDetail": "Mark via Slack",
"triageNotes": "",
"assignedTo": { "id": "usr...", "email": "mark@xray.tech", "name": "Mark Campos" },
"requestedBy": null,
"project": [],
"dueDate": null,
"startDate": null,
"hoursEstimated": null,
"hoursUsed": null,
"createdAt": "2026-03-10T14:30:00.000Z"
}
]
}
GET /api/tasks/:id
Get a single task by its Airtable record ID.
Example
curl -H "X-API-Key: your-key" https://tasks.xray.tech/api/tasks/recXXXXXXXXXXXXXX
Response
{ "task": { "id": "recXXXXXXXXXXXXXX", "title": "...", ... } }
POST /api/tasks
Create a new inbox task. Sets Status = "Backlog" and Triage Status = "New" automatically.
Request Body
| Field | Type | Required | Notes |
title | string | Yes | Max 120 characters |
description | string | No | Max 500 characters |
origin | string | No | Default: "Human". Options: Human, AI Agent, Automation |
originDetail | string | No | E.g., "Claude Code", "Zapier webhook" |
assignedTo | string | No | Email address. Defaults to authenticated user |
priority | string | No | Default: "Normal". Options: Normal, High, Urgent |
project | string | No | Airtable record ID of a project |
Example — Minimal
curl -X POST \
-H "X-API-Key: your-key" \
-H "Content-Type: application/json" \
-d '{"title": "Review Q1 metrics"}' \
https://tasks.xray.tech/api/tasks
Example — Full
curl -X POST \
-H "X-API-Key: your-key" \
-H "Content-Type: application/json" \
-d '{
"title": "Update client proposal",
"description": "Revise the SOW section with new pricing",
"origin": "AI Agent",
"originDetail": "Claude Code",
"priority": "High",
"assignedTo": "mark@xray.tech"
}' \
https://tasks.xray.tech/api/tasks
Response (201 Created)
{ "ok": true, "task": { "id": "recNEW...", "title": "Update client proposal", ... } }
Error Response (400)
{ "error": "Validation failed", "fields": { "title": "Required" } }
PATCH /api/tasks/:id
Partial update — only include fields you want to change.
Updatable Fields
| Field | Type | Notes |
title | string | |
description | string | |
priority | string | Normal, High, Urgent |
status | string | Backlog, In Progress, Done, etc. |
triageStatus | string | New, Accepted, Rejected, Needs More Info |
triageNotes | string | |
dueDate | string | Format: YYYY-MM-DD |
startDate | string | Format: YYYY-MM-DD |
hoursEstimated | number | |
assignedTo | string | Email address (e.g., someone@xray.tech) |
project | string | Airtable record ID |
originDetail | string | |
Example — Enrich a task
curl -X PATCH \
-H "X-API-Key: your-key" \
-H "Content-Type: application/json" \
-d '{
"dueDate": "2026-03-15",
"hoursEstimated": 4,
"priority": "High"
}' \
https://tasks.xray.tech/api/tasks/recXXXXXXXXXXXXXX
Example — Mark as done
curl -X PATCH \
-H "X-API-Key: your-key" \
-H "Content-Type: application/json" \
-d '{"status": "Done", "triageStatus": "Accepted"}' \
https://tasks.xray.tech/api/tasks/recXXXXXXXXXXXXXX
POST /api/tasks/:id/accept
Accept a task and link it to a project.
Request Body
| Field | Type | Required |
projectId | string | Yes |
Example
curl -X POST \
-H "X-API-Key: your-key" \
-H "Content-Type: application/json" \
-d '{"projectId": "recPROJECT123"}' \
https://tasks.xray.tech/api/tasks/recXXXXXXXXXXXXXX/accept
POST /api/tasks/:id/reject
Reject a task with a reason.
Request Body
| Field | Type | Required |
reason | string | Yes |
Example
curl -X POST \
-H "X-API-Key: your-key" \
-H "Content-Type: application/json" \
-d '{"reason": "Duplicate of existing task"}' \
https://tasks.xray.tech/api/tasks/recXXXXXXXXXXXXXX/reject
POST /api/tasks/:id/needs-info
Request more information before triaging.
Request Body
| Field | Type | Required |
note | string | Yes |
Example
curl -X POST \
-H "X-API-Key: your-key" \
-H "Content-Type: application/json" \
-d '{"note": "Which client is this for?"}' \
https://tasks.xray.tech/api/tasks/recXXXXXXXXXXXXXX/needs-info
GET /api/projects?q=search
Search projects by name (min 2 characters). Returns up to 10 matches.
Example
curl -H "X-API-Key: your-key" "https://tasks.xray.tech/api/projects?q=onboard"
Response
{ "projects": [{ "id": "recPROJECT123", "name": "Client Onboarding v2" }] }
GET /health
Health check (no auth required).
{ "status": "ok", "timestamp": "2026-03-10T15:00:00.000Z" }