# Endpoints

All paths are relative to `https://graph.microsoft.com/v1.0/sites/{siteId}`. Use `$expand=fields` on every list call so the response contains actual field values rather than just envelopes.

## Tickets — `SD_Tickets`

### List / filter tickets

```
GET /lists/SD_Tickets/items?$expand=fields&$filter=fields/SD_Status eq 'New'&$orderby=fields/Created desc&$top=50
```

Common filters:
- Open tickets: `fields/SD_Status eq 'New' or fields/SD_Status eq 'Assigned' or fields/SD_Status eq 'In Progress'`
- High priority: `fields/SD_Priority eq 'High' or fields/SD_Priority eq 'Urgent'`
- Assigned to a user: `fields/SD_AssignedTo eq 'agent@tenant.onmicrosoft.com'`
- In a space (v1.5+): `fields/SD_SpaceId eq 'space-abc'`
- Modified in last 24h: `fields/Modified ge '2026-04-23T00:00:00Z'`

### Get a single ticket

```
GET /lists/SD_Tickets/items/{itemId}?$expand=fields
```

### Create a ticket

```
POST /lists/SD_Tickets/items
Content-Type: application/json

{
  "fields": {
    "Title": "VPN not connecting from home",
    "SD_Description": "Split-tunnel started failing at 09:00 today.",
    "SD_Priority": "High",
    "SD_Status": "New",
    "SD_Category": "Network",
    "SD_SubmittedBy": "user@contoso.com",
    "SD_SubmittedByName": "Jane User",
    "SD_SubmittedByEmail": "user@contoso.com",
    "SD_SpaceId": "space-default"
  }
}
```

Returns the created item with its new `id`.

### Update a ticket

```
PATCH /lists/SD_Tickets/items/{itemId}/fields
Content-Type: application/json
If-Match: *

{ "SD_Status": "Resolved", "SD_AssignedTo": "agent@contoso.com" }
```

Note the trailing `/fields` and the `If-Match: *` header — that is Graph's shape for partial field updates.

### Delete a ticket

```
DELETE /lists/SD_Tickets/items/{itemId}
```

## Comments — `SD_Comments`

### List comments for a ticket

```
GET /lists/SD_Comments/items?$expand=fields&$filter=fields/SD_TicketId eq 123&$orderby=fields/Created asc
```

### Post a comment

```
POST /lists/SD_Comments/items
Content-Type: application/json

{
  "fields": {
    "Title": "Updated firewall rule",
    "SD_TicketId": 123,
    "SD_Body": "Added UDP 500 / 4500 to the VPN profile, please retest.",
    "SD_AuthorEmail": "agent@contoso.com",
    "SD_AuthorName": "Agent Smith",
    "SD_IsInternal": false
  }
}
```

Set `SD_IsInternal: true` to keep the comment hidden from the end-user portal.

## Agents — `SD_Agents`

```
GET /lists/SD_Agents/items?$expand=fields&$filter=fields/SD_IsActive eq true
```

Read-only from the API. Manage agents from the SPFx admin.

## Assets — `SD_Assets`

### List assets

```
GET /lists/SD_Assets/items?$expand=fields&$filter=fields/SD_Status eq 'In Use'
```

### Create an asset

```
POST /lists/SD_Assets/items
Content-Type: application/json

{
  "fields": {
    "Title": "LAPTOP-JANE-01",
    "SD_AssetTag": "AST-0142",
    "SD_Type": "Laptop",
    "SD_Status": "In Use",
    "SD_AssignedTo": "jane@contoso.com",
    "SD_SerialNumber": "SN1234567",
    "SD_Manufacturer": "Dell",
    "SD_Model": "Latitude 5540",
    "SD_PurchaseDate": "2025-10-01T00:00:00Z",
    "SD_WarrantyExpires": "2028-10-01T00:00:00Z"
  }
}
```

## Common response shapes

### List item envelope

```json
{
  "@odata.etag": "\"…\"",
  "id": "123",
  "createdDateTime": "2026-04-24T08:15:00Z",
  "lastModifiedDateTime": "2026-04-24T08:20:00Z",
  "fields": {
    "Title": "…",
    "SD_Status": "New",
    "SD_Priority": "High",
    "Created": "2026-04-24T08:15:00Z",
    "Modified": "2026-04-24T08:20:00Z"
  }
}
```

### Paged list

```json
{
  "value": [ { "id": "123", "fields": { … } }, … ],
  "@odata.nextLink": "https://graph.microsoft.com/v1.0/sites/…/items?$skiptoken=…"
}
```

Follow `@odata.nextLink` to page; Graph defaults to 200 rows, max 5000 with `$top=5000`.

## Errors

Typical HTTP responses:

| Status | Meaning | Action |
|--------|---------|--------|
| `401` | Token expired or secret wrong | Refresh the token; rotate the secret if persistent |
| `403` | Scope mismatch — e.g. writing to another site | Verify `siteId` matches the one from setup |
| `404` | List or item doesn't exist | Confirm the list name (`SD_Tickets`, not `Tickets`) |
| `409 / 412` | Etag mismatch on PATCH | Refetch, retry |
| `429` | Graph throttling | Honour `Retry-After`, back off |
| `500` | SharePoint transient | Retry with exponential backoff |

Graph error body:
```json
{ "error": { "code": "invalidRequest", "message": "…", "innerError": { "request-id": "…" } } }
```

Always log `innerError.request-id` — it is what Microsoft support will ask for.
