Webhook payload structure for work_order.status_changed

Need the exact payload structure for work_order.status_changed. Docs show an example but no schema. Specifically:

  • Is previous_status always present?
  • What's the timestamp format — ISO 8601 with millis or no?
  • Are custom fields included or do I need a follow-up API call?

Current handler is breaking on null assignee_id when status goes from assignedunassigned. Need to know what else can be null.

// What I'm receiving (sanitized):
{
  "event": "work_order.status_changed",
  "timestamp": "2025-09-28T14:32:17.842Z",
  "data": {
    "work_order_id": "wo_...",
    "status": "in_progress",
    "previous_status": "assigned",
    "assignee_id": "usr_...",
    "changed_at": "2025-09-28T14:32:15.000Z"
  }
}

Show me the full schema or point me to OpenAPI/Swagger.

Parents Reply Children
  • Agreed on OpenAPI. Internal ticket is ENG-4421 — no ETA but it's in the Q4 API polish backlog. I'll poke the team.

    For now, here's the validator I use internally (zod) if it helps:

    const WebhookPayload = z.object({
      event: z.literal('work_order.status_changed'),
      webhook_id: z.string(),
      timestamp: z.string().datetime(),
      data: z.object({
        work_order_id: z.string(),
        status: z.string(),
        previous_status: z.string().optional().nullable(),
        assignee_id: z.string().nullable(),
        team_id: z.string().nullable(),
        customer_id: z.string(),
        location_id: z.string().nullable(),
        scheduled_start: z.string().datetime().nullable(),
        scheduled_end: z.string().datetime().nullable(),
        changed_at: z.string().datetime(),
        changed_by: z.object({
          type: z.enum(['user', 'system', 'api']),
          id: z.string().nullable()
        })
      })
    });

    YMMV on the datetime validation — we include millis but not all parsers require them.