{
 "components": {
  "schemas": {
   "address.Address": {
    "properties": {
     "city": {
      "description": "City is the city name",
      "example": "San Francisco",
      "type": "string"
     },
     "country": {
      "description": "Country is the full country name",
      "example": "United States",
      "type": "string"
     },
     "country_code": {
      "description": "CountryCode is the ISO 3166-1 alpha-2 country code",
      "example": "US",
      "type": "string"
     },
     "county": {
      "description": "County is the county name",
      "example": "San Francisco County",
      "type": "string"
     },
     "formatted_name": {
      "description": "FormattedName is the full human-readable address string",
      "example": "123 Main St, Apt 4B, San Francisco, CA 94105, United States",
      "type": "string"
     },
     "formatted_name_short": {
      "description": "FormattedNameShort is a short human-readable address string",
      "example": "123 Main St, San Francisco",
      "type": "string"
     },
     "house_number": {
      "description": "HouseNumber is the building or house number",
      "example": "123",
      "type": "string"
     },
     "id": {
      "description": "ID is the unique identifier of the address",
      "example": "addr_01HXY",
      "type": "string"
     },
     "point": {
      "allOf": [
       {
        "$ref": "#/components/schemas/db.Point"
       }
      ],
      "description": "Point is the geographic coordinates of the address"
     },
     "postal_code": {
      "description": "PostalCode is the ZIP or postal code",
      "example": "94105",
      "type": "string"
     },
     "site_id": {
      "description": "SiteID is the site this address belongs to, or nil for global addresses",
      "example": "site_01HXY",
      "type": "string"
     },
     "source": {
      "description": "Source is the data provider that supplied this address (e.g. \"google\")",
      "example": "google",
      "type": "string"
     },
     "source_id": {
      "description": "SourceID is the external identifier from the data provider",
      "example": "ChIJIQBpAG2ahYAR_6128GcTUEo",
      "type": "string"
     },
     "state": {
      "description": "State is the full state or province name",
      "example": "California",
      "type": "string"
     },
     "state_code": {
      "description": "StateCode is the abbreviated state or province code",
      "example": "CA",
      "type": "string"
     },
     "street": {
      "description": "Street is the street name without the house number",
      "example": "Main St",
      "type": "string"
     },
     "street_address": {
      "description": "StreetAddress is the full first line of the street address",
      "example": "123 Main St",
      "type": "string"
     },
     "street_address2": {
      "description": "StreetAddress2 is the optional second address line (suite, apt, etc.)",
      "example": "Apt 4B",
      "type": "string"
     },
     "types": {
      "description": "Types is a list of classification labels for the address (e.g. [\"custom\"])",
      "items": {
       "type": "string"
      },
      "type": "array"
     }
    },
    "required": [
     "formatted_name",
     "formatted_name_short",
     "point"
    ],
    "type": "object"
   },
   "address.AddressRequest": {
    "properties": {
     "city": {
      "description": "City is the city name",
      "example": "San Francisco",
      "type": "string"
     },
     "country": {
      "description": "Country is the full country name",
      "example": "United States",
      "type": "string"
     },
     "point": {
      "description": "Point contains the geographic coordinates of the address",
      "properties": {
       "lat": {
        "description": "Lat is the latitude",
        "example": 37.7749,
        "type": "number"
       },
       "lng": {
        "description": "Lng is the longitude",
        "example": -122.4194,
        "type": "number"
       }
      },
      "type": "object"
     },
     "postal_code": {
      "description": "PostalCode is the ZIP or postal code",
      "example": "94105",
      "type": "string"
     },
     "state": {
      "description": "State is the full state name",
      "example": "California",
      "type": "string"
     },
     "street_address": {
      "description": "StreetAddress is the primary street line (e.g. \"123 Main St\")",
      "example": "123 Main St",
      "type": "string"
     },
     "street_address2": {
      "description": "StreetAddress2 is the optional secondary street line (e.g. \"Apt 4B\")",
      "example": "Apt 4B",
      "type": "string"
     }
    },
    "type": "object"
   },
   "admin.CreateOrganizationRequest": {
    "properties": {
     "address_id": {
      "type": "string"
     },
     "description": {
      "type": "string"
     },
     "email": {
      "type": "string"
     },
     "latitude": {
      "type": "number"
     },
     "longitude": {
      "type": "number"
     },
     "name": {
      "type": "string"
     },
     "phone": {
      "type": "string"
     },
     "phone_country": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "admin.CreateSiteRequest": {
    "properties": {
     "address_id": {
      "type": "string"
     },
     "currency": {
      "type": "string"
     },
     "description": {
      "type": "string"
     },
     "email": {
      "type": "string"
     },
     "industry_type": {
      "type": "string"
     },
     "name": {
      "type": "string"
     },
     "notes": {
      "type": "string"
     },
     "organization_id": {
      "type": "string"
     },
     "phone": {
      "type": "string"
     },
     "phone_country": {
      "type": "string"
     },
     "subdomain": {
      "type": "string"
     },
     "timezone": {
      "type": "string"
     },
     "unit_system": {
      "$ref": "#/components/schemas/site.UnitSystem"
     },
     "website": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "admin.CreateUserRequest": {
    "properties": {
     "display_name": {
      "type": "string"
     },
     "email": {
      "type": "string"
     },
     "first_name": {
      "type": "string"
     },
     "last_name": {
      "type": "string"
     },
     "organization_id": {
      "type": "string"
     },
     "password": {
      "type": "string"
     },
     "phone": {
      "type": "string"
     },
     "phone_country": {
      "type": "string"
     },
     "role": {
      "type": "string"
     },
     "site_id": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "admin.UpdateOrganizationRequest": {
    "properties": {
     "description": {
      "type": "string"
     },
     "email": {
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "is_active": {
      "type": "boolean"
     },
     "name": {
      "type": "string"
     },
     "phone": {
      "type": "string"
     },
     "phone_country": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "admin.UpdateSiteRequest": {
    "properties": {
     "address_id": {
      "type": "string"
     },
     "currency": {
      "type": "string"
     },
     "description": {
      "type": "string"
     },
     "email": {
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "is_active": {
      "type": "boolean"
     },
     "name": {
      "type": "string"
     },
     "notes": {
      "type": "string"
     },
     "phone": {
      "type": "string"
     },
     "phone_country": {
      "type": "string"
     },
     "subdomain": {
      "type": "string"
     },
     "timezone": {
      "type": "string"
     },
     "unit_system": {
      "$ref": "#/components/schemas/site.UnitSystem"
     },
     "website": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "admin.UpdateUserRequest": {
    "properties": {
     "display_name": {
      "type": "string"
     },
     "email": {
      "type": "string"
     },
     "first_name": {
      "type": "string"
     },
     "home_address": {
      "allOf": [
       {
        "$ref": "#/components/schemas/address.AddressRequest"
       }
      ],
      "description": "HomeAddress is an inline address to create and use as the user's home address."
     },
     "home_address_id": {
      "description": "HomeAddressID updates the user's home address by referencing an existing address.\nEmpty string clears the home address; omitted leaves it unchanged. Takes precedence\nover HomeAddress when both are supplied.",
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "is_active": {
      "type": "boolean"
     },
     "last_name": {
      "type": "string"
     },
     "password": {
      "type": "string"
     },
     "phone": {
      "type": "string"
     },
     "phone_country": {
      "type": "string"
     },
     "role": {
      "type": "string"
     },
     "site_id": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "api.ApiError": {
    "properties": {
     "code": {
      "example": "BAD_REQUEST",
      "type": "string"
     },
     "description": {
      "example": "detailed error description",
      "type": "string"
     },
     "message": {
      "example": "something went wrong",
      "type": "string"
     }
    },
    "type": "object"
   },
   "application.Application": {
    "properties": {
     "api_key": {
      "type": "string"
     },
     "created_at": {
      "type": "string"
     },
     "description": {
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "is_active": {
      "type": "boolean"
     },
     "name": {
      "type": "string"
     },
     "organization_id": {
      "type": "string"
     },
     "package_name": {
      "type": "string"
     },
     "role": {
      "type": "string"
     },
     "site_id": {
      "type": "string"
     },
     "updated_at": {
      "type": "string"
     }
    },
    "required": [
     "api_key",
     "name",
     "role"
    ],
    "type": "object"
   },
   "attachment.Attachment": {
    "properties": {
     "content_type": {
      "type": "string"
     },
     "created_at": {
      "type": "string"
     },
     "created_by_user_id": {
      "type": "string"
     },
     "file_name": {
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "is_active": {
      "type": "boolean"
     },
     "purpose": {
      "type": "string"
     },
     "remote_path": {
      "type": "string"
     },
     "remote_url": {
      "type": "string"
     },
     "site_id": {
      "type": "string"
     },
     "size": {
      "type": "integer"
     },
     "status": {
      "type": "string"
     },
     "stored_name": {
      "type": "string"
     },
     "updated_at": {
      "type": "string"
     }
    },
    "required": [
     "content_type",
     "created_at",
     "created_by_user_id",
     "file_name",
     "is_active",
     "remote_path",
     "site_id",
     "size",
     "stored_name",
     "updated_at"
    ],
    "type": "object"
   },
   "attachment.PresignRequest": {
    "properties": {
     "content_type": {
      "type": "string"
     },
     "file_name": {
      "type": "string"
     },
     "purpose": {
      "type": "string"
     },
     "size": {
      "type": "integer"
     }
    },
    "type": "object"
   },
   "attachment.PresignResponse": {
    "properties": {
     "attachment_id": {
      "type": "string"
     },
     "upload": {
      "$ref": "#/components/schemas/attachment.UploadTarget"
     }
    },
    "type": "object"
   },
   "attachment.UploadTarget": {
    "properties": {
     "expires_at": {
      "type": "string"
     },
     "headers": {
      "additionalProperties": {
       "type": "string"
      },
      "type": "object"
     },
     "method": {
      "type": "string"
     },
     "url": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "audit.Audit": {
    "properties": {
     "action": {
      "description": "e.g., \"create\", \"update\", \"delete\", \"dispatch\", required",
      "type": "string"
     },
     "changes": {
      "description": "Stores the diff of changes in JSON",
      "type": "object"
     },
     "created_at": {
      "type": "string"
     },
     "entity_id": {
      "description": "ID of the specific entity, required",
      "type": "string"
     },
     "entity_type": {
      "description": "e.g., \"Job\", \"Route\", \"Customer\", required",
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "is_active": {
      "type": "boolean"
     },
     "new_data": {
      "description": "Optional, store new state in JSON format",
      "type": "object"
     },
     "previous_data": {
      "description": "Optional, store old state in JSON format",
      "type": "object"
     },
     "site_id": {
      "description": "Site ID, required field",
      "type": "string"
     },
     "updated_at": {
      "type": "string"
     },
     "user_id": {
      "description": "User ID of the person making the change, required",
      "type": "string"
     }
    },
    "type": "object"
   },
   "authentication.AccessToken": {
    "properties": {
     "access_profile_id": {
      "type": "string"
     },
     "application_id": {
      "type": "string"
     },
     "created_at": {
      "type": "string"
     },
     "expiration_date": {
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "is_active": {
      "type": "boolean"
     },
     "site_id": {
      "type": "string"
     },
     "token": {
      "type": "string"
     },
     "user_id": {
      "type": "string"
     }
    },
    "required": [
     "access_profile_id",
     "application_id",
     "id",
     "site_id",
     "user_id"
    ],
    "type": "object"
   },
   "authentication.AuthContext": {
    "properties": {
     "access_token": {
      "$ref": "#/components/schemas/authentication.AccessToken"
     },
     "active_profile": {
      "$ref": "#/components/schemas/user.Profile"
     },
     "application": {
      "$ref": "#/components/schemas/application.Application"
     },
     "organization": {
      "$ref": "#/components/schemas/organization.Organization"
     },
     "site": {
      "$ref": "#/components/schemas/site.Site"
     },
     "user": {
      "$ref": "#/components/schemas/user.User"
     },
     "user_profiles": {
      "items": {
       "$ref": "#/components/schemas/user.Profile"
      },
      "type": "array"
     }
    },
    "type": "object"
   },
   "authentication.AuthRequest": {
    "properties": {
     "email": {
      "description": "Email is the user's email address",
      "example": "user@example.com",
      "type": "string"
     },
     "password": {
      "description": "Password is the user's password",
      "example": "supersecret",
      "type": "string"
     }
    },
    "required": [
     "email",
     "password"
    ],
    "type": "object"
   },
   "authentication.PasswordResetConfirmRequest": {
    "properties": {
     "new_password": {
      "description": "NewPassword is the desired new password (minimum 8 characters)",
      "example": "newpassword123",
      "minLength": 8,
      "type": "string"
     },
     "token": {
      "description": "Token is the password reset token received by email",
      "example": "abc123resettoken",
      "type": "string"
     }
    },
    "required": [
     "new_password",
     "token"
    ],
    "type": "object"
   },
   "authentication.PasswordResetRequest": {
    "properties": {
     "email": {
      "description": "Email is the address to send the reset link to",
      "example": "user@example.com",
      "type": "string"
     }
    },
    "required": [
     "email"
    ],
    "type": "object"
   },
   "authentication.PreAuthContextResponse": {
    "properties": {
     "profiles": {
      "description": "Profiles is the list of site profiles associated with the user",
      "items": {
       "$ref": "#/components/schemas/user.Profile"
      },
      "type": "array"
     },
     "token": {
      "description": "Token is a short-lived token used to complete authentication against a specific site",
      "example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
      "type": "string"
     },
     "user": {
      "allOf": [
       {
        "$ref": "#/components/schemas/authentication.PreAuthContextUser"
       }
      ],
      "description": "User contains basic information about the authenticated user"
     }
    },
    "type": "object"
   },
   "authentication.PreAuthContextUser": {
    "properties": {
     "email": {
      "description": "Email is the user's email address",
      "example": "user@example.com",
      "type": "string"
     },
     "first_name": {
      "description": "FirstName is the user's given name",
      "example": "Jane",
      "type": "string"
     },
     "id": {
      "description": "ID is the unique identifier of the user",
      "example": "usr_abc123",
      "type": "string"
     },
     "last_name": {
      "description": "LastName is the user's family name",
      "example": "Doe",
      "type": "string"
     },
     "phone": {
      "description": "Phone is the user's phone number",
      "example": "+15550001234",
      "type": "string"
     },
     "phone_country": {
      "description": "PhoneCountry is the ISO country code for the phone number",
      "example": "US",
      "type": "string"
     }
    },
    "type": "object"
   },
   "chat.ChatMessage": {
    "properties": {
     "attachments": {
      "items": {
       "$ref": "#/components/schemas/attachment.Attachment"
      },
      "type": "array"
     },
     "content": {
      "type": "string"
     },
     "created_at": {
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "is_active": {
      "type": "boolean"
     },
     "room_id": {
      "type": "string"
     },
     "sender": {
      "$ref": "#/components/schemas/chat.ChatRoomParticipantUser"
     },
     "sender_user_id": {
      "type": "string"
     },
     "site_id": {
      "type": "string"
     },
     "type": {
      "$ref": "#/components/schemas/chat.MessageType"
     },
     "updated_at": {
      "type": "string"
     }
    },
    "required": [
     "content",
     "room_id",
     "site_id"
    ],
    "type": "object"
   },
   "chat.ChatRoom": {
    "properties": {
     "created_at": {
      "type": "string"
     },
     "created_by_user": {
      "$ref": "#/components/schemas/chat.ChatRoomParticipantUser"
     },
     "created_by_user_id": {
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "is_active": {
      "type": "boolean"
     },
     "name": {
      "type": "string"
     },
     "participants": {
      "items": {
       "$ref": "#/components/schemas/chat.ChatRoomParticipant"
      },
      "type": "array"
     },
     "room_type": {
      "$ref": "#/components/schemas/chat.RoomType"
     },
     "site_id": {
      "type": "string"
     },
     "updated_at": {
      "type": "string"
     }
    },
    "required": [
     "name",
     "site_id"
    ],
    "type": "object"
   },
   "chat.ChatRoomParticipant": {
    "properties": {
     "created_at": {
      "type": "string"
     },
     "last_read_at": {
      "type": "string"
     },
     "room_id": {
      "type": "string"
     },
     "user": {
      "$ref": "#/components/schemas/chat.ChatRoomParticipantUser"
     },
     "user_id": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "chat.ChatRoomParticipantUser": {
    "properties": {
     "display_name": {
      "type": "string"
     },
     "first_name": {
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "last_name": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "chat.ChatRoomResponse": {
    "properties": {
     "created_at": {
      "type": "string"
     },
     "created_by_user": {
      "$ref": "#/components/schemas/chat.ChatRoomParticipantUser"
     },
     "created_by_user_id": {
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "is_active": {
      "type": "boolean"
     },
     "last_message": {
      "$ref": "#/components/schemas/chat.ChatMessage"
     },
     "name": {
      "type": "string"
     },
     "participants": {
      "items": {
       "$ref": "#/components/schemas/chat.ChatRoomParticipant"
      },
      "type": "array"
     },
     "room_type": {
      "$ref": "#/components/schemas/chat.RoomType"
     },
     "site_id": {
      "type": "string"
     },
     "unread_count": {
      "type": "integer"
     },
     "updated_at": {
      "type": "string"
     }
    },
    "required": [
     "name",
     "site_id"
    ],
    "type": "object"
   },
   "chat.MessageRequest": {
    "description": "Request body for sending a message to a chat room",
    "properties": {
     "attachment_ids": {
      "description": "AttachmentIDs reference confirmed (ready) attachments uploaded via the\npre-signed flow to attach to the message.",
      "items": {
       "type": "string"
      },
      "type": "array"
     },
     "content": {
      "example": "Hello, how are you?",
      "type": "string"
     },
     "recipient_id": {
      "example": "user_abc123",
      "type": "string"
     },
     "room_id": {
      "example": "room_xyz789",
      "type": "string"
     }
    },
    "type": "object"
   },
   "chat.MessageType": {
    "enum": [
     "text",
     "ai_response",
     "system"
    ],
    "type": "string",
    "x-enum-comments": {
     "MessageTypeAIResponse": "AI assistant reply",
     "MessageTypeSystem": "system-generated event",
     "MessageTypeText": "regular user message"
    },
    "x-enum-descriptions": [
     "regular user message",
     "AI assistant reply",
     "system-generated event"
    ],
    "x-enum-varnames": [
     "MessageTypeText",
     "MessageTypeAIResponse",
     "MessageTypeSystem"
    ]
   },
   "chat.ParticipantRequest": {
    "description": "Request body for adding a user to an existing chat room",
    "properties": {
     "room_id": {
      "description": "Room ID to which the participant is being added",
      "example": "room_xyz789",
      "type": "string"
     },
     "user_id": {
      "description": "User ID of the participant being added",
      "example": "user_abc123",
      "type": "string"
     }
    },
    "required": [
     "room_id",
     "user_id"
    ],
    "type": "object"
   },
   "chat.RoomRequest": {
    "description": "Request body for creating a new chat room with an initial recipient",
    "properties": {
     "recipient_id": {
      "example": "user_abc123",
      "type": "string"
     },
     "room_type": {
      "allOf": [
       {
        "$ref": "#/components/schemas/chat.RoomType"
       }
      ],
      "example": "standard"
     }
    },
    "type": "object"
   },
   "chat.RoomType": {
    "enum": [
     "standard",
     "direct",
     "assistant"
    ],
    "type": "string",
    "x-enum-comments": {
     "RoomTypeAssistant": "AI assistant conversation",
     "RoomTypeDirect": "1:1 DM between two users",
     "RoomTypeStandard": "general-purpose group chat"
    },
    "x-enum-descriptions": [
     "general-purpose group chat",
     "1:1 DM between two users",
     "AI assistant conversation"
    ],
    "x-enum-varnames": [
     "RoomTypeStandard",
     "RoomTypeDirect",
     "RoomTypeAssistant"
    ]
   },
   "customer.CreatePaymentMethodRequest": {
    "description": "Request body for creating and saving a new payment method (card) using a provider token",
    "properties": {
     "is_default": {
      "example": true,
      "type": "boolean"
     },
     "provider_payment_method_id": {
      "example": "pm_1NXxx2KZ6sXbs5ek",
      "type": "string"
     }
    },
    "required": [
     "provider_payment_method_id"
    ],
    "type": "object"
   },
   "customer.CustomerRequest": {
    "description": "Request body for creating a new customer account",
    "properties": {
     "email": {
      "example": "jane.doe@example.com",
      "type": "string"
     },
     "first_name": {
      "example": "Jane",
      "type": "string"
     },
     "home_address": {
      "allOf": [
       {
        "$ref": "#/components/schemas/address.AddressRequest"
       }
      ],
      "description": "HomeAddress is an inline address to create and use as the customer's home address."
     },
     "home_address_id": {
      "description": "HomeAddressID references an existing address to use as the customer's home address.\nTakes precedence over HomeAddress when both are supplied.",
      "type": "string"
     },
     "last_name": {
      "example": "Doe",
      "type": "string"
     },
     "password": {
      "example": "s3cureP@ss",
      "type": "string"
     },
     "phone": {
      "example": "5551234567",
      "type": "string"
     },
     "phone_country": {
      "example": "US",
      "type": "string"
     }
    },
    "type": "object"
   },
   "customer.CustomerUpdateRequest": {
    "description": "Request body for updating a customer's profile; only supplied fields are changed",
    "properties": {
     "email": {
      "example": "jane.doe@example.com",
      "type": "string"
     },
     "first_name": {
      "example": "Jane",
      "type": "string"
     },
     "home_address": {
      "allOf": [
       {
        "$ref": "#/components/schemas/address.AddressRequest"
       }
      ],
      "description": "HomeAddress is an inline address to create and use as the customer's home address."
     },
     "home_address_id": {
      "description": "HomeAddressID updates the customer's home address by referencing an existing address.\nEmpty string clears the home address; omitted leaves it unchanged. Takes precedence\nover HomeAddress when both are supplied.",
      "type": "string"
     },
     "id": {
      "example": "cust_abc123",
      "type": "string"
     },
     "last_name": {
      "example": "Doe",
      "type": "string"
     },
     "password": {
      "example": "newP@ssw0rd",
      "type": "string"
     },
     "phone": {
      "example": "5559876543",
      "type": "string"
     },
     "phone_country": {
      "example": "US",
      "type": "string"
     }
    },
    "type": "object"
   },
   "customers.Metrics": {
    "properties": {
     "active_in_range": {
      "type": "integer"
     },
     "customer_cancellation_rate": {
      "type": "number"
     },
     "new_in_range": {
      "type": "integer"
     },
     "total_customers": {
      "type": "integer"
     }
    },
    "type": "object"
   },
   "customfield.CreateDefinitionRequest": {
    "properties": {
     "data_type": {
      "$ref": "#/components/schemas/customfield.FieldType"
     },
     "entity_type": {
      "type": "string"
     },
     "is_required": {
      "type": "boolean"
     },
     "key": {
      "type": "string"
     },
     "label": {
      "type": "string"
     },
     "options": {
      "items": {
       "additionalProperties": true,
       "type": "object"
      },
      "type": "array"
     },
     "sort_order": {
      "type": "integer"
     }
    },
    "type": "object"
   },
   "customfield.Definition": {
    "properties": {
     "created_at": {
      "type": "string"
     },
     "data_type": {
      "$ref": "#/components/schemas/customfield.FieldType"
     },
     "entity_type": {
      "description": "e.g., \"worker\"",
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "is_active": {
      "type": "boolean"
     },
     "is_required": {
      "type": "boolean"
     },
     "key": {
      "description": "machine readable: 'license_number'",
      "type": "string"
     },
     "label": {
      "description": "human readable: 'License Number'",
      "type": "string"
     },
     "options": {
      "description": "For 'select' types: [\"A\", \"B\"]",
      "items": {
       "additionalProperties": true,
       "type": "object"
      },
      "type": "array"
     },
     "site_id": {
      "type": "string"
     },
     "sort_order": {
      "type": "integer"
     },
     "updated_at": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "customfield.FieldType": {
    "enum": [
     "text",
     "number",
     "select",
     "date",
     "checkbox"
    ],
    "type": "string",
    "x-enum-varnames": [
     "FieldTypeText",
     "FieldTypeNumber",
     "FieldTypeSelect",
     "FieldTypeDate",
     "FieldTypeCheckbox"
    ]
   },
   "customfield.UpdateDefinitionRequest": {
    "properties": {
     "is_active": {
      "type": "boolean"
     },
     "is_required": {
      "type": "boolean"
     },
     "label": {
      "type": "string"
     },
     "options": {
      "items": {
       "additionalProperties": true,
       "type": "object"
      },
      "type": "array"
     },
     "sort_order": {
      "type": "integer"
     }
    },
    "type": "object"
   },
   "db.JSOND-sitesettings_BrandingConfig": {
    "properties": {
     "data": {
      "$ref": "#/components/schemas/sitesettings.BrandingConfig"
     }
    },
    "type": "object"
   },
   "db.JsonMap": {
    "additionalProperties": true,
    "type": "object"
   },
   "db.PaginationRow": {
    "properties": {
     "page": {
      "type": "integer"
     },
     "pageSize": {
      "type": "integer"
     },
     "totalItems": {
      "format": "int64",
      "type": "integer"
     },
     "totalPages": {
      "type": "integer"
     }
    },
    "type": "object"
   },
   "db.Point": {
    "properties": {
     "lat": {
      "type": "number"
     },
     "lng": {
      "type": "number"
     }
    },
    "type": "object"
   },
   "dispatch.AvailableDriverResponse": {
    "properties": {
     "available": {
      "description": "true if on schedule and no conflict",
      "type": "boolean"
     },
     "driver": {
      "description": "worker user with profile and details"
     },
     "eta_to_job": {
      "description": "duration_minutes, estimated_arrival_at when available"
     },
     "unavailable_reason": {
      "description": "\"off_schedule\" | \"has_conflict\" when not available",
      "type": "string"
     }
    },
    "type": "object"
   },
   "dispatch.AvailableDriversRequest": {
    "properties": {
     "consider_conflicts": {
      "description": "if true, exclude or flag drivers with conflicting jobs",
      "type": "boolean"
     },
     "consider_schedule": {
      "description": "if true, exclude or flag drivers off-schedule",
      "type": "boolean"
     },
     "exclude_unavailable": {
      "description": "if true, exclude drivers that are off-schedule or have conflicts; if false, include them with availability flags",
      "type": "boolean"
     },
     "has_vehicle": {
      "description": "if true, only drivers with at least one assignable vehicle",
      "type": "boolean"
     },
     "job_id": {
      "description": "required",
      "type": "string"
     },
     "operational_status": {
      "description": "optional filter",
      "type": "string"
     },
     "search_query": {
      "description": "optional name/email search",
      "type": "string"
     }
    },
    "type": "object"
   },
   "dispatch.BulkDistributeRequest": {
    "properties": {
     "job_ids": {
      "items": {
       "type": "string"
      },
      "type": "array"
     },
     "optimize_routes": {
      "type": "boolean"
     },
     "require_confirmation": {
      "type": "boolean"
     },
     "start_at": {
      "type": "string"
     },
     "team_id": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "dispatch.BulkDistributeResponse": {
    "properties": {
     "failed_jobs": {
      "items": {
       "$ref": "#/components/schemas/dispatch.DispatchJobError"
      },
      "type": "array"
     },
     "routes": {
      "items": {
       "$ref": "#/components/schemas/dispatch.BulkDistributeRouteResult"
      },
      "type": "array"
     }
    },
    "type": "object"
   },
   "dispatch.BulkDistributeRouteResult": {
    "properties": {
     "dispatched_job_ids": {
      "items": {
       "type": "string"
      },
      "type": "array"
     },
     "driver_id": {
      "type": "string"
     },
     "driver_name": {
      "type": "string"
     },
     "optimized": {
      "type": "boolean"
     },
     "route_id": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "dispatch.ClaimJobRequest": {
    "properties": {
     "dispatch_id": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "dispatch.Dispatch": {
    "properties": {
     "assigned_to_driver_id": {
      "type": "string"
     },
     "assigned_to_vehicle_id": {
      "type": "string"
     },
     "completed_at": {
      "type": "string"
     },
     "created_at": {
      "type": "string"
     },
     "created_by_user_id": {
      "type": "string"
     },
     "dispatch_at": {
      "type": "string"
     },
     "dispatched_at": {
      "type": "string"
     },
     "driver_accepted": {
      "type": "boolean"
     },
     "driver_accepted_at": {
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "is_active": {
      "type": "boolean"
     },
     "job_id": {
      "type": "string"
     },
     "method": {
      "$ref": "#/components/schemas/dispatch.DispatchMethod"
     },
     "route_id": {
      "type": "string"
     },
     "site_id": {
      "type": "string"
     },
     "status": {
      "$ref": "#/components/schemas/dispatch.DispatchStatus"
     },
     "team_id": {
      "type": "string"
     },
     "updated_at": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "dispatch.DispatchJobError": {
    "properties": {
     "error": {
      "type": "string"
     },
     "job_id": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "dispatch.DispatchMethod": {
    "enum": [
     "manual",
     "opt-in",
     "round-robin",
     "priority",
     "load-balanced",
     "zone-based",
     "team",
     "auto"
    ],
    "type": "string",
    "x-enum-comments": {
     "DispatchMethodAuto": "Fully automated (future)",
     "DispatchMethodLoadBalanced": "Assigns jobs based on current driver workload.",
     "DispatchMethodManual": "Manual dispatch where jobs are directly assigned to a specific driver and vehicle.",
     "DispatchMethodOptIn": "Drivers choose jobs from an open pool",
     "DispatchMethodPriority": "Assigns jobs based on priority or urgency",
     "DispatchMethodRoundRobin": "Round-Robin Dispatch: Jobs are evenly distributed to drivers in a sequence.",
     "DispatchMethodTeam": "Auto-selected from team pool",
     "DispatchMethodZoneBased": "Assigns jobs based on the driver's designated area."
    },
    "x-enum-descriptions": [
     "Manual dispatch where jobs are directly assigned to a specific driver and vehicle.",
     "Drivers choose jobs from an open pool",
     "Round-Robin Dispatch: Jobs are evenly distributed to drivers in a sequence.",
     "Assigns jobs based on priority or urgency",
     "Assigns jobs based on current driver workload.",
     "Assigns jobs based on the driver's designated area.",
     "Auto-selected from team pool",
     "Fully automated (future)"
    ],
    "x-enum-varnames": [
     "DispatchMethodManual",
     "DispatchMethodOptIn",
     "DispatchMethodRoundRobin",
     "DispatchMethodPriority",
     "DispatchMethodLoadBalanced",
     "DispatchMethodZoneBased",
     "DispatchMethodTeam",
     "DispatchMethodAuto"
    ]
   },
   "dispatch.DispatchRequest": {
    "properties": {
     "driver_id": {
      "type": "string"
     },
     "job_id": {
      "type": "string"
     },
     "method": {
      "type": "string"
     },
     "require_confirmation": {
      "type": "boolean"
     },
     "route_id": {
      "description": "optional: target a specific route instead of auto-upsert",
      "type": "string"
     },
     "start_at": {
      "type": "string"
     },
     "vehicle_id": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "dispatch.DispatchRouteRequest": {
    "properties": {
     "driver_id": {
      "type": "string"
     },
     "method": {
      "type": "string"
     },
     "require_confirmation": {
      "type": "boolean"
     },
     "route_id": {
      "type": "string"
     },
     "start_at": {
      "type": "string"
     },
     "vehicle_id": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "dispatch.DispatchRouteResponse": {
    "properties": {
     "dispatched_job_ids": {
      "items": {
       "type": "string"
      },
      "type": "array"
     },
     "failed_jobs": {
      "items": {
       "$ref": "#/components/schemas/dispatch.DispatchJobError"
      },
      "type": "array"
     },
     "route": {
      "$ref": "#/components/schemas/route.Route"
     }
    },
    "type": "object"
   },
   "dispatch.DispatchStatus": {
    "enum": [
     "pending",
     "processing",
     "completed"
    ],
    "type": "string",
    "x-enum-varnames": [
     "DispatchStatusPending",
     "DispatchStatusProcessing",
     "DispatchStatusCompleted"
    ]
   },
   "dispatch.PoolJobResponse": {
    "properties": {
     "dispatch_id": {
      "type": "string"
     },
     "job": {},
     "posted_at": {
      "type": "string"
     },
     "team_id": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "dispatch.PostToPoolRequest": {
    "properties": {
     "job_ids": {
      "items": {
       "type": "string"
      },
      "type": "array"
     },
     "start_at": {
      "type": "string"
     },
     "team_id": {
      "description": "optional — if empty, job floats site-wide",
      "type": "string"
     }
    },
    "type": "object"
   },
   "dispatch.TeamDispatchJobRequest": {
    "properties": {
     "job_id": {
      "type": "string"
     },
     "require_confirmation": {
      "type": "boolean"
     },
     "route_id": {
      "type": "string"
     },
     "selection_strategy": {
      "description": "\"eta\" (default), \"load\", or \"round-robin\"",
      "type": "string"
     },
     "start_at": {
      "type": "string"
     },
     "team_id": {
      "type": "string"
     },
     "vehicle_id": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "dispatch.TeamDispatchResponse": {
    "properties": {
     "job": {},
     "route": {},
     "selected_driver_id": {
      "type": "string"
     },
     "selected_driver_name": {
      "type": "string"
     },
     "selection_strategy": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "dispatch.TeamDispatchRouteRequest": {
    "properties": {
     "require_confirmation": {
      "type": "boolean"
     },
     "route_id": {
      "type": "string"
     },
     "selection_strategy": {
      "description": "\"eta\" (default), \"load\", or \"round-robin\"",
      "type": "string"
     },
     "start_at": {
      "type": "string"
     },
     "team_id": {
      "type": "string"
     },
     "vehicle_id": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "driver.CancelJobRequest": {
    "properties": {
     "cancellation_notes": {
      "type": "string"
     },
     "job_id": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "driver.JobSearchParams": {
    "properties": {
     "completed_at_end": {
      "type": "string"
     },
     "completed_at_start": {
      "type": "string"
     },
     "page": {
      "type": "integer"
     },
     "page_size": {
      "type": "integer"
     },
     "workflow_state_ids": {
      "items": {
       "type": "string"
      },
      "type": "array"
     }
    },
    "type": "object"
   },
   "driver.ReturnJobRequest": {
    "properties": {
     "job_id": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "driver.RouteActionRequest": {
    "properties": {
     "route_id": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "driver.StopStateChangeRequest": {
    "properties": {
     "cancellation_notes": {
      "description": "reason when transitioning to cancelled",
      "type": "string"
     },
     "stop_id": {
      "type": "string"
     },
     "workflow_state_id": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "earnings.DriverEarning": {
    "properties": {
     "amount_cents": {
      "type": "integer"
     },
     "component_breakdown": {
      "items": {
       "$ref": "#/components/schemas/earnings.EarningsBreakdownItem"
      },
      "type": "array"
     },
     "created_at": {
      "type": "string"
     },
     "currency": {
      "type": "string"
     },
     "driver_user_id": {
      "type": "string"
     },
     "earned_at": {
      "type": "string"
     },
     "earnings_rule_id": {
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "job_actual_price_cents": {
      "type": "integer"
     },
     "job_distance_meters": {
      "type": "number"
     },
     "job_duration_seconds": {
      "type": "integer"
     },
     "job_id": {
      "type": "string"
     },
     "job_stop_count": {
      "type": "integer"
     },
     "site_id": {
      "type": "string"
     },
     "tip_amount_cents": {
      "type": "integer"
     },
     "total_amount_cents": {
      "type": "integer"
     },
     "updated_at": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "earnings.EarningsBreakdownItem": {
    "properties": {
     "amount": {
      "type": "number"
     },
     "component_type": {
      "$ref": "#/components/schemas/earnings.EarningsComponentType"
     },
     "input_label": {
      "description": "\"miles\", \"km\", \"minutes\", \"stops\", \"job_price\"",
      "type": "string"
     },
     "input_value": {
      "type": "number"
     },
     "rate": {
      "type": "number"
     }
    },
    "type": "object"
   },
   "earnings.EarningsComponent": {
    "properties": {
     "rate": {
      "type": "number"
     },
     "type": {
      "$ref": "#/components/schemas/earnings.EarningsComponentType"
     }
    },
    "type": "object"
   },
   "earnings.EarningsComponentRequest": {
    "properties": {
     "rate": {
      "type": "number"
     },
     "type": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "earnings.EarningsComponentType": {
    "enum": [
     "base",
     "per_distance_unit",
     "per_minute",
     "per_stop",
     "percentage_of_job",
     "wait_time",
     "service_fee"
    ],
    "type": "string",
    "x-enum-varnames": [
     "EarningsComponentTypeBase",
     "EarningsComponentTypePerDistanceUnit",
     "EarningsComponentTypePerMinute",
     "EarningsComponentTypePerStop",
     "EarningsComponentTypePercentageOfJob",
     "EarningsComponentTypeWaitTime",
     "EarningsComponentTypeServiceFee"
    ]
   },
   "earnings.EarningsRule": {
    "properties": {
     "components": {
      "items": {
       "$ref": "#/components/schemas/earnings.EarningsComponent"
      },
      "type": "array"
     },
     "created_at": {
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "is_active": {
      "type": "boolean"
     },
     "is_default": {
      "type": "boolean"
     },
     "maximum_amount": {
      "type": "number"
     },
     "minimum_amount": {
      "type": "number"
     },
     "name": {
      "type": "string"
     },
     "site_id": {
      "type": "string"
     },
     "updated_at": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "earnings.EarningsRuleCreateRequest": {
    "properties": {
     "components": {
      "items": {
       "$ref": "#/components/schemas/earnings.EarningsComponentRequest"
      },
      "type": "array"
     },
     "is_default": {
      "type": "boolean"
     },
     "maximum_amount": {
      "type": "number"
     },
     "minimum_amount": {
      "type": "number"
     },
     "name": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "earnings.EarningsRuleUpdateRequest": {
    "properties": {
     "components": {
      "items": {
       "$ref": "#/components/schemas/earnings.EarningsComponentRequest"
      },
      "type": "array"
     },
     "is_active": {
      "type": "boolean"
     },
     "is_default": {
      "type": "boolean"
     },
     "maximum_amount": {
      "type": "number"
     },
     "minimum_amount": {
      "type": "number"
     },
     "name": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "earnings.EarningsSummary": {
    "properties": {
     "driver_user_id": {
      "type": "string"
     },
     "job_count": {
      "type": "integer"
     },
     "total_amount_cents": {
      "type": "integer"
     },
     "total_cents": {
      "type": "integer"
     },
     "total_tip_cents": {
      "type": "integer"
     }
    },
    "type": "object"
   },
   "earnings.EarningsTimeSeries": {
    "properties": {
     "job_count": {
      "type": "integer"
     },
     "period": {
      "description": "\"2026-03-17\", \"2026-W12\", \"2026-03\"",
      "type": "string"
     },
     "total_amount_cents": {
      "type": "integer"
     },
     "total_cents": {
      "type": "integer"
     },
     "total_tip_cents": {
      "type": "integer"
     }
    },
    "type": "object"
   },
   "etacalc.StopETA": {
    "properties": {
     "cumulative_distance_meters": {
      "type": "number"
     },
     "cumulative_duration_seconds": {
      "type": "integer"
     },
     "estimated_arrival_at": {
      "type": "string"
     },
     "estimated_completion_at": {
      "type": "string"
     },
     "stop_id": {
      "type": "string"
     },
     "stop_index": {
      "type": "integer"
     },
     "type": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "etacalc.StopETAResult": {
    "properties": {
     "best_driver_id": {
      "type": "string"
     },
     "eligible_driver_count": {
      "type": "integer"
     },
     "located_driver_count": {
      "type": "integer"
     },
     "pickup_duration_seconds": {
      "type": "number"
     },
     "pickup_eta": {
      "type": "string"
     },
     "stops": {
      "items": {
       "$ref": "#/components/schemas/etacalc.StopETA"
      },
      "type": "array"
     }
    },
    "type": "object"
   },
   "etanotificationconfig.EtaNotificationConfigResponse": {
    "properties": {
     "created_at": {
      "type": "string"
     },
     "debounce_seconds": {
      "type": "integer"
     },
     "delivery_method": {
      "$ref": "#/components/schemas/notification.DeliveryMethod"
     },
     "enabled": {
      "type": "boolean"
     },
     "id": {
      "type": "string"
     },
     "recipient_type": {
      "$ref": "#/components/schemas/etanotificationconfig.RecipientType"
     },
     "template": {
      "$ref": "#/components/schemas/etanotificationconfig.TemplateResponse"
     },
     "trigger_type": {
      "$ref": "#/components/schemas/etanotificationconfig.TriggerType"
     },
     "trigger_value": {
      "type": "number"
     },
     "updated_at": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "etanotificationconfig.RecipientType": {
    "enum": [
     "customer",
     "driver",
     "admin"
    ],
    "type": "string",
    "x-enum-varnames": [
     "RecipientCustomer",
     "RecipientDriver",
     "RecipientAdmin"
    ]
   },
   "etanotificationconfig.TemplateRequest": {
    "properties": {
     "body": {
      "type": "string"
     },
     "title": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "etanotificationconfig.TemplateResponse": {
    "properties": {
     "body": {
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "is_custom": {
      "type": "boolean"
     },
     "title": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "etanotificationconfig.TriggerType": {
    "enum": [
     "time_before_arrival",
     "distance_away"
    ],
    "type": "string",
    "x-enum-varnames": [
     "TriggerTypeTimeBeforeArrival",
     "TriggerTypeDistanceAway"
    ]
   },
   "etanotificationconfig.UpsertEtaNotificationConfigRequest": {
    "properties": {
     "debounce_seconds": {
      "type": "integer"
     },
     "delivery_method": {
      "$ref": "#/components/schemas/notification.DeliveryMethod"
     },
     "enabled": {
      "type": "boolean"
     },
     "recipient_type": {
      "$ref": "#/components/schemas/etanotificationconfig.RecipientType"
     },
     "template": {
      "$ref": "#/components/schemas/etanotificationconfig.TemplateRequest"
     },
     "trigger_type": {
      "$ref": "#/components/schemas/etanotificationconfig.TriggerType"
     },
     "trigger_value": {
      "description": "minutes for time_before_arrival, miles for distance_away",
      "type": "number"
     }
    },
    "required": [
     "delivery_method",
     "recipient_type",
     "trigger_type",
     "trigger_value"
    ],
    "type": "object"
   },
   "gis.RouteRequest": {
    "properties": {
     "destination": {
      "$ref": "#/components/schemas/gis.WayPoint"
     },
     "options": {
      "properties": {
       "alternatives": {
        "type": "integer"
       },
       "avoid_features": {
        "items": {
         "type": "string"
        },
        "type": "array"
       },
       "departure_time": {
        "type": "string"
       },
       "optimize": {
        "type": "boolean"
       },
       "routing_mode": {
        "type": "string"
       },
       "transport_mode": {
        "type": "string"
       }
      },
      "type": "object"
     },
     "origin": {
      "$ref": "#/components/schemas/gis.WayPoint"
     },
     "waypoints": {
      "items": {
       "$ref": "#/components/schemas/gis.WayPoint"
      },
      "type": "array"
     }
    },
    "type": "object"
   },
   "gis.WayPoint": {
    "properties": {
     "id": {
      "type": "string"
     },
     "lat": {
      "type": "number"
     },
     "lng": {
      "type": "number"
     },
     "options": {
      "$ref": "#/components/schemas/gis.WayPointOptions"
     }
    },
    "type": "object"
   },
   "gis.WayPointOptions": {
    "properties": {
     "stop_duration": {
      "type": "integer"
     },
     "stop_over": {
      "type": "boolean"
     }
    },
    "type": "object"
   },
   "gis.WaypointSequenceRequest": {
    "properties": {
     "departure_time": {
      "type": "string"
     },
     "end": {
      "$ref": "#/components/schemas/gis.WaypointSequenceRequestWaypoint"
     },
     "optimize_for": {
      "type": "string"
     },
     "routing_mode": {
      "type": "string"
     },
     "start": {
      "$ref": "#/components/schemas/gis.WaypointSequenceRequestWaypoint"
     },
     "waypoints": {
      "items": {
       "$ref": "#/components/schemas/gis.WaypointSequenceRequestWaypoint"
      },
      "type": "array"
     }
    },
    "type": "object"
   },
   "gis.WaypointSequenceRequestWaypoint": {
    "properties": {
     "access_window": {
      "description": "Time window constraints (e.g., \"mo09:00:00+01:00|mo10:00:00+01:00\")",
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "lat": {
      "type": "number"
     },
     "lng": {
      "type": "number"
     },
     "service_time": {
      "type": "integer"
     }
    },
    "type": "object"
   },
   "integration.AvailableIntegration": {
    "properties": {
     "category": {
      "$ref": "#/components/schemas/integration.Category"
     },
     "config_schema": {
      "items": {
       "$ref": "#/components/schemas/integration.ConfigField"
      },
      "type": "array"
     },
     "description": {
      "type": "string"
     },
     "features": {
      "$ref": "#/components/schemas/integration.IntegrationFeatures"
     },
     "key": {
      "type": "string"
     },
     "name": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "integration.Category": {
    "enum": [
     "email",
     "payments",
     "streaming",
     "sms",
     "push",
     "notification",
     "ai",
     "mapping"
    ],
    "type": "string",
    "x-enum-varnames": [
     "CategoryEmail",
     "CategoryPayments",
     "CategoryStreaming",
     "CategorySMS",
     "CategoryPush",
     "CategoryNotification",
     "CategoryAI",
     "CategoryMapping"
    ]
   },
   "integration.ConfigField": {
    "properties": {
     "help_text": {
      "description": "e.g., \"You can find your API key in your Mailgun dashboard.\"",
      "type": "string"
     },
     "label": {
      "description": "e.g., \"API Key\"",
      "type": "string"
     },
     "name": {
      "description": "e.g., \"apiKey\"",
      "type": "string"
     },
     "placeholder": {
      "description": "e.g., \"key-...\"",
      "type": "string"
     },
     "required": {
      "type": "boolean"
     },
     "type": {
      "description": "e.g., \"text\", \"password\", \"boolean\"",
      "type": "string"
     }
    },
    "type": "object"
   },
   "integration.ConnectResponse": {
    "properties": {
     "integration_data": {
      "$ref": "#/components/schemas/integration.SiteIntegration"
     },
     "provider_response": {
      "$ref": "#/components/schemas/integration.ProviderConnectResponse"
     }
    },
    "type": "object"
   },
   "integration.IntegrationFeatures": {
    "properties": {
     "has_onboarding": {
      "description": "If true, the integration supports an onboarding flow (e.g., Stripe Connect)",
      "type": "boolean"
     }
    },
    "type": "object"
   },
   "integration.ProviderConnectResponse": {
    "properties": {
     "connect_url": {
      "description": "URL for a \"Connect with X\" button",
      "type": "string"
     },
     "redirect_url": {
      "description": "URL to redirect the user to immediately",
      "type": "string"
     }
    },
    "type": "object"
   },
   "integration.SiteIntegration": {
    "properties": {
     "config": {
      "$ref": "#/components/schemas/db.JsonMap"
     },
     "created_at": {
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "integration_key": {
      "description": "e.g., \"mailgun\", \"stripe\"",
      "type": "string"
     },
     "is_active": {
      "type": "boolean"
     },
     "routing_key": {
      "type": "string"
     },
     "site_id": {
      "type": "string"
     },
     "updated_at": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "integration.UpdateIntegrationRequest": {
    "properties": {
     "config": {
      "$ref": "#/components/schemas/db.JsonMap"
     },
     "is_active": {
      "type": "boolean"
     }
    },
    "type": "object"
   },
   "job.AddJobAttachmentsRequest": {
    "properties": {
     "attachment_ids": {
      "items": {
       "type": "string"
      },
      "type": "array"
     },
     "job_id": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "job.ApiJobCreate": {
    "properties": {
     "customer_email": {
      "type": "string"
     },
     "customer_first_name": {
      "type": "string"
     },
     "customer_last_name": {
      "type": "string"
     },
     "customer_notes": {
      "type": "string"
     },
     "customer_phone": {
      "type": "string"
     },
     "customer_phone_country": {
      "type": "string"
     },
     "customer_user_id": {
      "type": "string"
     },
     "driver_notes": {
      "type": "string"
     },
     "driver_user_id": {
      "type": "string"
     },
     "estimate_id": {
      "type": "string"
     },
     "internal_notes": {
      "type": "string"
     },
     "option_ids": {
      "items": {
       "type": "string"
      },
      "type": "array"
     },
     "override_zone_restriction": {
      "description": "OverrideZoneRestriction allows dispatchers/admins to create a job in a banned zone.\nThis field is stripped for customer callers — customers are always hard-blocked.",
      "type": "boolean"
     },
     "service_type_id": {
      "type": "string"
     },
     "stops": {
      "items": {
       "$ref": "#/components/schemas/job.ApiStopCreate"
      },
      "type": "array"
     }
    },
    "type": "object"
   },
   "job.ApiJobUpdate": {
    "properties": {
     "customer_notes": {
      "type": "string"
     },
     "customer_user_id": {
      "type": "string"
     },
     "driver_notes": {
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "internal_notes": {
      "type": "string"
     },
     "option_ids": {
      "items": {
       "type": "string"
      },
      "type": "array"
     },
     "stops": {
      "items": {
       "$ref": "#/components/schemas/job.ApiStopUpdate"
      },
      "type": "array"
     }
    },
    "type": "object"
   },
   "job.ApiStopCreate": {
    "properties": {
     "address_id": {
      "type": "string"
     },
     "city": {
      "type": "string"
     },
     "complete_after": {
      "type": "string"
     },
     "complete_before": {
      "type": "string"
     },
     "contact_name": {
      "type": "string"
     },
     "contact_phone": {
      "type": "string"
     },
     "contact_phone_country": {
      "type": "string"
     },
     "country": {
      "type": "string"
     },
     "customer_notes": {
      "type": "string"
     },
     "driver_notes": {
      "type": "string"
     },
     "internal_notes": {
      "type": "string"
     },
     "order": {
      "type": "integer"
     },
     "point": {
      "properties": {
       "lat": {
        "type": "number"
       },
       "lng": {
        "type": "number"
       }
      },
      "type": "object"
     },
     "postal_code": {
      "type": "string"
     },
     "state": {
      "type": "string"
     },
     "street_address": {
      "type": "string"
     },
     "street_address2": {
      "type": "string"
     },
     "type": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "job.ApiStopUpdate": {
    "properties": {
     "address_id": {
      "type": "string"
     },
     "city": {
      "type": "string"
     },
     "complete_after": {
      "type": "string"
     },
     "complete_before": {
      "type": "string"
     },
     "contact_name": {
      "type": "string"
     },
     "contact_phone": {
      "type": "string"
     },
     "contact_phone_country": {
      "type": "string"
     },
     "country": {
      "type": "string"
     },
     "customer_notes": {
      "type": "string"
     },
     "driver_notes": {
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "internal_notes": {
      "type": "string"
     },
     "postal_code": {
      "type": "string"
     },
     "state": {
      "type": "string"
     },
     "street_address": {
      "type": "string"
     },
     "street_address2": {
      "type": "string"
     },
     "type": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "job.BulkCancelJobRequest": {
    "properties": {
     "cancellation_notes": {
      "type": "string"
     },
     "ids": {
      "items": {
       "type": "string"
      },
      "type": "array"
     }
    },
    "type": "object"
   },
   "job.BulkDeleteJobRequest": {
    "properties": {
     "ids": {
      "items": {
       "type": "string"
      },
      "type": "array"
     }
    },
    "type": "object"
   },
   "job.BulkDuplicateJobRequest": {
    "properties": {
     "ids": {
      "items": {
       "type": "string"
      },
      "type": "array"
     }
    },
    "type": "object"
   },
   "job.BulkDuplicateJobResponse": {
    "properties": {
     "failed": {
      "items": {
       "$ref": "#/components/schemas/job.BulkJobResult"
      },
      "type": "array"
     },
     "succeeded": {
      "items": {
       "$ref": "#/components/schemas/job.Job"
      },
      "type": "array"
     }
    },
    "type": "object"
   },
   "job.BulkJobResponse": {
    "properties": {
     "failed": {
      "items": {
       "$ref": "#/components/schemas/job.BulkJobResult"
      },
      "type": "array"
     },
     "succeeded": {
      "items": {
       "type": "string"
      },
      "type": "array"
     }
    },
    "type": "object"
   },
   "job.BulkJobResult": {
    "properties": {
     "error": {
      "type": "string"
     },
     "id": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "job.CancelJobRequest": {
    "properties": {
     "cancellation_notes": {
      "description": "optional reason for cancellation",
      "type": "string"
     },
     "id": {
      "description": "job id",
      "type": "string"
     }
    },
    "type": "object"
   },
   "job.CollectPaymentRequest": {
    "properties": {
     "amount_cents": {
      "type": "integer"
     },
     "job_id": {
      "type": "string"
     },
     "notes": {
      "type": "string"
     },
     "payment_method": {
      "description": "optional override of the job's payment method at collection time",
      "type": "string"
     },
     "provider_name": {
      "type": "string"
     },
     "provider_transaction_id": {
      "type": "string"
     },
     "tip_amount_cents": {
      "description": "optional tip collected from customer (in cents)",
      "type": "integer"
     }
    },
    "required": [
     "job_id"
    ],
    "type": "object"
   },
   "job.Job": {
    "properties": {
     "actual_price": {
      "type": "number"
     },
     "application_id": {
      "type": "string"
     },
     "assigned_at": {
      "type": "string"
     },
     "attachments": {
      "items": {
       "$ref": "#/components/schemas/attachment.Attachment"
      },
      "type": "array"
     },
     "cancellation_notes": {
      "type": "string"
     },
     "cancelled_at": {
      "type": "string"
     },
     "cancelled_by_user_id": {
      "type": "string"
     },
     "completed_at": {
      "type": "string"
     },
     "contact_name": {
      "type": "string"
     },
     "contact_phone": {
      "type": "string"
     },
     "contact_phone_country": {
      "type": "string"
     },
     "created_at": {
      "type": "string"
     },
     "created_by_organization_id": {
      "type": "string"
     },
     "created_by_site_id": {
      "type": "string"
     },
     "created_by_user": {
      "$ref": "#/components/schemas/user.User"
     },
     "created_by_user_id": {
      "type": "string"
     },
     "customer": {
      "$ref": "#/components/schemas/user.User"
     },
     "customer_notes": {
      "type": "string"
     },
     "customer_rating": {
      "type": "integer"
     },
     "customer_rating_notes": {
      "type": "string"
     },
     "customer_user_id": {
      "type": "string"
     },
     "date_time_zone_offset": {
      "type": "integer"
     },
     "dispatched_at": {
      "type": "string"
     },
     "driver": {
      "$ref": "#/components/schemas/user.User"
     },
     "driver_notes": {
      "type": "string"
     },
     "driver_rating": {
      "type": "integer"
     },
     "driver_rating_notes": {
      "type": "string"
     },
     "driver_user_id": {
      "type": "string"
     },
     "estimate_id": {
      "type": "string"
     },
     "estimated_completion_at": {
      "type": "string"
     },
     "estimated_price": {
      "type": "number"
     },
     "estimated_start_at": {
      "description": "EstimatedStartAt and EstimatedCompletionAt cache the job busy window from stop ETAs and time windows; maintained by ETA updater and when job state changes.",
      "type": "string"
     },
     "eta_last_updated_at": {
      "type": "string"
     },
     "external_data": {
      "type": "string"
     },
     "external_id": {
      "type": "string"
     },
     "external_source": {
      "type": "string"
     },
     "fulfilled_by_organization_id": {
      "type": "string"
     },
     "fulfilled_by_site_id": {
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "internal_notes": {
      "type": "string"
     },
     "is_active": {
      "type": "boolean"
     },
     "is_reservation": {
      "type": "boolean"
     },
     "job_number": {
      "type": "integer"
     },
     "optimization_method": {
      "$ref": "#/components/schemas/job.JobOptimizationMethod"
     },
     "options": {
      "items": {
       "$ref": "#/components/schemas/option.Option"
      },
      "type": "array"
     },
     "payment_confirmation": {
      "type": "string"
     },
     "payment_method": {
      "type": "string"
     },
     "payment_status": {
      "type": "string"
     },
     "ready_at": {
      "type": "string"
     },
     "require_driver_confirmation": {
      "type": "boolean"
     },
     "service_type_id": {
      "type": "string"
     },
     "share_token": {
      "description": "ShareToken is the opaque public identifier for this job's tracking link (NULL until minted via\nPOST /job/{id}/share-token). It replaces the raw jobId on the public tracking endpoint.",
      "type": "string"
     },
     "site_id": {
      "type": "string"
     },
     "start_at": {
      "type": "string"
     },
     "started_at": {
      "type": "string"
     },
     "state_timestamps": {
      "$ref": "#/components/schemas/db.JsonMap"
     },
     "stops": {
      "items": {
       "$ref": "#/components/schemas/stop.Stop"
      },
      "type": "array"
     },
     "tip": {
      "type": "number"
     },
     "transaction": {
      "$ref": "#/components/schemas/payments.Transaction"
     },
     "transaction_id": {
      "type": "string"
     },
     "updated_at": {
      "type": "string"
     },
     "updated_by_user": {
      "$ref": "#/components/schemas/user.User"
     },
     "updated_by_user_id": {
      "type": "string"
     },
     "vehicle_id": {
      "type": "string"
     },
     "workflow_id": {
      "type": "string"
     },
     "workflow_state": {
      "$ref": "#/components/schemas/workflow.WorkflowState"
     },
     "workflow_state_id": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "job.JobOptimizationMethod": {
    "enum": [
     "none",
     "time",
     "distance"
    ],
    "type": "string",
    "x-enum-varnames": [
     "JobOptimizationMethodNone",
     "JobOptimizationMethodTime",
     "JobOptimizationMethodDistance"
    ]
   },
   "job.JobRouteMarker": {
    "properties": {
     "address": {
      "$ref": "#/components/schemas/address.Address"
     },
     "arrived_at": {
      "type": "string"
     },
     "completed_at": {
      "type": "string"
     },
     "directions_location": {
      "$ref": "#/components/schemas/mapprovider.Point"
     },
     "estimated_arrival_at": {
      "type": "string"
     },
     "estimated_completion_at": {
      "type": "string"
     },
     "estimated_start_at": {
      "type": "string"
     },
     "job_id": {
      "type": "string"
     },
     "order": {
      "type": "integer"
     },
     "started_at": {
      "type": "string"
     },
     "stop_id": {
      "type": "string"
     },
     "type": {
      "type": "string"
     },
     "workflow_state": {
      "$ref": "#/components/schemas/workflow.WorkflowState"
     }
    },
    "type": "object"
   },
   "job.JobRouteResponse": {
    "properties": {
     "actual_traveled_path_polyline": {
      "type": "string"
     },
     "directions": {
      "$ref": "#/components/schemas/mapprovider.Route"
     },
     "markers": {
      "items": {
       "$ref": "#/components/schemas/job.JobRouteMarker"
      },
      "type": "array"
     },
     "route_summary": {
      "$ref": "#/components/schemas/job.JobRouteSummary"
     },
     "suggested_path_polyline": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "job.JobRouteSummary": {
    "properties": {
     "total_distance_meters": {
      "type": "number"
     },
     "total_duration_seconds": {
      "type": "number"
     }
    },
    "type": "object"
   },
   "job.JobTrackerResponse": {
    "properties": {
     "customer_name": {
      "type": "string"
     },
     "driver_name": {
      "type": "string"
     },
     "eta_last_updated": {
      "type": "string"
     },
     "job_id": {
      "type": "string"
     },
     "site_id": {
      "type": "string"
     },
     "stops": {
      "items": {
       "$ref": "#/components/schemas/job.JobTrackerStop"
      },
      "type": "array"
     },
     "workflow_state": {
      "$ref": "#/components/schemas/job.JobTrackerWorkflowState"
     }
    },
    "type": "object"
   },
   "job.JobTrackerStop": {
    "properties": {
     "address": {
      "$ref": "#/components/schemas/address.Address"
     },
     "arrived_at": {
      "type": "string"
     },
     "cancellation_notes": {
      "type": "string"
     },
     "cancelled_at": {
      "type": "string"
     },
     "complete_after": {
      "type": "string"
     },
     "complete_before": {
      "type": "string"
     },
     "completed_at": {
      "type": "string"
     },
     "customer_notes": {
      "type": "string"
     },
     "estimated_arrival_at": {
      "type": "string"
     },
     "estimated_completion_at": {
      "type": "string"
     },
     "estimated_start_at": {
      "type": "string"
     },
     "eta_last_updated_at": {
      "type": "string"
     },
     "job_id": {
      "type": "string"
     },
     "order": {
      "type": "integer"
     },
     "started_at": {
      "type": "string"
     },
     "stop_id": {
      "type": "string"
     },
     "total_duration_seconds": {
      "type": "integer"
     },
     "type": {
      "type": "string"
     },
     "workflow_state": {
      "$ref": "#/components/schemas/job.JobTrackerWorkflowState"
     }
    },
    "type": "object"
   },
   "job.JobTrackerWorkflowState": {
    "properties": {
     "group": {
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "label": {
      "type": "string"
     },
     "name": {
      "type": "string"
     },
     "workflow_id": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "job.StopETAPreviewRequest": {
    "properties": {
     "option_ids": {
      "items": {
       "type": "string"
      },
      "type": "array"
     },
     "service_type_id": {
      "type": "string"
     },
     "stops": {
      "items": {
       "$ref": "#/components/schemas/job.StopETAPreviewStop"
      },
      "type": "array"
     }
    },
    "type": "object"
   },
   "job.StopETAPreviewStop": {
    "properties": {
     "id": {
      "type": "string"
     },
     "point": {
      "properties": {
       "lat": {
        "type": "number"
       },
       "lng": {
        "type": "number"
       }
      },
      "type": "object"
     },
     "service_duration_seconds": {
      "description": "ServiceDurationSeconds is the expected on-site time at this stop (loading/unloading),\nadded between arrival and departure when accumulating ETAs.",
      "type": "integer"
     },
     "type": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "job.UpdateJobStateRequest": {
    "properties": {
     "id": {
      "description": "job id",
      "type": "string"
     },
     "state_id": {
      "type": "string"
     },
     "state_params": {
      "additionalProperties": true,
      "type": "object"
     }
    },
    "type": "object"
   },
   "jobs.CompletionTimeStats": {
    "properties": {
     "avg": {
      "type": "number"
     },
     "p50": {
      "type": "number"
     },
     "p90": {
      "type": "number"
     },
     "p95": {
      "type": "number"
     },
     "p99": {
      "type": "number"
     }
    },
    "type": "object"
   },
   "jobs.DriverMetrics": {
    "properties": {
     "completed_jobs": {
      "type": "integer"
     },
     "completed_stops": {
      "type": "integer"
     },
     "pending_jobs": {
      "type": "integer"
     },
     "pending_stops": {
      "type": "integer"
     },
     "total_jobs": {
      "type": "integer"
     },
     "total_stops": {
      "type": "integer"
     }
    },
    "type": "object"
   },
   "jobs.Metrics": {
    "properties": {
     "by_state": {
      "additionalProperties": {
       "type": "integer"
      },
      "type": "object"
     },
     "cancellation_rate": {
      "type": "number"
     },
     "completion_time_seconds": {
      "$ref": "#/components/schemas/jobs.CompletionTimeStats"
     },
     "total_active": {
      "type": "integer"
     },
     "total_cancelled": {
      "type": "integer"
     },
     "total_completed": {
      "type": "integer"
     },
     "total_created": {
      "type": "integer"
     }
    },
    "type": "object"
   },
   "jobs.StateCounts": {
    "properties": {
     "states": {
      "additionalProperties": {
       "type": "integer"
      },
      "type": "object"
     }
    },
    "type": "object"
   },
   "locationhistory.ActivityType": {
    "enum": [
     "STILL",
     "WALKING",
     "RUNNING",
     "CYCLING",
     "DRIVING",
     "ON_FOOT",
     "ON_BICYCLE",
     "FLYING",
     "ON_TRAIN",
     "UNKNOWN"
    ],
    "type": "string",
    "x-enum-varnames": [
     "ActivityStill",
     "ActivityWalking",
     "ActivityRunning",
     "ActivityCycling",
     "ActivityDriving",
     "ActivityOnFoot",
     "ActivityOnBicycle",
     "ActivityFlying",
     "ActivityOnTrain",
     "ActivityUnknown"
    ]
   },
   "locationhistory.LocationHistory": {
    "properties": {
     "accuracy": {
      "type": "number"
     },
     "activity": {
      "$ref": "#/components/schemas/locationhistory.ActivityType"
     },
     "altitude": {
      "description": "Altitude in meters relative to sea level\n-20.4 means the device was 20.4 meters below sea level",
      "type": "number"
     },
     "battery_level": {
      "type": "integer"
     },
     "bearing": {
      "type": "number"
     },
     "created_at": {
      "type": "string"
     },
     "deleted_at": {
      "type": "string"
     },
     "device_id": {
      "description": "Device Info",
      "type": "string"
     },
     "device_model": {
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "is_charging": {
      "type": "boolean"
     },
     "is_mocked": {
      "type": "boolean"
     },
     "location_timestamp": {
      "description": "Timing",
      "type": "string"
     },
     "network_type": {
      "type": "string"
     },
     "organization_id": {
      "type": "string"
     },
     "point": {
      "$ref": "#/components/schemas/db.Point"
     },
     "provider": {
      "description": "Network Info",
      "type": "string"
     },
     "signal_strength": {
      "type": "integer"
     },
     "site_id": {
      "type": "string"
     },
     "speed_meters": {
      "type": "number"
     },
     "updated_at": {
      "type": "string"
     },
     "user_id": {
      "type": "string"
     },
     "vehicle_id": {
      "type": "string"
     },
     "vertical_accuracy": {
      "description": "VerticalAccuracy The estimated error in the altitude value\nA vertical_accuracy of 0.5 means the reported altitude is within ±0.5 meters of the actual altitude",
      "type": "number"
     }
    },
    "required": [
     "device_id",
     "point"
    ],
    "type": "object"
   },
   "locationhistory.LocationHistoryRequest": {
    "properties": {
     "accuracy": {
      "description": "Accuracy is the horizontal accuracy of the GPS fix in meters",
      "type": "number"
     },
     "activity": {
      "description": "Activity is the detected physical activity (e.g. DRIVING, WALKING, STILL)",
      "type": "string"
     },
     "altitude": {
      "description": "Altitude is the altitude in meters relative to sea level",
      "type": "number"
     },
     "battery_level": {
      "description": "BatteryLevel is the device battery percentage (0-100)",
      "type": "integer"
     },
     "bearing": {
      "description": "Bearing is the heading direction in degrees (0-360)",
      "type": "number"
     },
     "device_id": {
      "description": "Device Info\nDeviceID is the unique identifier of the device",
      "type": "string"
     },
     "device_model": {
      "description": "DeviceModel is the model name of the device",
      "type": "string"
     },
     "is_charging": {
      "description": "IsCharging indicates whether the device is currently charging",
      "type": "boolean"
     },
     "is_mocked": {
      "description": "IsMocked indicates whether the location was generated by a mock provider",
      "type": "boolean"
     },
     "location_timestamp": {
      "description": "LocationTimestamp is the time the location was recorded on the device (RFC3339)",
      "type": "string"
     },
     "network_type": {
      "description": "NetworkType is the active network connection type (e.g. wifi, lte)",
      "type": "string"
     },
     "point": {
      "description": "Point holds the GPS coordinates for this location entry",
      "properties": {
       "lat": {
        "description": "Lat is the latitude coordinate",
        "type": "number"
       },
       "lng": {
        "description": "Lng is the longitude coordinate",
        "type": "number"
       }
      },
      "required": [
       "lat",
       "lng"
      ],
      "type": "object"
     },
     "provider": {
      "description": "Network Info\nProvider is the location provider (e.g. gps, network, fused)",
      "type": "string"
     },
     "signal_strength": {
      "description": "SignalStrength is the network signal strength in dBm",
      "type": "integer"
     },
     "speed_meters": {
      "description": "SpeedMeters is the speed of the device in meters per second",
      "type": "number"
     },
     "vehicle_id": {
      "description": "VehicleID is the optional vehicle associated with this location entry",
      "type": "string"
     },
     "vertical_accuracy": {
      "description": "VerticalAccuracy is the estimated error in the altitude value in meters",
      "type": "number"
     }
    },
    "required": [
     "point"
    ],
    "type": "object"
   },
   "locationhistory.Metrics": {
    "properties": {
     "avg_distance_travelled_per_job": {
      "description": "meters",
      "type": "number"
     },
     "avg_speed_during_jobs": {
      "description": "m/s",
      "type": "number"
     },
     "avg_speed_overall": {
      "description": "m/s",
      "type": "number"
     },
     "time_driving": {
      "description": "seconds",
      "type": "number"
     },
     "time_stationary": {
      "description": "seconds",
      "type": "number"
     },
     "total_distance_driven": {
      "description": "meters",
      "type": "number"
     }
    },
    "type": "object"
   },
   "mapprovider.AddressPredictionResult": {
    "properties": {
     "matched_offsets": {
      "items": {
       "$ref": "#/components/schemas/mapprovider.PredictionMatchOffsets"
      },
      "type": "array"
     },
     "matched_text": {
      "type": "string"
     },
     "source": {
      "type": "string"
     },
     "source_id": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "mapprovider.FailedConstraint": {
    "properties": {
     "constraint": {
      "description": "raw HERE constraint string",
      "type": "string"
     },
     "kind": {
      "description": "\"access_window\" | \"before\" | \"service_time\" | \"other\"",
      "type": "string"
     },
     "reason": {
      "description": "raw reason code",
      "type": "integer"
     },
     "reason_string": {
      "description": "decoded human text",
      "type": "string"
     }
    },
    "type": "object"
   },
   "mapprovider.Location": {
    "properties": {
     "id": {
      "description": "ID of the location",
      "type": "string"
     },
     "original_point": {
      "allOf": [
       {
        "$ref": "#/components/schemas/mapprovider.Point"
       }
      ],
      "description": "Original latitude and longitude of the location"
     },
     "point": {
      "allOf": [
       {
        "$ref": "#/components/schemas/mapprovider.Point"
       }
      ],
      "description": "Latitude and longitude of the location"
     },
     "waypoint_index": {
      "description": "Index of the waypoint in the route",
      "type": "integer"
     }
    },
    "type": "object"
   },
   "mapprovider.Point": {
    "properties": {
     "lat": {
      "type": "number"
     },
     "lng": {
      "type": "number"
     }
    },
    "type": "object"
   },
   "mapprovider.PredictionMatchOffsets": {
    "properties": {
     "end_offset": {
      "type": "integer"
     },
     "start_offset": {
      "type": "integer"
     }
    },
    "type": "object"
   },
   "mapprovider.Route": {
    "properties": {
     "distance_meters": {
      "description": "Total distance in meters",
      "type": "number"
     },
     "duration_seconds": {
      "description": "Total duration in seconds",
      "type": "number"
     },
     "id": {
      "description": "To store the route ID, if provided",
      "type": "string"
     },
     "legs": {
      "description": "Segments or legs of the route",
      "items": {
       "$ref": "#/components/schemas/mapprovider.RouteLeg"
      },
      "type": "array"
     },
     "polyline": {
      "description": "Encoded polyline for the entire route",
      "type": "string"
     },
     "summary": {
      "description": "General summary or overview of the route",
      "type": "string"
     },
     "warnings": {
      "description": "Warnings is provider-level warnings (e.g. findsequence2 top-level warnings string).",
      "items": {
       "type": "string"
      },
      "type": "array"
     },
     "waypoint_feasibility": {
      "description": "WaypointFeasibility carries per-waypoint ETAs and constraint compliance as reported\nby the underlying sequencing/optimization call (e.g. HERE findsequence2). Keyed by\nthe caller-supplied waypoint ID. Empty when the provider doesn't return it.",
      "items": {
       "$ref": "#/components/schemas/mapprovider.WaypointFeasibility"
      },
      "type": "array"
     }
    },
    "type": "object"
   },
   "mapprovider.RouteLeg": {
    "properties": {
     "arrive_at": {
      "description": "End time of this leg",
      "type": "string"
     },
     "depart_at": {
      "description": "Start time of this leg",
      "type": "string"
     },
     "distance_meters": {
      "description": "Distance for this leg in meters",
      "type": "number"
     },
     "duration_seconds": {
      "description": "Duration for this leg in seconds",
      "type": "number"
     },
     "end_stop": {
      "allOf": [
       {
        "$ref": "#/components/schemas/mapprovider.Location"
       }
      ],
      "description": "Ending address of the leg, if available"
     },
     "polyline": {
      "description": "Encoded polyline for this step",
      "type": "string"
     },
     "start_stop": {
      "allOf": [
       {
        "$ref": "#/components/schemas/mapprovider.Location"
       }
      ],
      "description": "Starting address of the leg, if available"
     },
     "state": {
      "description": "State is the leg's execution-progress color: one of LegState{Completed,\nCurrent,Upcoming}. Empty for planner/geometry responses; populated by the\nroute-progress endpoints from stop workflow state.",
      "type": "string"
     }
    },
    "type": "object"
   },
   "mapprovider.RouteMatrixElement": {
    "properties": {
     "destination_index": {
      "type": "integer"
     },
     "distance_meters": {
      "type": "number"
     },
     "duration_seconds": {
      "type": "number"
     },
     "origin_index": {
      "type": "integer"
     }
    },
    "type": "object"
   },
   "mapprovider.RouteMatrixResult": {
    "properties": {
     "elements": {
      "items": {
       "$ref": "#/components/schemas/mapprovider.RouteMatrixElement"
      },
      "type": "array"
     },
     "num_destinations": {
      "type": "integer"
     },
     "num_origins": {
      "type": "integer"
     }
    },
    "type": "object"
   },
   "mapprovider.WayPointSequenceResult": {
    "properties": {
     "arrive_at": {
      "type": "string"
     },
     "constraints": {
      "description": "Constraints is retained for backward compatibility; mirrors FulfilledConstraints.",
      "items": {
       "type": "string"
      },
      "type": "array"
     },
     "depart_at": {
      "type": "string"
     },
     "fulfilled_constraints": {
      "items": {
       "type": "string"
      },
      "type": "array"
     },
     "id": {
      "type": "string"
     },
     "lat": {
      "type": "number"
     },
     "lng": {
      "type": "number"
     },
     "sequence": {
      "type": "integer"
     },
     "violated_constraints": {
      "items": {
       "type": "string"
      },
      "type": "array"
     }
    },
    "type": "object"
   },
   "mapprovider.WaypointFeasibility": {
    "properties": {
     "estimated_arrival": {
      "type": "string"
     },
     "estimated_departure": {
      "type": "string"
     },
     "failed_constraint_details": {
      "items": {
       "$ref": "#/components/schemas/mapprovider.FailedConstraint"
      },
      "type": "array"
     },
     "fulfilled_constraints": {
      "items": {
       "type": "string"
      },
      "type": "array"
     },
     "id": {
      "type": "string"
     },
     "sequence": {
      "type": "integer"
     },
     "violated_constraints": {
      "items": {
       "type": "string"
      },
      "type": "array"
     }
    },
    "type": "object"
   },
   "metrics.RevenueTimeSeriesDataPoint": {
    "properties": {
     "date": {
      "description": "ISO date format (YYYY-MM-DD)",
      "type": "string"
     },
     "revenue": {
      "description": "Revenue in this period",
      "type": "number"
     }
    },
    "type": "object"
   },
   "metrics.RevenueTimeSeriesResponse": {
    "properties": {
     "data": {
      "items": {
       "$ref": "#/components/schemas/metrics.RevenueTimeSeriesDataPoint"
      },
      "type": "array"
     },
     "from": {
      "description": "ISO date",
      "type": "string"
     },
     "granularity": {
      "description": "\"daily\", \"weekly\", \"monthly\"",
      "type": "string"
     },
     "to": {
      "description": "ISO date",
      "type": "string"
     }
    },
    "type": "object"
   },
   "metrics.TimeSeriesDataPoint": {
    "properties": {
     "active": {
      "description": "Active jobs at end of period (jobs only)",
      "type": "integer"
     },
     "cancellation_rate": {
      "description": "Cancellation rate for period (jobs only)",
      "type": "number"
     },
     "cancelled": {
      "description": "Jobs cancelled (jobs only)",
      "type": "integer"
     },
     "completed": {
      "description": "Jobs completed (jobs only)",
      "type": "integer"
     },
     "created": {
      "description": "Jobs/customers created in this period",
      "type": "integer"
     },
     "date": {
      "description": "ISO date format (YYYY-MM-DD)",
      "type": "string"
     },
     "total": {
      "description": "Cumulative total customers (customers only)",
      "type": "integer"
     }
    },
    "type": "object"
   },
   "metrics.TimeSeriesResponse": {
    "properties": {
     "data": {
      "items": {
       "$ref": "#/components/schemas/metrics.TimeSeriesDataPoint"
      },
      "type": "array"
     },
     "from": {
      "description": "ISO date",
      "type": "string"
     },
     "granularity": {
      "description": "\"daily\", \"weekly\", \"monthly\"",
      "type": "string"
     },
     "to": {
      "description": "ISO date",
      "type": "string"
     }
    },
    "type": "object"
   },
   "notification.DeliveryMethod": {
    "enum": [
     "sms",
     "push",
     "email"
    ],
    "type": "string",
    "x-enum-varnames": [
     "DeliveryMethodSMS",
     "DeliveryMethodPush",
     "DeliveryMethodEmail"
    ]
   },
   "notification.MarkReadRequest": {
    "properties": {
     "ids": {
      "items": {
       "type": "string"
      },
      "type": "array"
     }
    },
    "type": "object"
   },
   "notification.Notification": {
    "properties": {
     "body": {
      "type": "string"
     },
     "created_at": {
      "type": "string"
     },
     "delivery_method": {
      "$ref": "#/components/schemas/notification.DeliveryMethod"
     },
     "external_template_id": {
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "provider": {
      "type": "string"
     },
     "provider_request": {
      "type": "string"
     },
     "provider_response": {
      "type": "string"
     },
     "read_at": {
      "type": "string"
     },
     "related_entity_id": {
      "type": "string"
     },
     "related_entity_type": {
      "type": "string"
     },
     "send_at": {
      "type": "string"
     },
     "site_id": {
      "type": "string"
     },
     "status": {
      "$ref": "#/components/schemas/notification.Status"
     },
     "template_data": {
      "$ref": "#/components/schemas/db.JsonMap"
     },
     "template_id": {
      "type": "string"
     },
     "title": {
      "type": "string"
     },
     "type": {
      "description": "eg. job_updated, queue_reminder",
      "type": "string"
     },
     "updated_at": {
      "type": "string"
     },
     "user_id": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "notification.Status": {
    "enum": [
     "pending",
     "sent",
     "delivered",
     "failed"
    ],
    "type": "string",
    "x-enum-varnames": [
     "StatusPending",
     "StatusSent",
     "StatusDelivered",
     "StatusFailed"
    ]
   },
   "notification.UnreadCountResponse": {
    "properties": {
     "unread_count": {
      "type": "integer"
     }
    },
    "type": "object"
   },
   "notificationconfig.DefaultConfigWithTemplate": {
    "properties": {
     "delivery_method": {
      "$ref": "#/components/schemas/notification.DeliveryMethod"
     },
     "enabled": {
      "type": "boolean"
     },
     "notification_type": {
      "type": "string"
     },
     "recipient_type": {
      "$ref": "#/components/schemas/notificationconfig.RecipientType"
     },
     "template": {
      "$ref": "#/components/schemas/notificationconfig.TemplateResponse"
     }
    },
    "type": "object"
   },
   "notificationconfig.NotificationConfig": {
    "properties": {
     "created_at": {
      "type": "string"
     },
     "debounce_seconds": {
      "type": "integer"
     },
     "delivery_method": {
      "$ref": "#/components/schemas/notification.DeliveryMethod"
     },
     "enabled": {
      "type": "boolean"
     },
     "id": {
      "type": "string"
     },
     "recipient_type": {
      "$ref": "#/components/schemas/notificationconfig.RecipientType"
     },
     "site_id": {
      "type": "string"
     },
     "template_id": {
      "description": "NULL means use global default",
      "type": "string"
     },
     "updated_at": {
      "type": "string"
     },
     "workflow_state_id": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "notificationconfig.NotificationConfigResponse": {
    "properties": {
     "debounce_seconds": {
      "type": "integer"
     },
     "delivery_method": {
      "$ref": "#/components/schemas/notification.DeliveryMethod"
     },
     "enabled": {
      "type": "boolean"
     },
     "id": {
      "type": "string"
     },
     "is_custom_config": {
      "description": "True if a config row exists in DB",
      "type": "boolean"
     },
     "recipient_type": {
      "$ref": "#/components/schemas/notificationconfig.RecipientType"
     },
     "template": {
      "$ref": "#/components/schemas/notificationconfig.TemplateResponse"
     },
     "workflow_state_id": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "notificationconfig.RecipientType": {
    "enum": [
     "customer",
     "driver",
     "admin"
    ],
    "type": "string",
    "x-enum-varnames": [
     "RecipientCustomer",
     "RecipientDriver",
     "RecipientAdmin"
    ]
   },
   "notificationconfig.StateGroupDefaultsResponse": {
    "properties": {
     "configs": {
      "items": {
       "$ref": "#/components/schemas/notificationconfig.DefaultConfigWithTemplate"
      },
      "type": "array"
     },
     "state_group": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "notificationconfig.TemplateRequest": {
    "properties": {
     "body": {
      "type": "string"
     },
     "title": {
      "type": "string"
     }
    },
    "required": [
     "body"
    ],
    "type": "object"
   },
   "notificationconfig.TemplateResponse": {
    "properties": {
     "body": {
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "is_custom": {
      "description": "True if this is a site-specific template",
      "type": "boolean"
     },
     "title": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "notificationconfig.UpsertNotificationConfigRequest": {
    "properties": {
     "debounce_seconds": {
      "type": "integer"
     },
     "delivery_method": {
      "$ref": "#/components/schemas/notification.DeliveryMethod"
     },
     "enabled": {
      "type": "boolean"
     },
     "recipient_type": {
      "$ref": "#/components/schemas/notificationconfig.RecipientType"
     },
     "template": {
      "allOf": [
       {
        "$ref": "#/components/schemas/notificationconfig.TemplateRequest"
       }
      ],
      "description": "If provided, creates/updates a site-specific template"
     },
     "workflow_state_id": {
      "type": "string"
     }
    },
    "required": [
     "delivery_method",
     "recipient_type",
     "workflow_state_id"
    ],
    "type": "object"
   },
   "notificationconfig.WorkflowStateConfigsResponse": {
    "properties": {
     "configs": {
      "items": {
       "$ref": "#/components/schemas/notificationconfig.NotificationConfigResponse"
      },
      "type": "array"
     },
     "workflow_state_id": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "onboard.SignupRequest": {
    "properties": {
     "city": {
      "example": "New York",
      "type": "string"
     },
     "country": {
      "example": "US",
      "type": "string"
     },
     "email": {
      "example": "jane@example.com",
      "type": "string"
     },
     "first_name": {
      "example": "Jane",
      "type": "string"
     },
     "industry_type": {
      "example": "delivery",
      "type": "string"
     },
     "last_name": {
      "example": "Doe",
      "type": "string"
     },
     "latitude": {
      "example": 40.7128,
      "type": "number"
     },
     "longitude": {
      "example": -74.006,
      "type": "number"
     },
     "password": {
      "example": "s3cr3t",
      "type": "string"
     },
     "phone": {
      "example": "5550001234",
      "type": "string"
     },
     "phone_country": {
      "example": "US",
      "type": "string"
     },
     "postal_code": {
      "example": "10001",
      "type": "string"
     },
     "site_name": {
      "example": "Acme Deliveries",
      "type": "string"
     },
     "site_subdomain": {
      "example": "acme",
      "type": "string"
     },
     "state": {
      "example": "NY",
      "type": "string"
     },
     "street_address": {
      "example": "123 Main St",
      "type": "string"
     },
     "street_address2": {
      "example": "Suite 100",
      "type": "string"
     }
    },
    "type": "object"
   },
   "onboard.SignupResponse": {
    "properties": {
     "application": {
      "$ref": "#/components/schemas/application.Application"
     },
     "organization": {
      "$ref": "#/components/schemas/organization.Organization"
     },
     "site": {
      "$ref": "#/components/schemas/site.Site"
     },
     "user": {
      "$ref": "#/components/schemas/user.User"
     }
    },
    "type": "object"
   },
   "onboard.SignupSiteRequest": {
    "properties": {
     "address_id": {
      "example": "addr_01J...",
      "type": "string"
     },
     "currency": {
      "example": "USD",
      "type": "string"
     },
     "email": {
      "example": "east@acme.com",
      "type": "string"
     },
     "industry_type": {
      "example": "delivery",
      "type": "string"
     },
     "name": {
      "example": "Acme East",
      "type": "string"
     },
     "notes": {
      "example": "East coast hub",
      "type": "string"
     },
     "phone": {
      "example": "5550001234",
      "type": "string"
     },
     "phone_country": {
      "example": "US",
      "type": "string"
     },
     "subdomain": {
      "example": "acme-east",
      "type": "string"
     },
     "timezone": {
      "example": "EST",
      "type": "string"
     },
     "website": {
      "example": "https://east.acme.com",
      "type": "string"
     }
    },
    "type": "object"
   },
   "option.Option": {
    "properties": {
     "applicable_entities": {
      "description": "Already a []string",
      "items": {
       "$ref": "#/components/schemas/option.OptionEntityType"
      },
      "type": "array"
     },
     "created_at": {
      "type": "string"
     },
     "created_by": {
      "type": "string"
     },
     "description": {
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "is_active": {
      "type": "boolean"
     },
     "name": {
      "type": "string"
     },
     "site_id": {
      "type": "string"
     },
     "updated_at": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "option.OptionAssignRequest": {
    "properties": {
     "entity_id": {
      "description": "EntityID is the ID of the entity (worker, service type, or vehicle).",
      "example": "wrk_01J...",
      "type": "string"
     },
     "entity_type": {
      "allOf": [
       {
        "$ref": "#/components/schemas/option.OptionEntityType"
       }
      ],
      "description": "EntityType is the type of entity to assign the option to.\nValid values: worker, service_type, vehicle.",
      "enum": [
       "worker",
       "service_type",
       "vehicle",
       "job"
      ],
      "example": "worker"
     },
     "option_id": {
      "description": "OptionID is the ID of the option to assign.",
      "example": "opt_01J...",
      "type": "string"
     }
    },
    "required": [
     "entity_id",
     "entity_type",
     "option_id"
    ],
    "type": "object"
   },
   "option.OptionEntityType": {
    "enum": [
     "worker",
     "service_type",
     "vehicle",
     "job"
    ],
    "type": "string",
    "x-enum-varnames": [
     "OptionEntityTypeWorker",
     "OptionEntityTypeServiceType",
     "OptionEntityTypeVehicle",
     "OptionEntityTypeJob"
    ]
   },
   "option.OptionRequest": {
    "properties": {
     "applicable_entities": {
      "description": "ApplicableEntities lists the entity types this option can be assigned to.\nValid values: worker, service_type, vehicle, job.",
      "example": [
       "worker",
       "vehicle"
      ],
      "items": {
       "type": "string"
      },
      "type": "array"
     },
     "description": {
      "description": "Description provides additional detail about the option.",
      "example": "Guaranteed same-day delivery",
      "type": "string"
     },
     "is_active": {
      "description": "IsActive indicates whether the option is currently available for assignment.",
      "example": true,
      "type": "boolean"
     },
     "name": {
      "description": "Name is the display name of the option.",
      "example": "Express Delivery",
      "type": "string"
     }
    },
    "required": [
     "applicable_entities",
     "name"
    ],
    "type": "object"
   },
   "organization.Organization": {
    "properties": {
     "address": {
      "$ref": "#/components/schemas/address.Address"
     },
     "address_id": {
      "type": "string"
     },
     "created_at": {
      "type": "string"
     },
     "deleted_at": {
      "type": "string"
     },
     "description": {
      "type": "string"
     },
     "email": {
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "is_active": {
      "type": "boolean"
     },
     "name": {
      "type": "string"
     },
     "phone": {
      "type": "string"
     },
     "phone_country": {
      "type": "string"
     },
     "updated_at": {
      "type": "string"
     }
    },
    "required": [
     "address_id",
     "email",
     "name",
     "phone",
     "phone_country"
    ],
    "type": "object"
   },
   "organization.OrganizationRequest": {
    "properties": {
     "address_id": {
      "description": "AddressID is the ID of the organization's primary address record.",
      "example": "addr_01J...",
      "type": "string"
     },
     "description": {
      "description": "Description provides additional context about the organization.",
      "example": "Leading delivery company",
      "type": "string"
     },
     "email": {
      "description": "Email is the organization's primary contact email address.",
      "example": "contact@acme.com",
      "type": "string"
     },
     "id": {
      "description": "ID is the optional existing organization ID (used for updates).",
      "example": "org_01J...",
      "type": "string"
     },
     "name": {
      "description": "Name is the display name of the organization.",
      "example": "Acme Corp",
      "type": "string"
     },
     "phone": {
      "description": "Phone is the organization's contact phone number.",
      "example": "5550001234",
      "type": "string"
     },
     "phone_country": {
      "description": "PhoneCountry is the ISO 3166-1 alpha-2 country code for the phone number.",
      "example": "US",
      "type": "string"
     }
    },
    "type": "object"
   },
   "payments.InitializeSetupResponse": {
    "properties": {
     "providerClientSecret": {
      "type": "string"
     },
     "providerCustomerID": {
      "type": "string"
     },
     "providerSetupIntentID": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "payments.Metrics": {
    "properties": {
     "estimated_revenue_generated": {
      "type": "number"
     },
     "revenue_per_job_avg": {
      "type": "number"
     }
    },
    "type": "object"
   },
   "payments.OwnerType": {
    "enum": [
     "organization",
     "user",
     "site"
    ],
    "type": "string",
    "x-enum-varnames": [
     "OwnerTypeOrganization",
     "OwnerTypeUser",
     "OwnerTypeSite"
    ]
   },
   "payments.PaymentMethod": {
    "properties": {
     "card_brand": {
      "description": "Metadata for UI display",
      "type": "string"
     },
     "created_at": {
      "type": "string"
     },
     "exp_month": {
      "type": "integer"
     },
     "exp_year": {
      "type": "integer"
     },
     "id": {
      "type": "string"
     },
     "is_active": {
      "type": "boolean"
     },
     "is_default": {
      "type": "boolean"
     },
     "last4": {
      "type": "string"
     },
     "owner_id": {
      "description": "e.g. UserID or OrgID",
      "type": "string"
     },
     "owner_type": {
      "$ref": "#/components/schemas/payments.OwnerType"
     },
     "provider": {
      "description": "The Integration used to tokenize this card (e.g. \"stripe\")",
      "type": "string"
     },
     "site_id": {
      "type": "string"
     },
     "updated_at": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "payments.Transaction": {
    "properties": {
     "amount_cents": {
      "description": "stored in cents",
      "type": "integer"
     },
     "capture_method": {
      "allOf": [
       {
        "$ref": "#/components/schemas/payments.TransactionCaptureMethod"
       }
      ],
      "description": "\"automatic\" or \"manual\""
     },
     "created_at": {
      "type": "string"
     },
     "currency": {
      "description": "e.g. \"usd\"",
      "type": "string"
     },
     "entity_id": {
      "description": "e.g. job_id, subscription_id",
      "type": "string"
     },
     "entity_type": {
      "description": "e.g. \"job\", \"subscription\"",
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "payment_method_id": {
      "description": "Link back to the internal payment method used",
      "type": "string"
     },
     "provider_account_id": {
      "description": "e.g. \"acct_abc123\"",
      "type": "string"
     },
     "provider_key": {
      "description": "Provider Tracking",
      "type": "string"
     },
     "provider_metadata": {
      "allOf": [
       {
        "$ref": "#/components/schemas/db.JsonMap"
       }
      ],
      "description": "e.g. {\"payment_intent_id\": \"pi_...\"}"
     },
     "provider_payment_method_id": {
      "type": "string"
     },
     "provider_transaction_id": {
      "description": "e.g. \"pi_abc123\"",
      "type": "string"
     },
     "provider_transaction_status": {
      "type": "string"
     },
     "provider_user_id": {
      "description": "e.g. \"cus_abc123\"",
      "type": "string"
     },
     "site_id": {
      "type": "string"
     },
     "status": {
      "$ref": "#/components/schemas/payments.TransactionStatus"
     },
     "tip_amount_cents": {
      "description": "tip in cents, 0 if no tip",
      "type": "integer"
     },
     "updated_at": {
      "type": "string"
     },
     "user_id": {
      "description": "who initiated the transaction",
      "type": "string"
     }
    },
    "type": "object"
   },
   "payments.TransactionCaptureMethod": {
    "enum": [
     "automatic",
     "manual"
    ],
    "type": "string",
    "x-enum-varnames": [
     "CaptureMethodAutomatic",
     "CaptureMethodManual"
    ]
   },
   "payments.TransactionStatus": {
    "enum": [
     "pending",
     "authorized",
     "succeeded",
     "failed",
     "refunded",
     "voided"
    ],
    "type": "string",
    "x-enum-varnames": [
     "StatusPending",
     "StatusAuthorized",
     "StatusSucceeded",
     "StatusFailed",
     "StatusRefunded",
     "StatusVoided"
    ]
   },
   "pricing.AppliedOptionCharge": {
    "properties": {
     "amount": {
      "type": "number"
     },
     "option_id": {
      "type": "string"
     },
     "type": {
      "$ref": "#/components/schemas/pricing.PriceSurchargeType"
     }
    },
    "type": "object"
   },
   "pricing.EstimateRequestRouteOptions": {
    "properties": {
     "routing_mode": {
      "type": "string"
     },
     "transport_mode": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "pricing.EstimateRequestStop": {
    "properties": {
     "address": {
      "properties": {
       "point": {
        "properties": {
         "lat": {
          "type": "number"
         },
         "lng": {
          "type": "number"
         }
        },
        "type": "object"
       }
      },
      "type": "object"
     },
     "id": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "pricing.PriceComponent": {
    "properties": {
     "amount": {
      "type": "number"
     },
     "type": {
      "$ref": "#/components/schemas/pricing.PriceComponentType"
     }
    },
    "type": "object"
   },
   "pricing.PriceComponentRequest": {
    "properties": {
     "amount": {
      "type": "number"
     },
     "type": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "pricing.PriceComponentType": {
    "enum": [
     "base",
     "per_distance_unit",
     "per_minute",
     "per_stop",
     "service_fee",
     "wait_time"
    ],
    "type": "string",
    "x-enum-varnames": [
     "PriceComponentTypeBase",
     "PriceComponentTypePerDistanceUnit",
     "PriceComponentTypePerMinute",
     "PriceComponentTypePerStop",
     "PriceComponentTypeServiceFee",
     "PriceComponentTypeWaitTime"
    ]
   },
   "pricing.PriceEstimateItem": {
    "properties": {
     "applied_option_charges": {
      "items": {
       "$ref": "#/components/schemas/pricing.AppliedOptionCharge"
      },
      "type": "array"
     },
     "created_at": {
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "service_type": {
      "$ref": "#/components/schemas/servicetype.ServiceType"
     },
     "service_type_id": {
      "type": "string"
     },
     "site_id": {
      "type": "string"
     },
     "total_distance_meters": {
      "type": "number"
     },
     "total_duration_seconds": {
      "type": "number"
     },
     "total_price": {
      "type": "number"
     },
     "vehicle_id": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "pricing.PriceEstimateRequest": {
    "properties": {
     "destination": {
      "properties": {
       "address": {
        "properties": {
         "point": {
          "properties": {
           "lat": {
            "type": "number"
           },
           "lng": {
            "type": "number"
           }
          },
          "type": "object"
         }
        },
        "type": "object"
       },
       "id": {
        "type": "string"
       }
      },
      "type": "object"
     },
     "option_ids": {
      "description": "OptionIDs are job options the customer selected; each one matching a price-rule option\nmodifier adds its flat/percentage charge once per job.",
      "items": {
       "type": "string"
      },
      "type": "array"
     },
     "origin": {
      "properties": {
       "address": {
        "properties": {
         "point": {
          "properties": {
           "lat": {
            "type": "number"
           },
           "lng": {
            "type": "number"
           }
          },
          "type": "object"
         }
        },
        "type": "object"
       },
       "id": {
        "type": "string"
       }
      },
      "type": "object"
     },
     "route_options": {
      "$ref": "#/components/schemas/pricing.EstimateRequestRouteOptions"
     },
     "service_type_ids": {
      "items": {
       "type": "string"
      },
      "type": "array"
     },
     "stops": {
      "items": {
       "$ref": "#/components/schemas/pricing.EstimateRequestStop"
      },
      "type": "array"
     }
    },
    "type": "object"
   },
   "pricing.PriceEstimateResponse": {
    "properties": {
     "estimates": {
      "items": {
       "$ref": "#/components/schemas/pricing.PriceEstimateItem"
      },
      "type": "array"
     }
    },
    "type": "object"
   },
   "pricing.PriceRule": {
    "properties": {
     "cancellation_fee": {
      "type": "number"
     },
     "components": {
      "items": {
       "$ref": "#/components/schemas/pricing.PriceComponent"
      },
      "type": "array"
     },
     "conditions": {
      "items": {
       "$ref": "#/components/schemas/pricing.PriceRuleCondition"
      },
      "type": "array"
     },
     "created_at": {
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "is_active": {
      "type": "boolean"
     },
     "is_default": {
      "type": "boolean"
     },
     "maximum_price": {
      "type": "number"
     },
     "minimum_price": {
      "type": "number"
     },
     "name": {
      "type": "string"
     },
     "option_modifiers": {
      "items": {
       "$ref": "#/components/schemas/pricing.PriceRuleOptionModifier"
      },
      "type": "array"
     },
     "priority": {
      "type": "integer"
     },
     "service_type_modifiers": {
      "items": {
       "$ref": "#/components/schemas/pricing.PriceRuleServiceTypeModifier"
      },
      "type": "array"
     },
     "site_id": {
      "type": "string"
     },
     "surcharges": {
      "items": {
       "$ref": "#/components/schemas/pricing.PriceSurcharge"
      },
      "type": "array"
     },
     "updated_at": {
      "type": "string"
     },
     "vehicle_type_modifiers": {
      "items": {
       "$ref": "#/components/schemas/pricing.PriceRuleVehicleTypeModifier"
      },
      "type": "array"
     },
     "wait_time_buffer_minutes": {
      "type": "integer"
     },
     "zones": {
      "items": {
       "$ref": "#/components/schemas/pricing.PriceZone"
      },
      "type": "array"
     }
    },
    "type": "object"
   },
   "pricing.PriceRuleCondition": {
    "properties": {
     "amount": {
      "type": "number"
     },
     "type": {
      "$ref": "#/components/schemas/pricing.PriceRuleConditionType"
     },
     "value": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "pricing.PriceRuleConditionRequest": {
    "properties": {
     "amount": {
      "type": "number"
     },
     "type": {
      "type": "string"
     },
     "value": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "pricing.PriceRuleConditionType": {
    "enum": [
     "zone",
     "distance",
     "vehicle_type",
     "service_type",
     "service_requirement",
     "day_of_week",
     "time_range"
    ],
    "type": "string",
    "x-enum-varnames": [
     "PriceRuleConditionTypeZone",
     "PriceRuleConditionTypeDistance",
     "PriceRuleConditionTypeVehicleType",
     "PriceRuleConditionTypeServiceType",
     "PriceRuleConditionTypeServiceRequirement",
     "PriceRuleConditionTypeDayOfWeek",
     "PriceRuleConditionTypeTimeRange"
    ]
   },
   "pricing.PriceRuleOptionModifier": {
    "properties": {
     "amount": {
      "type": "number"
     },
     "option_id": {
      "type": "string"
     },
     "type": {
      "$ref": "#/components/schemas/pricing.PriceSurchargeType"
     }
    },
    "type": "object"
   },
   "pricing.PriceRuleOptionModifierRequest": {
    "properties": {
     "amount": {
      "type": "number"
     },
     "option_id": {
      "type": "string"
     },
     "type": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "pricing.PriceRuleRequest": {
    "properties": {
     "cancellation_fee": {
      "type": "number"
     },
     "components": {
      "items": {
       "$ref": "#/components/schemas/pricing.PriceComponentRequest"
      },
      "type": "array"
     },
     "conditions": {
      "items": {
       "$ref": "#/components/schemas/pricing.PriceRuleConditionRequest"
      },
      "type": "array"
     },
     "is_default": {
      "type": "boolean"
     },
     "maximum_price": {
      "type": "number"
     },
     "minimum_price": {
      "type": "number"
     },
     "name": {
      "type": "string"
     },
     "option_modifiers": {
      "items": {
       "$ref": "#/components/schemas/pricing.PriceRuleOptionModifierRequest"
      },
      "type": "array"
     },
     "priority": {
      "type": "integer"
     },
     "service_type_modifiers": {
      "items": {
       "$ref": "#/components/schemas/pricing.PriceRuleServiceTypeModifierRequest"
      },
      "type": "array"
     },
     "surcharges": {
      "items": {
       "$ref": "#/components/schemas/pricing.PriceSurchargeRequest"
      },
      "type": "array"
     },
     "vehicle_type_modifiers": {
      "items": {
       "$ref": "#/components/schemas/pricing.PriceRuleVehicleTypeModifierRequest"
      },
      "type": "array"
     },
     "wait_time_buffer_minutes": {
      "type": "integer"
     },
     "zones": {
      "items": {
       "$ref": "#/components/schemas/pricing.PriceZoneRequest"
      },
      "type": "array"
     }
    },
    "type": "object"
   },
   "pricing.PriceRuleServiceTypeModifier": {
    "properties": {
     "base_price": {
      "type": "number"
     },
     "price_per_distance_unit": {
      "type": "number"
     },
     "price_per_minute": {
      "type": "number"
     },
     "price_per_stop": {
      "type": "number"
     },
     "service_fee": {
      "type": "number"
     },
     "service_type_id": {
      "type": "string"
     },
     "wait_time": {
      "type": "number"
     }
    },
    "type": "object"
   },
   "pricing.PriceRuleServiceTypeModifierRequest": {
    "properties": {
     "base_price": {
      "type": "number"
     },
     "price_per_distance_unit": {
      "type": "number"
     },
     "price_per_minute": {
      "type": "number"
     },
     "price_per_stop": {
      "type": "number"
     },
     "service_fee": {
      "type": "number"
     },
     "service_type_id": {
      "type": "string"
     },
     "wait_time": {
      "type": "number"
     }
    },
    "type": "object"
   },
   "pricing.PriceRuleVehicleTypeModifier": {
    "properties": {
     "base_price": {
      "type": "number"
     },
     "price_per_distance_unit": {
      "type": "number"
     },
     "price_per_minute": {
      "type": "number"
     },
     "price_per_stop": {
      "type": "number"
     },
     "service_fee": {
      "type": "number"
     },
     "vehicle_type_id": {
      "type": "string"
     },
     "wait_time": {
      "type": "number"
     }
    },
    "type": "object"
   },
   "pricing.PriceRuleVehicleTypeModifierRequest": {
    "properties": {
     "base_price": {
      "type": "number"
     },
     "price_per_distance_unit": {
      "type": "number"
     },
     "price_per_minute": {
      "type": "number"
     },
     "price_per_stop": {
      "type": "number"
     },
     "service_fee": {
      "type": "number"
     },
     "vehicle_type_id": {
      "type": "string"
     },
     "wait_time": {
      "type": "number"
     }
    },
    "type": "object"
   },
   "pricing.PriceSurcharge": {
    "properties": {
     "amount": {
      "type": "number"
     },
     "id": {
      "type": "string"
     },
     "name": {
      "type": "string"
     },
     "scope": {
      "$ref": "#/components/schemas/pricing.PriceSurchargeScope"
     },
     "type": {
      "$ref": "#/components/schemas/pricing.PriceSurchargeType"
     }
    },
    "type": "object"
   },
   "pricing.PriceSurchargeRequest": {
    "properties": {
     "amount": {
      "type": "number"
     },
     "id": {
      "type": "string"
     },
     "name": {
      "type": "string"
     },
     "scope": {
      "type": "string"
     },
     "type": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "pricing.PriceSurchargeScope": {
    "enum": [
     "per_leg",
     "per_job"
    ],
    "type": "string",
    "x-enum-varnames": [
     "PriceSurchargeScopePerLeg",
     "PriceSurchargeScopePerJob"
    ]
   },
   "pricing.PriceSurchargeType": {
    "enum": [
     "flat_rate",
     "percentage"
    ],
    "type": "string",
    "x-enum-varnames": [
     "PriceSurchargeTypeFlatRate",
     "PriceSurchargeTypePercentage"
    ]
   },
   "pricing.PriceZone": {
    "properties": {
     "zone_id": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "pricing.PriceZoneRequest": {
    "properties": {
     "zone_id": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "push.RegisterPushTokenRequest": {
    "properties": {
     "device_id": {
      "description": "DeviceID is the unique identifier of the device",
      "type": "string"
     },
     "platform": {
      "description": "Platform is the device platform; must be \"ios\" or \"android\"",
      "type": "string"
     },
     "token": {
      "description": "Token is the push notification token provided by the device OS (APNs or FCM)",
      "type": "string"
     }
    },
    "required": [
     "device_id",
     "platform",
     "token"
    ],
    "type": "object"
   },
   "pushprovider.Platform": {
    "enum": [
     "android",
     "ios",
     "web"
    ],
    "type": "string",
    "x-enum-varnames": [
     "PlatformAndroid",
     "PlatformiOS",
     "PlatformWeb"
    ]
   },
   "pushtoken.PushToken": {
    "properties": {
     "created_at": {
      "type": "string"
     },
     "device_id": {
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "platform": {
      "allOf": [
       {
        "$ref": "#/components/schemas/pushprovider.Platform"
       }
      ],
      "description": "ios, android"
     },
     "provider": {
      "description": "sns, firebase, apns, onesignal, twilio",
      "type": "string"
     },
     "provider_id": {
      "description": "arn, fcm id etc.",
      "type": "string"
     },
     "site_id": {
      "type": "string"
     },
     "token": {
      "type": "string"
     },
     "updated_at": {
      "type": "string"
     },
     "user_id": {
      "type": "string"
     },
     "user_profile_id": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "route.EligibleJobsResponse": {
    "properties": {
     "items": {
      "items": {
       "$ref": "#/components/schemas/job.Job"
      },
      "type": "array"
     },
     "pagination": {
      "$ref": "#/components/schemas/db.PaginationRow"
     }
    },
    "type": "object"
   },
   "route.MergeRoutesRequest": {
    "properties": {
     "source_route_id": {
      "type": "string"
     },
     "target_route_id": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "route.PreviewResult": {
    "properties": {
     "estimated_completion_at": {
      "type": "string"
     },
     "geometry": {
      "allOf": [
       {
        "$ref": "#/components/schemas/mapprovider.Route"
       }
      ],
      "description": "Polylines, legs, ETAs for rendering on the map"
     },
     "route": {
      "allOf": [
       {
        "$ref": "#/components/schemas/route.Route"
       }
      ],
      "description": "Existing route, unchanged in DB"
     },
     "stop_feasibility": {
      "description": "Per-stop ETA + window status",
      "items": {
       "$ref": "#/components/schemas/route.StopFeasibility"
      },
      "type": "array"
     },
     "suggested_stop_order": {
      "description": "TSP-ordered stop IDs",
      "items": {
       "type": "string"
      },
      "type": "array"
     },
     "total_distance_meters": {
      "type": "number"
     },
     "total_duration_seconds": {
      "type": "number"
     },
     "warnings": {
      "items": {
       "$ref": "#/components/schemas/route.Warning"
      },
      "type": "array"
     }
    },
    "type": "object"
   },
   "route.PreviewRouteRequest": {
    "properties": {
     "avoid_features": {
      "items": {
       "type": "string"
      },
      "type": "array"
     },
     "depart_at": {
      "description": "DepartAt sets the HERE Maps departure time anchor (RFC 3339). When absent,\nthe routing call defaults to time.Now().",
      "type": "string"
     },
     "driver_id": {
      "type": "string"
     },
     "end_address_id": {
      "type": "string"
     },
     "mode": {
      "description": "Mode controls whether to run TSP (\"optimize\") or evaluate the given order\nas-is (\"manual\"). Defaults to \"optimize\".",
      "type": "string"
     },
     "route_id": {
      "description": "RouteID is the ID of an existing route. When present, the route's\nstart/end addresses, vehicle, driver, and OptimizationSettings are used\nas defaults (any request-level overrides below take precedence).",
      "type": "string"
     },
     "routing_mode": {
      "type": "string"
     },
     "start_address_id": {
      "description": "StartAddressID and EndAddressID are transient start/end overrides\n(e.g., \"preview this route starting from the depot\"). Never persisted.",
      "type": "string"
     },
     "stop_ids": {
      "description": "StopIDs defines the stop order for the preview. When supplied alongside\nRouteID it must be a permutation of the route's stops — every stop exactly\nonce, no duplicates and no extras. When supplied without RouteID it defines\nboth the set and the order (ad-hoc / pre-save mode).",
      "items": {
       "type": "string"
      },
      "type": "array"
     },
     "vehicle_id": {
      "description": "Routing-strategy overrides — transient, never persisted.",
      "type": "string"
     }
    },
    "type": "object"
   },
   "route.Route": {
    "properties": {
     "color": {
      "type": "string"
     },
     "completed_at": {
      "type": "string"
     },
     "created_at": {
      "type": "string"
     },
     "driver_id": {
      "type": "string"
     },
     "end_address": {
      "$ref": "#/components/schemas/address.Address"
     },
     "end_address_id": {
      "type": "string"
     },
     "estimated_completion_at": {
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "is_active": {
      "type": "boolean"
     },
     "is_locked": {
      "type": "boolean"
     },
     "label": {
      "type": "string"
     },
     "optimization_method": {
      "type": "string"
     },
     "optimization_settings": {
      "$ref": "#/components/schemas/db.JsonMap"
     },
     "organization_id": {
      "type": "string"
     },
     "site_id": {
      "type": "string"
     },
     "start_address": {
      "$ref": "#/components/schemas/address.Address"
     },
     "start_address_id": {
      "type": "string"
     },
     "start_at": {
      "type": "string"
     },
     "started_at": {
      "type": "string"
     },
     "status_id": {
      "type": "string"
     },
     "stops": {
      "items": {
       "$ref": "#/components/schemas/stop.Stop"
      },
      "type": "array"
     },
     "total_distance_meters": {
      "type": "number"
     },
     "total_duration_seconds": {
      "type": "number"
     },
     "updated_at": {
      "type": "string"
     },
     "vehicle_id": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "route.RouteRequest": {
    "properties": {
     "color": {
      "type": "string"
     },
     "end_address_id": {
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "is_locked": {
      "type": "boolean"
     },
     "label": {
      "type": "string"
     },
     "optimization_method": {
      "type": "string"
     },
     "optimization_settings": {
      "type": "string"
     },
     "start_address_id": {
      "type": "string"
     },
     "start_at": {
      "type": "string"
     },
     "stops": {
      "items": {
       "$ref": "#/components/schemas/route.StopRequest"
      },
      "type": "array"
     }
    },
    "type": "object"
   },
   "route.SplitRouteRequest": {
    "properties": {
     "route_id": {
      "type": "string"
     },
     "split_after_stop_index": {
      "type": "integer"
     }
    },
    "type": "object"
   },
   "route.SplitRouteResult": {
    "properties": {
     "first": {
      "allOf": [
       {
        "$ref": "#/components/schemas/route.Route"
       }
      ],
      "description": "Original route with stops 0..split_after_stop_index"
     },
     "second": {
      "allOf": [
       {
        "$ref": "#/components/schemas/route.Route"
       }
      ],
      "description": "New route with stops split_after_stop_index+1..end"
     }
    },
    "type": "object"
   },
   "route.StopFeasibility": {
    "properties": {
     "estimated_arrival": {
      "type": "string"
     },
     "estimated_departure": {
      "type": "string"
     },
     "in_window": {
      "description": "arrival is within [CompleteAfter, CompleteBefore]",
      "type": "boolean"
     },
     "order": {
      "description": "1-based position in suggested order",
      "type": "integer"
     },
     "stop_id": {
      "type": "string"
     },
     "violations": {
      "items": {
       "$ref": "#/components/schemas/route.StopViolation"
      },
      "type": "array"
     },
     "window_violation": {
      "description": "\"\" | \"early\" | \"late\" | \"violated\"",
      "type": "string"
     }
    },
    "type": "object"
   },
   "route.StopRequest": {
    "properties": {
     "id": {
      "type": "string"
     },
     "order": {
      "type": "integer"
     }
    },
    "type": "object"
   },
   "route.StopViolation": {
    "properties": {
     "detail_token": {
      "description": "provider token, e.g. \"deliveryTime\" / \"before\" / \"access_window\"",
      "type": "string"
     },
     "kind": {
      "description": "\"time_window\" | \"ordering\" | \"service_time\" | \"other\"",
      "type": "string"
     },
     "reason": {
      "description": "human-readable text, e.g. \"Not reachable in time\"",
      "type": "string"
     }
    },
    "type": "object"
   },
   "route.Warning": {
    "properties": {
     "code": {
      "description": "STOP_WINDOW_VIOLATION | DRIVER_OFF_SCHEDULE | DRIVER_HAS_CONFLICT",
      "type": "string"
     },
     "message": {
      "type": "string"
     },
     "stop_id": {
      "description": "set for stop-level warnings",
      "type": "string"
     }
    },
    "type": "object"
   },
   "rtc.CreateRoomRequest": {
    "properties": {
     "room_name": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "rtc.JoinResponse": {
    "properties": {
     "metadata": {
      "additionalProperties": true,
      "type": "object"
     },
     "token": {
      "description": "Access token for the client",
      "type": "string"
     },
     "url": {
      "description": "Server URL to connect to",
      "type": "string"
     }
    },
    "type": "object"
   },
   "rtc.JoinRoomRequest": {
    "properties": {
     "room_name": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "rtc.Room": {
    "properties": {
     "activeParticipants": {
      "type": "integer"
     },
     "createdAt": {
      "type": "string"
     },
     "emptyTimeout": {
      "type": "integer"
     },
     "id": {
      "type": "string"
     },
     "maxParticipants": {
      "type": "integer"
     },
     "metadata": {
      "additionalProperties": true,
      "description": "ProviderID-specific fields can be stored in AdditionalInfo",
      "type": "object"
     },
     "name": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "servicetype.ServiceType": {
    "properties": {
     "capacity": {
      "type": "integer"
     },
     "created_at": {
      "type": "string"
     },
     "description": {
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "image": {
      "description": "Image is the resolved (signed) image URL on read; it is NOT persisted for\nnew rows — the reference lives in ImageAttachmentID. Legacy rows may still\nhave a stored URL here.",
      "type": "string"
     },
     "image_attachment_id": {
      "description": "ImageAttachmentID references the uploaded image attachment; the signed URL is\nresolved into Image on read (mirrors how chat/job reference attachments).",
      "type": "string"
     },
     "is_active": {
      "type": "boolean"
     },
     "name": {
      "type": "string"
     },
     "organization_id": {
      "type": "string"
     },
     "price_details": {
      "type": "string"
     },
     "site_id": {
      "type": "string"
     },
     "updated_at": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "servicetype.ServiceTypeRequest": {
    "properties": {
     "capacity": {
      "type": "integer"
     },
     "description": {
      "type": "string"
     },
     "image": {
      "type": "string"
     },
     "image_attachment_id": {
      "description": "ImageAttachmentID references a confirmed (ready) attachment uploaded via the\npre-signed flow; the server resolves it to the image URL.",
      "type": "string"
     },
     "name": {
      "type": "string"
     },
     "price_details": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "settings.UpdateUserSettingsRequest": {
    "properties": {
     "email_notifications_enabled": {
      "type": "boolean"
     },
     "push_notifications_enabled": {
      "type": "boolean"
     },
     "sms_notifications_enabled": {
      "type": "boolean"
     }
    },
    "type": "object"
   },
   "settings.UserSettings": {
    "properties": {
     "created_at": {
      "type": "string"
     },
     "email_notifications_enabled": {
      "type": "boolean"
     },
     "id": {
      "type": "string"
     },
     "push_notifications_enabled": {
      "type": "boolean"
     },
     "site_id": {
      "type": "string"
     },
     "sms_notifications_enabled": {
      "type": "boolean"
     },
     "updated_at": {
      "type": "string"
     },
     "user_profile_id": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "site.PublicBrandingResponse": {
    "properties": {
     "accent_color": {
      "description": "hex, defaults to DefaultBrandColor",
      "type": "string"
     },
     "app_store_url": {
      "description": "iOS App Store link",
      "type": "string"
     },
     "brand_color": {
      "description": "hex, defaults to DefaultBrandColor",
      "type": "string"
     },
     "logo_url": {
      "description": "S3/CDN URL; null => render text logo",
      "type": "string"
     },
     "play_store_url": {
      "type": "string"
     },
     "site_name": {
      "description": "falls back to sites.name when empty",
      "type": "string"
     },
     "subdomain": {
      "type": "string"
     },
     "tagline": {
      "description": "e.g. \"Live Tracking\" chip",
      "type": "string"
     },
     "theme": {
      "description": "\"dark\" | \"light\"",
      "type": "string"
     }
    },
    "type": "object"
   },
   "site.Site": {
    "properties": {
     "address": {
      "$ref": "#/components/schemas/address.Address"
     },
     "address_id": {
      "type": "string"
     },
     "created_at": {
      "type": "string"
     },
     "currency": {
      "type": "string"
     },
     "date_format": {
      "type": "string"
     },
     "deleted_at": {
      "type": "string"
     },
     "description": {
      "type": "string"
     },
     "email": {
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "industry_type": {
      "type": "string"
     },
     "is_active": {
      "type": "boolean"
     },
     "locale": {
      "type": "string"
     },
     "name": {
      "type": "string"
     },
     "notes": {
      "type": "string"
     },
     "organization_id": {
      "type": "string"
     },
     "phone": {
      "type": "string"
     },
     "phone_country": {
      "type": "string"
     },
     "subdomain": {
      "type": "string"
     },
     "time_format": {
      "type": "string"
     },
     "timezone": {
      "type": "string"
     },
     "unit_system": {
      "$ref": "#/components/schemas/site.UnitSystem"
     },
     "updated_at": {
      "type": "string"
     },
     "website": {
      "type": "string"
     }
    },
    "required": [
     "address_id",
     "organization_id"
    ],
    "type": "object"
   },
   "site.SiteRequest": {
    "properties": {
     "address_id": {
      "type": "string"
     },
     "currency": {
      "type": "string"
     },
     "date_format": {
      "type": "string"
     },
     "description": {
      "type": "string"
     },
     "email": {
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "industry_type": {
      "type": "string"
     },
     "locale": {
      "type": "string"
     },
     "name": {
      "type": "string"
     },
     "notes": {
      "type": "string"
     },
     "phone": {
      "type": "string"
     },
     "phone_country": {
      "type": "string"
     },
     "subdomain": {
      "type": "string"
     },
     "time_format": {
      "type": "string"
     },
     "timezone": {
      "type": "string"
     },
     "unit_system": {
      "$ref": "#/components/schemas/site.UnitSystem"
     },
     "website": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "site.SiteUpdateRequest": {
    "properties": {
     "address_id": {
      "type": "string"
     },
     "currency": {
      "type": "string"
     },
     "date_format": {
      "type": "string"
     },
     "description": {
      "type": "string"
     },
     "email": {
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "industry_type": {
      "type": "string"
     },
     "locale": {
      "type": "string"
     },
     "name": {
      "type": "string"
     },
     "notes": {
      "type": "string"
     },
     "phone": {
      "type": "string"
     },
     "phone_country": {
      "type": "string"
     },
     "subdomain": {
      "type": "string"
     },
     "time_format": {
      "type": "string"
     },
     "timezone": {
      "type": "string"
     },
     "unit_system": {
      "$ref": "#/components/schemas/site.UnitSystem"
     },
     "website": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "site.UnitSystem": {
    "enum": [
     "metric",
     "imperial"
    ],
    "type": "string",
    "x-enum-varnames": [
     "UnitSystemMetric",
     "UnitSystemImperial"
    ]
   },
   "sitesettings.BrandingConfig": {
    "properties": {
     "accent_color": {
      "description": "hex, defaults to DefaultBrandColor",
      "type": "string"
     },
     "app_store_url": {
      "description": "iOS App Store link",
      "type": "string"
     },
     "brand_color": {
      "description": "hex, defaults to DefaultBrandColor",
      "type": "string"
     },
     "logo_url": {
      "description": "S3/CDN URL; null => render text logo",
      "type": "string"
     },
     "play_store_url": {
      "type": "string"
     },
     "site_name": {
      "description": "falls back to sites.name when empty",
      "type": "string"
     },
     "tagline": {
      "description": "e.g. \"Live Tracking\" chip",
      "type": "string"
     },
     "theme": {
      "description": "\"dark\" | \"light\"",
      "type": "string"
     }
    },
    "type": "object"
   },
   "sitesettings.BrandingRequest": {
    "properties": {
     "accent_color": {
      "type": "string"
     },
     "app_store_url": {
      "type": "string"
     },
     "brand_color": {
      "type": "string"
     },
     "logo_attachment_id": {
      "description": "LogoAttachmentID references a confirmed (ready) attachment uploaded via the\npre-signed flow; the server resolves it to LogoURL. Takes precedence over a\ndirectly-supplied LogoURL.",
      "type": "string"
     },
     "logo_url": {
      "type": "string"
     },
     "play_store_url": {
      "type": "string"
     },
     "site_name": {
      "type": "string"
     },
     "tagline": {
      "type": "string"
     },
     "theme": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "sitesettings.SiteSettings": {
    "properties": {
     "branding": {
      "$ref": "#/components/schemas/db.JSOND-sitesettings_BrandingConfig"
     },
     "created_at": {
      "type": "string"
     },
     "enable_email_notifications": {
      "type": "boolean"
     },
     "enable_push_notifications": {
      "type": "boolean"
     },
     "enable_sms_notifications": {
      "type": "boolean"
     },
     "id": {
      "type": "string"
     },
     "is_active": {
      "type": "boolean"
     },
     "last_job_number": {
      "type": "integer"
     },
     "location_min_poll_interval_seconds": {
      "type": "integer"
     },
     "organization_id": {
      "type": "string"
     },
     "site_id": {
      "type": "string"
     },
     "updated_at": {
      "type": "string"
     },
     "use_gps_for_actual_price": {
      "type": "boolean"
     }
    },
    "type": "object"
   },
   "sitesettings.SiteSettingsRequest": {
    "properties": {
     "branding": {
      "$ref": "#/components/schemas/sitesettings.BrandingRequest"
     },
     "enable_email_notifications": {
      "type": "boolean"
     },
     "enable_push_notifications": {
      "type": "boolean"
     },
     "enable_sms_notifications": {
      "type": "boolean"
     },
     "last_job_number": {
      "type": "integer"
     },
     "location_min_poll_interval_seconds": {
      "type": "integer"
     },
     "payment_provider": {
      "type": "string"
     },
     "use_gps_for_actual_price": {
      "type": "boolean"
     }
    },
    "type": "object"
   },
   "stop.CompleteActionRequest": {
    "description": "Request body for completing a stop action, including optional field values and file attachments.",
    "properties": {
     "stop_action_id": {
      "description": "StopActionID is the ID of the specific stop action instance to complete.",
      "type": "string"
     },
     "stop_id": {
      "description": "StopID is the ID of the stop the action belongs to.",
      "type": "string"
     },
     "values": {
      "allOf": [
       {
        "$ref": "#/components/schemas/db.JsonMap"
       }
      ],
      "description": "Values contains the form field values captured during completion (e.g. barcode, signature data)."
     }
    },
    "required": [
     "stop_action_id",
     "stop_id"
    ],
    "type": "object"
   },
   "stop.SkipActionRequest": {
    "description": "Request body for skipping a stop action with an optional reason.",
    "properties": {
     "reason": {
      "description": "Reason is an optional explanation for why the action was skipped.",
      "type": "string"
     },
     "stop_action_id": {
      "description": "StopActionID is the ID of the specific stop action instance to skip.",
      "type": "string"
     },
     "stop_id": {
      "description": "StopID is the ID of the stop the action belongs to.",
      "type": "string"
     }
    },
    "required": [
     "stop_action_id",
     "stop_id"
    ],
    "type": "object"
   },
   "stop.Stop": {
    "properties": {
     "actions": {
      "items": {
       "$ref": "#/components/schemas/stopaction.StopAction"
      },
      "type": "array"
     },
     "actual_address": {
      "$ref": "#/components/schemas/address.Address"
     },
     "actual_address_id": {
      "type": "string"
     },
     "address": {
      "$ref": "#/components/schemas/address.Address"
     },
     "address_id": {
      "type": "string"
     },
     "arrived_at": {
      "type": "string"
     },
     "cancellation_notes": {
      "type": "string"
     },
     "cancelled_at": {
      "type": "string"
     },
     "cancelled_by_user_id": {
      "type": "string"
     },
     "complete_after": {
      "type": "string"
     },
     "complete_before": {
      "type": "string"
     },
     "completed_at": {
      "type": "string"
     },
     "contact_name": {
      "type": "string"
     },
     "contact_phone": {
      "type": "string"
     },
     "contact_phone_country": {
      "type": "string"
     },
     "created_at": {
      "type": "string"
     },
     "customer_notes": {
      "type": "string"
     },
     "driver_distance_until_arrival_meters": {
      "type": "number"
     },
     "driver_duration_until_arrival_seconds": {
      "type": "integer"
     },
     "driver_duration_until_departure_seconds": {
      "type": "integer"
     },
     "driver_notes": {
      "type": "string"
     },
     "estimated_arrival_at": {
      "type": "string"
     },
     "estimated_completion_at": {
      "type": "string"
     },
     "estimated_departure_at": {
      "type": "string"
     },
     "estimated_start_at": {
      "type": "string"
     },
     "eta_calculation_method": {
      "type": "string"
     },
     "eta_calculation_source": {
      "type": "string"
     },
     "eta_last_updated_at": {
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "internal_notes": {
      "type": "string"
     },
     "is_active": {
      "type": "boolean"
     },
     "job_id": {
      "type": "string"
     },
     "order": {
      "type": "integer"
     },
     "site_id": {
      "type": "string"
     },
     "started_at": {
      "type": "string"
     },
     "total_duration_seconds": {
      "type": "integer"
     },
     "type": {
      "$ref": "#/components/schemas/stop.StopType"
     },
     "updated_at": {
      "type": "string"
     },
     "wait_time_seconds": {
      "type": "integer"
     },
     "workflow_id": {
      "type": "string"
     },
     "workflow_state": {
      "$ref": "#/components/schemas/workflow.WorkflowState"
     },
     "workflow_state_id": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "stop.StopType": {
    "enum": [
     "pickup",
     "dropoff",
     "waypoint"
    ],
    "type": "string",
    "x-enum-varnames": [
     "StopTypePickup",
     "StopTypeDropoff",
     "StopTypeWaypoint"
    ]
   },
   "stopaction.ActionType": {
    "enum": [
     "photo",
     "signature",
     "barcode_scan",
     "custom_form"
    ],
    "type": "string",
    "x-enum-varnames": [
     "ActionTypePhoto",
     "ActionTypeSignature",
     "ActionTypeBarcodeScan",
     "ActionTypeCustomForm"
    ]
   },
   "stopaction.ActionTypeOption": {
    "description": "Represents a single supported action type and its capabilities.",
    "properties": {
     "supports_attachments": {
      "description": "SupportsAttachments indicates whether this action type can include file attachments.",
      "type": "boolean"
     },
     "value": {
      "description": "Value is the action type identifier (e.g. \"photo\", \"signature\", \"barcode_scan\", \"custom_form\").",
      "type": "string"
     }
    },
    "type": "object"
   },
   "stopaction.MetadataResponse": {
    "description": "Contains reference data used to configure stop actions, including available types, trigger events, and field schemas.",
    "properties": {
     "action_types": {
      "description": "ActionTypes lists all supported action types and their capabilities.",
      "items": {
       "$ref": "#/components/schemas/stopaction.ActionTypeOption"
      },
      "type": "array"
     },
     "stop_action_statuses": {
      "description": "StopActionStatuses lists all possible statuses for a stop action instance.",
      "items": {
       "type": "string"
      },
      "type": "array"
     },
     "stop_types": {
      "description": "StopTypes lists all valid stop type values (e.g. \"pickup\", \"dropoff\", \"waypoint\").",
      "items": {
       "type": "string"
      },
      "type": "array"
     },
     "trigger_events": {
      "description": "TriggerEvents lists all valid trigger event values (e.g. \"on_arrival\", \"on_completion\").",
      "items": {
       "type": "string"
      },
      "type": "array"
     },
     "type_config_schemas": {
      "additionalProperties": {
       "additionalProperties": {
        "$ref": "#/components/schemas/stopaction.TypeConfigFieldSchema"
       },
       "type": "object"
      },
      "description": "TypeConfigSchemas maps each action type to its type_config field schemas.",
      "type": "object"
     }
    },
    "type": "object"
   },
   "stopaction.StopAction": {
    "properties": {
     "completed_at": {
      "type": "string"
     },
     "completed_by_user_id": {
      "type": "string"
     },
     "created_at": {
      "type": "string"
     },
     "description": {
      "description": "The user-facing description from the config",
      "type": "string"
     },
     "display_name": {
      "description": "--- Copied from SiteActionConfig at time of creation ---",
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "is_active": {
      "description": "--- Standard Fields ---",
      "type": "boolean"
     },
     "is_required": {
      "type": "boolean"
     },
     "site_id": {
      "type": "string"
     },
     "sort_order": {
      "type": "integer"
     },
     "status": {
      "allOf": [
       {
        "$ref": "#/components/schemas/stopaction.StopActionStatus"
       }
      ],
      "description": "--- Live Data for this instance ---"
     },
     "stop_action_config_id": {
      "description": "Renamed from ActionTemplateID",
      "type": "string"
     },
     "stop_id": {
      "type": "string"
     },
     "trigger_event": {
      "$ref": "#/components/schemas/stopaction.TriggerEvent"
     },
     "type": {
      "$ref": "#/components/schemas/stopaction.ActionType"
     },
     "updated_at": {
      "type": "string"
     },
     "values": {
      "$ref": "#/components/schemas/db.JsonMap"
     }
    },
    "type": "object"
   },
   "stopaction.StopActionConfig": {
    "properties": {
     "created_at": {
      "type": "string"
     },
     "display_description": {
      "type": "string"
     },
     "display_name": {
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "is_active": {
      "type": "boolean"
     },
     "is_required": {
      "type": "boolean"
     },
     "name": {
      "description": "Stable, internal name",
      "type": "string"
     },
     "site_id": {
      "type": "string"
     },
     "sort_order": {
      "type": "integer"
     },
     "stop_type": {
      "$ref": "#/components/schemas/stopaction.StopType"
     },
     "trigger_event": {
      "$ref": "#/components/schemas/stopaction.TriggerEvent"
     },
     "type": {
      "$ref": "#/components/schemas/stopaction.ActionType"
     },
     "type_config": {
      "$ref": "#/components/schemas/db.JsonMap"
     },
     "updated_at": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "stopaction.StopActionCreateConfigRequest": {
    "description": "Request body for creating a stop action configuration that will be applied to stops of a given type.",
    "properties": {
     "display_description": {
      "description": "DisplayDescription is an optional user-facing description of the action.",
      "type": "string"
     },
     "display_name": {
      "description": "DisplayName is the user-facing label shown in the driver app.",
      "type": "string"
     },
     "is_required": {
      "description": "IsRequired indicates whether drivers must complete this action before proceeding.",
      "type": "boolean"
     },
     "name": {
      "description": "Name is the stable internal identifier for this action config.",
      "type": "string"
     },
     "sort_order": {
      "description": "SortOrder controls the display order of actions within a stop.",
      "type": "integer"
     },
     "stop_type": {
      "allOf": [
       {
        "$ref": "#/components/schemas/stopaction.StopType"
       }
      ],
      "description": "StopType restricts this action to a specific stop type (pickup, dropoff, or waypoint)."
     },
     "trigger_event": {
      "allOf": [
       {
        "$ref": "#/components/schemas/stopaction.TriggerEvent"
       }
      ],
      "description": "TriggerEvent defines when this action is triggered (e.g. on_arrival, on_completion)."
     },
     "type": {
      "allOf": [
       {
        "$ref": "#/components/schemas/stopaction.ActionType"
       }
      ],
      "description": "Type specifies the kind of action (e.g. photo, signature, barcode_scan, custom_form)."
     },
     "type_config": {
      "allOf": [
       {
        "$ref": "#/components/schemas/db.JsonMap"
       }
      ],
      "description": "TypeConfig holds action-type-specific configuration (e.g. min/max photos)."
     }
    },
    "type": "object"
   },
   "stopaction.StopActionStatus": {
    "enum": [
     "pending",
     "started",
     "completed",
     "skipped"
    ],
    "type": "string",
    "x-enum-varnames": [
     "StopActionPending",
     "StopActionStarted",
     "StopActionCompleted",
     "StopActionSkipped"
    ]
   },
   "stopaction.StopActionUpdateConfigRequest": {
    "description": "Request body for updating a stop action configuration. All fields are optional; omitted fields are left unchanged.",
    "properties": {
     "display_description": {
      "description": "DisplayDescription updates the user-facing description.",
      "type": "string"
     },
     "display_name": {
      "description": "DisplayName updates the user-facing label.",
      "type": "string"
     },
     "id": {
      "description": "ID is the identifier of the stop action config to update.",
      "type": "string"
     },
     "is_active": {
      "description": "IsActive enables or disables the action config.",
      "type": "boolean"
     },
     "is_required": {
      "description": "IsRequired updates whether the action is mandatory.",
      "type": "boolean"
     },
     "name": {
      "description": "Name updates the stable internal identifier.",
      "type": "string"
     },
     "sort_order": {
      "description": "SortOrder updates the display ordering of the action.",
      "type": "integer"
     },
     "stop_type": {
      "allOf": [
       {
        "$ref": "#/components/schemas/stopaction.StopType"
       }
      ],
      "description": "StopType updates the stop type restriction."
     },
     "trigger_event": {
      "allOf": [
       {
        "$ref": "#/components/schemas/stopaction.TriggerEvent"
       }
      ],
      "description": "TriggerEvent updates when the action is triggered."
     },
     "type": {
      "allOf": [
       {
        "$ref": "#/components/schemas/stopaction.ActionType"
       }
      ],
      "description": "Type updates the action type."
     },
     "type_config": {
      "allOf": [
       {
        "$ref": "#/components/schemas/db.JsonMap"
       }
      ],
      "description": "TypeConfig updates the action-type-specific configuration."
     }
    },
    "type": "object"
   },
   "stopaction.StopType": {
    "enum": [
     "pickup",
     "dropoff",
     "waypoint"
    ],
    "type": "string",
    "x-enum-varnames": [
     "StopTypePickup",
     "StopTypeDropoff",
     "StopTypeWaypoint"
    ]
   },
   "stopaction.TriggerEvent": {
    "enum": [
     "started",
     "arrived",
     "completed",
     "cancelled"
    ],
    "type": "string",
    "x-enum-varnames": [
     "TriggerOnStarted",
     "TriggerOnArrived",
     "TriggerOnComplete",
     "TriggerOnCancelled"
    ]
   },
   "stopaction.TypeConfigFieldSchema": {
    "description": "JSON Schema-like descriptor for a single field within an action type's type_config.",
    "properties": {
     "items": {
      "allOf": [
       {
        "$ref": "#/components/schemas/stopaction.TypeConfigFieldSchema"
       }
      ],
      "description": "Items describes the element schema when Type is \"array\"."
     },
     "properties": {
      "additionalProperties": {
       "$ref": "#/components/schemas/stopaction.TypeConfigFieldSchema"
      },
      "description": "Properties describes the nested field schemas when Type is \"object\".",
      "type": "object"
     },
     "required": {
      "description": "Required indicates whether the field must be provided in type_config.",
      "type": "boolean"
     },
     "type": {
      "description": "Type is the data type of the field (e.g. \"string\", \"boolean\", \"number\", \"array\", \"object\").",
      "type": "string"
     }
    },
    "type": "object"
   },
   "team.Team": {
    "properties": {
     "color": {
      "type": "string"
     },
     "created_at": {
      "type": "string"
     },
     "description": {
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "is_active": {
      "type": "boolean"
     },
     "name": {
      "type": "string"
     },
     "organization_id": {
      "type": "string"
     },
     "site_id": {
      "type": "string"
     },
     "updated_at": {
      "type": "string"
     },
     "users": {
      "items": {
       "$ref": "#/components/schemas/team.TeamUser"
      },
      "type": "array"
     }
    },
    "type": "object"
   },
   "team.TeamRequest": {
    "properties": {
     "color": {
      "type": "string"
     },
     "description": {
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "name": {
      "type": "string"
     },
     "users": {
      "items": {
       "properties": {
        "id": {
         "type": "string"
        }
       },
       "type": "object"
      },
      "type": "array"
     }
    },
    "type": "object"
   },
   "team.TeamUser": {
    "properties": {
     "first_name": {
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "last_name": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "team.UserTeamRequest": {
    "properties": {
     "id": {
      "description": "Team id",
      "type": "string"
     },
     "user_id": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "user.ImportError": {
    "properties": {
     "field": {
      "description": "Field name that caused the error",
      "type": "string"
     },
     "reason": {
      "description": "Error message",
      "type": "string"
     },
     "row": {
      "description": "Row number (1-indexed)",
      "type": "integer"
     },
     "value": {
      "description": "The value that caused the error",
      "type": "string"
     }
    },
    "type": "object"
   },
   "user.ImportResponse": {
    "properties": {
     "errors": {
      "items": {
       "$ref": "#/components/schemas/user.ImportError"
      },
      "type": "array"
     },
     "failed": {
      "type": "integer"
     },
     "results": {
      "items": {
       "$ref": "#/components/schemas/user.ImportResult"
      },
      "type": "array"
     },
     "successful": {
      "type": "integer"
     },
     "total_processed": {
      "type": "integer"
     }
    },
    "type": "object"
   },
   "user.ImportResult": {
    "properties": {
     "email": {
      "description": "User email",
      "type": "string"
     },
     "error": {
      "type": "string"
     },
     "id": {
      "description": "Created user ID",
      "type": "string"
     },
     "row": {
      "description": "Row number (1-indexed)",
      "type": "integer"
     },
     "status": {
      "description": "\"success\" or \"failed\"",
      "type": "string"
     }
    },
    "type": "object"
   },
   "user.OnlineStatus": {
    "enum": [
     "online",
     "offline",
     "disrupted"
    ],
    "type": "string",
    "x-enum-comments": {
     "OnlineStatusDisrupted": "Intermittent connection issues",
     "OnlineStatusOffline": "No connection/updates",
     "OnlineStatusOnline": "Device actively sending updates"
    },
    "x-enum-descriptions": [
     "Device actively sending updates",
     "No connection/updates",
     "Intermittent connection issues"
    ],
    "x-enum-varnames": [
     "OnlineStatusOnline",
     "OnlineStatusOffline",
     "OnlineStatusDisrupted"
    ]
   },
   "user.Profile": {
    "properties": {
     "created_at": {
      "type": "string"
     },
     "display_name": {
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "image_attachment_id": {
      "type": "string"
     },
     "image_url": {
      "description": "ImageURL is the resolved (signed) profile image URL on read; for new rows it\nis derived from ImageAttachmentID, not persisted. Legacy rows may store a URL.",
      "type": "string"
     },
     "is_active": {
      "type": "boolean"
     },
     "last_activity_at": {
      "type": "string"
     },
     "last_login_at": {
      "type": "string"
     },
     "online_status": {
      "$ref": "#/components/schemas/user.OnlineStatus"
     },
     "online_status_updated_at": {
      "type": "string"
     },
     "organization_id": {
      "type": "string"
     },
     "role": {
      "type": "string"
     },
     "settings": {
      "description": "Populated by service layer"
     },
     "site": {
      "$ref": "#/components/schemas/user.Site"
     },
     "site_id": {
      "type": "string"
     },
     "type": {
      "$ref": "#/components/schemas/user.ProfileType"
     },
     "updated_at": {
      "type": "string"
     },
     "user_id": {
      "type": "string"
     }
    },
    "required": [
     "organization_id",
     "role",
     "site_id",
     "user_id"
    ],
    "type": "object"
   },
   "user.ProfileType": {
    "enum": [
     "customer",
     "worker"
    ],
    "type": "string",
    "x-enum-varnames": [
     "ProfileTypeCustomer",
     "ProfileTypeWorker"
    ]
   },
   "user.Site": {
    "properties": {
     "id": {
      "type": "string"
     },
     "name": {
      "type": "string"
     },
     "subdomain": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "user.User": {
    "properties": {
     "created_at": {
      "type": "string"
     },
     "details": {
      "description": "Not making this a pointer b/c it's an interface"
     },
     "email": {
      "type": "string"
     },
     "first_name": {
      "type": "string"
     },
     "home_address": {
      "allOf": [
       {
        "$ref": "#/components/schemas/address.Address"
       }
      ],
      "description": "HomeAddress is dual-purpose: on create it carries an inline address to be resolved by the\nservice (see resolveHomeAddressID), and on reads it holds the hydrated address row."
     },
     "home_address_id": {
      "description": "HomeAddressID references the user's home address (addresses.id). Nil when no home address is set.",
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "is_active": {
      "type": "boolean"
     },
     "last_name": {
      "type": "string"
     },
     "phone": {
      "type": "string"
     },
     "phone_country": {
      "type": "string"
     },
     "profile": {
      "$ref": "#/components/schemas/user.Profile"
     },
     "updated_at": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "vehicle.Vehicle": {
    "properties": {
     "axle_count": {
      "type": "integer"
     },
     "cargo_capacity_g": {
      "type": "integer"
     },
     "cargo_volume_ml": {
      "type": "integer"
     },
     "color": {
      "type": "string"
     },
     "created_at": {
      "type": "string"
     },
     "custom_attributes": {
      "type": "string"
     },
     "gross_weight_g": {
      "type": "integer"
     },
     "height_mm": {
      "type": "integer"
     },
     "id": {
      "type": "string"
     },
     "inspection_expiration_date": {
      "type": "string"
     },
     "insurance_expiration_date": {
      "type": "string"
     },
     "insurance_policy_number": {
      "type": "string"
     },
     "insurance_provider_name": {
      "type": "string"
     },
     "internal_notes": {
      "type": "string"
     },
     "is_active": {
      "type": "boolean"
     },
     "is_default": {
      "type": "boolean"
     },
     "length_mm": {
      "type": "integer"
     },
     "license_plate": {
      "type": "string"
     },
     "make": {
      "type": "string"
     },
     "model": {
      "type": "string"
     },
     "options": {
      "items": {
       "$ref": "#/components/schemas/option.Option"
      },
      "type": "array"
     },
     "organization_id": {
      "type": "string"
     },
     "owner": {
      "$ref": "#/components/schemas/user.User"
     },
     "owner_user_id": {
      "type": "string"
     },
     "registration_expiration_date": {
      "type": "string"
     },
     "registration_number": {
      "type": "string"
     },
     "registration_owner_name": {
      "type": "string"
     },
     "seating_capacity": {
      "type": "integer"
     },
     "site_id": {
      "type": "string"
     },
     "updated_at": {
      "type": "string"
     },
     "vehicle_type": {
      "$ref": "#/components/schemas/vehicle.VehicleType"
     },
     "vehicle_type_id": {
      "type": "string"
     },
     "vin": {
      "type": "string"
     },
     "width_mm": {
      "type": "integer"
     },
     "year": {
      "type": "integer"
     }
    },
    "type": "object"
   },
   "vehicle.VehicleCreateRequest": {
    "properties": {
     "axle_count": {
      "type": "integer"
     },
     "cargo_capacity_g": {
      "type": "integer"
     },
     "cargo_volume_ml": {
      "type": "integer"
     },
     "color": {
      "type": "string"
     },
     "custom_attributes": {
      "type": "string"
     },
     "gross_weight_g": {
      "type": "integer"
     },
     "height_mm": {
      "type": "integer"
     },
     "inspection_expiration_date": {
      "type": "string"
     },
     "insurance_expiration_date": {
      "type": "string"
     },
     "insurance_policy_number": {
      "type": "string"
     },
     "insurance_provider_name": {
      "type": "string"
     },
     "internal_notes": {
      "type": "string"
     },
     "length_mm": {
      "type": "integer"
     },
     "license_plate": {
      "type": "string"
     },
     "make": {
      "type": "string"
     },
     "model": {
      "type": "string"
     },
     "option_ids": {
      "items": {
       "type": "string"
      },
      "type": "array"
     },
     "owner_user_id": {
      "type": "string"
     },
     "registration_expiration_date": {
      "type": "string"
     },
     "registration_number": {
      "type": "string"
     },
     "registration_owner_name": {
      "type": "string"
     },
     "seating_capacity": {
      "type": "integer"
     },
     "vehicle_type_id": {
      "type": "string"
     },
     "vin": {
      "type": "string"
     },
     "width_mm": {
      "type": "integer"
     },
     "year": {
      "type": "integer"
     }
    },
    "type": "object"
   },
   "vehicle.VehicleType": {
    "properties": {
     "created_at": {
      "type": "string"
     },
     "description": {
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "is_active": {
      "type": "boolean"
     },
     "name": {
      "type": "string"
     },
     "site_id": {
      "type": "string"
     },
     "transport_mode": {
      "type": "string"
     },
     "updated_at": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "vehicle.VehicleTypeCreateRequest": {
    "properties": {
     "description": {
      "type": "string"
     },
     "name": {
      "type": "string"
     },
     "transport_mode": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "vehicle.VehicleTypeUpdateRequest": {
    "properties": {
     "description": {
      "type": "string"
     },
     "is_active": {
      "type": "boolean"
     },
     "name": {
      "type": "string"
     },
     "transport_mode": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "vehicle.VehicleUpdateRequest": {
    "properties": {
     "axle_count": {
      "type": "integer"
     },
     "cargo_capacity_g": {
      "type": "integer"
     },
     "cargo_volume_ml": {
      "type": "integer"
     },
     "color": {
      "type": "string"
     },
     "custom_attributes": {
      "type": "string"
     },
     "gross_weight_g": {
      "type": "integer"
     },
     "height_mm": {
      "type": "integer"
     },
     "inspection_expiration_date": {
      "type": "string"
     },
     "insurance_expiration_date": {
      "type": "string"
     },
     "insurance_policy_number": {
      "type": "string"
     },
     "insurance_provider_name": {
      "type": "string"
     },
     "internal_notes": {
      "type": "string"
     },
     "is_active": {
      "type": "boolean"
     },
     "is_default": {
      "type": "boolean"
     },
     "length_mm": {
      "type": "integer"
     },
     "license_plate": {
      "type": "string"
     },
     "make": {
      "type": "string"
     },
     "model": {
      "type": "string"
     },
     "option_ids": {
      "items": {
       "type": "string"
      },
      "type": "array"
     },
     "owner_user_id": {
      "type": "string"
     },
     "registration_expiration_date": {
      "type": "string"
     },
     "registration_number": {
      "type": "string"
     },
     "registration_owner_name": {
      "type": "string"
     },
     "seating_capacity": {
      "type": "integer"
     },
     "vehicle_type_id": {
      "type": "string"
     },
     "vin": {
      "type": "string"
     },
     "width_mm": {
      "type": "integer"
     },
     "year": {
      "type": "integer"
     }
    },
    "type": "object"
   },
   "webhook.Webhook": {
    "properties": {
     "created_at": {
      "type": "string"
     },
     "custom_headers": {
      "allOf": [
       {
        "$ref": "#/components/schemas/db.JsonMap"
       }
      ],
      "description": "Custom HTTP headers to include in webhook delivery"
     },
     "deleted_at": {
      "type": "string"
     },
     "events": {
      "description": "Array of event names like [\"job:create\", \"job:update\"]",
      "items": {
       "type": "string"
      },
      "type": "array"
     },
     "id": {
      "type": "string"
     },
     "is_active": {
      "type": "boolean"
     },
     "secret_key": {
      "description": "For HMAC signing",
      "type": "string"
     },
     "site_id": {
      "type": "string"
     },
     "updated_at": {
      "type": "string"
     },
     "url": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "webhook.WebhookRequest": {
    "properties": {
     "custom_headers": {
      "additionalProperties": {
       "type": "string"
      },
      "description": "Custom HTTP headers as key-value pairs",
      "type": "object"
     },
     "events": {
      "items": {
       "type": "string"
      },
      "minItems": 1,
      "type": "array"
     },
     "is_active": {
      "type": "boolean"
     },
     "secret_key": {
      "type": "string"
     },
     "url": {
      "type": "string"
     }
    },
    "required": [
     "events",
     "url"
    ],
    "type": "object"
   },
   "webhook.WebhookResponse": {
    "properties": {
     "created_at": {
      "type": "string"
     },
     "events": {
      "items": {
       "type": "string"
      },
      "type": "array"
     },
     "id": {
      "type": "string"
     },
     "is_active": {
      "type": "boolean"
     },
     "site_id": {
      "type": "string"
     },
     "updated_at": {
      "type": "string"
     },
     "url": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "webhook.WebhookSearchResponse": {
    "properties": {
     "webhooks": {
      "items": {
       "$ref": "#/components/schemas/webhook.WebhookResponse"
      },
      "type": "array"
     }
    },
    "type": "object"
   },
   "worker.NearbyWorkerLocation": {
    "description": "Last-known location for a nearby worker",
    "properties": {
     "lat": {
      "type": "number"
     },
     "lng": {
      "type": "number"
     },
     "timestamp": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "worker.NearbyWorkerMatch": {
    "description": "Worker located within the search radius, with distance from the anchor point",
    "properties": {
     "distance_meters": {
      "description": "DistanceMeters is the straight-line distance from the anchor point to the worker.",
      "type": "number"
     },
     "location": {
      "allOf": [
       {
        "$ref": "#/components/schemas/worker.NearbyWorkerLocation"
       }
      ],
      "description": "Location is the worker's last known location (from the Redis cache)."
     },
     "user": {
      "allOf": [
       {
        "$ref": "#/components/schemas/user.User"
       }
      ],
      "description": "User is the matched worker (full profile + worker details)."
     }
    },
    "type": "object"
   },
   "worker.NearbyWorkersResponse": {
    "description": "Workers matched by the nearby search, ordered by ascending distance",
    "properties": {
     "results": {
      "items": {
       "$ref": "#/components/schemas/worker.NearbyWorkerMatch"
      },
      "type": "array"
     }
    },
    "type": "object"
   },
   "worker.OperationalStatus": {
    "enum": [
     "active",
     "inactive",
     "break"
    ],
    "type": "string",
    "x-enum-varnames": [
     "OperationalStatusActive",
     "OperationalStatusInactive",
     "OperationalStatusBreak"
    ]
   },
   "worker.WorkerRequest": {
    "description": "Request body for creating a new worker (driver, dispatcher, or admin)",
    "properties": {
     "assigned_to_vehicle_id": {
      "type": "string"
     },
     "custom_fields": {
      "additionalProperties": true,
      "type": "object"
     },
     "display_name": {
      "type": "string"
     },
     "driver_license_class": {
      "type": "string"
     },
     "driver_license_expiration_date": {
      "type": "string"
     },
     "driver_license_number": {
      "type": "string"
     },
     "earnings_rule_id": {
      "type": "string"
     },
     "email": {
      "type": "string"
     },
     "first_name": {
      "type": "string"
     },
     "home_address": {
      "allOf": [
       {
        "$ref": "#/components/schemas/address.AddressRequest"
       }
      ],
      "description": "HomeAddress is an inline address to create and use as the worker's home address."
     },
     "home_address_id": {
      "description": "HomeAddressID references an existing address to use as the worker's home address.\nTakes precedence over HomeAddress when both are supplied.",
      "type": "string"
     },
     "image_attachment_id": {
      "description": "ImageAttachmentID references a confirmed (ready) attachment uploaded via the\npre-signed flow; the server resolves it to the profile image URL.",
      "type": "string"
     },
     "last_name": {
      "type": "string"
     },
     "option_ids": {
      "items": {
       "type": "string"
      },
      "type": "array"
     },
     "password": {
      "type": "string"
     },
     "phone": {
      "type": "string"
     },
     "phone_country": {
      "type": "string"
     },
     "role": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "worker.WorkerSchedule": {
    "properties": {
     "created_at": {
      "type": "string"
     },
     "day_of_week": {
      "description": "0=Sun, 1=Mon, ..., 6=Sat",
      "type": "integer"
     },
     "deleted_at": {
      "type": "string"
     },
     "end_time": {
      "description": "\"17:00\"",
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "is_active": {
      "type": "boolean"
     },
     "site_id": {
      "type": "string"
     },
     "start_time": {
      "description": "\"09:00\"",
      "type": "string"
     },
     "updated_at": {
      "type": "string"
     },
     "worker_id": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "worker.WorkerScheduleOverride": {
    "properties": {
     "created_at": {
      "type": "string"
     },
     "date": {
      "description": "\"2025-12-25\"",
      "type": "string"
     },
     "deleted_at": {
      "type": "string"
     },
     "end_time": {
      "description": "Optional: Override hours",
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "is_active": {
      "type": "boolean"
     },
     "is_unavailable": {
      "type": "boolean"
     },
     "note": {
      "description": "\"Doctor's Appointment\"",
      "type": "string"
     },
     "site_id": {
      "type": "string"
     },
     "start_time": {
      "description": "Optional: Override hours",
      "type": "string"
     },
     "updated_at": {
      "type": "string"
     },
     "worker_id": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "worker.WorkerScheduleOverrideRequest": {
    "description": "Request body for creating a one-time date-specific schedule override (e.g. day off or modified hours)",
    "properties": {
     "date": {
      "description": "\"2025-12-25\"",
      "type": "string"
     },
     "end_time": {
      "description": "Optional: Override hours",
      "type": "string"
     },
     "is_unavailable": {
      "type": "boolean"
     },
     "note": {
      "description": "\"Doctor's Appointment\"",
      "type": "string"
     },
     "start_time": {
      "description": "Optional: Override hours",
      "type": "string"
     },
     "worker_id": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "worker.WorkerScheduleOverrideUpdateRequest": {
    "description": "Request body for partially updating a one-time schedule override; all fields are optional",
    "properties": {
     "date": {
      "type": "string"
     },
     "end_time": {
      "type": "string"
     },
     "is_unavailable": {
      "type": "boolean"
     },
     "note": {
      "type": "string"
     },
     "start_time": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "worker.WorkerScheduleRequest": {
    "description": "Request body for creating a recurring weekly schedule entry for a worker",
    "properties": {
     "day_of_week": {
      "description": "0=Sun, 1=Mon, ..., 6=Sat",
      "type": "integer"
     },
     "end_time": {
      "description": "\"17:00\"",
      "type": "string"
     },
     "start_time": {
      "description": "\"09:00\"",
      "type": "string"
     },
     "worker_id": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "worker.WorkerScheduleUpdateRequest": {
    "description": "Request body for partially updating a recurring weekly schedule entry; all fields are optional",
    "properties": {
     "day_of_week": {
      "type": "integer"
     },
     "end_time": {
      "type": "string"
     },
     "start_time": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "worker.WorkerSearchAutoCompleteResponse": {
    "description": "Slim worker representation used for autocomplete suggestions",
    "properties": {
     "display_name": {
      "type": "string"
     },
     "email": {
      "type": "string"
     },
     "first_name": {
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "last_name": {
      "type": "string"
     },
     "phone": {
      "type": "string"
     },
     "phone_country": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "worker.WorkerUpdateRequest": {
    "description": "Request body for updating worker details. Pointer fields are optional and only updated when provided",
    "properties": {
     "assigned_to_vehicle_id": {
      "type": "string"
     },
     "custom_fields": {
      "additionalProperties": true,
      "type": "object"
     },
     "display_name": {
      "type": "string"
     },
     "driver_license_class": {
      "type": "string"
     },
     "driver_license_expiration_date": {
      "type": "string"
     },
     "driver_license_number": {
      "type": "string"
     },
     "earnings_rule_id": {
      "type": "string"
     },
     "email": {
      "type": "string"
     },
     "first_name": {
      "type": "string"
     },
     "home_address": {
      "allOf": [
       {
        "$ref": "#/components/schemas/address.AddressRequest"
       }
      ],
      "description": "HomeAddress is an inline address to create and use as the worker's home address."
     },
     "home_address_id": {
      "description": "HomeAddressID updates the worker's home address by referencing an existing address.\nEmpty string clears the home address; omitted leaves it unchanged. Takes precedence\nover HomeAddress when both are supplied.",
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "image_attachment_id": {
      "description": "ImageAttachmentID references a confirmed (ready) attachment uploaded via the\npre-signed flow; the server resolves it to the profile image URL.",
      "type": "string"
     },
     "is_active": {
      "type": "boolean"
     },
     "last_name": {
      "type": "string"
     },
     "operational_status": {
      "$ref": "#/components/schemas/worker.OperationalStatus"
     },
     "option_ids": {
      "items": {
       "type": "string"
      },
      "type": "array"
     },
     "password": {
      "type": "string"
     },
     "phone": {
      "type": "string"
     },
     "phone_country": {
      "type": "string"
     },
     "profile_id": {
      "type": "string"
     },
     "role": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "workers.Leaderboard": {
    "properties": {
     "workers": {
      "items": {
       "$ref": "#/components/schemas/workers.LeaderboardEntry"
      },
      "type": "array"
     }
    },
    "type": "object"
   },
   "workers.LeaderboardEntry": {
    "properties": {
     "jobs_completed": {
      "type": "integer"
     },
     "name": {
      "type": "string"
     },
     "stops_completed": {
      "type": "integer"
     },
     "worker_id": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "workers.Metrics": {
    "properties": {
     "avg_jobs_per_user": {
      "type": "number"
     },
     "total_active": {
      "type": "integer"
     },
     "total_on_duty": {
      "type": "integer"
     }
    },
    "type": "object"
   },
   "workflow.EntityType": {
    "enum": [
     "job",
     "stop",
     "route"
    ],
    "type": "string",
    "x-enum-varnames": [
     "EntityTypeJob",
     "EntityTypeStop",
     "EntityTypeRoute"
    ]
   },
   "workflow.StateGroup": {
    "enum": [
     "pending",
     "assigned",
     "started",
     "completed",
     "cancelled"
    ],
    "type": "string",
    "x-enum-varnames": [
     "StateGroupPending",
     "StateGroupAssigned",
     "StateGroupStarted",
     "StateGroupCompleted",
     "StateGroupCancelled"
    ]
   },
   "workflow.StateType": {
    "enum": [
     "internal",
     "custom"
    ],
    "type": "string",
    "x-enum-varnames": [
     "StateTypeInternal",
     "StateTypeCustom"
    ]
   },
   "workflow.UpsertStatePayload": {
    "properties": {
     "description": {
      "description": "Description provides additional context about the state",
      "type": "string"
     },
     "group": {
      "allOf": [
       {
        "$ref": "#/components/schemas/workflow.StateGroup"
       }
      ],
      "description": "Group is the lifecycle phase this state belongs to (e.g. pending, started, completed)"
     },
     "id": {
      "description": "ID is the existing state ID; omit to create a new state",
      "type": "string"
     },
     "label": {
      "description": "Label is the human-readable display name for the state",
      "type": "string"
     },
     "name": {
      "description": "Name is the internal machine-readable identifier for the state",
      "type": "string"
     }
    },
    "type": "object"
   },
   "workflow.UpsertWorkflowStatesPayload": {
    "properties": {
     "states": {
      "description": "States is the list of states to create or update for the workflow",
      "items": {
       "$ref": "#/components/schemas/workflow.UpsertStatePayload"
      },
      "type": "array"
     },
     "workflow_id": {
      "description": "WorkflowID is the ID of the workflow whose states are being upserted",
      "type": "string"
     }
    },
    "type": "object"
   },
   "workflow.Workflow": {
    "properties": {
     "created_at": {
      "type": "string"
     },
     "default_state_name": {
      "type": "string"
     },
     "description": {
      "type": "string"
     },
     "entity_type": {
      "$ref": "#/components/schemas/workflow.EntityType"
     },
     "id": {
      "type": "string"
     },
     "is_active": {
      "type": "boolean"
     },
     "name": {
      "type": "string"
     },
     "site_id": {
      "type": "string"
     },
     "states": {
      "items": {
       "$ref": "#/components/schemas/workflow.WorkflowState"
      },
      "type": "array"
     },
     "updated_at": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "workflow.WorkflowState": {
    "properties": {
     "created_at": {
      "type": "string"
     },
     "description": {
      "type": "string"
     },
     "entity_type": {
      "$ref": "#/components/schemas/workflow.EntityType"
     },
     "group": {
      "$ref": "#/components/schemas/workflow.StateGroup"
     },
     "id": {
      "type": "string"
     },
     "is_active": {
      "type": "boolean"
     },
     "label": {
      "type": "string"
     },
     "name": {
      "type": "string"
     },
     "order": {
      "type": "integer"
     },
     "site_id": {
      "type": "string"
     },
     "type": {
      "$ref": "#/components/schemas/workflow.StateType"
     },
     "updated_at": {
      "type": "string"
     },
     "workflow_id": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "zone.ServiceRestriction": {
    "enum": [
     "none",
     "banned",
     "caution"
    ],
    "type": "string",
    "x-enum-varnames": [
     "ServiceRestrictionAllowed",
     "ServiceRestrictionBanned",
     "ServiceRestrictionCaution"
    ]
   },
   "zone.ServiceabilityCheckResponse": {
    "properties": {
     "in_zone": {
      "description": "InZone is true when the point falls inside at least one active zone.",
      "type": "boolean"
     },
     "message": {
      "description": "Message is a human-readable string for the UI; empty when there is no restriction.",
      "type": "string"
     },
     "service_restriction": {
      "$ref": "#/components/schemas/zone.ServiceRestriction"
     },
     "serviceable": {
      "description": "Serviceable is false only when the point falls inside a banned zone.",
      "type": "boolean"
     },
     "zone_id": {
      "type": "string"
     },
     "zone_name": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "zone.ShapeType": {
    "enum": [
     "polygon",
     "circle"
    ],
    "type": "string",
    "x-enum-varnames": [
     "ShapeTypePolygon",
     "ShapeTypeCircle"
    ]
   },
   "zone.Zone": {
    "properties": {
     "color": {
      "type": "string"
     },
     "created_at": {
      "description": "create & read only",
      "type": "string"
     },
     "id": {
      "type": "string"
     },
     "is_active": {
      "type": "boolean"
     },
     "name": {
      "type": "string"
     },
     "priority": {
      "type": "integer"
     },
     "service_restriction": {
      "$ref": "#/components/schemas/zone.ServiceRestriction"
     },
     "shape": {
      "items": {
       "$ref": "#/components/schemas/db.Point"
      },
      "type": "array"
     },
     "shape_metadata": {
      "additionalProperties": true,
      "type": "object"
     },
     "shape_type": {
      "$ref": "#/components/schemas/zone.ShapeType"
     },
     "site_id": {
      "type": "string"
     },
     "updated_at": {
      "type": "string"
     }
    },
    "type": "object"
   },
   "zone.ZoneRequest": {
    "properties": {
     "color": {
      "description": "Color is a hex color code used for map display",
      "type": "string"
     },
     "id": {
      "description": "ID is the zone identifier (used for updates)",
      "type": "string"
     },
     "is_active": {
      "description": "IsActive indicates whether this zone is currently enabled",
      "type": "boolean"
     },
     "name": {
      "description": "Name is the human-readable label for the zone",
      "type": "string"
     },
     "priority": {
      "description": "Priority determines zone precedence when multiple zones overlap",
      "type": "integer"
     },
     "service_restriction": {
      "description": "ServiceRestriction defines how this zone affects service (none, banned, caution)",
      "type": "string"
     },
     "shape": {
      "description": "Shape is the ordered list of lat/lng coordinate pairs defining the zone boundary",
      "items": {
       "properties": {
        "lat": {
         "type": "number"
        },
        "lng": {
         "type": "number"
        }
       },
       "type": "object"
      },
      "type": "array"
     },
     "shape_metadata": {
      "additionalProperties": true,
      "description": "ShapeMetadata holds additional shape-specific configuration (e.g. radius for circles)",
      "type": "object"
     },
     "shape_type": {
      "description": "ShapeType is the geometric shape of the zone (e.g. polygon, circle)",
      "type": "string"
     }
    },
    "type": "object"
   }
  },
  "securitySchemes": {
   "AccessTokenAuth": {
    "in": "header",
    "name": "x-access-token",
    "type": "apiKey"
   },
   "ApiKeyAuth": {
    "in": "header",
    "name": "x-api-key",
    "type": "apiKey"
   }
  }
 },
 "info": {
  "contact": {},
  "description": "# RouteIQ API\n\nRouteIQ is a multi-tenant delivery management platform. This API powers job dispatch, route optimization, driver tracking, and customer notifications.\n\n## Getting Started\n\nAll API requests require a valid site context (identified by subdomain) and authentication credentials. Base URL:\n\n```\nhttps://<subdomain>.routeiq.app/api\n```\n\n## Authentication\n\nEvery API request carries both headers:\n\n| Header | Identifies |\n|--------|------------|\n| `x-api-key: <key>` | Your application |\n| `x-access-token: <token>` | The signed-in user |\n\nObtain an access token by signing in (see the authentication endpoints). Tokens expire and must be refreshed.\n\n## Multi-Tenancy\n\nEvery request is scoped to a **site** identified by the subdomain in the `Host` header. All data is fully isolated between sites. You cannot access data from one site using credentials from another.\n\n## Pagination\n\nList endpoints support cursor-based or offset pagination via query parameters:\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `page` | integer | Page number (1-indexed) |\n| `per_page` | integer | Results per page (default 20, max 100) |\n\nResponses include a `meta` object with `total`, `page`, and `per_page` fields.\n\n## Filtering and Sorting\n\nMost list endpoints accept:\n- `sort_by` — field name, with `sort_order` set to `asc` or `desc` (e.g. `sort_by=created_at&sort_order=desc`)\n- Filter fields vary per endpoint and are documented inline\n\n## Error Handling\n\nAll errors follow a consistent JSON structure:\n\n```json\n{\n  \"error\": \"human-readable message\",\n  \"code\": \"ERROR_CODE\"\n}\n```\n\nHTTP status codes:\n- `400` — Validation error or bad request\n- `401` — Missing or invalid credentials\n- `403` — Insufficient permissions\n- `404` — Resource not found\n- `409` — Conflict (e.g. duplicate)\n- `422` — Unprocessable entity\n- `500` — Internal server error\n\n## Rate Limiting\n\nAPI requests are rate-limited per API key / access token. When the limit is exceeded, the API returns `429 Too Many Requests`. Retry after the interval specified in the `Retry-After` response header.\n\n## Partial Updates\n\n`PATCH` endpoints use a three-state update model:\n\n| JSON value | Meaning |\n|------------|---------|\n| `\"field\": <value>` | Set field to value |\n| Field omitted | Leave field unchanged |\n| `\"field\": null` | Clear / unset field |\n",
  "title": "RouteIQ API",
  "version": "1.0"
 },
 "openapi": "3.0.3",
 "paths": {
  "/address": {
   "get": {
    "description": "Get an address by id for the authenticated site",
    "parameters": [
     {
      "description": "Address ID",
      "in": "query",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/address.Address"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "404": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Not Found"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get address",
    "tags": [
     "address"
    ]
   },
   "post": {
    "description": "Create a new address for the authenticated site",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/address.AddressRequest"
       }
      }
     },
     "description": "Address payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/address.Address"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Create address",
    "tags": [
     "address"
    ]
   },
   "put": {
    "description": "Update an existing address by id for the authenticated site",
    "parameters": [
     {
      "description": "Address ID",
      "in": "query",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/address.AddressRequest"
       }
      }
     },
     "description": "Address update payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/address.Address"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Update address",
    "tags": [
     "address"
    ]
   }
  },
  "/address/details": {
   "get": {
    "description": "Geocode a free-form address string and return a structured address object",
    "parameters": [
     {
      "description": "Address string to geocode",
      "in": "query",
      "name": "address",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/address.Address"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Address details",
    "tags": [
     "address"
    ]
   }
  },
  "/address/reverse": {
   "get": {
    "description": "Reverse geocode latitude and longitude coordinates into a structured address",
    "parameters": [
     {
      "description": "Latitude",
      "in": "query",
      "name": "lat",
      "required": true,
      "schema": {
       "type": "number"
      }
     },
     {
      "description": "Longitude",
      "in": "query",
      "name": "lng",
      "required": true,
      "schema": {
       "type": "number"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/address.Address"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Reverse geocode",
    "tags": [
     "address"
    ]
   }
  },
  "/address/search/autocomplete": {
   "get": {
    "description": "Return autocomplete predictions for an address search query",
    "parameters": [
     {
      "description": "Search query",
      "in": "query",
      "name": "query",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Session token for billing grouping",
      "in": "query",
      "name": "session_token",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Latitude to bias results toward (overrides site address bias)",
      "in": "query",
      "name": "lat",
      "schema": {
       "type": "number"
      }
     },
     {
      "description": "Longitude to bias results toward (overrides site address bias)",
      "in": "query",
      "name": "lng",
      "schema": {
       "type": "number"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/mapprovider.AddressPredictionResult"
         },
         "type": "array"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Address search autocomplete",
    "tags": [
     "address"
    ]
   }
  },
  "/admin/organization/": {
   "get": {
    "description": "Retrieves a single organization record by its ID",
    "parameters": [
     {
      "description": "Organization ID",
      "in": "query",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/organization.Organization"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get an organization by ID",
    "tags": [
     "admin"
    ]
   },
   "post": {
    "description": "Creates a new organization record",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/admin.CreateOrganizationRequest"
       }
      }
     },
     "description": "Organization creation payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "201": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/organization.Organization"
        }
       }
      },
      "description": "Created"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Create an organization",
    "tags": [
     "admin"
    ]
   },
   "put": {
    "description": "Updates an existing organization record by ID",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/admin.UpdateOrganizationRequest"
       }
      }
     },
     "description": "Organization update payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/organization.Organization"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Update an organization",
    "tags": [
     "admin"
    ]
   }
  },
  "/admin/organization/search": {
   "get": {
    "description": "Searches organizations with optional filters and returns a paginated list",
    "parameters": [
     {
      "description": "Filter by organization name",
      "in": "query",
      "name": "name",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Filter by active status",
      "in": "query",
      "name": "is_active",
      "schema": {
       "type": "boolean"
      }
     },
     {
      "description": "Page number",
      "in": "query",
      "name": "page",
      "schema": {
       "type": "integer"
      }
     },
     {
      "description": "Number of items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "type": "integer"
      }
     },
     {
      "description": "Sort field: name, is_active, created_at",
      "in": "query",
      "name": "sort_by",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Sort direction: asc or desc",
      "in": "query",
      "name": "sort_order",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/organization.Organization"
         },
         "type": "array"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Search organizations",
    "tags": [
     "admin"
    ]
   }
  },
  "/admin/site/": {
   "get": {
    "description": "Retrieves a single site record by its ID",
    "parameters": [
     {
      "description": "Site ID",
      "in": "query",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/site.Site"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get a site by ID",
    "tags": [
     "admin"
    ]
   },
   "post": {
    "description": "Creates a new site record and initializes default site resources",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/admin.CreateSiteRequest"
       }
      }
     },
     "description": "Site creation payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "201": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/site.Site"
        }
       }
      },
      "description": "Created"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Create a site",
    "tags": [
     "admin"
    ]
   },
   "put": {
    "description": "Updates an existing site record by ID",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/admin.UpdateSiteRequest"
       }
      }
     },
     "description": "Site update payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/site.Site"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Update a site",
    "tags": [
     "admin"
    ]
   }
  },
  "/admin/site/search": {
   "get": {
    "description": "Searches sites with optional filters and returns a paginated list",
    "parameters": [
     {
      "description": "Filter by site name",
      "in": "query",
      "name": "name",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Filter by subdomain",
      "in": "query",
      "name": "subdomain",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Filter by organization ID",
      "in": "query",
      "name": "organization_id",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Filter by active status",
      "in": "query",
      "name": "is_active",
      "schema": {
       "type": "boolean"
      }
     },
     {
      "description": "Page number",
      "in": "query",
      "name": "page",
      "schema": {
       "type": "integer"
      }
     },
     {
      "description": "Number of items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "type": "integer"
      }
     },
     {
      "description": "Sort field: name, subdomain, created_at, is_active",
      "in": "query",
      "name": "sort_by",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Sort direction: asc or desc",
      "in": "query",
      "name": "sort_order",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/site.Site"
         },
         "type": "array"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Search sites",
    "tags": [
     "admin"
    ]
   }
  },
  "/admin/user/": {
   "get": {
    "description": "Retrieves a single user record by its ID",
    "parameters": [
     {
      "description": "User ID",
      "in": "query",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/user.User"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get a user by ID",
    "tags": [
     "admin"
    ]
   },
   "post": {
    "description": "Creates a new user account with an associated site profile and worker details",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/admin.CreateUserRequest"
       }
      }
     },
     "description": "User creation payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "201": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/user.User"
        }
       }
      },
      "description": "Created"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Create a user",
    "tags": [
     "admin"
    ]
   },
   "put": {
    "description": "Updates an existing user account within a specific site. The home address may be set via an existing `home_address_id` or an inline `home_address` object; sending `home_address_id` as an empty string clears it.",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/admin.UpdateUserRequest"
       }
      }
     },
     "description": "User update payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/user.User"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Update a user",
    "tags": [
     "admin"
    ]
   }
  },
  "/admin/user/search": {
   "get": {
    "description": "Searches users with optional filters and returns a flat list",
    "parameters": [
     {
      "description": "Filter by site ID",
      "in": "query",
      "name": "site_id",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Filter by organization ID",
      "in": "query",
      "name": "organization_id",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Filter by email address",
      "in": "query",
      "name": "email",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Filter by user role",
      "in": "query",
      "name": "role",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Filter by active status",
      "in": "query",
      "name": "is_active",
      "schema": {
       "type": "boolean"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/user.User"
         },
         "type": "array"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Search users",
    "tags": [
     "admin"
    ]
   }
  },
  "/app/": {
   "get": {
    "description": "Retrieves a single application record for the authenticated site by its ID",
    "parameters": [
     {
      "description": "Application ID",
      "in": "query",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/application.Application"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get an application by ID",
    "tags": [
     "application"
    ]
   },
   "post": {
    "description": "Creates a new application for the authenticated site and organization",
    "parameters": [
     {
      "description": "Application name",
      "in": "query",
      "name": "name",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Application description",
      "in": "query",
      "name": "description",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/application.Application"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Create a new application",
    "tags": [
     "application"
    ]
   }
  },
  "/attachment/": {
   "get": {
    "description": "Retrieves a single attachment record for the authenticated site by its ID",
    "parameters": [
     {
      "description": "Attachment ID",
      "in": "query",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/attachment.Attachment"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get an attachment by ID",
    "tags": [
     "attachment"
    ]
   },
   "post": {
    "description": "DEPRECATED: prefer the pre-signed flow (POST /attachment/presign then POST /attachment/{id}/confirm). Accepts multipart form data and uploads the provided files server-side.",
    "requestBody": {
     "content": {
      "multipart/form-data": {
       "schema": {
        "properties": {
         "attachments": {
          "description": "File(s) to upload",
          "format": "binary",
          "type": "string",
          "x-formData-name": "attachments"
         }
        },
        "required": [
         "attachments"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/attachment.Attachment"
         },
         "type": "array"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Upload one or more attachments (deprecated)",
    "tags": [
     "attachment"
    ]
   }
  },
  "/attachment/presign": {
   "post": {
    "description": "Validates the file against the purpose policy and returns a pre-signed URL the client uploads bytes to directly. A pending attachment is created; call confirm after the upload finishes.",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/attachment.PresignRequest"
       }
      }
     },
     "description": "Presign request",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/attachment.PresignResponse"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Request a pre-signed upload",
    "tags": [
     "attachment"
    ]
   }
  },
  "/attachment/{id}/confirm": {
   "post": {
    "description": "Verifies the uploaded object (existence, size, sniffed content type) against the purpose policy and marks the attachment ready. Returns the attachment with its public URL.",
    "parameters": [
     {
      "description": "Attachment ID",
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/attachment.Attachment"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Confirm a pre-signed upload",
    "tags": [
     "attachment"
    ]
   }
  },
  "/audit/search": {
   "get": {
    "description": "Searches and returns audit log entries for the authenticated site",
    "parameters": [
     {
      "description": "Filter by entity type (e.g. job, stop, user)",
      "in": "query",
      "name": "entity_type",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Filter by entity ID",
      "in": "query",
      "name": "entity_id",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Filter by user who made the change",
      "in": "query",
      "name": "user_id",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Filter by action (e.g. create, update, delete)",
      "in": "query",
      "name": "action",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Filter records created at or after this datetime (RFC3339)",
      "in": "query",
      "name": "from",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Filter records created at or before this datetime (RFC3339)",
      "in": "query",
      "name": "to",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Page number (default 1)",
      "in": "query",
      "name": "page",
      "schema": {
       "type": "integer"
      }
     },
     {
      "description": "Items per page (default 100)",
      "in": "query",
      "name": "page_size",
      "schema": {
       "type": "integer"
      }
     },
     {
      "description": "Sort field: entity_type, entity_id, action, user_id, created_at",
      "in": "query",
      "name": "sort_by",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Sort direction: asc or desc",
      "in": "query",
      "name": "sort_order",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/audit.Audit"
         },
         "type": "array"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Search audit records",
    "tags": [
     "audit"
    ]
   }
  },
  "/audit/{id}": {
   "get": {
    "description": "Returns a single audit log entry by its ID",
    "parameters": [
     {
      "description": "Audit record ID",
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/audit.Audit"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "404": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Not Found"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get audit record by ID",
    "tags": [
     "audit"
    ]
   }
  },
  "/auth/": {
   "post": {
    "description": "First step of the login flow. Validates email and password then returns a temporary token and list of site profiles the user can log into.",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/authentication.AuthRequest"
       }
      }
     },
     "description": "User credentials",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/authentication.PreAuthContextResponse"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     }
    },
    "summary": "Pre-authenticate user",
    "tags": [
     "authentication"
    ]
   }
  },
  "/auth/config": {
   "get": {
    "description": "Returns the current Casbin access control policy as JSON. Useful for clients that need to perform local permission checks.",
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "additionalProperties": true,
         "type": "object"
        }
       }
      },
      "description": "OK"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get access control policy",
    "tags": [
     "authentication"
    ]
   }
  },
  "/auth/context": {
   "get": {
    "description": "Returns the full authentication context for the currently authenticated user, including user details, organization, site, application, access token, and profiles.",
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/authentication.AuthContext"
        }
       }
      },
      "description": "OK"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get authenticated session context",
    "tags": [
     "authentication"
    ]
   }
  },
  "/auth/logout": {
   "post": {
    "description": "Invalidates the current access token and logs the user out of the current site session.",
    "responses": {
     "204": {
      "description": "No Content"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Log out the current user",
    "tags": [
     "authentication"
    ]
   }
  },
  "/auth/password-reset/confirm": {
   "post": {
    "description": "Completes the password reset flow by validating the reset token and setting the new password.",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/authentication.PasswordResetConfirmRequest"
       }
      }
     },
     "description": "Reset token and new password",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "204": {
      "description": "No Content"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "summary": "Confirm a password reset",
    "tags": [
     "authentication"
    ]
   }
  },
  "/auth/password-reset/request": {
   "post": {
    "description": "Sends a password reset email to the given address if an account exists. Always returns 204 to prevent email enumeration.",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/authentication.PasswordResetRequest"
       }
      }
     },
     "description": "Email address to send the reset link to",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "204": {
      "description": "No Content"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "summary": "Request a password reset",
    "tags": [
     "authentication"
    ]
   }
  },
  "/auth/provider/{provider}": {
   "post": {
    "description": "Authenticates a user using a third-party OAuth provider token (e.g. Google). Returns a full AuthContext on success.",
    "parameters": [
     {
      "description": "OAuth provider name (e.g. 'google')",
      "in": "path",
      "name": "provider",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "OAuth ID token from the provider",
      "in": "query",
      "name": "token",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Site ID to authenticate against",
      "in": "query",
      "name": "site_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Application name (e.g. 'dashboard', 'driver')",
      "in": "query",
      "name": "app",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Profile type to authenticate as ('worker' or 'customer')",
      "in": "query",
      "name": "profile_type",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/authentication.AuthContext"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     }
    },
    "summary": "Authenticate with an OAuth provider",
    "tags": [
     "authentication"
    ]
   }
  },
  "/auth/site": {
   "post": {
    "description": "Completes the login flow by authenticating a user against a specific site. Accepts either (site_id + email + password) or (profile_id + token + app). Returns a full AuthContext on success.",
    "parameters": [
     {
      "description": "Application name (e.g. 'dashboard', 'driver')",
      "in": "query",
      "name": "app",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Site ID to authenticate against",
      "in": "query",
      "name": "site_id",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "User email (required when using site_id + password login)",
      "in": "query",
      "name": "email",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "User password (required when using site_id + email login)",
      "in": "query",
      "name": "password",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Profile ID (used with token-based login)",
      "in": "query",
      "name": "profile_id",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Pre-auth token (used with profile_id-based login)",
      "in": "query",
      "name": "token",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/authentication.AuthContext"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     }
    },
    "summary": "Authenticate and start a site session",
    "tags": [
     "authentication"
    ]
   }
  },
  "/auth/token": {
   "post": {
    "description": "Refreshes or validates an existing access token for the given site. Returns a full AuthContext when the token is valid.",
    "parameters": [
     {
      "description": "Site ID to authenticate against",
      "in": "query",
      "name": "site_id",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/authentication.AuthContext"
        }
       }
      },
      "description": "OK"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Authenticate by existing token",
    "tags": [
     "authentication"
    ]
   }
  },
  "/chat/assistant/room": {
   "get": {
    "description": "Returns the authenticated user's AI assistant room, creating one if it doesn't exist",
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/chat.ChatRoomResponse"
        }
       }
      },
      "description": "OK"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get or create the AI assistant chat room",
    "tags": [
     "chat"
    ]
   }
  },
  "/chat/room": {
   "post": {
    "description": "Creates a new chat room with the authenticated user and the specified recipient as initial participants",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/chat.RoomRequest"
       }
      }
     },
     "description": "Room creation payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/chat.ChatRoom"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Create a chat room",
    "tags": [
     "chat"
    ]
   }
  },
  "/chat/room/message": {
   "post": {
    "description": "Sends a new message to a specific chat room. Attach files by referencing confirmed attachments via attachment_ids (uploaded through the pre-signed flow).",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/chat.MessageRequest"
       }
      }
     },
     "description": "Message payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/chat.ChatMessage"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Send a message to a room",
    "tags": [
     "chat"
    ]
   }
  },
  "/chat/room/messages": {
   "get": {
    "description": "Retrieves all messages for a specific chat room (paginated chat history)",
    "parameters": [
     {
      "description": "Room ID",
      "in": "query",
      "name": "room_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Page number",
      "in": "query",
      "name": "page",
      "schema": {
       "type": "integer"
      }
     },
     {
      "description": "Number of messages per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "type": "integer"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/chat.ChatMessage"
         },
         "type": "array"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get room messages",
    "tags": [
     "chat"
    ]
   }
  },
  "/chat/room/participant": {
   "post": {
    "description": "Adds a user as a participant to an existing chat room",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/chat.ParticipantRequest"
       }
      }
     },
     "description": "Participant details",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/chat.ChatRoom"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Add a participant to a room",
    "tags": [
     "chat"
    ]
   }
  },
  "/chat/rooms": {
   "get": {
    "description": "Retrieves all chat rooms for the currently authenticated user",
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/chat.ChatRoomResponse"
         },
         "type": "array"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get user's chat rooms",
    "tags": [
     "chat"
    ]
   }
  },
  "/custom-field": {
   "delete": {
    "description": "Soft-deletes a custom field definition by ID on the authenticated site",
    "parameters": [
     {
      "description": "Definition ID",
      "in": "query",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "204": {
      "description": "No Content"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Delete custom field definition",
    "tags": [
     "customfield"
    ]
   },
   "get": {
    "description": "Returns all custom field definitions for a given entity type on the authenticated site",
    "parameters": [
     {
      "description": "Entity type (e.g. worker)",
      "in": "query",
      "name": "entity_type",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/customfield.Definition"
         },
         "type": "array"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "List custom field definitions",
    "tags": [
     "customfield"
    ]
   },
   "post": {
    "description": "Creates a new custom field definition for a given entity type on the authenticated site",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/customfield.CreateDefinitionRequest"
       }
      }
     },
     "description": "Custom field definition payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/customfield.Definition"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Create custom field definition",
    "tags": [
     "customfield"
    ]
   },
   "put": {
    "description": "Updates an existing custom field definition by ID on the authenticated site",
    "parameters": [
     {
      "description": "Definition ID",
      "in": "query",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/customfield.UpdateDefinitionRequest"
       }
      }
     },
     "description": "Custom field update payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/customfield.Definition"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Update custom field definition",
    "tags": [
     "customfield"
    ]
   }
  },
  "/customer": {
   "get": {
    "description": "Retrieves a customer by their ID for the current site",
    "parameters": [
     {
      "description": "Customer ID",
      "in": "query",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/user.User"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get a customer",
    "tags": [
     "customer"
    ]
   },
   "post": {
    "description": "Creates a new customer user account and associates them with the current site. A home address may be supplied as an existing `home_address_id` or an inline `home_address` object (the id wins when both are sent).",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/customer.CustomerRequest"
       }
      }
     },
     "description": "Customer details",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/user.User"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Create a customer",
    "tags": [
     "customer"
    ]
   },
   "put": {
    "description": "Updates the details of an existing customer by their ID. The home address may be set via an existing `home_address_id` or an inline `home_address` object; sending `home_address_id` as an empty string clears it.",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/customer.CustomerUpdateRequest"
       }
      }
     },
     "description": "Customer update payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/user.User"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Update a customer",
    "tags": [
     "customer"
    ]
   }
  },
  "/customer/export": {
   "get": {
    "description": "Exports all customers for the current site in the requested format (csv or json); defaults to CSV",
    "parameters": [
     {
      "description": "Export format: csv or json",
      "in": "query",
      "name": "format",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "text/csv": {
        "schema": {
         "type": "string"
        }
       }
      },
      "description": "File download (CSV or JSON)"
     },
     "400": {
      "content": {
       "text/csv": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "text/csv": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Export customers",
    "tags": [
     "customer"
    ]
   }
  },
  "/customer/import": {
   "post": {
    "description": "Bulk imports customers from a CSV or JSON file upload, or from a JSON request body",
    "requestBody": {
     "content": {
      "multipart/form-data": {
       "schema": {
        "properties": {
         "file": {
          "description": "CSV or JSON file to import",
          "format": "binary",
          "type": "string",
          "x-formData-name": "file"
         }
        },
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/user.ImportResponse"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Import customers",
    "tags": [
     "customer"
    ]
   }
  },
  "/customer/search": {
   "get": {
    "description": "Searches customers by one or more fields: first name, last name, email, phone, and phone country",
    "parameters": [
     {
      "description": "First name filter",
      "in": "query",
      "name": "first_name",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Last name filter",
      "in": "query",
      "name": "last_name",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Email filter",
      "in": "query",
      "name": "email",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Phone country code filter",
      "in": "query",
      "name": "phone_country",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Phone number filter",
      "in": "query",
      "name": "phone",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Page number (default 1)",
      "in": "query",
      "name": "page",
      "schema": {
       "type": "integer"
      }
     },
     {
      "description": "Items per page (default 100)",
      "in": "query",
      "name": "page_size",
      "schema": {
       "type": "integer"
      }
     },
     {
      "description": "Sort field: first_name, last_name, email, phone, created_at",
      "in": "query",
      "name": "sort_by",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Sort direction: asc or desc",
      "in": "query",
      "name": "sort_order",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/user.User"
         },
         "type": "array"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Search customers",
    "tags": [
     "customer"
    ]
   }
  },
  "/customer/search/autocomplete": {
   "get": {
    "description": "Returns a list of customers matching the given query string, intended for autocomplete UI",
    "parameters": [
     {
      "description": "Search query string",
      "in": "query",
      "name": "q",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/user.User"
         },
         "type": "array"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Autocomplete customer search",
    "tags": [
     "customer"
    ]
   }
  },
  "/customer/settings": {
   "get": {
    "description": "Retrieves the notification preferences for the currently authenticated customer",
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/settings.UserSettings"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get customer notification settings",
    "tags": [
     "customer"
    ]
   },
   "put": {
    "description": "Updates the notification preferences for the currently authenticated customer; only supplied fields are changed",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/settings.UpdateUserSettingsRequest"
       }
      }
     },
     "description": "Settings update payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/settings.UserSettings"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Update customer notification settings",
    "tags": [
     "customer"
    ]
   }
  },
  "/customer/signup": {
   "post": {
    "description": "Allows a customer to self-register an account for the current site",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/customer.CustomerRequest"
       }
      }
     },
     "description": "Customer signup details",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/user.User"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Customer self-signup",
    "tags": [
     "customer"
    ]
   }
  },
  "/dispatch/assign": {
   "post": {
    "description": "Assigns a job to a specific driver and vehicle, optionally scheduling the start time and requiring driver confirmation",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/dispatch.DispatchRequest"
       }
      }
     },
     "description": "Dispatch assignment payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/dispatch.Dispatch"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Assign job to driver",
    "tags": [
     "dispatch"
    ]
   }
  },
  "/dispatch/auto": {
   "post": {
    "description": "Triggers automatic dispatch of pending jobs on the authenticated site (not yet implemented)",
    "responses": {
     "200": {
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Auto-dispatch jobs",
    "tags": [
     "dispatch"
    ]
   }
  },
  "/dispatch/available-drivers": {
   "get": {
    "description": "Returns drivers that are available to be assigned to the specified job, with optional filtering by schedule, conflicts, and vehicle availability",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/dispatch.AvailableDriversRequest"
       }
      }
     },
     "description": "Available drivers filter payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/dispatch.AvailableDriverResponse"
         },
         "type": "array"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "List available drivers",
    "tags": [
     "dispatch"
    ]
   }
  },
  "/dispatch/available-vehicles": {
   "get": {
    "description": "Returns vehicles that are available to be assigned for the given driver on the authenticated site",
    "parameters": [
     {
      "description": "Driver ID to filter vehicles for",
      "in": "query",
      "name": "driver_id",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/dispatch.Dispatch"
         },
         "type": "array"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "List available vehicles",
    "tags": [
     "dispatch"
    ]
   }
  },
  "/dispatch/cancel": {
   "post": {
    "description": "Cancels an active dispatch for the specified job on the authenticated site (not yet implemented)",
    "responses": {
     "200": {
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Cancel dispatch",
    "tags": [
     "dispatch"
    ]
   }
  },
  "/dispatch/opt-in": {
   "post": {
    "description": "Allows a driver to opt in to receiving dispatch offers on the authenticated site (not yet implemented)",
    "responses": {
     "200": {
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Opt in driver to dispatch pool",
    "tags": [
     "dispatch"
    ]
   }
  },
  "/dispatch/pool": {
   "get": {
    "description": "Returns jobs available in the dispatch pool for the authenticated driver, including team-scoped and floating site-wide jobs",
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/dispatch.PoolJobResponse"
         },
         "type": "array"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get available pool jobs",
    "tags": [
     "dispatch"
    ]
   },
   "post": {
    "description": "Posts one or more jobs to the dispatch pool. Optionally scopes to a team; if no team is provided, jobs float site-wide for any on-duty driver to claim.",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/dispatch.PostToPoolRequest"
       }
      }
     },
     "description": "Pool post payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/dispatch.Dispatch"
         },
         "type": "array"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Post jobs to dispatch pool",
    "tags": [
     "dispatch"
    ]
   }
  },
  "/dispatch/pool/claim": {
   "post": {
    "description": "Allows an on-duty driver to claim a job from the dispatch pool. First-come-first-served; returns an error if another driver claimed it first.",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/dispatch.ClaimJobRequest"
       }
      }
     },
     "description": "Claim payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/dispatch.Dispatch"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Claim a job from the pool",
    "tags": [
     "dispatch"
    ]
   }
  },
  "/dispatch/route": {
   "post": {
    "description": "Assigns a driver and vehicle to a pre-built route and batch-dispatches all jobs on the route in one operation",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/dispatch.DispatchRouteRequest"
       }
      }
     },
     "description": "Route dispatch payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/dispatch.DispatchRouteResponse"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Dispatch route to driver",
    "tags": [
     "dispatch"
    ]
   }
  },
  "/dispatch/team/assign": {
   "post": {
    "description": "Dispatches a job to the best available on-duty driver in the specified team using the chosen selection strategy",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/dispatch.TeamDispatchJobRequest"
       }
      }
     },
     "description": "Team dispatch payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/dispatch.TeamDispatchResponse"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Dispatch job to team",
    "tags": [
     "dispatch"
    ]
   }
  },
  "/dispatch/team/bulk-distribute": {
   "post": {
    "description": "Distributes a batch of jobs across available on-duty drivers in the specified team. Uses HERE Maps route matrix to cluster jobs geographically and auto-creates optimized routes per driver.",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/dispatch.BulkDistributeRequest"
       }
      }
     },
     "description": "Bulk distribute payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/dispatch.BulkDistributeResponse"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Bulk distribute jobs to team",
    "tags": [
     "dispatch"
    ]
   }
  },
  "/dispatch/team/route": {
   "post": {
    "description": "Assigns the best available on-duty driver in the specified team to a pre-built route",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/dispatch.TeamDispatchRouteRequest"
       }
      }
     },
     "description": "Team route dispatch payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/dispatch.TeamDispatchResponse"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Dispatch route to team",
    "tags": [
     "dispatch"
    ]
   }
  },
  "/dispatch/unassign": {
   "post": {
    "description": "Removes the driver and vehicle assignment from the specified job on the authenticated site",
    "parameters": [
     {
      "description": "Job ID to unassign",
      "in": "query",
      "name": "job_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/dispatch.Dispatch"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Unassign job from driver",
    "tags": [
     "dispatch"
    ]
   }
  },
  "/driver/job/cancel": {
   "post": {
    "description": "Cancels a job assigned to the authenticated driver.",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/driver.CancelJobRequest"
       }
      }
     },
     "description": "Cancel job payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/job.Job"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     },
     "404": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Not Found"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Cancel a job (driver)",
    "tags": [
     "driver"
    ]
   }
  },
  "/driver/job/payment/collect": {
   "post": {
    "description": "Records payment collection for a non-gateway job (cash, POS, voucher, etc.). The job must be in 'completed' state and assigned to the authenticated driver.",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/job.CollectPaymentRequest"
       }
      }
     },
     "description": "Payment collection payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "additionalProperties": {
          "type": "string"
         },
         "type": "object"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Collect payment for a completed job",
    "tags": [
     "driver"
    ]
   }
  },
  "/driver/job/return": {
   "post": {
    "description": "Returns a job assigned to the authenticated driver back to dispatch for reassignment (job becomes 'ready', driver/vehicle cleared, stops removed from the route). Unlike cancellation the job stays alive. Use when the driver cannot complete the job but it is still valid (e.g. vehicle breakdown).",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/driver.ReturnJobRequest"
       }
      }
     },
     "description": "Return job payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/job.Job"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     },
     "404": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Not Found"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Return a job to dispatch",
    "tags": [
     "driver"
    ]
   }
  },
  "/driver/job/search": {
   "get": {
    "description": "Returns jobs assigned to the authenticated driver, filterable by workflow state, completion date range, and pagination",
    "parameters": [
     {
      "description": "Page number (default 1)",
      "in": "query",
      "name": "page",
      "schema": {
       "type": "integer"
      }
     },
     {
      "description": "Items per page (default 100)",
      "in": "query",
      "name": "page_size",
      "schema": {
       "type": "integer"
      }
     },
     {
      "description": "Sort field: created_at, job_number, started_at, completed_at",
      "in": "query",
      "name": "sort_by",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Sort direction: asc or desc",
      "in": "query",
      "name": "sort_order",
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/driver.JobSearchParams"
       }
      }
     },
     "description": "Job search filter payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/job.Job"
         },
         "type": "array"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Search driver jobs",
    "tags": [
     "driver"
    ]
   }
  },
  "/driver/job/{jobId}": {
   "get": {
    "description": "Returns a single job the authenticated driver is allowed to see: a job assigned to them, or a job that belongs to a route assigned to them. Use this instead of the generic GET /job/{id}, which only authorizes drivers on direct job assignment.",
    "parameters": [
     {
      "description": "Job ID",
      "in": "path",
      "name": "jobId",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/job.Job"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "404": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Not Found"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get a job for the driver",
    "tags": [
     "driver"
    ]
   }
  },
  "/driver/metrics": {
   "get": {
    "description": "Returns job and stop counts (total, completed, pending) for the authenticated driver; supports optional date range via from/to query params (YYYY-MM-DD)",
    "parameters": [
     {
      "description": "Start date (YYYY-MM-DD)",
      "in": "query",
      "name": "from",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "End date (YYYY-MM-DD)",
      "in": "query",
      "name": "to",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/jobs.DriverMetrics"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get driver metrics",
    "tags": [
     "driver"
    ]
   }
  },
  "/driver/route/active": {
   "get": {
    "description": "Returns the currently active (started) or first pending route for today for the authenticated driver",
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/route.Route"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get active route",
    "tags": [
     "driver"
    ]
   }
  },
  "/driver/route/complete": {
   "post": {
    "description": "Transitions the specified route to the completed state for the authenticated driver",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/driver.RouteActionRequest"
       }
      }
     },
     "description": "Route complete payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/route.Route"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Complete a route",
    "tags": [
     "driver"
    ]
   }
  },
  "/driver/route/return": {
   "post": {
    "description": "Returns ALL of the authenticated driver's remaining (non-terminal) jobs on the route back to dispatch for reassignment — the \"I can't continue my route\" action. Each job is processed independently, so partial success is possible.",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/driver.RouteActionRequest"
       }
      }
     },
     "description": "Return route payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/job.BulkJobResponse"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Return a route to dispatch",
    "tags": [
     "driver"
    ]
   }
  },
  "/driver/route/search": {
   "get": {
    "description": "Returns routes for the authenticated driver filtered by status, start date, and end date",
    "parameters": [
     {
      "description": "Route status ID filter",
      "in": "query",
      "name": "status_id",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Start date filter (YYYY-MM-DD)",
      "in": "query",
      "name": "start_date",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "End date filter (YYYY-MM-DD)",
      "in": "query",
      "name": "end_date",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Page number (default 1)",
      "in": "query",
      "name": "page",
      "schema": {
       "type": "integer"
      }
     },
     {
      "description": "Items per page (default 100)",
      "in": "query",
      "name": "page_size",
      "schema": {
       "type": "integer"
      }
     },
     {
      "description": "Sort field: label, status_id, created_at, start_at",
      "in": "query",
      "name": "sort_by",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Sort direction: asc or desc",
      "in": "query",
      "name": "sort_order",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/route.Route"
         },
         "type": "array"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Search driver routes",
    "tags": [
     "driver"
    ]
   }
  },
  "/driver/route/start": {
   "post": {
    "description": "Transitions the specified route to the started state for the authenticated driver",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/driver.RouteActionRequest"
       }
      }
     },
     "description": "Route start payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/route.Route"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Start a route",
    "tags": [
     "driver"
    ]
   }
  },
  "/driver/route/{routeId}/map": {
   "get": {
    "description": "Returns full-route geometry, markers, and summary for a route assigned to the authenticated driver.",
    "parameters": [
     {
      "description": "Route ID",
      "in": "path",
      "name": "routeId",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/job.JobRouteResponse"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get map route data for a driver route",
    "tags": [
     "driver"
    ]
   }
  },
  "/driver/stop/state": {
   "post": {
    "description": "Transitions a stop to the specified workflow state; the driver must own the route and the route must be started. When transitioning to the cancelled state, an optional cancellation_notes reason is recorded on the stop (e.g. \"recipient not home\").",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/driver.StopStateChangeRequest"
       }
      }
     },
     "description": "Stop state change payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/stop.Stop"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Change stop state",
    "tags": [
     "driver"
    ]
   }
  },
  "/driver/vehicle/search": {
   "get": {
    "description": "Returns all vehicles owned by or assigned to the authenticated driver",
    "parameters": [
     {
      "description": "Page number (default 1)",
      "in": "query",
      "name": "page",
      "schema": {
       "type": "integer"
      }
     },
     {
      "description": "Items per page (default 100)",
      "in": "query",
      "name": "page_size",
      "schema": {
       "type": "integer"
      }
     },
     {
      "description": "Sort field: make, model, year, license_plate, created_at",
      "in": "query",
      "name": "sort_by",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Sort direction: asc or desc",
      "in": "query",
      "name": "sort_order",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/vehicle.Vehicle"
         },
         "type": "array"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "List driver vehicles",
    "tags": [
     "driver"
    ]
   }
  },
  "/earnings": {
   "get": {
    "description": "Get a single driver earning record by ID with full component breakdown. Drivers can only see their own earnings.",
    "parameters": [
     {
      "description": "Driver Earning ID",
      "in": "query",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/earnings.DriverEarning"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "404": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Not Found"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get driver earning",
    "tags": [
     "earnings"
    ]
   }
  },
  "/earnings/rules": {
   "delete": {
    "description": "Delete an earnings rule by id for the authenticated site",
    "parameters": [
     {
      "description": "Earnings rule ID",
      "in": "query",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "type": "string"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Delete earnings rule",
    "tags": [
     "earnings"
    ]
   },
   "get": {
    "description": "Get an earnings rule by id for the authenticated site",
    "parameters": [
     {
      "description": "Earnings rule ID",
      "in": "query",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/earnings.EarningsRule"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "404": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Not Found"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get earnings rule",
    "tags": [
     "earnings"
    ]
   },
   "post": {
    "description": "Create a new earnings rule for the authenticated site",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/earnings.EarningsRuleCreateRequest"
       }
      }
     },
     "description": "Earnings rule payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/earnings.EarningsRule"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Create earnings rule",
    "tags": [
     "earnings"
    ]
   },
   "put": {
    "description": "Update an existing earnings rule by id for the authenticated site",
    "parameters": [
     {
      "description": "Earnings rule ID",
      "in": "query",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/earnings.EarningsRuleUpdateRequest"
       }
      }
     },
     "description": "Earnings rule update payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/earnings.EarningsRule"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Update earnings rule",
    "tags": [
     "earnings"
    ]
   }
  },
  "/earnings/rules/search": {
   "get": {
    "description": "List all earnings rules for the authenticated site",
    "parameters": [
     {
      "description": "Page number (default 1)",
      "in": "query",
      "name": "page",
      "schema": {
       "type": "integer"
      }
     },
     {
      "description": "Items per page (default 100)",
      "in": "query",
      "name": "page_size",
      "schema": {
       "type": "integer"
      }
     },
     {
      "description": "Sort field: name, is_default, is_active, created_at",
      "in": "query",
      "name": "sort_by",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Sort direction: asc or desc",
      "in": "query",
      "name": "sort_order",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/earnings.EarningsRule"
         },
         "type": "array"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Search earnings rules",
    "tags": [
     "earnings"
    ]
   }
  },
  "/earnings/search": {
   "get": {
    "description": "List driver earnings records with optional filters. Drivers can only see their own earnings.",
    "parameters": [
     {
      "description": "Filter by driver user ID (admin/dispatcher only)",
      "in": "query",
      "name": "driver_user_id",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Filter by job ID",
      "in": "query",
      "name": "job_id",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Filter by earned_at >= start_date (RFC3339)",
      "in": "query",
      "name": "start_date",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Filter by earned_at <= end_date (RFC3339)",
      "in": "query",
      "name": "end_date",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Page number (default 1)",
      "in": "query",
      "name": "page",
      "schema": {
       "type": "integer"
      }
     },
     {
      "description": "Items per page (default 100)",
      "in": "query",
      "name": "page_size",
      "schema": {
       "type": "integer"
      }
     },
     {
      "description": "Sort field: earned_at, created_at, amount_cents, driver_user_id, job_id",
      "in": "query",
      "name": "sort_by",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Sort direction: asc or desc",
      "in": "query",
      "name": "sort_order",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/earnings.DriverEarning"
         },
         "type": "array"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Search driver earnings",
    "tags": [
     "earnings"
    ]
   }
  },
  "/earnings/summary": {
   "get": {
    "description": "Get aggregated earnings totals for a driver within an optional date range. Drivers can only see their own summary.",
    "parameters": [
     {
      "description": "Driver user ID (admin/dispatcher only)",
      "in": "query",
      "name": "driver_user_id",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Start date (RFC3339)",
      "in": "query",
      "name": "start_date",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "End date (RFC3339)",
      "in": "query",
      "name": "end_date",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/earnings.EarningsSummary"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get driver earnings summary",
    "tags": [
     "earnings"
    ]
   }
  },
  "/earnings/time-series": {
   "get": {
    "description": "Get time-bucketed earnings for a driver. group_by can be day, week, or month. Drivers can only see their own data.",
    "parameters": [
     {
      "description": "Driver user ID (admin/dispatcher only)",
      "in": "query",
      "name": "driver_user_id",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Grouping: day, week, or month",
      "in": "query",
      "name": "group_by",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Start date (RFC3339)",
      "in": "query",
      "name": "start_date",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "End date (RFC3339)",
      "in": "query",
      "name": "end_date",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/earnings.EarningsTimeSeries"
         },
         "type": "array"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get driver earnings time series",
    "tags": [
     "earnings"
    ]
   }
  },
  "/gis/route": {
   "post": {
    "description": "Calculates a route between an origin and destination, optionally passing through intermediate waypoints. POST (not GET) because the request is a JSON body, which browsers cannot attach to a GET.",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/gis.RouteRequest"
       }
      }
     },
     "description": "Route request",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/mapprovider.Route"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Calculate a route",
    "tags": [
     "gis"
    ]
   }
  },
  "/gis/route/sequence": {
   "get": {
    "description": "Calculates the optimal ordering of waypoints between a fixed start and end point",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/gis.WaypointSequenceRequest"
       }
      }
     },
     "description": "Waypoint sequence request",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/mapprovider.WayPointSequenceResult"
         },
         "type": "array"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Optimize waypoint sequence",
    "tags": [
     "gis"
    ]
   }
  },
  "/gis/routematrix": {
   "get": {
    "description": "Calculates a duration and distance matrix between multiple origins and destinations using the legacy route matrix API",
    "parameters": [
     {
      "description": "Route matrix ID",
      "in": "query",
      "name": "id",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/mapprovider.RouteMatrixResult"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get a route matrix",
    "tags": [
     "gis"
    ]
   }
  },
  "/integration/": {
   "get": {
    "description": "Returns all integrations that have been configured for the authenticated site",
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/integration.SiteIntegration"
         },
         "type": "array"
        }
       }
      },
      "description": "OK"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "List site integrations",
    "tags": [
     "integration"
    ]
   }
  },
  "/integration/available": {
   "get": {
    "description": "Returns all integrations that the system supports, including their configuration schema",
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/integration.AvailableIntegration"
         },
         "type": "array"
        }
       }
      },
      "description": "OK"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "List available integrations",
    "tags": [
     "integration"
    ]
   }
  },
  "/integration/webhook/inbound": {
   "post": {
    "description": "Single unauthenticated endpoint that receives and routes inbound webhook events from third-party providers. For site-scoped webhooks, supply the webhook_routing_key query parameter.",
    "parameters": [
     {
      "description": "Integration key (e.g. stripe, mailgun)",
      "in": "query",
      "name": "key",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Site-scoped webhook routing key",
      "in": "query",
      "name": "webhook_routing_key",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "additionalProperties": true,
         "type": "object"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "summary": "Receive an inbound webhook",
    "tags": [
     "integration"
    ]
   }
  },
  "/integration/{id}": {
   "delete": {
    "description": "Soft-deletes a specific integration for the authenticated site by ID",
    "parameters": [
     {
      "description": "Integration ID",
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "204": {
      "description": "No Content"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Delete an integration",
    "tags": [
     "integration"
    ]
   },
   "put": {
    "description": "Updates the configuration and active status for a specific integration by ID",
    "parameters": [
     {
      "description": "Integration ID",
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/integration.UpdateIntegrationRequest"
       }
      }
     },
     "description": "Update integration request",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/integration.SiteIntegration"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Update an integration",
    "tags": [
     "integration"
    ]
   }
  },
  "/integration/{id}/sync": {
   "post": {
    "description": "Triggers an on-demand sync for an integration that supports it, refreshing its status and configuration from the remote provider",
    "parameters": [
     {
      "description": "Integration ID",
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/integration.SiteIntegration"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Sync an integration",
    "tags": [
     "integration"
    ]
   }
  },
  "/integration/{key}/connect": {
   "post": {
    "description": "Starts the onboarding or connection flow for an integration. Always creates a new site integration record with is_active set to true.",
    "parameters": [
     {
      "description": "Integration key (e.g. stripe, mailgun)",
      "in": "path",
      "name": "key",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/integration.ConnectResponse"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Connect an integration",
    "tags": [
     "integration"
    ]
   }
  },
  "/job": {
   "get": {
    "description": "Returns all jobs for the authenticated site filtered by workflow state.",
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/job.Job"
         },
         "type": "array"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "List jobs by site and workflow state",
    "tags": [
     "job"
    ]
   },
   "post": {
    "description": "Creates a new job with the provided data. If the authenticated user is a customer, restricted fields are sanitized.",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/job.ApiJobCreate"
       }
      }
     },
     "description": "Job creation payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/job.Job"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Create a new job",
    "tags": [
     "job"
    ]
   },
   "put": {
    "description": "Updates an existing job. Field-level restrictions apply based on the authenticated user's role (driver, customer, dispatcher/admin).",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/job.ApiJobUpdate"
       }
      }
     },
     "description": "Job update payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/job.Job"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     },
     "404": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Not Found"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Update a job",
    "tags": [
     "job"
    ]
   }
  },
  "/job/attachment": {
   "delete": {
    "description": "Soft-deletes the link between an attachment and a job. The underlying file is not deleted.",
    "parameters": [
     {
      "description": "Job ID",
      "in": "query",
      "name": "job_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Attachment ID",
      "in": "query",
      "name": "attachment_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "204": {
      "description": "No Content"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     },
     "404": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Not Found"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Remove an attachment from a job",
    "tags": [
     "job"
    ]
   },
   "get": {
    "description": "Returns all active attachments linked to the specified job.",
    "parameters": [
     {
      "description": "Job ID",
      "in": "query",
      "name": "job_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/attachment.Attachment"
         },
         "type": "array"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     },
     "404": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Not Found"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get attachments for a job",
    "tags": [
     "job"
    ]
   },
   "post": {
    "description": "Links confirmed attachments (uploaded via the pre-signed flow) to the specified job by id.",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/job.AddJobAttachmentsRequest"
       }
      }
     },
     "description": "Job id and attachment ids",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/job.Job"
         },
         "type": "array"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     },
     "404": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Not Found"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Add attachments to a job",
    "tags": [
     "job"
    ]
   }
  },
  "/job/bulk": {
   "delete": {
    "description": "Soft-deletes multiple jobs in a single request. Only completed or cancelled jobs can be deleted. Each job is processed independently — partial success is possible.",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/job.BulkDeleteJobRequest"
       }
      }
     },
     "description": "List of job IDs to delete",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/job.BulkJobResponse"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Bulk delete jobs",
    "tags": [
     "job"
    ]
   }
  },
  "/job/bulk/cancel": {
   "put": {
    "description": "Cancels multiple jobs in a single request. Each job is processed independently — partial success is possible.",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/job.BulkCancelJobRequest"
       }
      }
     },
     "description": "List of job IDs to cancel",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/job.BulkJobResponse"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Bulk cancel jobs",
    "tags": [
     "job"
    ]
   }
  },
  "/job/bulk/duplicate": {
   "post": {
    "description": "Duplicates multiple jobs in a single request. Each job is processed independently — partial success is possible.",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/job.BulkDuplicateJobRequest"
       }
      }
     },
     "description": "List of job IDs to duplicate",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/job.BulkDuplicateJobResponse"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Bulk duplicate jobs",
    "tags": [
     "job"
    ]
   }
  },
  "/job/cancel": {
   "put": {
    "description": "Cancels a job. Customers may cancel their own jobs; workers must have admin or dispatcher role.",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/job.CancelJobRequest"
       }
      }
     },
     "description": "Cancel job payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/job.Job"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     },
     "404": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Not Found"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Cancel a job",
    "tags": [
     "job"
    ]
   }
  },
  "/job/eta-notification-configs": {
   "get": {
    "description": "Returns all ETA notification configs for the authenticated site, including template data.",
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/etanotificationconfig.EtaNotificationConfigResponse"
         },
         "type": "array"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "List ETA notification configs",
    "tags": [
     "job-eta-notification-config"
    ]
   },
   "post": {
    "description": "Creates a new ETA notification config or updates an existing one for the authenticated site.",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/etanotificationconfig.UpsertEtaNotificationConfigRequest"
       }
      }
     },
     "description": "ETA notification config payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/etanotificationconfig.EtaNotificationConfigResponse"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Create or update an ETA notification config",
    "tags": [
     "job-eta-notification-config"
    ]
   }
  },
  "/job/eta-notification-configs/{id}": {
   "delete": {
    "description": "Deletes an ETA notification config by its ID. The config must belong to the authenticated site.",
    "parameters": [
     {
      "description": "ETA notification config ID",
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "additionalProperties": {
          "type": "string"
         },
         "type": "object"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     },
     "404": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Not Found"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Delete an ETA notification config",
    "tags": [
     "job-eta-notification-config"
    ]
   },
   "get": {
    "description": "Returns a single ETA notification config by its ID for the authenticated site.",
    "parameters": [
     {
      "description": "ETA notification config ID",
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/etanotificationconfig.EtaNotificationConfigResponse"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     },
     "404": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Not Found"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get an ETA notification config by ID",
    "tags": [
     "job-eta-notification-config"
    ]
   }
  },
  "/job/eta/preview": {
   "post": {
    "description": "Returns read-only stop ETAs for a not-yet-created job from the given ordered stops, assuming dispatch now. Same eligible-pool semantics as GET /job/{id}/eta: option_ids must be carried by the driver or their assigned vehicle; service_type_id adds the service type's required options. Nothing is persisted.",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/job.StopETAPreviewRequest"
       }
      }
     },
     "description": "Stop ETA preview request",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/etacalc.StopETAResult"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Preview stop ETAs for a prospective job",
    "tags": [
     "job"
    ]
   }
  },
  "/job/notification-configs": {
   "get": {
    "description": "Returns all raw notification config records for the authenticated site.",
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/notificationconfig.NotificationConfig"
         },
         "type": "array"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "List notification configs",
    "tags": [
     "job-notification-config"
    ]
   },
   "post": {
    "description": "Creates a new notification config or updates an existing one for the given workflow state, recipient type, and delivery method.",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/notificationconfig.UpsertNotificationConfigRequest"
       }
      }
     },
     "description": "Notification config payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/notificationconfig.NotificationConfig"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     },
     "404": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Not Found"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Create or update a notification config",
    "tags": [
     "job-notification-config"
    ]
   }
  },
  "/job/notification-configs/config/{id}": {
   "delete": {
    "description": "Deletes a specific notification config by its ID. The config must belong to the authenticated site.",
    "parameters": [
     {
      "description": "Notification config ID",
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "additionalProperties": {
          "type": "string"
         },
         "type": "object"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     },
     "404": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Not Found"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Delete a notification config",
    "tags": [
     "job-notification-config"
    ]
   }
  },
  "/job/notification-configs/defaults": {
   "get": {
    "description": "Returns the default notification config specifications for all workflow state groups, including default template content for UI prepopulation.",
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/notificationconfig.StateGroupDefaultsResponse"
         },
         "type": "array"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get default notification configs",
    "tags": [
     "job-notification-config"
    ]
   }
  },
  "/job/notification-configs/state/{workflow_state_id}": {
   "delete": {
    "description": "Deletes all notification configs associated with the given workflow state for the authenticated site.",
    "parameters": [
     {
      "description": "Workflow State ID",
      "in": "path",
      "name": "workflow_state_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "additionalProperties": {
          "type": "string"
         },
         "type": "object"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Delete all notification configs for a workflow state",
    "tags": [
     "job-notification-config"
    ]
   }
  },
  "/job/notification-configs/{workflow_state_id}": {
   "get": {
    "description": "Returns all notification configs for the given workflow state, including template data for each recipient/delivery combination.",
    "parameters": [
     {
      "description": "Workflow State ID",
      "in": "path",
      "name": "workflow_state_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/notificationconfig.WorkflowStateConfigsResponse"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     },
     "404": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Not Found"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get notification configs for a workflow state",
    "tags": [
     "job-notification-config"
    ]
   }
  },
  "/job/notification-configs/{workflow_state_id}/{recipient_type}/{delivery_method}": {
   "get": {
    "description": "Returns the notification config for a specific workflow state, recipient type, and delivery method combination, including template data.",
    "parameters": [
     {
      "description": "Workflow State ID",
      "in": "path",
      "name": "workflow_state_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Recipient type (customer, driver, admin)",
      "in": "path",
      "name": "recipient_type",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Delivery method (sms, email, push)",
      "in": "path",
      "name": "delivery_method",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/notificationconfig.NotificationConfigResponse"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     },
     "404": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Not Found"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get a specific notification config",
    "tags": [
     "job-notification-config"
    ]
   }
  },
  "/job/payment/authorize": {
   "post": {
    "description": "Initiates a payment authorization for the specified job using the configured payment gateway.",
    "parameters": [
     {
      "description": "Job ID",
      "in": "query",
      "name": "job_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/payments.Transaction"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Authorize a payment for a job",
    "tags": [
     "job"
    ]
   }
  },
  "/job/payment/capture": {
   "post": {
    "description": "Captures a previously authorized payment for the specified job.",
    "parameters": [
     {
      "description": "Job ID",
      "in": "query",
      "name": "job_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/payments.Transaction"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Capture an authorized payment for a job",
    "tags": [
     "job"
    ]
   }
  },
  "/job/payment/collect": {
   "post": {
    "description": "Records collection of a payment via non-gateway methods such as cash, POS, or third-party providers.",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/job.CollectPaymentRequest"
       }
      }
     },
     "description": "Collect payment payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/payments.Transaction"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Collect a non-gateway payment for a job",
    "tags": [
     "job"
    ]
   }
  },
  "/job/payment/refund": {
   "post": {
    "description": "Issues a refund for a captured payment associated with the specified job.",
    "parameters": [
     {
      "description": "Job ID",
      "in": "query",
      "name": "job_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/payments.Transaction"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Refund a payment for a job",
    "tags": [
     "job"
    ]
   }
  },
  "/job/payment/status": {
   "get": {
    "description": "Returns the current payment status for the specified job.",
    "parameters": [
     {
      "description": "Job ID",
      "in": "query",
      "name": "job_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/payments.Transaction"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get payment status for a job",
    "tags": [
     "job"
    ]
   }
  },
  "/job/search": {
   "get": {
    "description": "Returns jobs filtered by role. Drivers see only their assigned jobs; customers see only their own jobs; dispatchers can filter by driver_user_id and workflow_state_id.",
    "parameters": [
     {
      "description": "Filter by driver user ID (dispatcher only)",
      "in": "query",
      "name": "driver_user_id",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Filter by workflow state ID (repeatable)",
      "in": "query",
      "name": "workflow_state_id",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Filter by creation date start (RFC3339)",
      "in": "query",
      "name": "created_at_start",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Filter by creation date end (RFC3339)",
      "in": "query",
      "name": "created_at_end",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Page number (default 1)",
      "in": "query",
      "name": "page",
      "schema": {
       "type": "integer"
      }
     },
     {
      "description": "Items per page (default 100)",
      "in": "query",
      "name": "page_size",
      "schema": {
       "type": "integer"
      }
     },
     {
      "description": "Sort field: created_at, job_number, started_at, completed_at",
      "in": "query",
      "name": "sort_by",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Sort direction: asc or desc",
      "in": "query",
      "name": "sort_order",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/job.Job"
         },
         "type": "array"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Search jobs",
    "tags": [
     "job"
    ]
   }
  },
  "/job/state": {
   "put": {
    "description": "Transitions a job to a new workflow state. Accepts optional state parameters for state-specific logic.",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/job.UpdateJobStateRequest"
       }
      }
     },
     "description": "Job state update payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/job.Job"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Update job state",
    "tags": [
     "job"
    ]
   }
  },
  "/job/stop": {
   "delete": {
    "description": "Removes a stop from an existing job. The user must have access to the parent job.",
    "parameters": [
     {
      "description": "Stop ID",
      "in": "query",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Job ID",
      "in": "query",
      "name": "job_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "204": {
      "description": "No Content"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     },
     "404": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Not Found"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Delete a stop from a job",
    "tags": [
     "job"
    ]
   },
   "post": {
    "description": "Adds a new stop to an existing job. The user must have access to the parent job.",
    "parameters": [
     {
      "description": "Job ID",
      "in": "query",
      "name": "job_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Existing address ID",
      "in": "query",
      "name": "address_id",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Stop type (pickup, dropoff, return)",
      "in": "query",
      "name": "type",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Contact phone number",
      "in": "query",
      "name": "contact_phone",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Contact phone country code",
      "in": "query",
      "name": "contact_phone_country",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Customer notes",
      "in": "query",
      "name": "customer_notes",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Complete before datetime (RFC3339)",
      "in": "query",
      "name": "complete_before",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Complete after datetime (RFC3339)",
      "in": "query",
      "name": "complete_after",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Bypass banned zone restrictions (dispatcher/admin only; ignored for customers)",
      "in": "query",
      "name": "override_zone_restriction",
      "schema": {
       "type": "boolean"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/stop.Stop"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     },
     "404": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Not Found"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Create a stop on a job",
    "tags": [
     "job"
    ]
   },
   "put": {
    "description": "Updates an existing stop on a job. The user must have access to the parent job.",
    "parameters": [
     {
      "description": "Job ID",
      "in": "query",
      "name": "job_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Stop ID",
      "in": "query",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Existing address ID",
      "in": "query",
      "name": "address_id",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Stop type (pickup, dropoff, return)",
      "in": "query",
      "name": "type",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Contact phone number",
      "in": "query",
      "name": "contact_phone",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Contact phone country code",
      "in": "query",
      "name": "contact_phone_country",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Customer notes",
      "in": "query",
      "name": "customer_notes",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Complete before datetime (RFC3339)",
      "in": "query",
      "name": "complete_before",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Complete after datetime (RFC3339)",
      "in": "query",
      "name": "complete_after",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/stop.Stop"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     },
     "404": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Not Found"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Update a stop on a job",
    "tags": [
     "job"
    ]
   }
  },
  "/job/track/{shareToken}": {
   "get": {
    "description": "Returns public tracking information for a job including workflow state, stops with ETAs, and privacy-masked driver/customer names. Keyed by an opaque share token minted via POST /job/{id}/share-token.",
    "parameters": [
     {
      "description": "Job share token",
      "in": "path",
      "name": "shareToken",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/job.JobTrackerResponse"
        }
       }
      },
      "description": "OK"
     },
     "404": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Not Found"
     }
    },
    "summary": "Track a job (public)",
    "tags": [
     "job"
    ]
   }
  },
  "/job/{id}": {
   "get": {
    "description": "Returns a single job by its ID. Access is restricted based on the authenticated user's role.",
    "parameters": [
     {
      "description": "Job ID",
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/job.Job"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     },
     "404": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Not Found"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get a job by ID",
    "tags": [
     "job"
    ]
   }
  },
  "/job/{id}/duplicate": {
   "post": {
    "description": "Creates a new job by copying an existing one. Copies customer, stops (with addresses and time windows), service type, notes, and options. The source job's estimate is automatically cloned. Driver assignment, payment data, attachments, ETA data, and lifecycle timestamps are reset.",
    "parameters": [
     {
      "description": "Source Job ID",
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/job.Job"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     },
     "404": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Not Found"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Duplicate a job",
    "tags": [
     "job"
    ]
   }
  },
  "/job/{id}/eta": {
   "get": {
    "description": "Returns read-only stop ETAs for the job assuming dispatch now: the pickup ETA of the nearest eligible driver and cumulative per-stop arrival times. The eligible pool is filterable by option_ids (comma-separated; satisfied by driver or assigned-vehicle options) and service_type_id (its required options are added to the filter). Nothing is persisted. eligible_driver_count of 0 is a valid answer, not an error.",
    "parameters": [
     {
      "description": "Job ID",
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Comma-separated option IDs the driver/vehicle must carry",
      "in": "query",
      "name": "option_ids",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Service type whose required options are added to the filter",
      "in": "query",
      "name": "service_type_id",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/etacalc.StopETAResult"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     },
     "404": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Not Found"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get what-if stop ETAs for a job",
    "tags": [
     "job"
    ]
   }
  },
  "/job/{id}/route": {
   "get": {
    "description": "Returns the route associated with a job. Access is restricted based on the authenticated user's role.",
    "parameters": [
     {
      "description": "Job ID",
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "additionalProperties": true,
         "type": "object"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     },
     "404": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Not Found"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get route data for a job",
    "tags": [
     "job"
    ]
   }
  },
  "/location-history": {
   "post": {
    "description": "Creates a new location history record for the authenticated user, storing GPS coordinates, device info, and activity type",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/locationhistory.LocationHistoryRequest"
       }
      }
     },
     "description": "Location history data",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/locationhistory.LocationHistory"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Record a location history entry",
    "tags": [
     "location-history"
    ]
   }
  },
  "/location-history/search": {
   "get": {
    "description": "Searches location history records for a user within a time range. Defaults to the last hour if no range is provided",
    "parameters": [
     {
      "description": "User ID to filter by",
      "in": "query",
      "name": "user_id",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Start of time range (RFC3339)",
      "in": "query",
      "name": "from",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "End of time range (RFC3339)",
      "in": "query",
      "name": "to",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Page number (default 1)",
      "in": "query",
      "name": "page",
      "schema": {
       "type": "integer"
      }
     },
     {
      "description": "Items per page (default 100)",
      "in": "query",
      "name": "page_size",
      "schema": {
       "type": "integer"
      }
     },
     {
      "description": "Sort direction on location_timestamp: asc or desc",
      "in": "query",
      "name": "sort_order",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Downsample to every Nth point to thin the trail (N>=2). Omit for the full record.",
      "in": "query",
      "name": "sample",
      "schema": {
       "type": "integer"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/locationhistory.LocationHistory"
         },
         "type": "array"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Search location history",
    "tags": [
     "location-history"
    ]
   }
  },
  "/metrics/customers": {
   "get": {
    "description": "Returns aggregated customer statistics for the site within an optional date range, including new, active, and total customer counts",
    "parameters": [
     {
      "description": "Start of date range (RFC3339)",
      "in": "query",
      "name": "from",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "End of date range (RFC3339)",
      "in": "query",
      "name": "to",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/customers.Metrics"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get customer metrics overview",
    "tags": [
     "metrics"
    ]
   }
  },
  "/metrics/customers/time-series": {
   "get": {
    "description": "Returns time-series customer statistics (created, total) for the site. The from and to query params are required. Granularity is auto-selected or can be specified",
    "parameters": [
     {
      "description": "Start of date range (RFC3339, required)",
      "in": "query",
      "name": "from",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "End of date range (RFC3339, required)",
      "in": "query",
      "name": "to",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Time granularity: daily, weekly, monthly, or auto",
      "in": "query",
      "name": "granularity",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/metrics.TimeSeriesResponse"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get customers time-series data",
    "tags": [
     "metrics"
    ]
   }
  },
  "/metrics/jobs": {
   "get": {
    "description": "Returns aggregated job statistics for the site within an optional date range, including counts by state, completion times, and cancellation rate",
    "parameters": [
     {
      "description": "Start of date range (RFC3339)",
      "in": "query",
      "name": "from",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "End of date range (RFC3339)",
      "in": "query",
      "name": "to",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/jobs.Metrics"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get job metrics overview",
    "tags": [
     "metrics"
    ]
   }
  },
  "/metrics/jobs/state-counts": {
   "get": {
    "description": "Returns a snapshot of the current number of jobs in each state for the site",
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/jobs.StateCounts"
        }
       }
      },
      "description": "OK"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get current job state counts",
    "tags": [
     "metrics"
    ]
   }
  },
  "/metrics/jobs/time-series": {
   "get": {
    "description": "Returns time-series job statistics (created, completed, cancelled, active) for the site. The from and to query params are required. Granularity is auto-selected or can be specified",
    "parameters": [
     {
      "description": "Start of date range (RFC3339, required)",
      "in": "query",
      "name": "from",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "End of date range (RFC3339, required)",
      "in": "query",
      "name": "to",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Time granularity: daily, weekly, monthly, or auto",
      "in": "query",
      "name": "granularity",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/metrics.TimeSeriesResponse"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get jobs time-series data",
    "tags": [
     "metrics"
    ]
   }
  },
  "/metrics/location-history": {
   "get": {
    "description": "Returns aggregated location history metrics for the site within a date range, including average speeds, driving time, and total distance driven. The from and to query params are required",
    "parameters": [
     {
      "description": "Start of date range (RFC3339)",
      "in": "query",
      "name": "from",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "End of date range (RFC3339)",
      "in": "query",
      "name": "to",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/locationhistory.Metrics"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get location history metrics",
    "tags": [
     "metrics"
    ]
   }
  },
  "/metrics/payments": {
   "get": {
    "description": "Returns aggregated payment and revenue statistics for the site within a date range. The from and to query params are required",
    "parameters": [
     {
      "description": "Start of date range (RFC3339)",
      "in": "query",
      "name": "from",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "End of date range (RFC3339)",
      "in": "query",
      "name": "to",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/payments.Metrics"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get payment metrics overview",
    "tags": [
     "metrics"
    ]
   }
  },
  "/metrics/payments/time-series": {
   "get": {
    "description": "Returns time-series revenue data for the site within a date range. The from and to query params are required. Granularity is auto-selected or can be specified",
    "parameters": [
     {
      "description": "Start of date range (RFC3339)",
      "in": "query",
      "name": "from",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "End of date range (RFC3339)",
      "in": "query",
      "name": "to",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Time granularity: daily, weekly, monthly, or auto",
      "in": "query",
      "name": "granularity",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/metrics.RevenueTimeSeriesResponse"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get revenue time-series data",
    "tags": [
     "metrics"
    ]
   }
  },
  "/metrics/workers": {
   "get": {
    "description": "Returns aggregated workforce statistics for the site within an optional date range, including on-duty counts and average jobs per worker",
    "parameters": [
     {
      "description": "Start of date range (RFC3339)",
      "in": "query",
      "name": "from",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "End of date range (RFC3339)",
      "in": "query",
      "name": "to",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/workers.Metrics"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get worker metrics overview",
    "tags": [
     "metrics"
    ]
   }
  },
  "/metrics/workers/leaderboard": {
   "get": {
    "description": "Returns a ranked list of workers by jobs and stops completed within a required date range. The from and to query params are required",
    "parameters": [
     {
      "description": "Start of date range (RFC3339, required)",
      "in": "query",
      "name": "from",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "End of date range (RFC3339, required)",
      "in": "query",
      "name": "to",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Maximum number of workers to return (default 10)",
      "in": "query",
      "name": "limit",
      "schema": {
       "type": "integer"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/workers.Leaderboard"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get worker leaderboard",
    "tags": [
     "metrics"
    ]
   }
  },
  "/notification/mark-all-read": {
   "post": {
    "description": "Marks all of the authenticated user's unread notifications as read.",
    "responses": {
     "200": {
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Mark all notifications as read",
    "tags": [
     "notification"
    ]
   }
  },
  "/notification/mark-read": {
   "post": {
    "description": "Marks the given notification IDs as read for the authenticated user. Already-read notifications are left unchanged (idempotent).",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/notification.MarkReadRequest"
       }
      }
     },
     "description": "Notification IDs to mark read",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Mark notifications as read",
    "tags": [
     "notification"
    ]
   }
  },
  "/notification/push/register": {
   "post": {
    "description": "Registers or updates a device push notification token for the authenticated user. Supports iOS and Android platforms",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/push.RegisterPushTokenRequest"
       }
      }
     },
     "description": "Push token registration data",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/pushtoken.PushToken"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Register a push notification token",
    "tags": [
     "push-notification"
    ]
   }
  },
  "/notification/search": {
   "get": {
    "description": "Returns a paginated list of notifications for the authenticated user, filtered by the provided query parameters.",
    "parameters": [
     {
      "description": "Filter by notification type (e.g. job_updated, queue_reminder)",
      "in": "query",
      "name": "type",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Filter by delivery method: sms, push, email",
      "in": "query",
      "name": "delivery_method",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Filter by status: pending, sent, delivered, failed",
      "in": "query",
      "name": "status",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Filter by related entity type",
      "in": "query",
      "name": "related_entity_type",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Filter by related entity ID",
      "in": "query",
      "name": "related_entity_id",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Filter by read state: true (read) or false (unread). Omit for all.",
      "in": "query",
      "name": "read",
      "schema": {
       "type": "boolean"
      }
     },
     {
      "description": "Page number (default 1)",
      "in": "query",
      "name": "page",
      "schema": {
       "type": "integer"
      }
     },
     {
      "description": "Number of items per page (default 100)",
      "in": "query",
      "name": "page_size",
      "schema": {
       "type": "integer"
      }
     },
     {
      "description": "Sort field: type, delivery_method, status, created_at, read_at, send_at",
      "in": "query",
      "name": "sort_by",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Sort direction: asc or desc",
      "in": "query",
      "name": "sort_order",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/notification.Notification"
         },
         "type": "array"
        }
       }
      },
      "description": "Total unread count is returned in meta.notification.unread_count"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Search notifications",
    "tags": [
     "notification"
    ]
   }
  },
  "/notification/unread-count": {
   "get": {
    "description": "Returns the number of unread notifications for the authenticated user. Lightweight endpoint for polling the badge without fetching a page.",
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/notification.UnreadCountResponse"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get unread notification count",
    "tags": [
     "notification"
    ]
   }
  },
  "/option": {
   "delete": {
    "description": "Soft-deletes an option by ID for the authenticated site",
    "parameters": [
     {
      "description": "Option ID",
      "in": "query",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "type": "string"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Delete an option",
    "tags": [
     "option"
    ]
   },
   "get": {
    "description": "Retrieves a single option by its ID for the authenticated site",
    "parameters": [
     {
      "description": "Option ID",
      "in": "query",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/option.Option"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get an option by ID",
    "tags": [
     "option"
    ]
   },
   "post": {
    "description": "Creates a new option for the authenticated site",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/option.OptionRequest"
       }
      }
     },
     "description": "Option payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/option.Option"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Create an option",
    "tags": [
     "option"
    ]
   },
   "put": {
    "description": "Updates an existing option by ID for the authenticated site",
    "parameters": [
     {
      "description": "Option ID",
      "in": "query",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/option.OptionRequest"
       }
      }
     },
     "description": "Updated option payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/option.Option"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Update an option",
    "tags": [
     "option"
    ]
   }
  },
  "/option/assign": {
   "delete": {
    "description": "Removes an option assignment from a worker, service type, or vehicle",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/option.OptionAssignRequest"
       }
      }
     },
     "description": "Option assignment payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "type": "string"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Unassign an option from an entity",
    "tags": [
     "option"
    ]
   },
   "post": {
    "description": "Assigns an existing option to a worker, service type, or vehicle",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/option.OptionAssignRequest"
       }
      }
     },
     "description": "Option assignment payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "type": "string"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Assign an option to an entity",
    "tags": [
     "option"
    ]
   }
  },
  "/option/search": {
   "get": {
    "description": "Returns a list of options matching the given search criteria for the authenticated site",
    "parameters": [
     {
      "description": "Filter by option name",
      "in": "query",
      "name": "name",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/option.Option"
         },
         "type": "array"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Search options",
    "tags": [
     "option"
    ]
   }
  },
  "/organization": {
   "get": {
    "description": "Retrieves a single organization record by its ID",
    "parameters": [
     {
      "description": "Organization ID",
      "in": "query",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/organization.Organization"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get an organization by ID",
    "tags": [
     "organization"
    ]
   },
   "post": {
    "description": "Creates a new organization record with the provided details",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/organization.OrganizationRequest"
       }
      }
     },
     "description": "Organization payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/organization.Organization"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Create an organization",
    "tags": [
     "organization"
    ]
   }
  },
  "/payment-methods": {
   "delete": {
    "description": "Removes a saved payment method from the authenticated customer's account",
    "parameters": [
     {
      "description": "Payment method ID",
      "in": "query",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "204": {
      "description": "No content"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Delete a payment method",
    "tags": [
     "customer"
    ]
   },
   "get": {
    "description": "Retrieves all saved payment methods for the authenticated customer",
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/payments.PaymentMethod"
         },
         "type": "array"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "List payment methods",
    "tags": [
     "customer"
    ]
   },
   "post": {
    "description": "Saves a new payment method (card) for the authenticated customer using a provider payment method token",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/customer.CreatePaymentMethodRequest"
       }
      }
     },
     "description": "Payment method creation payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/payments.PaymentMethod"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Create a payment method",
    "tags": [
     "customer"
    ]
   }
  },
  "/payment-methods/default": {
   "post": {
    "description": "Sets an existing payment method as the default for the authenticated customer",
    "parameters": [
     {
      "description": "Payment method ID",
      "in": "query",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "204": {
      "description": "No content"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Set default payment method",
    "tags": [
     "customer"
    ]
   }
  },
  "/payment-methods/initialize": {
   "post": {
    "description": "Creates a provider setup intent and returns the client secret needed by the frontend to collect and save a new payment method",
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/payments.InitializeSetupResponse"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Initialize payment method setup",
    "tags": [
     "customer"
    ]
   }
  },
  "/pricing": {
   "delete": {
    "description": "Delete a price rule by id for the authenticated site",
    "parameters": [
     {
      "description": "Price rule ID",
      "in": "query",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "type": "string"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Delete price rule",
    "tags": [
     "pricing"
    ]
   },
   "get": {
    "description": "Get a price rule by id for the authenticated site",
    "parameters": [
     {
      "description": "Price rule ID",
      "in": "query",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/pricing.PriceRule"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "404": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Not Found"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get price rule",
    "tags": [
     "pricing"
    ]
   },
   "post": {
    "description": "Create a new price rule for the authenticated site",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/pricing.PriceRuleRequest"
       }
      }
     },
     "description": "Price rule payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/pricing.PriceRule"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Create price rule",
    "tags": [
     "pricing"
    ]
   },
   "put": {
    "description": "Update an existing price rule by id for the authenticated site",
    "parameters": [
     {
      "description": "Price rule ID",
      "in": "query",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/pricing.PriceRuleRequest"
       }
      }
     },
     "description": "Price rule update payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/pricing.PriceRule"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Update price rule",
    "tags": [
     "pricing"
    ]
   }
  },
  "/pricing/estimate": {
   "post": {
    "description": "Calculates and persists per-service-type price estimates for the given origin, destination, and stops. The route is computed server-side for pricing only and is not returned — fetch route geometry and ETAs from POST /gis/route. option_ids apply matching price-rule option modifiers (flat_rate/percentage) once per job; applied charges are returned per estimate.",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/pricing.PriceEstimateRequest"
       }
      }
     },
     "description": "Price estimate request",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/pricing.PriceEstimateResponse"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get price estimates",
    "tags": [
     "pricing"
    ]
   }
  },
  "/pricing/search": {
   "get": {
    "description": "Search price rules for the authenticated site by name",
    "parameters": [
     {
      "description": "Filter by name",
      "in": "query",
      "name": "name",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Page number (default 1)",
      "in": "query",
      "name": "page",
      "schema": {
       "type": "integer"
      }
     },
     {
      "description": "Items per page (default 100)",
      "in": "query",
      "name": "page_size",
      "schema": {
       "type": "integer"
      }
     },
     {
      "description": "Sort field: name, priority, is_default, is_active, created_at",
      "in": "query",
      "name": "sort_by",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Sort direction: asc or desc",
      "in": "query",
      "name": "sort_order",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/pricing.PriceRule"
         },
         "type": "array"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Search price rules",
    "tags": [
     "pricing"
    ]
   }
  },
  "/route": {
   "delete": {
    "description": "Delete a route by id for the authenticated site",
    "parameters": [
     {
      "description": "Route ID",
      "in": "query",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "204": {
      "description": "No Content"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Delete route",
    "tags": [
     "route"
    ]
   },
   "get": {
    "description": "Get a route by id for the authenticated site; drivers may only access their own routes",
    "parameters": [
     {
      "description": "Route ID",
      "in": "query",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/route.Route"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "404": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Not Found"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get route",
    "tags": [
     "route"
    ]
   },
   "post": {
    "description": "Create a new route for the authenticated site",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/route.RouteRequest"
       }
      }
     },
     "description": "Route payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/route.Route"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Create route",
    "tags": [
     "route"
    ]
   },
   "put": {
    "description": "Update an existing route by id for the authenticated site",
    "parameters": [
     {
      "description": "Route ID",
      "in": "query",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/route.RouteRequest"
       }
      }
     },
     "description": "Route update payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/route.Route"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Update route",
    "tags": [
     "route"
    ]
   }
  },
  "/route/eligible-jobs": {
   "get": {
    "description": "Returns paginated jobs whose workflow state is in the pending group and that have no stop currently on an active route. When exclude_route_id is supplied, stops belonging only to that route are treated as unrouted (supports the edit-route flow).",
    "parameters": [
     {
      "description": "Route ID to exclude from the 'already routed' check",
      "in": "query",
      "name": "exclude_route_id",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Page number (default 1)",
      "in": "query",
      "name": "page",
      "schema": {
       "type": "integer"
      }
     },
     {
      "description": "Page size (default 50)",
      "in": "query",
      "name": "page_size",
      "schema": {
       "type": "integer"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/route.EligibleJobsResponse"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "List jobs eligible to add to a route",
    "tags": [
     "route"
    ]
   }
  },
  "/route/merge": {
   "post": {
    "description": "Merge a source route into a target route. The source route's stops are appended to the target; the source route is deleted.",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/route.MergeRoutesRequest"
       }
      }
     },
     "description": "Merge request",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/route.Route"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Merge routes",
    "tags": [
     "route"
    ]
   }
  },
  "/route/preview": {
   "post": {
    "description": "Read-only feasibility check. Accepts route_id, stop_ids, or both. route_id only: evaluates the route's persisted stop order. route_id + stop_ids: evaluates the supplied order (stop_ids must be a permutation of the route's stops — use for drag-to-reorder). stop_ids only: ad-hoc check before a route exists (pre-save mode). mode=\"optimize\" (default) runs TSP; mode=\"manual\" evaluates the given order as-is. start_address_id/end_address_id optionally override the start/end point. depart_at (RFC 3339) overrides the HERE Maps departure-time anchor; when absent, the earliest stop complete_after/complete_before window drives the anchor so ETAs reflect the actual delivery day. Nothing is persisted.",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/route.PreviewRouteRequest"
       }
      }
     },
     "description": "Preview request",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/route.PreviewResult"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Preview route (optimize or evaluate as-given)",
    "tags": [
     "route"
    ]
   }
  },
  "/route/search": {
   "get": {
    "description": "Search routes for the authenticated site; drivers only see their own routes, dispatchers and admins can filter by driver, label, status, and date range",
    "parameters": [
     {
      "description": "Filter by label",
      "in": "query",
      "name": "label",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Filter by status ID",
      "in": "query",
      "name": "status_id",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Filter by driver ID (dispatcher/admin only)",
      "in": "query",
      "name": "driver_id",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Filter by start date (YYYY-MM-DD)",
      "in": "query",
      "name": "start_date",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Filter by end date (YYYY-MM-DD)",
      "in": "query",
      "name": "end_date",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Page number (default 1)",
      "in": "query",
      "name": "page",
      "schema": {
       "type": "integer"
      }
     },
     {
      "description": "Items per page (default 100)",
      "in": "query",
      "name": "page_size",
      "schema": {
       "type": "integer"
      }
     },
     {
      "description": "Sort field: label, status_id, created_at, start_at",
      "in": "query",
      "name": "sort_by",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Sort direction: asc or desc",
      "in": "query",
      "name": "sort_order",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/route.Route"
         },
         "type": "array"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Search routes",
    "tags": [
     "route"
    ]
   }
  },
  "/route/split": {
   "post": {
    "description": "Split a route into two at the given stop index. Stops 0..split_after_stop_index stay on the original route; the remainder move to a new route.",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/route.SplitRouteRequest"
       }
      }
     },
     "description": "Split request",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/route.SplitRouteResult"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Split route",
    "tags": [
     "route"
    ]
   }
  },
  "/rtc/room": {
   "post": {
    "description": "Create a new real-time communication room for the authenticated site",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/rtc.CreateRoomRequest"
       }
      }
     },
     "description": "Create room payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/rtc.Room"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Create RTC room",
    "tags": [
     "rtc"
    ]
   }
  },
  "/rtc/room/join": {
   "post": {
    "description": "Join an existing real-time communication room and receive an access token for the authenticated user",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/rtc.JoinRoomRequest"
       }
      }
     },
     "description": "Join room payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/rtc.JoinResponse"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Join RTC room",
    "tags": [
     "rtc"
    ]
   }
  },
  "/servicetype": {
   "get": {
    "description": "Get a service type by ID for the authenticated site",
    "parameters": [
     {
      "description": "Service type ID",
      "in": "query",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/servicetype.ServiceType"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "404": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Not Found"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get service type",
    "tags": [
     "service-type"
    ]
   },
   "post": {
    "description": "Create a new service type for the authenticated site. Set an image by referencing a confirmed attachment via image_attachment_id (uploaded through the pre-signed flow).",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/servicetype.ServiceTypeRequest"
       }
      }
     },
     "description": "Service type payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/servicetype.ServiceType"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Create service type",
    "tags": [
     "service-type"
    ]
   },
   "put": {
    "description": "Update an existing service type by ID for the authenticated site. Set an image by referencing a confirmed attachment via image_attachment_id (uploaded through the pre-signed flow).",
    "parameters": [
     {
      "description": "Service type ID",
      "in": "query",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/servicetype.ServiceTypeRequest"
       }
      }
     },
     "description": "Service type update payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/servicetype.ServiceType"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Update service type",
    "tags": [
     "service-type"
    ]
   }
  },
  "/servicetype/search": {
   "get": {
    "description": "Get all service types for the authenticated site",
    "parameters": [
     {
      "description": "Page number (default 1)",
      "in": "query",
      "name": "page",
      "schema": {
       "type": "integer"
      }
     },
     {
      "description": "Items per page (default 100)",
      "in": "query",
      "name": "page_size",
      "schema": {
       "type": "integer"
      }
     },
     {
      "description": "Sort field: name, created_at, is_active",
      "in": "query",
      "name": "sort_by",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Sort direction: asc or desc",
      "in": "query",
      "name": "sort_order",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/servicetype.ServiceType"
         },
         "type": "array"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "List service types",
    "tags": [
     "service-type"
    ]
   }
  },
  "/signup": {
   "post": {
    "description": "Creates a new organization, site, and admin user in a single onboarding flow",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/onboard.SignupRequest"
       }
      }
     },
     "description": "Signup payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/onboard.SignupResponse"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Sign up a new organization",
    "tags": [
     "onboard"
    ]
   }
  },
  "/signup/site": {
   "post": {
    "description": "Creates a new site under the authenticated user's organization and initializes default resources",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/onboard.SignupSiteRequest"
       }
      }
     },
     "description": "New site payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/site.Site"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Create a new site for an existing organization",
    "tags": [
     "onboard"
    ]
   }
  },
  "/site": {
   "get": {
    "description": "Get a site by ID for the authenticated organization",
    "parameters": [
     {
      "description": "Site ID",
      "in": "query",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/site.Site"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "404": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Not Found"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get site",
    "tags": [
     "site"
    ]
   },
   "post": {
    "description": "Create a new site for the authenticated organization",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/site.SiteRequest"
       }
      }
     },
     "description": "Site payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/site.Site"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Create site",
    "tags": [
     "site"
    ]
   },
   "put": {
    "description": "Update an existing site by ID for the authenticated organization",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/site.SiteUpdateRequest"
       }
      }
     },
     "description": "Site update payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/site.Site"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Update site",
    "tags": [
     "site"
    ]
   }
  },
  "/site/branding/public": {
   "get": {
    "description": "Public, unauthenticated endpoint that returns branding for the site resolved from the request subdomain (or the subdomain query param). Used by the customer/tracking apps to theme themselves before login.",
    "parameters": [
     {
      "description": "Site subdomain (falls back to the request host subdomain)",
      "in": "query",
      "name": "subdomain",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/site.PublicBrandingResponse"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "404": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Not Found"
     }
    },
    "summary": "Get public site branding (by subdomain)",
    "tags": [
     "site"
    ]
   }
  },
  "/site/search": {
   "get": {
    "description": "Search sites by name or subdomain for the authenticated organization",
    "parameters": [
     {
      "description": "Site name filter",
      "in": "query",
      "name": "name",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Subdomain filter",
      "in": "query",
      "name": "subdomain",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Page number (default 1)",
      "in": "query",
      "name": "page",
      "schema": {
       "type": "integer"
      }
     },
     {
      "description": "Items per page (default 100)",
      "in": "query",
      "name": "page_size",
      "schema": {
       "type": "integer"
      }
     },
     {
      "description": "Sort field: name, subdomain, created_at, is_active",
      "in": "query",
      "name": "sort_by",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Sort direction: asc or desc",
      "in": "query",
      "name": "sort_order",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/site.Site"
         },
         "type": "array"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Search sites",
    "tags": [
     "site"
    ]
   }
  },
  "/sitesettings": {
   "get": {
    "description": "Get the settings for the authenticated site",
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/sitesettings.SiteSettings"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "404": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Not Found"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get site settings",
    "tags": [
     "site-settings"
    ]
   },
   "put": {
    "description": "Update the settings for the authenticated site, including branding. The branding\nlogo is set by referencing a confirmed attachment via branding.logo_attachment_id\n(uploaded through the pre-signed flow: POST /attachment/presign then confirm).",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/sitesettings.SiteSettingsRequest"
       }
      }
     },
     "description": "Site settings update payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/sitesettings.SiteSettings"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Update site settings",
    "tags": [
     "site-settings"
    ]
   }
  },
  "/stop/action/complete": {
   "post": {
    "description": "Marks a stop action as completed, capturing any submitted field values. Attachments (photos, signatures, etc.) are uploaded via the pre-signed flow and referenced by id in values.attachment_ids.",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/stop.CompleteActionRequest"
       }
      }
     },
     "description": "Completion payload (attachment ids go in values.attachment_ids)",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/stopaction.StopAction"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Complete a stop action",
    "tags": [
     "stop"
    ]
   }
  },
  "/stop/action/config": {
   "delete": {
    "description": "Soft-deletes the stop action configuration with the given id for the authenticated site.",
    "parameters": [
     {
      "description": "ID of the stop action config to delete",
      "in": "query",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "type": "string"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Delete a stop action configuration",
    "tags": [
     "stop-action"
    ]
   },
   "get": {
    "description": "Returns all active stop action configurations for the authenticated site.",
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/stopaction.StopActionConfig"
         },
         "type": "array"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "List stop action configurations",
    "tags": [
     "stop-action"
    ]
   },
   "post": {
    "description": "Creates a new stop action configuration for the authenticated site. The configuration defines an action (e.g. photo, signature) that drivers must complete at stops of the specified type.",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/stopaction.StopActionCreateConfigRequest"
       }
      }
     },
     "description": "Stop action config creation payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/stopaction.StopActionConfig"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Create a stop action configuration",
    "tags": [
     "stop-action"
    ]
   },
   "put": {
    "description": "Updates an existing stop action configuration identified by the id field in the request body. Only provided fields are updated; omitted fields remain unchanged.",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/stopaction.StopActionUpdateConfigRequest"
       }
      }
     },
     "description": "Stop action config update payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/stopaction.StopActionConfig"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Update a stop action configuration",
    "tags": [
     "stop-action"
    ]
   }
  },
  "/stop/action/config/metadata": {
   "get": {
    "description": "Returns metadata about available action types, trigger events, stop types, stop action statuses, and type_config field schemas. Used by the frontend to render dynamic configuration forms.",
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/stopaction.MetadataResponse"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get stop action metadata",
    "tags": [
     "stop-action"
    ]
   }
  },
  "/stop/action/skip": {
   "post": {
    "description": "Marks a stop action as skipped with an optional reason. The action must be in a state that allows skipping.",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/stop.SkipActionRequest"
       }
      }
     },
     "description": "Stop action skip payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/stopaction.StopAction"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Skip a stop action",
    "tags": [
     "stop"
    ]
   }
  },
  "/stop/state": {
   "put": {
    "description": "Transitions a stop to a new workflow state identified by workflow_state_id. Both stop_id and workflow_state_id are provided as query or path parameters.",
    "parameters": [
     {
      "description": "ID of the stop to update",
      "in": "query",
      "name": "stop_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Target workflow state ID",
      "in": "query",
      "name": "workflow_state_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/stop.Stop"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Update stop workflow state",
    "tags": [
     "stop"
    ]
   }
  },
  "/team": {
   "get": {
    "description": "Retrieves a team by its ID for the current site",
    "parameters": [
     {
      "description": "Team ID",
      "in": "query",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/team.Team"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get a team",
    "tags": [
     "team"
    ]
   },
   "post": {
    "description": "Creates a new team for the current site and organization",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/team.TeamRequest"
       }
      }
     },
     "description": "Team details",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/team.Team"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Create a team",
    "tags": [
     "team"
    ]
   },
   "put": {
    "description": "Updates an existing team by its ID for the current site",
    "parameters": [
     {
      "description": "Team ID",
      "in": "query",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/team.TeamRequest"
       }
      }
     },
     "description": "Team update details",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/team.Team"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Update a team",
    "tags": [
     "team"
    ]
   }
  },
  "/team/adduser": {
   "post": {
    "description": "Adds a user to an existing team for the current site",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/team.UserTeamRequest"
       }
      }
     },
     "description": "User and team IDs",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/team.Team"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Add user to team",
    "tags": [
     "team"
    ]
   }
  },
  "/team/search": {
   "get": {
    "description": "Retrieves all teams for the current site",
    "parameters": [
     {
      "description": "Page number (default 1)",
      "in": "query",
      "name": "page",
      "schema": {
       "type": "integer"
      }
     },
     {
      "description": "Items per page (default 100)",
      "in": "query",
      "name": "page_size",
      "schema": {
       "type": "integer"
      }
     },
     {
      "description": "Sort field: name, created_at, is_active",
      "in": "query",
      "name": "sort_by",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Sort direction: asc or desc",
      "in": "query",
      "name": "sort_order",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/team.Team"
         },
         "type": "array"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Search teams",
    "tags": [
     "team"
    ]
   }
  },
  "/vehicle": {
   "delete": {
    "description": "Soft-deletes a vehicle by its ID for the current site",
    "parameters": [
     {
      "description": "Vehicle ID",
      "in": "query",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Delete a vehicle",
    "tags": [
     "vehicle"
    ]
   },
   "get": {
    "description": "Retrieves a vehicle by its ID for the current site",
    "parameters": [
     {
      "description": "Vehicle ID",
      "in": "query",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/vehicle.Vehicle"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get a vehicle",
    "tags": [
     "vehicle"
    ]
   },
   "post": {
    "description": "Creates a new vehicle for the current site and organization",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/vehicle.VehicleCreateRequest"
       }
      }
     },
     "description": "Vehicle details",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/vehicle.Vehicle"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Create a vehicle",
    "tags": [
     "vehicle"
    ]
   },
   "put": {
    "description": "Updates an existing vehicle by its ID for the current site",
    "parameters": [
     {
      "description": "Vehicle ID",
      "in": "query",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/vehicle.VehicleUpdateRequest"
       }
      }
     },
     "description": "Vehicle update details",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/vehicle.Vehicle"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Update a vehicle",
    "tags": [
     "vehicle"
    ]
   }
  },
  "/vehicle-type": {
   "get": {
    "description": "Returns all active vehicle types for the current site",
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/vehicle.VehicleType"
         },
         "type": "array"
        }
       }
      },
      "description": "OK"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "List vehicle types",
    "tags": [
     "vehicle-type"
    ]
   },
   "post": {
    "description": "Creates a new configurable vehicle type for the current site",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/vehicle.VehicleTypeCreateRequest"
       }
      }
     },
     "description": "Vehicle type details",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/vehicle.VehicleType"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Create a vehicle type",
    "tags": [
     "vehicle-type"
    ]
   }
  },
  "/vehicle-type/{id}": {
   "delete": {
    "description": "Soft-deletes a vehicle type by ID for the current site",
    "parameters": [
     {
      "description": "Vehicle Type ID",
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Delete a vehicle type",
    "tags": [
     "vehicle-type"
    ]
   },
   "get": {
    "description": "Retrieves a single vehicle type by ID for the current site",
    "parameters": [
     {
      "description": "Vehicle Type ID",
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/vehicle.VehicleType"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get a vehicle type",
    "tags": [
     "vehicle-type"
    ]
   },
   "put": {
    "description": "Updates an existing vehicle type by ID for the current site",
    "parameters": [
     {
      "description": "Vehicle Type ID",
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/vehicle.VehicleTypeUpdateRequest"
       }
      }
     },
     "description": "Vehicle type update details",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/vehicle.VehicleType"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Update a vehicle type",
    "tags": [
     "vehicle-type"
    ]
   }
  },
  "/vehicle/search": {
   "get": {
    "description": "Searches vehicles by optional filters: owner user ID, vehicle type ID, VIN, make, and model",
    "parameters": [
     {
      "description": "Owner user ID filter",
      "in": "query",
      "name": "owner_user_id",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Vehicle type ID filter",
      "in": "query",
      "name": "vehicle_type_id",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "VIN filter",
      "in": "query",
      "name": "vin",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Make filter",
      "in": "query",
      "name": "make",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Model filter",
      "in": "query",
      "name": "model",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Page number (default 1)",
      "in": "query",
      "name": "page",
      "schema": {
       "type": "integer"
      }
     },
     {
      "description": "Items per page (default 100)",
      "in": "query",
      "name": "page_size",
      "schema": {
       "type": "integer"
      }
     },
     {
      "description": "Sort field: make, model, year, license_plate, created_at",
      "in": "query",
      "name": "sort_by",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Sort direction: asc or desc",
      "in": "query",
      "name": "sort_order",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/vehicle.Vehicle"
         },
         "type": "array"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Search vehicles",
    "tags": [
     "vehicle"
    ]
   }
  },
  "/webhook": {
   "delete": {
    "description": "Deletes a webhook by its ID for the current site",
    "parameters": [
     {
      "description": "Webhook ID",
      "in": "query",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "204": {
      "description": "No Content"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Delete a webhook",
    "tags": [
     "webhook"
    ]
   },
   "get": {
    "description": "Retrieves a webhook by its ID for the current site",
    "parameters": [
     {
      "description": "Webhook ID",
      "in": "query",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/webhook.Webhook"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get a webhook",
    "tags": [
     "webhook"
    ]
   },
   "post": {
    "description": "Creates a new webhook subscription for the current site",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/webhook.WebhookRequest"
       }
      }
     },
     "description": "Webhook details",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/webhook.Webhook"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Create a webhook",
    "tags": [
     "webhook"
    ]
   },
   "put": {
    "description": "Updates an existing webhook by its ID for the current site",
    "parameters": [
     {
      "description": "Webhook ID",
      "in": "query",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/webhook.WebhookRequest"
       }
      }
     },
     "description": "Webhook update details",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/webhook.Webhook"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Update a webhook",
    "tags": [
     "webhook"
    ]
   }
  },
  "/webhook/search": {
   "get": {
    "description": "Retrieves all webhooks for the current site, including inactive ones",
    "parameters": [
     {
      "description": "Page number (default 1)",
      "in": "query",
      "name": "page",
      "schema": {
       "type": "integer"
      }
     },
     {
      "description": "Items per page (default 100)",
      "in": "query",
      "name": "page_size",
      "schema": {
       "type": "integer"
      }
     },
     {
      "description": "Sort field: url, is_active, created_at",
      "in": "query",
      "name": "sort_by",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Sort direction: asc or desc",
      "in": "query",
      "name": "sort_order",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/webhook.WebhookSearchResponse"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Search webhooks",
    "tags": [
     "webhook"
    ]
   }
  },
  "/worker": {
   "delete": {
    "description": "Soft-deletes a worker from the current site. A worker cannot delete themselves",
    "parameters": [
     {
      "description": "Worker ID",
      "in": "query",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "204": {
      "description": "No Content"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Delete a worker",
    "tags": [
     "worker"
    ]
   },
   "get": {
    "description": "Retrieves a worker by their ID for the current site (including inactive workers). Defaults to the authenticated user's own profile when no id is supplied. Non-admin/dispatcher callers may only fetch their own profile.",
    "parameters": [
     {
      "description": "Worker ID (defaults to current user)",
      "in": "query",
      "name": "id",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/user.User"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get a worker",
    "tags": [
     "worker"
    ]
   },
   "post": {
    "description": "Creates a new worker user account (driver, dispatcher, or admin) and associates them with the current site. Set a profile image by referencing a confirmed attachment via image_attachment_id (uploaded through the pre-signed flow). A home address may be supplied as an existing `home_address_id` or an inline `home_address` object (the id wins when both are sent).",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/worker.WorkerRequest"
       }
      }
     },
     "description": "Worker details",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/user.User"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Create a worker",
    "tags": [
     "worker"
    ]
   },
   "put": {
    "description": "Updates the details of an existing worker. Admins can update any worker; non-admins can only update their own profile. Set a profile image by referencing a confirmed attachment via image_attachment_id (uploaded through the pre-signed flow). The home address may be set via an existing `home_address_id` or an inline `home_address` object; sending `home_address_id` as an empty string clears it.",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/worker.WorkerUpdateRequest"
       }
      }
     },
     "description": "Worker update payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/user.User"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "401": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Unauthorized"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Update a worker",
    "tags": [
     "worker"
    ]
   }
  },
  "/worker/import": {
   "post": {
    "description": "Bulk imports workers from a CSV or JSON file upload, or from a JSON body. Returns a summary of created and failed records",
    "requestBody": {
     "content": {
      "multipart/form-data": {
       "schema": {
        "properties": {
         "file": {
          "description": "CSV or JSON file containing worker data",
          "format": "binary",
          "type": "string",
          "x-formData-name": "file"
         }
        },
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/user.ImportResponse"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Import workers",
    "tags": [
     "worker"
    ]
   }
  },
  "/worker/nearby": {
   "get": {
    "description": "Returns workers whose last reported location is within `radius` meters of the supplied anchor point. Used by dispatcher map flows (drag-and-drop pin, address pin). Results are ordered by ascending distance and exclude operationally-inactive workers. Backed by a per-site Redis GEO index populated on every accepted location update.",
    "parameters": [
     {
      "description": "Anchor latitude (WGS84)",
      "in": "query",
      "name": "lat",
      "required": true,
      "schema": {
       "type": "number"
      }
     },
     {
      "description": "Anchor longitude (WGS84)",
      "in": "query",
      "name": "lng",
      "required": true,
      "schema": {
       "type": "number"
      }
     },
     {
      "description": "Search radius in meters (1 - 50000)",
      "in": "query",
      "name": "radius",
      "required": true,
      "schema": {
       "type": "number"
      }
     },
     {
      "description": "Max results (default 100, max 500)",
      "in": "query",
      "name": "limit",
      "schema": {
       "type": "integer"
      }
     },
     {
      "description": "Filter to workers with this online_status (e.g. online)",
      "in": "query",
      "name": "online_status",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Filter to workers with this operational_status (e.g. active)",
      "in": "query",
      "name": "operational_status",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/worker.NearbyWorkersResponse"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Find workers near a map point",
    "tags": [
     "worker"
    ]
   }
  },
  "/worker/schedule": {
   "delete": {
    "description": "Deletes a recurring weekly schedule entry by its ID",
    "parameters": [
     {
      "description": "Schedule ID",
      "in": "query",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "204": {
      "description": "No Content"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Delete a worker schedule",
    "tags": [
     "worker"
    ]
   },
   "get": {
    "description": "Retrieves a worker schedule entry by its ID",
    "parameters": [
     {
      "description": "Schedule ID",
      "in": "query",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/worker.WorkerSchedule"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get a worker schedule",
    "tags": [
     "worker"
    ]
   },
   "post": {
    "description": "Creates a new recurring weekly schedule entry for a worker. Defaults to the authenticated user if worker_id is not provided",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/worker.WorkerScheduleRequest"
       }
      }
     },
     "description": "Worker schedule details",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/worker.WorkerSchedule"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Create a worker schedule",
    "tags": [
     "worker"
    ]
   },
   "put": {
    "description": "Updates an existing recurring weekly schedule entry by its ID",
    "parameters": [
     {
      "description": "Schedule ID",
      "in": "query",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/worker.WorkerScheduleUpdateRequest"
       }
      }
     },
     "description": "Schedule update payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/worker.WorkerSchedule"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Update a worker schedule",
    "tags": [
     "worker"
    ]
   }
  },
  "/worker/schedule/override": {
   "delete": {
    "description": "Deletes a one-time schedule override by its ID",
    "parameters": [
     {
      "description": "Schedule override ID",
      "in": "query",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "204": {
      "description": "No Content"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Delete a worker schedule override",
    "tags": [
     "worker"
    ]
   },
   "get": {
    "description": "Retrieves a specific one-time schedule override by its ID",
    "parameters": [
     {
      "description": "Schedule override ID",
      "in": "query",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/worker.WorkerScheduleOverride"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get a worker schedule override",
    "tags": [
     "worker"
    ]
   },
   "post": {
    "description": "Creates a one-time date-specific schedule override for a worker, such as a day off or modified hours. Defaults to the authenticated user if worker_id is not provided",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/worker.WorkerScheduleOverrideRequest"
       }
      }
     },
     "description": "Schedule override details",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/worker.WorkerScheduleOverride"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Create a worker schedule override",
    "tags": [
     "worker"
    ]
   },
   "put": {
    "description": "Updates an existing one-time schedule override by its ID",
    "parameters": [
     {
      "description": "Schedule override ID",
      "in": "query",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/worker.WorkerScheduleOverrideUpdateRequest"
       }
      }
     },
     "description": "Schedule override update payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/worker.WorkerScheduleOverride"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Update a worker schedule override",
    "tags": [
     "worker"
    ]
   }
  },
  "/worker/schedule/override/worker": {
   "get": {
    "description": "Retrieves all one-time schedule overrides for a worker, optionally filtered by a date range. Defaults to the authenticated user if worker_id is not provided",
    "parameters": [
     {
      "description": "Worker ID (defaults to authenticated user)",
      "in": "query",
      "name": "worker_id",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Start date filter (YYYY-MM-DD)",
      "in": "query",
      "name": "start_date",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "End date filter (YYYY-MM-DD)",
      "in": "query",
      "name": "end_date",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/worker.WorkerScheduleOverride"
         },
         "type": "array"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get schedule overrides for a worker",
    "tags": [
     "worker"
    ]
   }
  },
  "/worker/schedule/worker": {
   "get": {
    "description": "Retrieves all recurring weekly schedule entries for a worker. Defaults to the authenticated user if worker_id is not provided",
    "parameters": [
     {
      "description": "Worker ID (defaults to authenticated user)",
      "in": "query",
      "name": "worker_id",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/worker.WorkerSchedule"
         },
         "type": "array"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get schedules for a worker",
    "tags": [
     "worker"
    ]
   }
  },
  "/worker/search": {
   "get": {
    "description": "Searches workers by one or more fields: first name, last name, email, phone, role, display name, online status, operational status, and active state",
    "parameters": [
     {
      "description": "First name filter",
      "in": "query",
      "name": "first_name",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Last name filter",
      "in": "query",
      "name": "last_name",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Email filter",
      "in": "query",
      "name": "email",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Phone country code filter",
      "in": "query",
      "name": "phone_country",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Phone number filter",
      "in": "query",
      "name": "phone",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Role filter (driver, dispatcher, admin)",
      "in": "query",
      "name": "role",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Display name filter",
      "in": "query",
      "name": "display_name",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Online status filter",
      "in": "query",
      "name": "online_status",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Operational status filter (active, inactive, break)",
      "in": "query",
      "name": "operational_status",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Active status filter",
      "in": "query",
      "name": "is_active",
      "schema": {
       "type": "boolean"
      }
     },
     {
      "description": "Page number (default 1)",
      "in": "query",
      "name": "page",
      "schema": {
       "type": "integer"
      }
     },
     {
      "description": "Items per page (default 100)",
      "in": "query",
      "name": "page_size",
      "schema": {
       "type": "integer"
      }
     },
     {
      "description": "Sort field: first_name, last_name, email, phone, role, online_status, operational_status, is_active, created_at",
      "in": "query",
      "name": "sort_by",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Sort direction: asc or desc",
      "in": "query",
      "name": "sort_order",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/user.User"
         },
         "type": "array"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Search workers",
    "tags": [
     "worker"
    ]
   }
  },
  "/worker/search/autocomplete": {
   "get": {
    "description": "Returns a lightweight list of workers matching the query string for autocomplete suggestions",
    "parameters": [
     {
      "description": "Search query string",
      "in": "query",
      "name": "q",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Role filter (driver, dispatcher, admin)",
      "in": "query",
      "name": "role",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/worker.WorkerSearchAutoCompleteResponse"
         },
         "type": "array"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Autocomplete worker search",
    "tags": [
     "worker"
    ]
   }
  },
  "/worker/settings": {
   "get": {
    "description": "Retrieves notification preferences for the currently authenticated worker",
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/settings.UserSettings"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get worker notification settings",
    "tags": [
     "worker"
    ]
   },
   "put": {
    "description": "Updates push, email, and/or SMS notification preferences for the currently authenticated worker",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/settings.UpdateUserSettingsRequest"
       }
      }
     },
     "description": "Notification settings update payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/settings.UserSettings"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "500": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Internal Server Error"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Update worker notification settings",
    "tags": [
     "worker"
    ]
   }
  },
  "/workflow": {
   "get": {
    "description": "Get all workflows for the authenticated site",
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/workflow.Workflow"
         },
         "type": "array"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "List workflows",
    "tags": [
     "workflow"
    ]
   }
  },
  "/workflow/states": {
   "put": {
    "description": "Create or update the states for a given workflow for the authenticated site",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/workflow.UpsertWorkflowStatesPayload"
       }
      }
     },
     "description": "Upsert workflow states payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/workflow.Workflow"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Upsert workflow states",
    "tags": [
     "workflow"
    ]
   }
  },
  "/zone": {
   "get": {
    "description": "Get a geographic zone by ID for the authenticated site",
    "parameters": [
     {
      "description": "Zone ID",
      "in": "query",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/zone.Zone"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     },
     "404": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Not Found"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Get zone",
    "tags": [
     "zone"
    ]
   },
   "post": {
    "description": "Create a new geographic zone for the authenticated site",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/zone.ZoneRequest"
       }
      }
     },
     "description": "Zone payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/zone.Zone"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Create zone",
    "tags": [
     "zone"
    ]
   }
  },
  "/zone/search": {
   "get": {
    "description": "Get all geographic zones for the authenticated site",
    "parameters": [
     {
      "description": "Page number (default 1)",
      "in": "query",
      "name": "page",
      "schema": {
       "type": "integer"
      }
     },
     {
      "description": "Items per page (default 100)",
      "in": "query",
      "name": "page_size",
      "schema": {
       "type": "integer"
      }
     },
     {
      "description": "Sort field: name, priority, created_at, is_active",
      "in": "query",
      "name": "sort_by",
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Sort direction: asc or desc",
      "in": "query",
      "name": "sort_order",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "items": {
          "$ref": "#/components/schemas/zone.Zone"
         },
         "type": "array"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Search zones",
    "tags": [
     "zone"
    ]
   }
  },
  "/zone/serviceability": {
   "get": {
    "description": "Check whether a geographic point can be serviced based on zone restrictions. Returns serviceable=true for points outside all zones.",
    "parameters": [
     {
      "description": "Latitude of the point to check",
      "in": "query",
      "name": "lat",
      "required": true,
      "schema": {
       "type": "number"
      }
     },
     {
      "description": "Longitude of the point to check",
      "in": "query",
      "name": "lng",
      "required": true,
      "schema": {
       "type": "number"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/zone.ServiceabilityCheckResponse"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Check zone serviceability",
    "tags": [
     "zone"
    ]
   }
  },
  "/zone/{id}": {
   "delete": {
    "description": "Delete a geographic zone by ID for the authenticated site",
    "parameters": [
     {
      "description": "Zone ID",
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "type": "string"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Delete zone",
    "tags": [
     "zone"
    ]
   },
   "put": {
    "description": "Update an existing geographic zone by ID for the authenticated site",
    "parameters": [
     {
      "description": "Zone ID",
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/zone.ZoneRequest"
       }
      }
     },
     "description": "Zone update payload",
     "required": true,
     "x-originalParamName": "body"
    },
    "responses": {
     "200": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/zone.Zone"
        }
       }
      },
      "description": "OK"
     },
     "400": {
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/api.ApiError"
        }
       }
      },
      "description": "Bad Request"
     }
    },
    "security": [
     {
      "AccessTokenAuth": []
     },
     {
      "ApiKeyAuth": []
     }
    ],
    "summary": "Update zone",
    "tags": [
     "zone"
    ]
   }
  }
 },
 "tags": [
  {
   "description": "Manage customer and site addresses with geocoding and validation.\n\n## Overview\n\nAddress records store physical locations used by customers, sites, and stops. Every address is geocoded to latitude/longitude coordinates for routing and distance calculations.\n\n## Geocoding\n\nAddresses are automatically geocoded on creation and update using the configured map provider. If geocoding fails, the address is still saved but routing features will be unavailable until coordinates are resolved.",
   "name": "address"
  },
  {
   "description": "Administrative operations for managing users, roles, and system configuration.\n\n## Overview\n\nAdmin endpoints are restricted to users with the `admin` role. They provide access to user management, role assignment, and system-wide configuration that affects all users on a site.\n\n## Access Control\n\nAll admin endpoints require the `admin` role. Attempting to call these endpoints with a non-admin user will return `403 Forbidden`.",
   "name": "admin"
  },
  {
   "description": "Manage API applications and their credentials.\n\n## Overview\n\nApplications represent server-to-server integrations. Each application has an API key that can be used in the `x-api-key` header to authenticate requests without a user session.\n\n## API Keys\n\nAPI keys are scoped to a site and optionally to specific permissions. Rotate keys regularly and store them securely — they are only shown once at creation time.",
   "name": "application"
  },
  {
   "description": "The AI assistant lets site users query their RouteIQ business data (jobs, drivers, routes, metrics) via SMS, WhatsApp, or voice. There are no admin API endpoints for the assistant itself — it is activated by configuring the Twilio integration and ensuring users have phone numbers on their profiles.\n\n## Setup\n\n1. Create the Twilio site integration via `POST /api/integration` and note the `routing_key` in the response.\n2. In the Twilio Console, set the phone number's Messaging Webhook URL to:\n   ```\n   https://{your-domain}/api/integration/webhook/inbound?key=twilio&webhook_routing_key={routing_key}\n   ```\n3. Optionally configure a per-site Anthropic API key via the Anthropic integration (BYOK). If omitted, the platform `ANTHROPIC_API_KEY` is used.\n4. Ensure users have a phone number on their profile (`users.phone`) — this is how the assistant identifies who is texting.",
   "name": "assistant"
  },
  {
   "description": "Upload, retrieve, and manage file attachments.\n\n## Overview\n\nAttachments store files (images, documents, signatures) associated with jobs, stops, and other entities. Files are stored in S3 and served via pre-signed URLs.\n\n## Supported File Types\n\n- Images: `image/jpeg`, `image/png`, `image/webp`\n- Documents: `application/pdf`\n- Maximum file size: 10 MB per attachment\n\n## Upload Flow\n\n1. Request an upload URL via `POST /api/attachments/upload-url`\n2. Upload the file directly to S3 using the returned pre-signed URL\n3. Confirm the upload by calling `POST /api/attachments` with the returned key",
   "name": "attachment"
  },
  {
   "description": "View audit logs tracking changes to entities across the system.\n\n## Overview\n\nEvery create, update, and delete operation on key entities (jobs, stops, routes, users) is recorded in the audit log. Records are immutable and retained for compliance purposes.\n\n## Filtering\n\nAudit logs can be filtered by:\n- `entity_type` — the type of entity changed (e.g. `job`, `stop`, `user`)\n- `entity_id` — the specific entity\n- `user_id` — the user who made the change\n- `from` / `to` — time range",
   "name": "audit"
  },
  {
   "description": "Sign in, sign out, token management, and password operations.\n\n## Overview\n\nAuthentication endpoints handle the full identity lifecycle: signing in, refreshing tokens, signing out, and resetting passwords.\n\n## Sign In\n\n```\nPOST /api/auth/signin\n```\n\nReturns a `bearer_token` (for web clients) and an `access_token` (for mobile apps). Both are scoped to the site identified by the request subdomain.\n\n## Token Refresh\n\nBearer tokens expire after a configurable TTL. Use `POST /api/auth/refresh` with the current token to obtain a new one without re-entering credentials.\n\n## Password Reset\n\n1. `POST /api/auth/forgot-password` — sends a reset link to the user's email\n2. `POST /api/auth/reset-password` — sets a new password using the token from the email",
   "name": "authentication"
  },
  {
   "description": "Real-time messaging with chat rooms, messages, and file sharing.\n\n## Overview\n\nChat provides in-app messaging between dispatchers and drivers. Messages are grouped into rooms associated with jobs or routes.\n\n## Rooms\n\nEach job or route can have an associated chat room. Rooms are created automatically when the first message is sent.\n\n## File Sharing\n\nFiles can be attached to chat messages using the same upload flow as the `attachment` endpoints.",
   "name": "chat"
  },
  {
   "description": "Create, update, and manage customer records and their associated data.\n\n## Overview\n\nCustomers represent the recipients of delivery services. Each customer can have multiple addresses and contact methods. Customer records are site-scoped.\n\n## Associated Data\n\n- **Addresses** — delivery locations associated with the customer\n- **Jobs** — historical and active jobs for the customer\n- **Custom fields** — additional data defined by the site's custom field configuration",
   "name": "customer"
  },
  {
   "description": "Define and manage custom fields for extending entity data models.\n\n## Overview\n\nCustom fields allow sites to attach additional structured data to entities like jobs, stops, and customers without schema changes.\n\n## Field Types\n\nSupported field types:\n- `text` — free-form string\n- `number` — numeric value\n- `boolean` — true/false\n- `date` — ISO 8601 date\n- `select` — single value from a predefined list\n- `multi_select` — multiple values from a predefined list",
   "name": "customfield"
  },
  {
   "description": "Dispatch jobs and routes to drivers with optimized assignments.\n\n## Overview\n\nDispatch endpoints handle the assignment of jobs and routes to drivers. The dispatcher can assign individual jobs or full routes, and the system notifies drivers in real time.\n\n## Assignment States\n\nA job or route moves through the following dispatch states:\n1. `pending` — created, not yet dispatched\n2. `dispatched` — sent to driver, awaiting acceptance\n3. `accepted` — driver has accepted\n4. `in_progress` — driver is actively working\n5. `completed` — all stops finished\n6. `cancelled` — cancelled before completion",
   "name": "dispatch"
  },
  {
   "description": "Manage driver profiles, availability, and real-time location tracking.\n\n## Overview\n\nDrivers are users with the `driver` role. Driver profiles include vehicle assignment, availability status, and real-time GPS location.\n\n## Location Tracking\n\nDriver location is updated by the mobile app at a configurable interval. The latest location is available via `GET /api/drivers/:id/location`. Historical location data is queryable via the `location-history` endpoints.\n\n## Availability\n\nDrivers have an availability status (`available`, `on_break`, `off_duty`) that dispatchers can filter on when assigning jobs.",
   "name": "driver"
  },
  {
   "description": "Configure driver commission rules and track per-job earnings automatically.\n\n## Overview\n\nThe earnings package implements a configurable, component-based commission system. When a job is completed and payment succeeds, earnings are calculated automatically and recorded against the driver. Earnings records are immutable audit trails — they are never edited after creation.\n\n## How Earnings Are Calculated\n\nCalculation is triggered automatically via the `job:update` event when a job reaches a `completed` workflow state and `payment_status == \"succeeded\"`. It can also be triggered for cash/POS payments (which now emit a `job:update` event after `collectPayment` succeeds).\n\nThe process is **idempotent** — if an earning already exists for a given job+driver pair, the existing record is returned and no duplicate is created.\n\n### Step-by-step\n\n1. Look up the driver's assigned `earnings_rule_id` from their worker details.\n2. If none is assigned, fall back to the site's default earnings rule.\n3. Apply each component in the rule to produce a commission subtotal.\n4. Clamp the subtotal to `[minimum_amount, maximum_amount]` (max ignored if 0).\n5. Add the job's full tip on top (tip is always 100% driver-owned, not subject to components or clamping).\n6. Store the result with a per-component breakdown for auditability.\n\n## Earnings Components\n\n| Component | Description |\n|-----------|-------------|\n| `base` | Flat amount per job regardless of distance, time, or stops |\n| `per_distance_unit` | Rate × distance driven (respects site unit system: miles or km) |\n| `per_minute` | Rate × total job duration in minutes |\n| `per_stop` | Rate × number of stops in the job |\n| `percentage_of_job` | Rate (0–100%) × job price (actual if available, else estimated) |\n\nComponents are additive. Any combination is valid. Duplicate component types within a single rule are rejected.\n\n## Earnings Rules\n\nRules are created at the site level. Each rule has a name, a set of components, and optional floor/ceiling amounts. One rule per site can be marked `is_default` — this is the fallback used for drivers without an explicitly assigned rule.\n\nTo assign a rule to a specific driver, set `earnings_rule_id` on the worker via the worker update endpoint.\n\n## Access Control\n\n| Role | Capabilities |\n|------|-------------|\n| `admin` | Full CRUD on earnings rules; read all earnings records |\n| `dispatcher` | Read earnings rules; read all earnings records |\n| `driver` | Read own earnings only (search, summary, time-series, single record) |\n\nDrivers cannot specify a `driver_user_id` other than their own — the API enforces this automatically.\n\n## Reporting\n\nThree reporting endpoints are available:\n\n- **`/earnings/search`** — paginated list of individual earning records with filters (driver, job, date range)\n- **`/earnings/summary`** — aggregated totals (commission + tips + total) and job count for a driver within a date range\n- **`/earnings/time-series`** — earnings broken down by time period (`day`, `week`, or `month`), useful for charts and payroll summaries",
   "name": "earnings"
  },
  {
   "description": "Geographic information services including geocoding and distance calculations.\n\n## Overview\n\nGIS endpoints provide geocoding (address → coordinates), reverse geocoding (coordinates → address), and distance/duration matrix calculations between multiple points.\n\n## Geocoding\n\n```\nGET /api/gis/geocode?address=<address>\n```\n\nReturns a list of candidate locations with coordinates, formatted address, and confidence score.\n\n## Distance Matrix\n\nCalculate travel distances and estimated durations between multiple origin/destination pairs. Used internally for route optimization.",
   "name": "gis"
  },
  {
   "description": "Configure and manage third-party integrations.\n\n## Overview\n\nIntegrations connect RouteIQ to external platforms (e-commerce, ERP, WMS). Each integration has a type, credentials, and sync settings.\n\n## Integration Types\n\n- **Shopify** — import orders as jobs automatically\n- **WooCommerce** — import orders from WooCommerce stores\n- **Custom webhook** — receive jobs via inbound webhooks\n\n## Sync Status\n\nEach integration has a sync status indicating when it last successfully synced and any errors encountered.",
   "name": "integration"
  },
  {
   "description": "Create, update, and track delivery jobs through their lifecycle.\n\n## Overview\n\nA **job** is the core unit of work in RouteIQ. It represents a delivery task assigned to a single driver, containing one or more stops.\n\n## Job Lifecycle\n\nJobs move through a finite set of states managed by a state machine:\n\n```\ncreated → dispatched → accepted → in_progress → completed\n                                               → cancelled\n```\n\nState transitions are triggered either by dispatcher actions or by driver actions in the mobile app.\n\n## Stops\n\nEach job contains one or more stops. A stop represents a physical location where the driver must perform an action (pickup, dropoff, or return). Stops are ordered and executed sequentially.\n\n## Jobs vs Routes\n\n- A **job** is the customer-facing unit: it tracks a single delivery end-to-end\n- A **route** is a dispatcher-defined execution plan grouping stops from multiple jobs for optimization\n\nJobs can exist independently of routes. When a job is added to a route, its stops are included in the route's optimized stop sequence.",
   "name": "job"
  },
  {
   "description": "Configure ETA-based notification rules for job updates.\n\n## Overview\n\nETA notification configs define rules for sending automated notifications when a driver's estimated time of arrival crosses a threshold. For example, notify the customer when the driver is 15 minutes away.\n\n## Trigger Conditions\n\n- `minutes_before` — trigger when ETA drops below this value\n- `notification_type` — `sms`, `email`, or `push`\n- `recipient` — `customer`, `dispatcher`, or a specific user",
   "name": "job-eta-notification-config"
  },
  {
   "description": "Configure notification preferences and rules for job events.\n\n## Overview\n\nJob notification configs define which events on a job trigger notifications, to whom, and via which channel. Configs are defined per site and can be overridden per job.\n\n## Triggerable Events\n\n- `job_created` — new job created\n- `job_dispatched` — job assigned to driver\n- `job_accepted` — driver accepted the job\n- `job_completed` — all stops completed\n- `job_cancelled` — job cancelled\n- `stop_arrived` — driver arrived at a stop\n- `stop_completed` — stop marked complete",
   "name": "job-notification-config"
  },
  {
   "description": "Query historical location data for drivers and vehicles.\n\n## Overview\n\nLocation history records the GPS track of each driver over time. Data is captured by the mobile app and stored with a timestamp, coordinates, speed, and heading.\n\n## Querying\n\n```\nGET /api/location-history?driver_id=<id>&from=<ISO8601>&to=<ISO8601>\n```\n\nReturns a time-ordered array of location points. For high-frequency tracking data, use pagination to avoid large payloads.\n\n## Retention\n\nLocation history is retained for a configurable period (default 90 days). Older data is archived or purged depending on site settings.",
   "name": "location-history"
  },
  {
   "description": "Retrieve performance metrics and analytics data.\n\n## Overview\n\nMetrics endpoints provide aggregated performance data for drivers, routes, and the overall operation. Data is pre-aggregated for fast reads.\n\n## Available Metrics\n\n- **Driver performance** — on-time rate, jobs completed, distance driven\n- **Route efficiency** — planned vs actual duration and distance\n- **Stop metrics** — average dwell time, failed delivery rate\n- **Operational overview** — jobs by status, daily throughput",
   "name": "metrics"
  },
  {
   "description": "Tenant onboarding and initial setup workflows.\n\n## Overview\n\nOnboarding endpoints handle the provisioning of new sites (tenants). They are typically called once during account creation and are restricted to platform administrators.\n\n## Onboarding Steps\n\n1. Create the organization\n2. Create the site with subdomain\n3. Create the first admin user\n4. Configure initial settings (timezone, currency, service types)\n5. Invite additional users",
   "name": "onboard"
  },
  {
   "description": "Manage configurable options and dropdown values.\n\n## Overview\n\nOptions provide the enumerable values used by select-type custom fields and other configurable dropdowns throughout the platform. They are site-scoped and fully customizable.\n\n## Structure\n\nEach option belongs to a named **option group** (e.g. `item_type`, `cancellation_reason`). Options within a group are ordered and can be marked as the default selection.",
   "name": "option"
  },
  {
   "description": "Manage organizations and their settings.\n\n## Overview\n\nAn organization is the top-level container for one or more sites. Organization-level settings apply to all sites within it.\n\n## Sites\n\nEach organization can have multiple sites (tenants), each with its own subdomain and independent data. Site management is available via the `site` endpoints.",
   "name": "organization"
  },
  {
   "description": "Configure pricing rules, components, and rate calculations.\n\n## Overview\n\nThe pricing engine calculates job costs based on configurable components, conditions, and geographic zones. Pricing is flexible enough to model flat rates, per-mile charges, time-based fees, and zone-specific overrides.\n\n## Pricing Components\n\n| Component | Description |\n|-----------|-------------|\n| `base_fee` | Fixed charge per job |\n| `per_mile` | Charge per mile/km of route distance |\n| `per_stop` | Charge per stop in the job |\n| `wait_time` | Charge per minute of driver wait time |\n| `weight` | Charge per unit of item weight |\n\n## Conditions\n\nComponents can be conditional — applied only when specific criteria are met (e.g. service type, time of day, zone).\n\n## Zones\n\nZone-based pricing allows different rates for deliveries within specific geographic boundaries. Zones are defined using polygon shapes on the `zone` endpoints.",
   "name": "pricing"
  },
  {
   "description": "Send and manage push notifications to mobile devices.\n\n## Overview\n\nPush notifications are sent to driver and customer mobile apps via APNs (iOS) and FCM (Android). Device tokens are registered automatically when a user signs in on a mobile device.\n\n## Sending Notifications\n\nNotifications are typically triggered automatically by job and stop state changes configured in `job-notification-config`. Direct push notifications can also be sent via this API.\n\n## Device Tokens\n\nDevice tokens are managed automatically. When a user signs in on a new device or the token rotates, the app registers the new token via `POST /api/push-notifications/register`.",
   "name": "push-notification"
  },
  {
   "description": "Create, optimize, and manage delivery routes.\n\n## Overview\n\nA **route** is a dispatcher-defined execution plan that groups stops from multiple jobs into an optimized sequence for a single driver. Routes are the primary planning tool for high-volume operations.\n\n## Route vs Job\n\n- A **job** is independent — it tracks a delivery for one customer\n- A **route** groups stops from many jobs for operational efficiency\n\nJobs exist before routes. A dispatcher creates a route, adds job stops to it, optimizes the sequence, and dispatches it to a driver.\n\n## Optimization\n\nRoute optimization reorders stops to minimize total travel distance/time while respecting time windows and other constraints. Call `POST /api/routes/:id/optimize` to trigger optimization.\n\n## Route States\n\n```\ndraft → optimized → dispatched → in_progress → completed\n                                              → cancelled\n```",
   "name": "route"
  },
  {
   "description": "Real-time communication features including video and voice calls.\n\n## Overview\n\nRTC (real-time communication) endpoints provide LiveKit-based video and voice call functionality between dispatchers and drivers.\n\n## Room Tokens\n\nTo join a call, a client requests a room token via `POST /api/rtc/token`. The token is passed to the LiveKit SDK on the client side to join the room.\n\n## Rooms\n\nRooms are created on demand. A room associated with a job or route allows dispatcher-driver communication in context.",
   "name": "rtc"
  },
  {
   "description": "Define and manage service types for categorizing jobs.\n\n## Overview\n\nService types categorize jobs by the nature of the service (e.g. \"same-day delivery\", \"express\", \"scheduled\"). Service types can have different pricing rules, SLAs, and operational constraints.\n\n## Usage\n\nWhen creating a job, specify a `service_type_id` to apply the associated pricing and configuration. Service types are site-scoped.\n\n## Configuration\n\nEach service type can define:\n- Display name and description\n- Default SLA (e.g. deliver within 4 hours)\n- Linked pricing rules\n- Required stop actions",
   "name": "service-type"
  },
  {
   "description": "Manage sites (tenants) and their configuration.\n\n## Overview\n\nA site is a tenant within an organization. Each site has a unique subdomain, its own user base, and fully isolated data. Site settings control branding, timezone, currency, and operational defaults.\n\n## Subdomain\n\nThe site subdomain is used to identify the tenant in every API request via the `Host` header. Subdomains cannot be changed after creation.\n\n## Site Status\n\nSites can be `active`, `suspended`, or `archived`. Suspended sites cannot be accessed by their users until reactivated.",
   "name": "site"
  },
  {
   "description": "Configure site-level settings and preferences.\n\n## Overview\n\nSite settings control operational defaults, branding, and feature flags for a site. Settings are applied globally to all users and jobs within the site.\n\n## Common Settings\n\n| Setting | Description |\n|---------|-------------|\n| `timezone` | Default timezone for date/time display |\n| `currency` | Currency for pricing and estimates |\n| `distance_unit` | `km` or `miles` |\n| `date_format` | Preferred date display format |\n| `notifications_enabled` | Master toggle for outbound notifications |",
   "name": "site-settings"
  },
  {
   "description": "Manage individual stops within jobs and routes.\n\n## Overview\n\nA **stop** represents a physical location where the driver must perform an action. Stops are the atomic unit of delivery work — each job contains one or more stops.\n\n## Stop Types\n\n| Type | Description |\n|------|-------------|\n| `pickup` | Driver picks up items at this location |\n| `dropoff` | Driver delivers items at this location |\n| `return` | Driver returns undelivered items |\n\n## Stop Lifecycle\n\nStops move through states independently of the parent job:\n\n```\npending → arrived → in_progress → completed\n                               → failed\n```\n\nA job is completed when all its stops reach a terminal state (`completed` or `failed`).\n\n## Proof of Delivery\n\nStops can require proof-of-delivery actions (signature, photo) configured via the `stop-action` endpoints.",
   "name": "stop"
  },
  {
   "description": "Define and execute actions required at each stop (e.g., signature capture, photo proof).\n\n## Overview\n\nStop actions define the tasks a driver must complete at a stop before marking it as done. Actions are configured per service type and can be overridden per stop.\n\n## Action Types\n\n| Action | Description |\n|--------|-------------|\n| `signature` | Capture recipient signature |\n| `photo` | Take a photo as proof of delivery |\n| `barcode_scan` | Scan a barcode on the package |\n| `notes` | Enter free-text notes |\n| `checklist` | Complete a configurable checklist |\n\n## Enforcement\n\nIf required actions are not completed, the driver cannot mark the stop as `completed`. Actions are validated server-side.\n\n## Capturing Action Data\n\nDrivers submit action results via `POST /api/stops/:id/actions/:action_id/complete` with the captured data (base64 image, signature SVG, scanned code, etc.).",
   "name": "stop-action"
  },
  {
   "description": "Create and manage teams of workers with zone assignments.\n\n## Overview\n\nTeams group workers (drivers) for organizational and operational purposes. Teams can be restricted to specific geographic zones, and jobs within those zones are preferentially assigned to the team.\n\n## Zone Restrictions\n\nAssign zones to a team to limit where its members operate. The dispatch optimizer uses zone assignments to suggest appropriate driver-job matches.\n\n## Team Membership\n\nWorkers can belong to multiple teams. Team membership is managed via the team's member list endpoints.",
   "name": "team"
  },
  {
   "description": "Manage fleet and personal vehicles with assignment tracking.\n\n## Overview\n\nVehicles can be fleet-owned or driver-owned (personal). Each driver can have an active vehicle assignment that is used for route planning (vehicle capacity, type restrictions).\n\n## Vehicle Types\n\nVehicle type determines capacity constraints and restrictions:\n- `car` — small packages, city deliveries\n- `van` — medium cargo\n- `truck` — large cargo, requires special routing\n- `motorcycle` — express, small packages only\n\n## Assignment\n\nAssign a vehicle to a driver via `POST /api/vehicles/:id/assign`. Only one vehicle can be active per driver at a time.",
   "name": "vehicle"
  },
  {
   "description": "Configure webhook endpoints for event-driven notifications.\n\n## Overview\n\nWebhooks allow external systems to receive real-time event notifications from RouteIQ. When a subscribed event occurs, RouteIQ sends an HTTP POST to the configured URL.\n\n## Supported Events\n\n- `job.created`, `job.dispatched`, `job.completed`, `job.cancelled`\n- `stop.arrived`, `stop.completed`, `stop.failed`\n- `driver.location_updated`\n- `route.completed`\n\n## Delivery Guarantees\n\nWebhooks are delivered at least once. Your endpoint must be idempotent. If delivery fails (non-2xx response), RouteIQ retries with exponential backoff for up to 24 hours.\n\n## Signature Verification\n\nEach webhook request includes an `X-RouteIQ-Signature` header. Verify this signature using your webhook secret to ensure the request is genuine.",
   "name": "webhook"
  },
  {
   "description": "Manage worker profiles, skills, and assignments.\n\n## Overview\n\nWorkers are users who perform physical tasks — primarily drivers. Worker profiles store contact info, skills, certifications, and operational metadata.\n\n## Skills\n\nWorkers can have tagged skills (e.g. `fragile_handling`, `cold_chain`, `heavy_lift`) that can be matched against job requirements during dispatch.\n\n## Worker vs Driver\n\nAll drivers are workers, but not all workers are drivers. Workers with the `driver` role appear in driver-specific contexts (dispatch, location tracking).",
   "name": "worker"
  },
  {
   "description": "Define and manage workflow states and transitions for jobs and stops.\n\n## Overview\n\nWorkflows define the valid states and transitions for jobs and stops. Custom workflows allow sites to extend or replace the default state machine with their own business-specific states.\n\n## Default Workflow\n\nThe default job workflow:\n```\ncreated → dispatched → accepted → in_progress → completed\n                                               → cancelled\n```\n\n## Custom States\n\nSites can define additional intermediate states (e.g. `at_warehouse`, `out_for_delivery`) that appear between the standard states in the driver app.",
   "name": "workflow"
  },
  {
   "description": "Define geographic zones for pricing, restrictions, and team assignments.\n\n## Overview\n\nZones are polygon-shaped geographic areas used for pricing rules, team assignments, and operational restrictions. They are defined using GeoJSON polygons stored with MySQL spatial data types.\n\n## Use Cases\n\n- **Pricing zones** — apply different rates within a zone (e.g. downtown surcharge)\n- **Team zones** — restrict teams to operate only within specific zones\n- **Service zones** — restrict which service types are available in an area\n- **Exclusion zones** — mark areas where deliveries are not permitted\n\n## Creating Zones\n\nZones are defined by a GeoJSON `Polygon` feature. Use any GIS tool to draw the polygon boundary and pass the coordinates to `POST /api/zones`.",
   "name": "zone"
  }
 ]
}