Browse the docs

API reference

Time and leave

The caller's own time, leave, expenses, and the workspace's goals.

My time

GET/v1/time

The caller's running timer and own time entries between two days (default the last 7, max 31). Never rates, costs or anyone else's time.

Requires time.read

Query parameters

  • fromstring

    YYYY-MM-DD; defaults to six days before to.

  • tostring

    YYYY-MM-DD; defaults to today in the caller's timezone.

Request
curl "https://atrix.dev/api/v1/time" \
  -H "Authorization: Bearer $ATRIX_TOKEN"
Response
{
  "timer": {
    "id": "cm4r6a1bc0008wq08k5m2p7xz",
    "startedAt": "2026-10-27T05:12:40.000Z",
    "projectId": "cm3y1k7mn0000ab07c3d5f8gh",
    "projectName": "Atrix AI",
    "issueId": "cm4c2n9qr0011de08f6h3j1kw",
    "issueTitle": "Fix invite dead end",
    "note": "",
    "billable": true
  },
  "todayMinutes": 48,
  "timezone": "Asia/Dubai",
  "entries": [
    {
      "id": "cm4r5t8yu0007wq08e2j9n4lb",
      "date": "2026-10-26",
      "minutes": 90,
      "projectId": "cm3y1k7mn0000ab07c3d5f8gh",
      "projectName": "Atrix AI",
      "issueId": null,
      "issueTitle": null,
      "note": "Onboarding review",
      "billable": true,
      "source": "MANUAL",
      "running": false,
      "locked": false,
      "invoiced": false,
      "start": "2026-10-26T05:00:00.000Z",
      "end": "2026-10-26T06:30:00.000Z"
    }
  ],
  "totalMinutes": 90
}

Log time

POST/v1/time/log

Logs time already worked on a day that is not in the future, optionally from a start time. Refused if that week is submitted or approved.

Requires time.write

Body

  • datestringrequired

    YYYY-MM-DD, not in the future.

  • minutesintegerrequired

    1 to 1440.

  • startstring

    HH:MM in the caller's timezone.

  • projectIdstring

    A product id, slug or name.

  • issueIdstring

    An issue id or title; its product is used.

  • notestring

    Up to 500 characters.

Request
curl -X POST "https://atrix.dev/api/v1/time/log" \
  -H "Authorization: Bearer $ATRIX_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "date": "…", "minutes": 1 }'
Response
{
  "entry": {
    "id": "cm4r5t8yu0007wq08e2j9n4lb",
    "date": "2026-10-26",
    "minutes": 90,
    "projectId": "cm3y1k7mn0000ab07c3d5f8gh",
    "projectName": "Atrix AI",
    "issueId": null,
    "issueTitle": null,
    "note": "Onboarding review",
    "billable": true,
    "source": "MANUAL",
    "running": false,
    "locked": false,
    "invoiced": false,
    "start": "2026-10-26T05:00:00.000Z",
    "end": "2026-10-26T06:30:00.000Z"
  },
  "overlap": false
}

Start my timer

POST/v1/time/timer/start

Starts the caller's timer, optionally on a product and/or issue. A timer already running is stopped and saved first.

Requires time.write

Body

  • projectIdstring

    A product id, slug or name.

  • issueIdstring

    An issue id or title; its product is used.

  • notestring

    Up to 500 characters.

Request
curl -X POST "https://atrix.dev/api/v1/time/timer/start" \
  -H "Authorization: Bearer $ATRIX_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "projectId": "cm9x2k1a0000", "issueId": "cm9x2k1a0000" }'
Response
{
  "timer": {
    "id": "cm4r6a1bc0008wq08k5m2p7xz",
    "startedAt": "2026-10-27T05:12:40.000Z",
    "projectId": "cm3y1k7mn0000ab07c3d5f8gh",
    "projectName": "Atrix AI",
    "issueId": "cm4c2n9qr0011de08f6h3j1kw",
    "issueTitle": "Fix invite dead end",
    "note": "",
    "billable": true
  },
  "stoppedPrevious": false
}

Stop my timer

POST/v1/time/timer/stop

Stops the caller's running timer and saves it as one or more entries, split at midnight. 422 when no timer is running.

