# Atlas Service Desk — API Atlas Service Desk is a Jira-shaped. Its vocabulary is **Issues · Projects · Transitions · Sprints**. A record is an Issue identified by `issueKey` (for example `ATL-1042`). Base URL: `https://necogoode-systems.azurewebsites.net` Authentication: none (demo system, public). Content type: `application/json`. ## Identifiers this system emits | Identifier | Example | Notes | |---|---|---| | `issueKey` | ATL-1042 | the issue key in the project | | `reporter` | nadia.hollis@northwind-traders.example | the email address that raised the issue | > Atlas Service Desk holds **no reference to the CRM ContactId** and no employee number. Joining an Issue to a CRM Contact has to go through the email address. Any ContactId or employee number sent to this API is dropped and reported back in `droppedFields`. ## Endpoints ### `GET /api/servicedesk/records` List every Issue, newest first. ```bash curl -s https://necogoode-systems.azurewebsites.net/api/servicedesk/records ``` ```json { "ok": true, "count": 1, "records": [ { "issueKey": "ATL-1042", "createdAt": "2026-08-29T09:14:02.113Z", "eventCount": 2, "lastDelivery": { "httpStatus": 202, "receiptStatus": "accepted", "receiptReason": null } } ] } ``` ### `POST /api/servicedesk/records` Create an Issue. **Emits `atlas.issue.created`.** ```bash curl -s -X POST https://necogoode-systems.azurewebsites.net/api/servicedesk/records \ -H 'content-type: application/json' \ -d '{ "summary": "Equipment request for new starter Nadia Hollis", "project": "ATL", "issueType": "Service Request", "reporter": "nadia.hollis@northwind-traders.example", "assignee": "IT Support Centre", "priority": "Medium", "status": "Open", "sprint": "IT Ops Sprint 24", "labels": "onboarding,equipment" }' ``` ```json { "ok": true, "record": { "issueKey": "ATL-1042", ... }, "event": { "eventType": "atlas.issue.created", "externalEventId": "servicedesk-ATL-1042-0001", "delivery": { "httpStatus": 202, "receiptStatus": "accepted", "receiptReason": null } } } ``` Optional body keys on every write: `occurredAt` (ISO — backdates the record and the event) and `emit: false` (suppress the webhook). A create missing a required field returns `400 { "ok": false, "error": "missing required field(s): ..." }`. Identifiers belonging to another system are dropped before the record is written and returned in `droppedFields`. #### Body fields | Field | Type | Required | Notes | |---|---|---|---| | `summary` | string | yes | Summary | | `description` | string | no | Description | | `project` | string (enum) | no | Project — one of: `ATL`, `OPS`, `FAC` | | `issueType` | string (enum) | no | Issue type — one of: `Service Request`, `Task`, `Incident`, `Change` | | `reporter` | string | yes | Reporter (email) | | `assignee` | string | no | Assignee | | `priority` | string (enum) | no | Priority — one of: `Low`, `Medium`, `High`, `Critical` | | `status` | string (enum) | no | Status — one of: `Open`, `In Progress`, `In Review`, `Waiting for Reporter`, `Resolved`, `Closed` | | `sprint` | string | no | Sprint | | `labels` | string | no | Labels (comma separated) | | `equipmentPackage` | string (enum) | no | Equipment package — one of: `standard`, `specialist` | ### `GET /api/servicedesk/records/{id}` Read one Issue. 404 if unknown. ### `PATCH /api/servicedesk/records/{id}` Update an Issue. **Emits `atlas.issue.updated`** with a new `externalEventId` and the same `issueKey`. The payload carries `changedFields`, an array of the field names supplied. ```bash curl -s -X PATCH https://necogoode-systems.azurewebsites.net/api/servicedesk/records/ATL-1042 \ -H 'content-type: application/json' -d '{"priority":"High","assignee":"IT Support Centre"}' ``` ### `POST /api/servicedesk/records/{id}/transition` Move the Issue to another status in the project workflow. **Emits `atlas.issue.transitioned`.** ```bash curl -s -X POST https://necogoode-systems.azurewebsites.net/api/servicedesk/records/ATL-1042/transition \ -H 'content-type: application/json' -d '{"to":"In Review","comment":"Passed to IT Support Centre"}' ``` | Body field | Type | Required | Notes | |---|---|---|---| | `to` | string | yes | one of: `Open`, `In Progress`, `In Review`, `Waiting for Reporter`, `Resolved`, `Closed` | | `comment` | string | no | | ### `GET /api/servicedesk/records/{id}/events` Every event Atlas Service Desk has emitted for that record, oldest first, each with the SoloLift delivery outcome. ### `GET /api/servicedesk/events?limit=200` Every event this system has emitted, newest first. ### `POST /api/servicedesk/chaos` Emit a deliberately awkward event so anomaly detection can be exercised. `{ "mode": "out_of_order" | "duplicate" | "omit_field" | "unknown_type", "recordId": "ATL-1042" }` | Mode | What it does | |---|---| | `out_of_order` | emits `atlas.issue.updated` stamped 36h **before** the record was created | | `duplicate` | replays the record's last event verbatim, reusing its `externalEventId` | | `omit_field` | emits an update whose payload is missing the normally-present `reporter` | | `unknown_type` | emits `atlas.issue.frobnicated`, a type this system does not normally emit | ### `POST /api/servicedesk/seed` Generate backdated history. `{ "count": 20, "from": "2026-06-20T00:00:00Z", "to": "2026-08-29T00:00:00Z", "includeAction": true }` Optional: `fieldRatios` (probability an optional field is populated, e.g. `{"CostCentre":0.35}`), `specialistRatio`, `template` (values forced onto every seeded record), `emit:false`. ### `GET /api/_health` `{ "ok": true, "build": "" }` ## Events emitted | Event type | When | Payload fields | |---|---|---| | `atlas.issue.created` | a Issue is created | `issueKey`, `summary`, `description`, `project`, `issueType`, `reporter`, `assignee`, `priority`, `status`, `sprint`, `labels`, `equipmentPackage`, `createdAt` | | `atlas.issue.updated` | a Issue is edited or re-submitted | as above, plus `changedFields` | | `atlas.issue.transitioned` | transition issue | as above, plus `fromStatus`, `toStatus`, `transitionComment` | | `atlas.issue.frobnicated` | chaos only — never emitted in normal operation | as above | Each emission POSTs to `{SOLOLIFT_BASE_URL}/api/v1/events/ingest` with `x-sololift-signature: sha256=` and the envelope `{ eventSourceId, externalEventId, eventType, subject, occurredAt, payload }`. `externalEventId` is `servicedesk--<4-digit sequence>`.