Skip to main content

Player Cart Incidents API

Version: 1.0 Base Path: /players/me/cart-incidents Authentication: 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

FieldTypeRequiredDescription
reservationIdUUIDYesYour cart reservation ID
holeNumberIntegerYesHole number (1-18)
descriptionStringNoDescription 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

StatusCodeDescription
400PLAYER_NOT_FOUNDUnable to resolve player identity
400ACTIVE_INCIDENT_EXISTSAn active incident already exists for this reservation
400COURSE_NOT_FOUNDUnable to determine course for this reservation
403NOT_YOUR_RESERVATIONYou do not have access to this cart reservation
404RESERVATION_NOT_FOUNDCart reservation not found

List My Incidents

Get all cart incidents you have reported.

GET /players/me/cart-incidents

Query Parameters

ParameterTypeDefaultDescription
statusString-Filter by status
limitInteger50Max results (1-100)
offsetInteger0Skip results

Status Values

  • REPORTED - Initial report, waiting for staff
  • ACKNOWLEDGED - Staff has seen the report
  • REPLACEMENT_ASSIGNED - A replacement cart is on the way
  • RESOLVED - Issue has been resolved
  • CANCELLED - 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

ParameterTypeDescription
incidentIdUUIDThe 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

StatusCodeDescription
403NOT_YOUR_INCIDENTYou do not have access to this incident
404INCIDENT_NOT_FOUNDIncident 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

ParameterTypeDescription
incidentIdUUIDThe 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

StatusCodeDescription
400CANNOT_CANCELCannot cancel - already acknowledged by staff
403NOT_YOUR_INCIDENTYou do not have access to this incident
404INCIDENT_NOT_FOUNDIncident 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

FieldTypeRequiredDescription
filenameStringYesOriginal filename
sizeIntegerYesFile size in bytes (max 10MB)
mimeTypeStringYesMIME 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

FieldTypeRequiredDescription
keyStringYesS3 key returned from upload-url
mimeTypeStringYesMIME 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

ParameterTypeDescription
incidentIdUUIDThe incident ID

Response

[
{
"id": "photo-uuid",
"url": "https://...",
"mimeType": "image/jpeg",
"uploadedAt": "2026-01-07T10:30:00Z"
}
]

Errors

StatusCodeDescription
403NOT_YOUR_INCIDENTYou do not have access to this incident
404INCIDENT_NOT_FOUNDIncident 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

EventDescription
cart.incident.reportedNew incident reported
cart.incident.acknowledgedStaff acknowledged the incident
cart.incident.replacement-assignedReplacement cart dispatched
cart.incident.resolvedIncident resolved
cart.incident.escalatedSLA 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.