Requires time.write

Request
curl -X POST "https://atrix.dev/api/v1/time/timer/stop" \
  -H "Authorization: Bearer $ATRIX_TOKEN"
Response
{
  "minutes": 52,
  "entryIds": [
    "cm4r6a1bc0008wq08k5m2p7xz"
  ],
  "discarded": false,
  "overlap": false
}

My leave

GET/v1/leave/balances

The caller's annual-leave balance for this year, the leave types they can request, their upcoming and pending requests, and who approves them.

Requires leave.read

Request
curl "https://atrix.dev/api/v1/leave/balances" \
  -H "Authorization: Bearer $ATRIX_TOKEN"
Response
{
  "balance": {
    "year": 2026,
    "entitled": 22,
    "carryIn": 3,
    "used": 9,
    "pending": 2,
    "remaining": 14
  },
  "types": [
    {
      "key": "ANNUAL",
      "name": "Annual leave",
      "paid": true,
      "requiresApproval": true
    }
  ],
  "upcoming": [
    {
      "id": "cm4s1e4fg0003pl08t7w2y5ua",
      "type": "ANNUAL",
      "typeName": "Annual leave",
      "start": "2026-11-16",
      "end": "2026-11-17",
      "startHalf": false,
      "endHalf": false,
      "days": 2,
      "status": "PENDING",
      "reason": null,
      "canCancel": true
    }
  ],
  "approvers": [
    "Moeid Saleem"
  ],
  "today": "2026-10-27"
}

Who is out today

GET/v1/leave/out-today

Names of colleagues out of office today. Never the type of leave, a reason or the dates.

Requires leave.read

Request
curl "https://atrix.dev/api/v1/leave/out-today" \
  -H "Authorization: Bearer $ATRIX_TOKEN"
Response
{
  "out": [
    {
      "name": "Sara Khan"
    }
  ]
}

Request leave

POST/v1/leave/requests

Asks for leave for the caller, counting working days and checking balance and clashes, then notifies approvers. With dryRun true it only returns the preview.

Requires leave.write

Body

  • typestringrequired

    A leave type key from /leave/balances, e.g. ANNUAL or SICK.

  • startstringrequired

    YYYY-MM-DD.

  • endstringrequired

    YYYY-MM-DD, not before start.

  • startHalfboolean

    Start with a half day (afternoon only).

  • endHalfboolean

    End with a half day (morning only).

  • reasonstring

    Up to 500 characters, shown to the caller and their approvers only.

  • dryRunboolean

    Preview without submitting.

Request
curl -X POST "https://atrix.dev/api/v1/leave/requests" \
  -H "Authorization: Bearer $ATRIX_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "type": "…", "start": "…", "end": "…" }'
Response
{
  "request": {
    "id": "cm4s1e4fg0003pl08t7w2y5ua",
    "status": "PENDING",
    "days": 2,
    "start": "2026-11-16",
    "end": "2026-11-17"
  },
  "preview": {
    "days": 2,
    "holidays": [],
    "weekendDays": 0,
    "remaining": 14,
    "after": 12,
    "needsApproval": true,
    "crowded": [
      {
        "date": "2026-11-16",
        "count": 1
      }
    ]
  },
  "notified": [
    "Moeid Saleem"
  ]
}

Cancel my leave

DELETE/v1/leave/requests/{id}

Cancels one of the caller's own pending or approved requests while the app still allows it; approvers are told.

Requires leave.write

Path parameters

  • idstringrequired

    The leave request id.

Request
curl -X DELETE "https://atrix.dev/api/v1/leave/requests/ID" \
  -H "Authorization: Bearer $ATRIX_TOKEN"
Response
{
  "cancelled": {
    "id": "cm4s1e4fg0003pl08t7w2y5ua",
    "start": "2026-11-16",
    "end": "2026-11-17",
    "days": 2
  }
}

My expenses

GET/v1/expenses

The caller's own claims with expenses dated in a window (default the last 30 days, max 92), with status and totals in minor units. Receipts are flagged, never returned.

Requires expenses.read

Query parameters

  • fromstring

    YYYY-MM-DD; defaults to 29 days before to.

  • tostring

    YYYY-MM-DD; defaults to today.

