AtlasWork, planned itself.

The AI-native, all-in-one work platform. Tasks, projects, CRM, contracts, and analytics in one calm workspace.

All systems operational
  • SOC 2 II
  • ISO 27001
  • HIPAA
  • GDPR

Product

  • Overview
  • PDF tools
  • Diagram tools
  • People & HR
  • Integrations
  • Marketplace
  • Pricing

Resources

  • Guides
  • Glossary
  • Compare
  • Docs
  • API reference
  • Support
  • Changelog
  • Status

Company

  • About
  • Careers
  • Press
  • Contact

Legal & trust

  • Trust center
  • Security
  • Privacy
  • Terms
  • DPA
  • GDPR
  • SLA
  • Refunds
  • Google API data
Atlas, a product by wrxstack.com·© 2026 wrxstack·All rights reserved
PrivacyTermsSecurityStatus
Skip to documentation
Docs
Back to Atlas

Start here

  • Overview

Developer

  • REST API guide
  • Authentication
  • API reference
  • MCP (AI agents)
  • SDKs
  • Quick actions

Webhooks

  • Overview
  • Quickstart
  • Events
  • Payloads and headers
  • Security and signing
  • Delivery and retries
  • Managing via API

Connect

  • Connectors
  • Integrations

Product

  • Collaboration and chat

Reference

  • Glossary
  • Keyboard shortcuts
  • Module reference

Developer

REST API

Atlas exposes a hand-curated, hardened public REST surface under /v1/. One bearer header gets you in. This guide covers auth, success and error responses (every status code with an example body), rate limits, idempotency, pagination, and webhooks, and points you at the interactive reference for every route.

Start at the interactive reference

Every endpoint, parameter, scope, request body, and status code, rendered live from the OpenAPI spec with copyable request samples and a Try It console. This guide explains the concepts; the reference is the source of truth for each route.

Open the API reference

Browse every endpoint, parameter, schema, and error in a searchable three-column reference. It is CSP-safe and always reflects the live spec, so it never drifts from the deployed server.

Rendered live from https://api-atlas.wrxstack.com/v1/openapi.json.


Quickstart

Go from nothing to your first authenticated request in about a minute.

  1. 1

    Mint a Personal Access Token

    Open Settings, then API access, and click New token. Pick the narrowest scope set (start with tasks:read). The token is shown once and starts with atlas_pat_.
  2. 2

    Send your first request

    Pass the token as a bearer header and read your tasks. This lists the first 50 tasks in your workspace.
    curl -H "Authorization: Bearer atlas_pat_REPLACE_ME" \
      https://api-atlas.wrxstack.com/v1/tasks?limit=50
  3. 3

    Go deep in the reference

    Open the interactive reference to see every route, its parameters, and its full response shape, each with a request sample you can copy.

Keep tokens narrow

Start with read-only scopes and widen only when a call needs it. You can revoke and rotate a token at any time without touching the rest of your integration.

Authentication

Every /v1 request carries a bearer token. The same header accepts a Personal Access Token (atlas_pat_...) or a session JWT. PATs are the recommended path for server-to-server use because they are scope-bounded and revocable independently of any user session.

http
Authorization: Bearer atlas_pat_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Full authentication guide

This section is the quick version. For the complete story - minting, rotating, and revoking PATs, plus the OAuth 2.0 authorization-code + PKCE flow, refresh, introspection, revocation, and discovery - see Authentication. It also has a PAT vs OAuth comparison to help you pick.

Scopes are enforced per request

A PAT authenticates but a call still fails with 403 (insufficient_scope) if the token is missing the scope that route requires. The problem body lists requiredScopes and grantedScopes so you know exactly what to add. Session-JWT calls bypass the scope gate (the session is implicitly all-scopes). See the 403 example below.

Success responses

Successful calls return application/json (never problem+json). Reads answer 200; creates answer 201 with a Location header. List endpoints are always an { items, nextCursor } envelope, so a single item and a thousand share one shape. Every response also carries an x-request-id header for support tracing.

200

OK - GET /v1/tasks (paginated list)

Collection reads return the requested page under items plus an opaque nextCursor (null on the last page). Rate-limit headers ride along on every 2xx.

http
HTTP/1.1 200 OK
Content-Type: application/json
x-request-id: 3f1a9c02-7d4e-4b1a-9c8f-2a6b1e0d5f77
X-RateLimit-Class: read
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 299

{
  "items": [
    {
      "id": "tsk_01HW3T2K8X9Y2VPRZGQX9NDY1F",
      "projectId": "prj_01HW3S9QZ4M0V6B7C8D9E0F1G2",
      "title": "Review Q3 forecast",
      "status": "TODO",
      "priority": "HIGH",
      "dueOn": "2026-05-01T17:00:00Z",
      "assigneeId": "usr_01HW3RA2B3C4D5E6F7G8H9J0K1",
      "version": 1,
      "createdAt": "2026-04-18T09:12:44Z",
      "updatedAt": "2026-04-18T09:12:44Z"
    }
  ],
  "nextCursor": "eyJpZCI6InRza18wMUhXM1QifQ=="
}
201

