Player Cart Incidents API
Version: 1.0 Base Path:
/players/me/cart-incidentsAuthentication: Bearer JWT (Cookie or Header)
Overview
The Cart Incidents API allows players to report stuck or malfunctioning golf carts during their round and track the status of their reports.
Authentication
All endpoints require a valid JWT token. The API identifies the player from the authenticated user's email.
# Cookie-based (recommended)
curl -X POST /api/players/me/cart-incidents \
--cookie "access_token=<jwt>"
# Header-based
curl -X POST /api/players/me/cart-incidents \
-H "Authorization: Bearer <jwt>"
Endpoints
Report a Stuck Cart
Report that your cart is stuck at a specific hole.
POST /players/me/cart-incidents
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
reservationId | UUID | Yes | Your cart reservation ID |
holeNumber | Integer | Yes | Hole number (1-18) |
description | String | No | Description of the issue (max 500 chars) |
Example Request
{
"reservationId": "550e8400-e29b-41d4-a716-446655440000",
"holeNumber": 7,
"description": "Cart won't start after stopping at the 7th tee box"
}
Response
{
"id": "a3bb189e-8bf9-3888-9912-ace4e6543002",
"reservationId": "550e8400-e29b-41d4-a716-446655440000",
"courseId": "c1234567-e29b-41d4-a716-446655440000",
"holeNumber": 7,
"description": "Cart won't start after stopping at the 7th tee box",
"status": "REPORTED",
"replacementCartAssigned": false,
"reportedAt": "2026-01-06T10:30:00Z",
"acknowledgedAt": null,
"resolvedAt": null
}
Errors
| Status | Code | Description |
|---|---|---|
| 400 | PLAYER_NOT_FOUND | Unable to resolve player identity |
| 400 | ACTIVE_INCIDENT_EXISTS | An active incident already exists for this reservation |
| 400 | COURSE_NOT_FOUND | Unable to determine course for this reservation |
| 403 | NOT_YOUR_RESERVATION | You do not have access to this cart reservation |
| 404 | RESERVATION_NOT_FOUND | Cart reservation not found |
List My Incidents
Get all cart incidents you have reported.
GET /players/me/cart-incidents
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
status | String | - | Filter by status |
limit | Integer | 50 | Max results (1-100) |
offset | Integer | 0 | Skip results |
Status Values
REPORTED- Initial report, waiting for staffACKNOWLEDGED- Staff has seen the reportREPLACEMENT_ASSIGNED- A replacement cart is on the wayRESOLVED- Issue has been resolvedCANCELLED- You cancelled the report
Example Request
GET /players/me/cart-incidents?status=REPORTED&limit=10
Response
[
{
"id": "a3bb189e-8bf9-3888-9912-ace4e6543002",
"reservationId": "550e8400-e29b-41d4-a716-446655440000",
"courseId": "c1234567-e29b-41d4-a716-446655440000",
"holeNumber": 7,
"description": "Cart won't start",
"status": "ACKNOWLEDGED",
"replacementCartAssigned": false,
"reportedAt": "2026-01-06T10:30:00Z",
"acknowledgedAt": "2026-01-06T10:32:00Z",
"resolvedAt": null
}
]
Get Incident Status
Check the current status of a specific incident.
GET /players/me/cart-incidents/:incidentId
Path Parameters
| Parameter | Type | Description |
|---|---|---|
incidentId | UUID | The incident ID |
Response
{
"id": "a3bb189e-8bf9-3888-9912-ace4e6543002",
"reservationId": "550e8400-e29b-41d4-a716-446655440000",
"courseId": "c1234567-e29b-41d4-a716-446655440000",
"holeNumber": 7,
"description": "Cart won't start",
"status": "REPLACEMENT_ASSIGNED",
"replacementCartAssigned": true,
"reportedAt": "2026-01-06T10:30:00Z",
"acknowledgedAt": "2026-01-06T10:32:00Z",
"resolvedAt": null
}
Errors
| Status | Code | Description |
|---|---|---|
| 403 | NOT_YOUR_INCIDENT | You do not have access to this incident |
| 404 | INCIDENT_NOT_FOUND | Incident not found |
Cancel My Incident
Cancel an incident you reported. Only possible if staff has not yet acknowledged it.
PATCH /players/me/cart-incidents/:incidentId/cancel
Path Parameters
| Parameter | Type | Description |
|---|---|---|
incidentId | UUID | The incident ID to cancel |
Response
{
"id": "a3bb189e-8bf9-3888-9912-ace4e6543002",
"reservationId": "550e8400-e29b-41d4-a716-446655440000",
"courseId": "c1234567-e29b-41d4-a716-446655440000",
"holeNumber": 7,
"description": "Cart won't start",
"status": "CANCELLED",
"replacementCartAssigned": false,
"reportedAt": "2026-01-06T10:30:00Z",
"acknowledgedAt": null,
"resolvedAt": "2026-01-06T10:35:00Z"
}
Errors
| Status | Code | Description |
|---|---|---|
| 400 | CANNOT_CANCEL | Cannot cancel - already acknowledged by staff |
| 403 | NOT_YOUR_INCIDENT | You do not have access to this incident |
| 404 | INCIDENT_NOT_FOUND | Incident not found |
Get Photo Upload URL
Request a presigned URL to upload a photo for an incident.
POST /players/me/cart-incidents/:incidentId/photos/upload-url
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
filename | String | Yes | Original filename |
size | Integer | Yes | File size in bytes (max 10MB) |
mimeType | String | Yes | MIME type (image/jpeg, image/png) |
Response
{
"uploadUrl": "https://s3.amazonaws.com/...",
"key": "incidents/abc123/photo-001.jpg"
}
Confirm Photo Upload
After uploading to S3, confirm the photo to attach it to the incident.
POST /players/me/cart-incidents/:incidentId/photos
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
key | String | Yes | S3 key returned from upload-url |
mimeType | String | Yes | MIME type of uploaded file |
Response
{
"id": "photo-uuid",
"url": "https://...",
"uploadedAt": "2026-01-07T10:30:00Z"
}
List My Incident Photos
Get all photos attached to an incident.
GET /players/me/cart-incidents/:incidentId/photos
Path Parameters
| Parameter | Type | Description |
|---|---|---|
incidentId | UUID | The incident ID |
Response
[
{
"id": "photo-uuid",
"url": "https://...",
"mimeType": "image/jpeg",
"uploadedAt": "2026-01-07T10:30:00Z"
}
]
Errors
| Status | Code | Description |
|---|---|---|
| 403 | NOT_YOUR_INCIDENT | You do not have access to this incident |
| 404 | INCIDENT_NOT_FOUND | Incident not found |
Status Flow
┌─────────┐
│REPORTED │ ◄── Player reports issue
└────┬────┘
│
┌────▼────┐
│ACKNOWLEDGED│ ◄── Staff sees report
└────┬────┘
│
┌────────▼─────────┐
│REPLACEMENT_ASSIGNED│ ◄── Cart on the way
└────────┬─────────┘
│
┌────▼────┐
│RESOLVED │ ◄── Issue fixed
└─────────┘
Player can CANCEL only from REPORTED status.
Real-Time Updates
For real-time status updates, connect to the TeeTime WebSocket gateway:
// Build WebSocket URL with auth token
const protocol = window.location.protocol === 'https:' ? 'wss' : 'ws';
const wsUrl = `${protocol}://${window.location.host}/api/ws/tee-sheet?token=${accessToken}`;
const ws = new WebSocket(wsUrl);
// Subscribe to your club's events
ws.onopen = () => {
ws.send(JSON.stringify({
event: 'subscribe',
data: { room: `club:${clubId}` }
}));
};
// Listen for incident updates
ws.onmessage = (message) => {
const { event } = JSON.parse(message.data);
if (event?.type?.startsWith('cart.incident')) {
console.log('Incident update:', event.type, event.data);
}
};
Event Types
| Event | Description |
|---|---|
cart.incident.reported | New incident reported |
cart.incident.acknowledged | Staff acknowledged the incident |
cart.incident.replacement-assigned | Replacement cart dispatched |
cart.incident.resolved | Incident resolved |
cart.incident.escalated | SLA breach - incident escalated |
Rate Limits
- Report incident: 5 requests per minute
- List/Get: 60 requests per minute
Support
If you experience issues with the cart incident system, contact course staff directly or call the pro shop.