Request
curl "https://atrix.dev/api/v1/expenses" \
  -H "Authorization: Bearer $ATRIX_TOKEN"
Response
{
  "from": "2026-09-28",
  "to": "2026-10-27",
  "receiptRequiredAboveMinor": 5000,
  "claims": [
    {
      "id": "cm4t3g7hj0001mn08r4s6v9xc",
      "title": "October expenses",
      "status": "SUBMITTED",
      "currency": "USD",
      "claimTotalMinor": 4250,
      "inRangeMinor": 4250,
      "submittedAt": "2026-10-20T11:03:00.000Z",
      "decidedAt": null,
      "decisionNote": null,
      "reimbursedAt": null,
      "blocker": null,
      "items": [
        {
          "id": "cm4t3g8kl0002mn08w1x3z5bd",
          "date": "2026-10-19",
          "merchant": "Careem",
          "category": "TRAVEL",
          "amountMinor": 4250,
          "note": "",
          "hasReceipt": false,
          "projectName": null
        }
      ]
    }
  ],
  "totalsMinorByCurrency": {
    "USD": 4250
  }
}

File an expense

POST/v1/expenses

Adds an expense for the caller and sends it for approval. If the amount needs a receipt, or it joins an open draft that already has expenses, it stays a DRAFT with submitted false.

Requires expenses.write

Body

  • datestringrequired

    YYYY-MM-DD, the day it was paid.

  • amountnumberrequired

    Positive, in major units, e.g. 12.50.

  • currencystringrequired

    A three-letter code, e.g. USD.

  • categoryenumrequired

    The expense category.

    TRAVELMEALSSOFTWAREEQUIPMENTOTHER

  • merchantstringrequired

    1-80 characters.

  • notestring

    Up to 400 characters.

Request
curl -X POST "https://atrix.dev/api/v1/expenses" \
  -H "Authorization: Bearer $ATRIX_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "date": "…", "amount": 1, "currency": "…", "category": "TRAVEL", "merchant": "…" }'
Response
{
  "claimId": "cm4t3g7hj0001mn08r4s6v9xc",
  "itemId": "cm4t3g8kl0002mn08w1x3z5bd",
  "submitted": true,
  "status": "SUBMITTED",
  "message": "Sent for approval."
}

Delete a draft claim

DELETE/v1/expenses/{id}

Deletes one of the caller's own DRAFT claims and the expenses in it. Anything sent, approved or paid is refused.

Requires expenses.write

Path parameters

  • idstringrequired

    The claim id.

Request
curl -X DELETE "https://atrix.dev/api/v1/expenses/ID" \
  -H "Authorization: Bearer $ATRIX_TOKEN"
Response
{
  "deleted": "cm4t3g7hj0001mn08r4s6v9xc"
}

Send a draft claim

POST/v1/expenses/{id}/submit

Sends one of the caller's own DRAFT claims for approval. 404 if it is not theirs, 409 if already sent, 422 when it cannot be sent yet (e.g. a required receipt is missing).

Requires expenses.write

Path parameters

  • idstringrequired

    The claim id.

Request
curl -X POST "https://atrix.dev/api/v1/expenses/ID/submit" \
  -H "Authorization: Bearer $ATRIX_TOKEN"
Response
{
  "claimId": "cm4t3g7hj0001mn08r4s6v9xc",
  "submitted": true,
  "status": "SUBMITTED",
  "message": "Sent for approval."
}

Attach a receipt

POST/v1/expenses/items/{itemId}/receipt

Attaches or replaces the receipt on one of the caller's own draft expenses, as multipart file or raw bytes (JPEG, PNG, WebP, HEIC or PDF, up to 8 MB). 404 not theirs, 409 no longer a draft, 413 too large, 415 wrong type, 429 over the day's count.

Requires expenses.write

Path parameters

  • itemIdstringrequired

    The expense item id.

Body

  • filefile

    The receipt as a multipart/form-data part; or send the raw bytes as the body instead.

Request
curl -X POST "https://atrix.dev/api/v1/expenses/items/ITEMID/receipt" \
  -H "Authorization: Bearer $ATRIX_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "file": "…" }'