Created - POST /v1/tasks (the created resource)

Creates return the full resource, including its server-assigned id, version, and timestamps, plus a Location header. Replaying the same Idempotency-Key returns this exact 201 again (see Idempotency).

http
HTTP/1.1 201 Created
Content-Type: application/json
Location: /v1/tasks/tsk_01HW3T2K8X9Y2VPRZGQX9NDY1F
x-request-id: 9b2c4d6e-1f38-4a5b-8c7d-0e9f1a2b3c4d

{
  "id": "tsk_01HW3T2K8X9Y2VPRZGQX9NDY1F",
  "projectId": "prj_01HW3S9QZ4M0V6B7C8D9E0F1G2",
  "title": "Review Q3 forecast",
  "status": "TODO",
  "priority": "HIGH",
  "dueOn": "2026-05-01T17:00:00Z",
  "assigneeId": null,
  "version": 1,
  "createdAt": "2026-04-18T09:12:44Z",
  "updatedAt": "2026-04-18T09:12:44Z"
}

Errors

Every non-2xx response uses one consistent envelope: RFC 9457 / RFC 7807 problem+json. Always branch on Content-Type - success is application/json, any error is application/problem+json - and read status from the body, not just the status line.

The error envelope

Five members are always present. The type URI is the stable, machine-readable identifier for the problem class (branch on it, not on the human copy); detail is the human message for this specific request. Generic problems use type: "about:blank" and lean on title. Specific problem types add extension members, called out per status below.

http
HTTP/1.1 403 Forbidden
Content-Type: application/problem+json
x-request-id: f47ac10b-58cc-4372-a567-0e02b2c3d479

{
  "type": "https://atlas.dev/errors/insufficient-scope",
  "title": "Insufficient scope",
  "status": 403,
  "detail": "This Personal Access Token is missing one of the required scopes: tasks:write.",
  "requiredScopes": ["tasks:write"],
  "grantedScopes": ["tasks:read"],
  "requestId": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
}
FieldTypeMeaning
typestring (uri)Stable identifier for the problem class. https://atlas.dev/errors/<slug> for known types, else about:blank.
titlestringShort, human summary of the problem type. Same for every instance of that type.
statusintegerThe HTTP status, mirrored in the body so it survives logging and proxies.
detailstringHuman explanation specific to this request. Safe to surface to developers.
requestIdstringCorrelation id, also returned in the x-request-id header. Quote it in support requests.

Extension members you will meet below: errors[] (422 validation, with a path, message, and code per field), requiredScopes / grantedScopes (403 insufficient scope), and rateLimit (429).

At a glance

StatusWhen you see itRetry?
400Malformed request or a value a storage constraint rejects.No, fix the request
401Missing, unknown, revoked, or expired token.No, re-auth
403Token lacks the required scope, or origin is blocked.No, widen the token
404Resource missing, or invisible to your tenant.No
409Unique collision or stale If-Match version.Yes, re-read then retry
422Body parsed but failed field validation.No, fix the fields
429Rate bucket exhausted. Retry-After header set.Yes, after Retry-After
500Server fault. Body is generic; requestId traces it.Yes, with backoff

Every status, with an example

400

Bad Request

The request itself is malformed - unparseable JSON, a value that a storage constraint rejects (for example a string that is too long), or a required value missing at the persistence layer. Field-level schema failures come back as 422 instead.

http
HTTP/1.1 400 Bad Request
Content-Type: application/problem+json
x-request-id: 1a2b3c4d-5e6f-4708-8192-a3b4c5d6e7f8

{
  "type": "about:blank",
  "title": "Bad Request",
  "status": 400,
  "detail": "One or more values are invalid.",
  "requestId": "1a2b3c4d-5e6f-4708-8192-a3b4c5d6e7f8"
}
401

Unauthorized

No bearer token, or the token is empty, unknown, revoked, or expired. Mint or rotate the PAT and retry. The detail narrows the cause (for example Personal access token revoked).

http
HTTP/1.1 401 Unauthorized
Content-Type: application/problem+json
x-request-id: 7c9e2f14-3a5b-4d6e-8f70-1b2c3d4e5f60

{
  "type": "about:blank",
  "title": "Unauthorized",
  "status": 401,
  "detail": "Invalid or expired access token",
  "requestId": "7c9e2f14-3a5b-4d6e-8f70-1b2c3d4e5f60"
}
403

Forbidden

