API Reference

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 can be generated directly from the web interface:

  1. Sign in to the web app with your @xray.tech account.
  2. Navigate to the Settings tab in the main navigation.
  3. Enter a name for your key (e.g. "Zapier Integration") and click Generate New Key.
  4. Copy the generated secret key. Keep it safe—it will not be shown again.

Note for Administrators: Global machine keys can still be hardcoded via the API_KEY_MAP environment variable if desired (format: key:email:Name).

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

FieldTypeRequiredNotes
titlestringYesMax 120 characters
descriptionstringNoMax 500 characters
originstringNoDefault: "Human". Options: Human, AI Agent, Automation
originDetailstringNoE.g., "Claude Code", "Zapier webhook"
assignedTostringNoEmail address. Defaults to authenticated user
prioritystringNoDefault: "Normal". Options: Normal, High, Urgent
projectstringNoAirtable 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

FieldTypeNotes
titlestring
descriptionstring
prioritystringNormal, High, Urgent
statusstringBacklog, In Progress, Done, etc.
triageStatusstringNew, Accepted, Rejected, Needs More Info
triageNotesstring
dueDatestringFormat: YYYY-MM-DD
startDatestringFormat: YYYY-MM-DD
hoursEstimatednumber
assignedTostringEmail address (e.g., someone@xray.tech)
projectstringAirtable record ID
originDetailstring

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

FieldTypeRequired
projectIdstringYes

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

FieldTypeRequired
reasonstringYes

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

FieldTypeRequired
notestringYes

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 /api/clients

List all clients in the system for contextual dropdowns or filtering.

Example

curl -H "X-API-Key: your-key" "https://tasks.xray.tech/api/clients"

Response

{ "clients": [{ "id": "recCLIENT123", "name": "ACME Corp" }] }

GET /api/meetings/recent

Fetch recent meetings. By default, it returns meetings you attended or created.

Parameters

ParamDescription
allSet to true to fetch all meetings globally.
clientAirtable Client Record ID or Client Name string.
start / endISO Date boundaries (e.g. 2025-01-01)

Example

curl -H "X-API-Key: your-key" "https://tasks.xray.tech/api/meetings/recent?all=true&client=recCLIENT123"

Response

{
  "meetings": [
    {
      "id": "recMEETING123",
      "name": "Weekly Sync with ACME",
      "date": "2026-03-25T10:00:00.000Z",
      "duration": 3600,
      "link": { "label": "View Transcript", "url": "https://otter.ai/..." },
      "project": ["recPROJECT123"],
      "projectName": ["ACME Q1 Deliverables"],
      "client": ["recCLIENT123"],
      "clientName": ["ACME Corp"],
      "users": ["mark@xray.tech"],
      "summary": "Discussed the new onboarding flow.",
      "keyProgress": "Frontend components are complete.",
      "decisionsMade": "We will use Bolt.js for the Slack app.",
      "nextActions": "- Mark to finalize the API docs.\n- Jane to deploy to staging.",
      "actionable": "# Raw Action Items Markdown..."
    }
  ]
}

GET /health

Health check (no auth required).

{ "status": "ok", "timestamp": "2026-03-10T15:00:00.000Z" }

Error Responses

All errors return a JSON object with an error field:

StatusMeaningExample
400Bad request / validation{ "error": "Validation failed", "fields": { "title": "Required" } }
401Not authenticated{ "error": "Not authenticated" }
404Not found{ "error": "Task not found" }
502Airtable upstream error{ "error": "Failed to fetch tasks from Airtable" }