Response
{
  "claimId": "cm4t3g7hj0001mn08r4s6v9xc",
  "itemId": "cm4t3g8kl0002mn08w1x3z5bd",
  "hasReceipt": true,
  "receipt": {
    "mime": "image/jpeg",
    "name": "careem-receipt.jpg"
  }
}

List goals

GET/v1/goals

Goals whose period overlaps a window (default this quarter), with owner, status, rolled-up progress 0-100 and whether a check-in is due. Other people's private goals are never returned.

Requires goals.read

Query parameters

  • fromstring

    YYYY-MM-DD; defaults to the start of this quarter.

  • tostring

    YYYY-MM-DD; defaults to the end of this quarter.

  • mineboolean

    Only goals the caller owns.

  • statusenum

    Only goals with this status.

    ON_TRACKAT_RISKOFF_TRACKDONE

Request
curl "https://atrix.dev/api/v1/goals" \
  -H "Authorization: Bearer $ATRIX_TOKEN"
Response
{
  "period": {
    "start": "2026-10-01",
    "end": "2026-12-31"
  },
  "goals": [
    {
      "id": "cm4u8j2kl0004qr08h6n1p3ty",
      "title": "Reach 50 paying workspaces",
      "level": "COMPANY",
      "status": "AT_RISK",
      "ownerId": "cm3z8p1aa0000qs07h2k5t9we",
      "ownerName": "Sara Khan",
      "parentGoalId": null,
      "periodStart": "2026-10-01",
      "periodEnd": "2026-12-31",
      "visibility": "WORKSPACE",
      "progress": 38,
      "krCount": 3,
      "lastCheckInAt": "2026-10-20T09:00:00.000Z",
      "checkInDue": true,
      "mine": true,
      "canEdit": true
    }
  ]
}

Get a goal

GET/v1/goals/{id}

One goal with key results, recent check-ins, the goals above and below it, and linked products and issues. Deal amounts are null unless the caller may see deal values; a private goal that is not theirs is a 404.

Requires goals.read

Path parameters

  • idstringrequired

    The goal id.

Request
curl "https://atrix.dev/api/v1/goals/ID" \
  -H "Authorization: Bearer $ATRIX_TOKEN"
Response
{
  "id": "cm4u8j2kl0004qr08h6n1p3ty",
  "title": "Reach 50 paying workspaces",
  "status": "AT_RISK",
  "progress": 38,
  "description": "Self-serve conversions only.",
  "expected": 30,
  "keyResults": [
    {
      "id": "cm4u8j3mn0005qr08x2c4v6bn",
      "title": "Paying workspaces",
      "kind": "NUMBER",
      "source": "MANUAL",
      "unit": null,
      "progress": 38,
      "start": 0,
      "target": 50,
      "current": 19,
      "redacted": false,
      "note": null,
      "linkProject": null,
      "linkIssue": null
    }
  ],
  "checkIns": [
    {
      "id": "cm4u9a1bc0006qr08d4f7g9hj",
      "status": "AT_RISK",
      "note": "Trial conversion is slow.",
      "progress": 38,
      "at": "2026-10-20T09:00:00.000Z",
      "authorName": "Sara Khan"
    }
  ],
  "ancestors": [],
  "children": [],
  "links": [
    {
      "id": "cm4u9b2cd0007qr08k1l3m5np",
      "kind": "project",
      "label": "Atrix AI",
      "href": "/dashboard/projects/atrix-ai"
    }
  ]
}

Check in on a goal

POST/v1/goals/{id}/check-in

Posts a check-in as the caller with a status, note and optional new values for manual key results. Only the goal's owner or a workspace admin may.

Requires goals.write

Path parameters

  • idstringrequired

    The goal id.

Body

  • statusenumrequired

    The goal's status as of this check-in.

    ON_TRACKAT_RISKOFF_TRACKDONE

  • notestring

    Up to 2000 characters.

  • valuesobject[]

    Up to 12 of { krId, value }, new current values for manual key results.

Request
curl -X POST "https://atrix.dev/api/v1/goals/ID/check-in" \
  -H "Authorization: Bearer $ATRIX_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "status": "ON_TRACK" }'
Response
{
  "progress": 42
}