The token is valid but not allowed to do this. The common case is a PAT missing a required scope; the body then carries requiredScopes and grantedScopes so you can widen the token. A browser origin outside the CORS allowlist also 403s.

http
HTTP/1.1 403 Forbidden
Content-Type: application/problem+json
x-request-id: f47ac10b-58cc-4372-a567-0e02b2c3d479

{
  "type": "https://atlas.dev/errors/insufficient-scope",
  "title": "Insufficient scope",
  "status": 403,
  "detail": "This Personal Access Token is missing one of the required scopes: tasks:write.",
  "requiredScopes": ["tasks:write"],
  "grantedScopes": ["tasks:read"],
  "requestId": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
}
404

Not Found

The resource does not exist, or it exists in another tenant your token cannot see. Atlas does not distinguish the two on purpose - a cross-tenant id is indistinguishable from a missing one, so ids never leak across tenants.

http
HTTP/1.1 404 Not Found
Content-Type: application/problem+json
x-request-id: 2d4f6a8c-0e13-4257-9b8d-6f0a1c3e5d70

{
  "type": "about:blank",
  "title": "Not Found",
  "status": 404,
  "detail": "The requested resource was not found.",
  "requestId": "2d4f6a8c-0e13-4257-9b8d-6f0a1c3e5d70"
}
409

Conflict

The write collides with existing state: a unique value already in use, an If-Match version that is now stale (optimistic concurrency), or a transient write conflict. Re-read the resource, merge, and retry with the fresh version.

http
HTTP/1.1 409 Conflict
Content-Type: application/problem+json
x-request-id: 8e0c2a46-9f7b-4d31-a0c5-2e4f6a8b0d13

{
  "type": "about:blank",
  "title": "Conflict",
  "status": 409,
  "detail": "The operation conflicted with a concurrent change. Please retry.",
  "requestId": "8e0c2a46-9f7b-4d31-a0c5-2e4f6a8b0d13"
}
422

Unprocessable Entity

The body parsed but failed schema validation. The response adds an errors array with one entry per failing field: its path, a human message, and a machine code. Fix the listed fields and resend.

http
HTTP/1.1 422 Unprocessable Entity
Content-Type: application/problem+json
x-request-id: 5b7d9f11-2c4e-4638-8a0b-1d3f5a7c9e02

{
  "type": "https://atlas.dev/errors/validation",
  "title": "Validation failed",
  "status": 422,
  "detail": "One or more fields failed validation",
  "errors": [
    {
      "path": "title",
      "message": "String must contain at least 1 character(s)",
      "code": "too_small"
    },
    {
      "path": "priority",
      "message": "Invalid enum value. Expected 'LOW' | 'MEDIUM' | 'HIGH'",
      "code": "invalid_enum_value"
    }
  ],
  "requestId": "5b7d9f11-2c4e-4638-8a0b-1d3f5a7c9e02"
}
429

Too Many Requests

You exhausted a per-tenant rate bucket (read, write, or ai). The response includes a Retry-After header (seconds) plus the X-RateLimit-* family, and a rateLimit object in the body. Honour Retry-After; it is authoritative.

http
HTTP/1.1 429 Too Many Requests
Content-Type: application/problem+json
Retry-After: 12
X-RateLimit-Class: write
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1746123456
x-request-id: 0c1d2e3f-4a5b-4c6d-8e9f-a0b1c2d3e4f5

{
  "type": "https://atlas.dev/errors/rate-limited",
  "title": "Rate limit exceeded",
  "status": 429,
  "detail": "Too many write requests for this tenant. Retry in 12s.",
  "rateLimit": {
    "class": "write",
    "limit": 60,
    "windowMs": 60000,
    "retryAfterSec": 12,
    "tier": "pro"
  },
  "requestId": "0c1d2e3f-4a5b-4c6d-8e9f-a0b1c2d3e4f5"
}
500

Internal Server Error

Something failed on our side. The body is deliberately generic - it never leaks internal detail - but the requestId (also in x-request-id) lets support trace the exact failure. Safe to retry with exponential backoff (300ms, 800ms, 2s).

http
HTTP/1.1 500 Internal Server Error
Content-Type: application/problem+json
x-request-id: a1b2c3d4-e5f6-4708-9a0b-1c2d3e4f5061

{
  "type": "about:blank",
  "title": "Internal Server Error",
  "status": 500,
  "detail": "An unexpected error occurred.",
  "requestId": "a1b2c3d4-e5f6-4708-9a0b-1c2d3e4f5061"
}

Rate limits

Every route is classified read, write, or ai. Each class has its own per-tenant bucket. The ceilings below are defaults; your tenant may have a higher limit configured.

ClassDefault ceilingApplies to
read300/mGET requests on /v1/* (excluding /v1/ai/*)
write60/mPOST/PATCH/PUT/DELETE on /v1/*
ai20/mAny /v1/ai/* call (read or write)

429 response shape

When you hit a bucket, Atlas returns 429 with Retry-After (seconds), X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset (Unix seconds when the bucket resets). Honour Retry-After; it is authoritative.

Idempotency

Every POST route accepts an Idempotency-Key header. Replaying the same key (same tenant) within 24h returns the original 2xx response verbatim, including the resource id. This is what makes retries safe on flaky networks.

bash
curl -X POST https://api-atlas.wrxstack.com/v1/tasks \
  -H "Authorization: Bearer atlas_pat_REPLACE_ME" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "projectId": "prj_...",
    "title": "Review Q3 forecast",
    "priority": "HIGH",
    "dueOn": "2026-05-01T17:00:00Z"
  }'

Use a fresh UUID per logical operation: uuidgen on the shell, randomUUID() in Node, or any stable hash you can re-derive on retry. Do not reuse a key for different requests; Atlas matches on the key, not the body.


Pagination

List endpoints return a cursor. Pass nextCursor back as ?cursor= to get the following page. Cursors are opaque, so never parse or modify them.

bash
# First page
curl -H "Authorization: Bearer atlas_pat_..." \
  "https://api-atlas.wrxstack.com/v1/tasks?limit=50"
#  { "items": [...], "nextCursor": "eyJpZCI6Li4ufQ==" }

# Next page
curl -H "Authorization: Bearer atlas_pat_..." \
  "https://api-atlas.wrxstack.com/v1/tasks?limit=50&cursor=eyJpZCI6Li4ufQ=="

Webhooks

Subscribe delivery URLs via /v1/webhooks. Atlas signs every payload with HMAC-SHA256 and retries failed deliveries automatically on a fixed schedule (60s, 5m, 30m, 2h, 12h).

http
POST https://your.app/atlas-webhook
content-type: application/json
x-atlas-event: task.created
x-atlas-webhook-signature: 3b8f...e21a
x-atlas-webhook-timestamp: 1783412096000
x-atlas-webhook-id: whd_5a1b2c3d
x-atlas-delivery: evt_01HW3T:0

Verify the canonical x-atlas-webhook-signature header, subscribe to events, and replay deliveries: the dedicated Webhooks guide covers events, payloads and headers, signature verification in five languages, and the full retry schedule end to end.


SDKs and clients

The official TypeScript client mirrors the REST surface 1:1. For AI agents, the MCP server wraps the same endpoints in a model-friendly tool catalogue.

typescript
import { createAtlasClient } from '@atlas/client';

const atlas = createAtlasClient({
  baseUrl: 'https://api-atlas.wrxstack.com',
  // PATs are passed verbatim, no refresh logic needed.
  getAccessToken: () => process.env.ATLAS_API_KEY ?? null,
});

const { items } = await atlas.tasks.list({ limit: 50 });
const created = await atlas.tasks.create({
  projectId: 'prj_...',
  title: 'Review Q3 forecast',
  priority: 'HIGH',
});

Building an AI agent integration? See the MCP setup guide for Claude Desktop, Cursor, and Cline configuration.


Downloads

All three artefacts are generated server-side from the same hand-written OpenAPI 3.1 source, so nothing is ever stale.

  • OpenAPI 3.1 specMachine-readable spec with x-required-scopes, x-ratelimit-class, and x-rate-limits extensions.openapi.json
  • Postman collectionPostman v2.1, grouped by tag, with bearer auth, Idempotency-Key, and sample bodies pre-wired.postman.json
  • Postman environmentCompanion environment template. Paste your PAT into apiKey and you are sending real requests.environment.json

FAQ

Can I use a session cookie or JWT instead of a PAT?
Yes, the bearer header accepts either. JWT-authenticated calls bypass the scope gate (the session is implicitly all-scopes). PATs are still recommended for server-to-server because they are tenant-scoped, scope-narrowed, and revocable independently of any user session.
Why does my POST occasionally return the same id twice?
You sent the same Idempotency-Key twice within 24h. That is by design: the second call returns the original 2xx response so you do not double-create. Use a fresh UUID for each logical create.
How do I update a task without overwriting concurrent edits?
Pass the task's current version field as If-Match: <version>. If the task changed in the meantime you get a 409; re-read, merge, and retry.
Is there a sandbox or staging environment?
Self-host Atlas with a separate Postgres for sandbox. The same OpenAPI spec applies; just point your PAT-minting client and baseUrl at the sandbox URL.
How do I get notified when the spec changes?
Watch the release notes; every public-API change is documented there. The spec also bumps info.version on breaking changes.

On this page

  • Interactive reference
  • Quickstart
  • Authentication
  • Success responses
  • Errors
  • Rate limits
  • Idempotency
  • Pagination
  • Webhooks
  • SDKs and clients
  • Downloads
  • FAQ