{
  "swagger": "2.0",
  "info": {
    "title": "Delivery Locker Cloud API",
    "version": "1.0",
    "contact": {
      "name": "KioskForce",
      "url": "https://kioskforce.com",
      "email": "contact@kioskforce.com"
    }
  },
  "tags": [
    {
      "name": "DeliveryService",
      "description": "DeliveryService provides the API for delivery service providers to interact with the delivery lockers. The calls to this endpoints are initiated by the delivery service providers"
    }
  ],
  "schemes": [
    "https"
  ],
  "consumes": [
    "application/json"
  ],
  "produces": [
    "application/json"
  ],
  "paths": {
    "/api/delivery/external/v1/echo": {
      "post": {
        "operationId": "DeliveryService_Echo",
        "responses": {
          "200": {
            "description": "A successful response.",
            "schema": {
              "$ref": "#/definitions/deliveryexternalv1EchoResponse"
            }
          },
          "403": {
            "description": "Returned when the client does not have permission to access the resource.",
            "schema": {}
          },
          "404": {
            "description": "Returned when the resource does not exist.",
            "schema": {
              "type": "string",
              "format": "string"
            }
          },
          "500": {
            "description": "Server error",
            "schema": {
              "$ref": "#/definitions/rpcStatus"
            }
          },
          "default": {
            "description": "An unexpected error response.",
            "schema": {
              "$ref": "#/definitions/rpcStatus"
            }
          }
        },
        "parameters": [
          {
            "name": "body",
            "in": "body",
            "required": true,
            "schema": {
              "$ref": "#/definitions/deliveryexternalv1EchoRequest"
            }
          }
        ],
        "tags": [
          "DeliveryService"
        ]
      }
    },
    "/api/delivery/external/v1/machines/search": {
      "post": {
        "summary": "SearchMachines searches for machines based on the provided location and radius. It returns a list of machines that are within the specified radius from the given latitude and longitude.",
        "operationId": "DeliveryService_SearchMachines",
        "responses": {
          "200": {
            "description": "A successful response.",
            "schema": {
              "$ref": "#/definitions/deliveryexternalv1SearchMachinesResponse"
            }
          },
          "403": {
            "description": "Returned when the client does not have permission to access the resource.",
            "schema": {}
          },
          "404": {
            "description": "Returned when the resource does not exist.",
            "schema": {
              "type": "string",
              "format": "string"
            }
          },
          "500": {
            "description": "Server error",
            "schema": {
              "$ref": "#/definitions/rpcStatus"
            }
          },
          "default": {
            "description": "An unexpected error response.",
            "schema": {
              "$ref": "#/definitions/rpcStatus"
            }
          }
        },
        "parameters": [
          {
            "name": "body",
            "in": "body",
            "required": true,
            "schema": {
              "$ref": "#/definitions/deliveryexternalv1SearchMachinesRequest"
            }
          }
        ],
        "tags": [
          "DeliveryService"
        ]
      }
    },
    "/api/delivery/external/v1/machines/{machine_id}": {
      "get": {
        "summary": "GetMachine retrieves the machine detail information with machine_id. Machine ID is the unique identifier of a machine",
        "operationId": "DeliveryService_GetMachine",
        "responses": {
          "200": {
            "description": "A successful response.",
            "schema": {
              "$ref": "#/definitions/deliveryexternalv1GetMachineResponse"
            }
          },
          "403": {
            "description": "Returned when the client does not have permission to access the resource.",
            "schema": {}
          },
          "404": {
            "description": "Returned when the resource does not exist.",
            "schema": {
              "type": "string",
              "format": "string"
            }
          },
          "500": {
            "description": "Server error",
            "schema": {
              "$ref": "#/definitions/rpcStatus"
            }
          },
          "default": {
            "description": "An unexpected error response.",
            "schema": {
              "$ref": "#/definitions/rpcStatus"
            }
          }
        },
        "parameters": [
          {
            "name": "machine_id",
            "description": "machine_id is the unique identifier of a machine. This is generated by KF delivery platform. Max length: 128 characters. It's guaranteed that different machines will have different machine_id. And if a machine has been moved to a different location, it will have a different machine_id.",
            "in": "path",
            "required": true,
            "type": "string"
          }
        ],
        "tags": [
          "DeliveryService"
        ]
      }
    },
    "/api/delivery/external/v1/maintenances": {
      "post": {
        "summary": "RequestMaintenance allows platforms to report cell or locker issues that require\noperations team attention. This creates a maintenance ticket in the system and\ncan optionally block the cell immediately to prevent further reservations.",
        "operationId": "DeliveryService_RequestMaintenance",
        "responses": {
          "200": {
            "description": "A successful response.",
            "schema": {
              "$ref": "#/definitions/v1RequestMaintenanceResponse"
            }
          },
          "403": {
            "description": "Returned when the client does not have permission to access the resource.",
            "schema": {}
          },
          "404": {
            "description": "Returned when the resource does not exist.",
            "schema": {
              "type": "string",
              "format": "string"
            }
          },
          "500": {
            "description": "Server error",
            "schema": {
              "$ref": "#/definitions/rpcStatus"
            }
          },
          "default": {
            "description": "An unexpected error response.",
            "schema": {
              "$ref": "#/definitions/rpcStatus"
            }
          }
        },
        "parameters": [
          {
            "name": "body",
            "in": "body",
            "required": true,
            "schema": {
              "$ref": "#/definitions/v1RequestMaintenanceRequest"
            }
          }
        ],
        "tags": [
          "DeliveryService"
        ]
      }
    },
    "/api/delivery/external/v1/reservations": {
      "get": {
        "summary": "ListOngoingReservations retrieves all ongoing (not finished) reservations for the authenticated platform.",
        "description": "Ongoing reservations are defined as reservations that are actively in use and have not reached a terminal state.\nThis includes reservations in the following states:\n- RESERVATION_STATUS_PENDING (1): Cell reserved but package not yet dropped off by rider/driver\n- RESERVATION_STATUS_DROPPED_OFF (2): Package dropped off in cell, waiting for consumer pickup\n- RESERVATION_STATUS_PICKED_UP (3): Consumer picked up the package, BUT still within the pickup grace period\n\nGrace Period Logic:\nThe pickup grace period allows consumers to repeatedly open the door after initial pickup (in case they\naccidentally closed it). A reservation remains \"ongoing\" during this grace period:\n- Grace period duration: Specified in ReserveCellRequest.grace_period_pickup_in_seconds (default: 120 seconds)\n- Grace period starts: After the FIRST successful pickup (when state transitions to PICKED_UP)\n- During grace period: Consumer can call PickUp API multiple times or use pickup_code repeatedly\n- After grace period expires: Reservation is excluded from this list (considered terminal/finished)\n- Calculation: A reservation is ongoing if: (current_time - picked_up_at) \u003c= grace_period_pickup_seconds\n\nExcluded states (considered finished/terminal):\n- RESERVATION_STATUS_PICKED_UP (3): ONLY if the pickup grace period has expired (consumer can no longer open door)\n- RESERVATION_STATUS_CANCELLED (4): Platform cancelled the reservation before drop-off\n- RESERVATION_STATUS_ABANDONED (5): Platform requested to abandon the pickup after drop-off\n\nResults are ordered by creation time in ascending order (oldest first) and support pagination.\nThe platform can only see their own reservations based on the authenticated API key (X-API-Key header).\n\nUse cases:\n- Monitor active deliveries that are in progress\n- Track packages waiting for consumer pickup\n- Track packages where consumer can still access the cell (within grace period after pickup)\n- Identify reservations that may need attention (e.g., long wait times)\n- Build dashboards showing current delivery status across all locations\n- Support for \"repeat pickup\" scenarios during grace period\n\nPagination behavior:\n- Default page_size is 100 if not specified\n- If the number of returned reservations is less than page_size, there are no more results\n- Use next_page_token from response to fetch the next page\n- Results remain consistent within a pagination sequence even if reservations change state",
        "operationId": "DeliveryService_ListOngoingReservations",
        "responses": {
          "200": {
            "description": "A successful response.",
            "schema": {
              "$ref": "#/definitions/v1ListOngoingReservationsResponse"
            }
          },
          "403": {
            "description": "Returned when the client does not have permission to access the resource.",
            "schema": {}
          },
          "404": {
            "description": "Returned when the resource does not exist.",
            "schema": {
              "type": "string",
              "format": "string"
            }
          },
          "500": {
            "description": "Server error",
            "schema": {
              "$ref": "#/definitions/rpcStatus"
            }
          },
          "default": {
            "description": "An unexpected error response.",
            "schema": {
              "$ref": "#/definitions/rpcStatus"
            }
          }
        },
        "parameters": [
          {
            "name": "page_size",
            "description": "page_size is the maximum number of reservations to return per page.\nDefault: 100 if not specified or if set to 0.\nMaximum: 1000 (values above 1000 will be capped to 1000).\nRecommended: Use default for most cases; use smaller values (e.g., 10-50) for UI lists with frequent updates.",
            "in": "query",
            "required": false,
            "type": "integer",
            "format": "int32"
          },
          {
            "name": "page_token",
            "description": "page_token is used for pagination to retrieve the next page of results.\nProvide the value from next_page_token in the previous response.\nLeave empty for the first request.\nThe page_token encodes the pagination state and should not be parsed or modified by clients.",
            "in": "query",
            "required": false,
            "type": "string"
          },
          {
            "name": "created_after",
            "description": "created_after filters reservations to only include those created after this unix timestamp.\nThe filter is EXCLUSIVE, meaning reservations created exactly at this timestamp are NOT included.\nValue is in epoch seconds (not milliseconds).\n\nExample: created_after=1699999999 returns reservations created at 1700000000 or later.\n\nUse cases:\n- Incremental sync: Track reservations created since last query\n- Time-based filtering: Query only recent reservations\n- Reduce payload: Skip older reservations that have already been processed\n\nNote: This filter is applied BEFORE pagination, so it affects total_count and pagination behavior.",
            "in": "query",
            "required": false,
            "type": "string",
            "format": "int64"
          }
        ],
        "tags": [
          "DeliveryService"
        ]
      },
      "post": {
        "summary": "ReserveCell is used by the service provider to reserve a cell for a delivery. Once being reserved, the optimizer will make the cell available for delivery rider/driver to drop off the package. It's recommended to call this method as soon as possible after the consumer is about to place order to guarantee the availability of the service in peak hours.",
        "operationId": "DeliveryService_ReserveCell",
        "responses": {
          "200": {
            "description": "A successful response.",
            "schema": {
              "$ref": "#/definitions/v1ReserveCellResponse"
            }
          },
          "403": {
            "description": "Returned when the client does not have permission to access the resource.",
            "schema": {}
          },
          "404": {
            "description": "Returned when the resource does not exist.",
            "schema": {
              "type": "string",
              "format": "string"
            }
          },
          "500": {
            "description": "Server error",
            "schema": {
              "$ref": "#/definitions/rpcStatus"
            }
          },
          "default": {
            "description": "An unexpected error response.",
            "schema": {
              "$ref": "#/definitions/rpcStatus"
            }
          }
        },
        "parameters": [
          {
            "name": "body",
            "in": "body",
            "required": true,
            "schema": {
              "$ref": "#/definitions/v1ReserveCellRequest"
            }
          }
        ],
        "tags": [
          "DeliveryService"
        ]
      }
    },
    "/api/delivery/external/v1/reservations/{reservation_id}": {
      "get": {
        "summary": "GetReservation retrieves the details of a specific reservation by its ID. This allows platforms to query the current status and all information about a reservation.",
        "operationId": "DeliveryService_GetReservation",
        "responses": {
          "200": {
            "description": "A successful response.",
            "schema": {
              "$ref": "#/definitions/deliveryexternalv1GetReservationResponse"
            }
          },
          "403": {
            "description": "Returned when the client does not have permission to access the resource.",
            "schema": {}
          },
          "404": {
            "description": "Returned when the resource does not exist.",
            "schema": {
              "type": "string",
              "format": "string"
            }
          },
          "500": {
            "description": "Server error",
            "schema": {
              "$ref": "#/definitions/rpcStatus"
            }
          },
          "default": {
            "description": "An unexpected error response.",
            "schema": {
              "$ref": "#/definitions/rpcStatus"
            }
          }
        },
        "parameters": [
          {
            "name": "reservation_id",
            "description": "reservation_id is the unique identifier of the reservation to retrieve",
            "in": "path",
            "required": true,
            "type": "string"
          }
        ],
        "tags": [
          "DeliveryService"
        ]
      }
    },
    "/api/delivery/external/v1/reservations/{reservation_id}/abandons": {
      "post": {
        "summary": "AbandonPickUp is used by the service provider to abandon the pickup of the package. This is used when the consumer has requested to abandon the package. The operation team will be notified and schedule clean up.",
        "operationId": "DeliveryService_AbandonPickUp",
        "responses": {
          "200": {
            "description": "A successful response.",
            "schema": {
              "$ref": "#/definitions/v1AbandonPickUpResponse"
            }
          },
          "403": {
            "description": "Returned when the client does not have permission to access the resource.",
            "schema": {}
          },
          "404": {
            "description": "Returned when the resource does not exist.",
            "schema": {
              "type": "string",
              "format": "string"
            }
          },
          "500": {
            "description": "Server error",
            "schema": {
              "$ref": "#/definitions/rpcStatus"
            }
          },
          "default": {
            "description": "An unexpected error response.",
            "schema": {
              "$ref": "#/definitions/rpcStatus"
            }
          }
        },
        "parameters": [
          {
            "name": "reservation_id",
            "in": "path",
            "required": true,
            "type": "string"
          },
          {
            "name": "body",
            "in": "body",
            "required": true,
            "schema": {
              "type": "object"
            }
          }
        ],
        "tags": [
          "DeliveryService"
        ]
      }
    },
    "/api/delivery/external/v1/reservations/{reservation_id}/deletes": {
      "post": {
        "summary": "CancelReservation is used by the service provider to cancel a reservation. If the reservation is not being used yet (when the driver/rider has not dropped off the package), the reservation will be cancelled and the cell will be released for other deliveries. If the reservation is being used (when the driver/rider has dropped off the package, and the consumer has requested to abandon the food), the cancellation will fail with an error, in which case call AbandonPickUp instead.",
        "operationId": "DeliveryService_CancelReservation",
        "responses": {
          "200": {
            "description": "A successful response.",
            "schema": {
              "$ref": "#/definitions/v1CancelReservationResponse"
            }
          },
          "403": {
            "description": "Returned when the client does not have permission to access the resource.",
            "schema": {}
          },
          "404": {
            "description": "Returned when the resource does not exist.",
            "schema": {
              "type": "string",
              "format": "string"
            }
          },
          "500": {
            "description": "Server error",
            "schema": {
              "$ref": "#/definitions/rpcStatus"
            }
          },
          "default": {
            "description": "An unexpected error response.",
            "schema": {
              "$ref": "#/definitions/rpcStatus"
            }
          }
        },
        "parameters": [
          {
            "name": "reservation_id",
            "in": "path",
            "required": true,
            "type": "string"
          },
          {
            "name": "body",
            "in": "body",
            "required": true,
            "schema": {
              "type": "object"
            }
          }
        ],
        "tags": [
          "DeliveryService"
        ]
      }
    },
    "/api/delivery/external/v1/reservations/{reservation_id}/dropoffs": {
      "post": {
        "summary": "DropOff opens the door for riders/drivers to drop off the package.",
        "description": "State Transition Behavior:\n- FIRST CALL: Changes reservation state from PENDING to DROPPED_OFF IMMEDIATELY (door opens)\n- SUBSEQUENT CALLS: During grace period, door can be re-opened without changing state\n\nGrace Period:\n- The grace period starts AFTER the first successful door open\n- Default: 120 seconds (configurable via grace_period_dropoff_in_seconds in ReserveCell)\n- Purpose: Allows rider/driver to re-open the door if accidentally closed\n- State remains DROPPED_OFF throughout the grace period\n\nAlternative Access Method:\n- Riders/drivers can also use the drop_off_code or drop_off_qrcode on the machine\n- Both methods share the same grace period timer",
        "operationId": "DeliveryService_DropOff",
        "responses": {
          "200": {
            "description": "A successful response.",
            "schema": {
              "$ref": "#/definitions/v1DropOffResponse"
            }
          },
          "403": {
            "description": "Returned when the client does not have permission to access the resource.",
            "schema": {}
          },
          "404": {
            "description": "Returned when the resource does not exist.",
            "schema": {
              "type": "string",
              "format": "string"
            }
          },
          "500": {
            "description": "Server error",
            "schema": {
              "$ref": "#/definitions/rpcStatus"
            }
          },
          "default": {
            "description": "An unexpected error response.",
            "schema": {
              "$ref": "#/definitions/rpcStatus"
            }
          }
        },
        "parameters": [
          {
            "name": "reservation_id",
            "in": "path",
            "required": true,
            "type": "string"
          },
          {
            "name": "body",
            "in": "body",
            "required": true,
            "schema": {
              "type": "object"
            }
          }
        ],
        "tags": [
          "DeliveryService"
        ]
      }
    },
    "/api/delivery/external/v1/reservations/{reservation_id}/open-door": {
      "post": {
        "summary": "Open door for a reservation (out-of-band)",
        "description": "Opens the locker door associated with a reservation without changing reservation state. This is an out-of-band request intended for customer support and troubleshooting. Works from cell allocation through pickup grace period and until cell is reallocated. A webhook EVENT_TYPE_OPEN_DOOR_FULFILLED will be sent when the door operation completes.",
        "operationId": "DeliveryService_OpenDoor",
        "responses": {
          "200": {
            "description": "A successful response.",
            "schema": {
              "$ref": "#/definitions/deliveryexternalv1OpenDoorResponse"
            }
          },
          "403": {
            "description": "Returned when the client does not have permission to access the resource.",
            "schema": {}
          },
          "404": {
            "description": "Returned when the resource does not exist.",
            "schema": {
              "type": "string",
              "format": "string"
            }
          },
          "500": {
            "description": "Server error",
            "schema": {
              "$ref": "#/definitions/rpcStatus"
            }
          },
          "default": {
            "description": "An unexpected error response.",
            "schema": {
              "$ref": "#/definitions/rpcStatus"
            }
          }
        },
        "parameters": [
          {
            "name": "reservation_id",
            "description": "Unique identifier of the reservation",
            "in": "path",
            "required": true,
            "type": "string"
          },
          {
            "name": "body",
            "in": "body",
            "required": true,
            "schema": {
              "type": "object",
              "properties": {
                "reason": {
                  "type": "string",
                  "title": "Optional reason for opening door (for audit purposes)\nExamples: \"Customer called support - can't open door\", \"Testing door mechanism\"\nMax length: 1024 characters"
                },
                "platform_reference_id": {
                  "type": "string",
                  "title": "Platform's internal reference ID (support ticket ID, case number, etc.)\nThis will be echoed back in the response and webhook for correlation.\nExamples: \"SUP-12345\", \"CASE-9876\", \"TICKET-ABC123\"\nUse this to link the door open request to your internal systems.\nMax length: 256 characters"
                }
              }
            }
          }
        ],
        "tags": [
          "Delivery Service"
        ]
      }
    },
    "/api/delivery/external/v1/reservations/{reservation_id}/pickups": {
      "post": {
        "summary": "PickUp opens the door for consumers to pick up the package.",
        "description": "Prerequisites:\n- Package must be dropped off first (state must be DROPPED_OFF)\n- Will fail if called before rider/driver completes drop-off\n\nState Transition Behavior:\n- FIRST CALL: Changes reservation state from DROPPED_OFF to PICKED_UP IMMEDIATELY (door opens)\n- SUBSEQUENT CALLS: During grace period, door can be re-opened without changing state\n\nGrace Period:\n- The grace period starts AFTER the first successful door open\n- Default: 120 seconds (configurable via grace_period_pickup_in_seconds in ReserveCell)\n- Purpose: Allows consumer to re-open the door if accidentally closed\n- State remains PICKED_UP throughout the grace period\n\nAlternative Access Method:\n- Consumers can also use the pickup_code or pickup_qrcode on the machine\n- Both methods share the same grace period timer",
        "operationId": "DeliveryService_PickUp",
        "responses": {
          "200": {
            "description": "A successful response.",
            "schema": {
              "$ref": "#/definitions/v1PickUpResponse"
            }
          },
          "403": {
            "description": "Returned when the client does not have permission to access the resource.",
            "schema": {}
          },
          "404": {
            "description": "Returned when the resource does not exist.",
            "schema": {
              "type": "string",
              "format": "string"
            }
          },
          "500": {
            "description": "Server error",
            "schema": {
              "$ref": "#/definitions/rpcStatus"
            }
          },
          "default": {
            "description": "An unexpected error response.",
            "schema": {
              "$ref": "#/definitions/rpcStatus"
            }
          }
        },
        "parameters": [
          {
            "name": "reservation_id",
            "in": "path",
            "required": true,
            "type": "string"
          },
          {
            "name": "body",
            "in": "body",
            "required": true,
            "schema": {
              "type": "object"
            }
          }
        ],
        "tags": [
          "DeliveryService"
        ]
      }
    }
  },
  "definitions": {
    "ListOngoingReservationsResponseReservationInfo": {
      "type": "object",
      "properties": {
        "reservation_id": {
          "type": "string",
          "description": "reservation_id is the unique identifier of the reservation.\nUse this ID with GetReservation, DropOff, PickUp, CancelReservation, or AbandonPickUp APIs."
        },
        "machine_id": {
          "type": "string",
          "description": "machine_id is the unique identifier of the machine where the package is or will be stored.\nUse this with GetMachine API to retrieve full machine details."
        },
        "platform_order_id": {
          "type": "string",
          "description": "platform_order_id is the order identifier provided by the platform during reservation creation.\nThis is the same value passed in ReserveCellRequest.platform_order_id.\nUse this to correlate reservations with your internal order system."
        },
        "status": {
          "$ref": "#/definitions/v1GetReservationResponseReservationStatus",
          "description": "State transitions:\nPENDING -\u003e DROPPED_OFF: Rider/driver successfully dropped off the package (via DropOff API or drop_off_code)\nPENDING -\u003e CANCELLED: Platform cancelled the reservation (via CancelReservation API)\nDROPPED_OFF -\u003e PICKED_UP: Consumer picked up the package (via PickUp API or pickup_code)\nDROPPED_OFF -\u003e ABANDONED: Platform requested to abandon the pickup (via AbandonPickUp API)\nPICKED_UP -\u003e (removed from list): Grace period expires, reservation becomes terminal\n\nGrace period behavior:\nWhen status is PICKED_UP, the reservation remains in this list only if:\n(current_time - picked_up_at) \u003c= grace_period_pickup_seconds\nThis allows you to track reservations where consumers can still re-access the cell.",
          "title": "status is the current state of the reservation.\nFor ongoing reservations, this will be one of:\n- RESERVATION_STATUS_PENDING: Cell reserved, waiting for rider/driver to drop off the package\n- RESERVATION_STATUS_DROPPED_OFF: Package dropped off, waiting for consumer to pick up\n- RESERVATION_STATUS_PICKED_UP: Consumer picked up the package, still within grace period (can re-open door)"
        },
        "created_at": {
          "type": "string",
          "format": "date-time",
          "description": "created_at is the timestamp when the reservation was initially created via ReserveCell API.\nThis timestamp is immutable and never changes throughout the reservation lifecycle.\nAll results are ordered by this field in ascending order (oldest first)."
        },
        "dropped_off_at": {
          "type": "string",
          "format": "date-time",
          "description": "dropped_off_at is the timestamp when the package was dropped off by the rider/driver.\nThis field is populated when status is DROPPED_OFF or PICKED_UP.\nIt remains empty when status is PENDING.\nUse this to calculate how long a package has been waiting for pickup."
        },
        "picked_up_at": {
          "type": "string",
          "format": "date-time",
          "title": "picked_up_at is the timestamp when the consumer first picked up the package.\nThis field is only populated when status is PICKED_UP (within grace period).\nIt remains empty when status is PENDING or DROPPED_OFF.\nUse this to calculate remaining grace period time: grace_period - (current_time - picked_up_at)"
        },
        "cell": {
          "$ref": "#/definitions/deliveryexternalv1Cell",
          "description": "cell contains the physical cell/door information where the package is stored.\nThis field is populated when status is DROPPED_OFF or PICKED_UP (after successful drop-off).\nIt remains empty when status is PENDING (cell not yet assigned).\nThe cell assignment is determined by the locker system based on package size and cell availability."
        }
      },
      "description": "ReservationInfo provides essential information about an ongoing reservation.\nThis is a lightweight view optimized for list displays, containing only the most relevant fields.\nUse GetReservation to retrieve complete details including access codes and full machine information.",
      "required": [
        "reservation_id",
        "machine_id",
        "platform_order_id",
        "status",
        "created_at"
      ]
    },
    "deliveryexternalv1Cell": {
      "type": "object",
      "properties": {
        "description": {
          "type": "string",
          "title": "e.g. A03, B05"
        },
        "cell_id": {
          "type": "string",
          "description": "cell_id is the unique identifier of a cell within a machine. This is generated by KF delivery platform. Max length: 128 characters."
        }
      },
      "description": "Cell is the description of a cell/door in the machine.",
      "required": [
        "description",
        "cell_id"
      ]
    },
    "deliveryexternalv1CellInformation": {
      "type": "object",
      "properties": {
        "width": {
          "type": "integer",
          "format": "int32",
          "title": "width of the cell in millimeters, e.g. 300"
        },
        "height": {
          "type": "integer",
          "format": "int32",
          "title": "height of the cell in millimeters, e.g. 300"
        },
        "depth": {
          "type": "integer",
          "format": "int32",
          "title": "depth of the cell in millimeters, e.g. 300"
        },
        "heating": {
          "type": "boolean",
          "description": "if the cell is capable of keeping the package warm."
        },
        "cooling": {
          "type": "boolean",
          "description": "if the cell is capable of keeping the package cool."
        },
        "weight_sensor": {
          "type": "boolean",
          "title": "if the cell is equipped with a weight sensor"
        }
      },
      "required": [
        "width",
        "height",
        "depth",
        "heating",
        "cooling",
        "weight_sensor"
      ]
    },
    "deliveryexternalv1EchoRequest": {
      "type": "object",
      "properties": {
        "message": {
          "type": "string"
        }
      }
    },
    "deliveryexternalv1EchoResponse": {
      "type": "object",
      "properties": {
        "message": {
          "type": "string"
        }
      }
    },
    "deliveryexternalv1GetMachineResponse": {
      "type": "object",
      "properties": {
        "machine": {
          "$ref": "#/definitions/deliveryexternalv1Machine"
        }
      },
      "required": [
        "machine"
      ]
    },
    "deliveryexternalv1GetReservationResponse": {
      "type": "object",
      "properties": {
        "reservation_id": {
          "type": "string",
          "title": "reservation_id is the unique identifier of the reservation"
        },
        "machine_id": {
          "type": "string",
          "title": "machine_id is the unique identifier of the machine"
        },
        "machine": {
          "$ref": "#/definitions/deliveryexternalv1Machine",
          "title": "Machine details"
        },
        "platform_order_id": {
          "type": "string",
          "title": "platform_order_id provided by the platform"
        },
        "notes": {
          "type": "string",
          "title": "optional notes attached to the reservation"
        },
        "status": {
          "$ref": "#/definitions/v1GetReservationResponseReservationStatus",
          "title": "Current status of the reservation"
        },
        "created_at": {
          "type": "string",
          "format": "date-time",
          "title": "Timestamp when the reservation was created"
        },
        "drop_off_code": {
          "type": "string",
          "title": "Drop-off access codes"
        },
        "drop_off_qrcode": {
          "type": "string"
        },
        "drop_off_qrcode_url": {
          "type": "string"
        },
        "pickup_code": {
          "type": "string",
          "title": "Pick-up access codes"
        },
        "pickup_code_qrcode": {
          "type": "string"
        },
        "pickup_code_qrcode_url": {
          "type": "string"
        },
        "cell": {
          "$ref": "#/definitions/deliveryexternalv1Cell",
          "title": "Cell assigned (only present after drop-off)"
        },
        "dropped_off_at": {
          "type": "string",
          "format": "date-time",
          "title": "Timestamp when package was dropped off (optional)"
        },
        "picked_up_at": {
          "type": "string",
          "format": "date-time",
          "title": "Timestamp when package was picked up (optional)"
        },
        "cancelled_at": {
          "type": "string",
          "format": "date-time",
          "title": "Timestamp when reservation was cancelled (optional)"
        },
        "abandoned_at": {
          "type": "string",
          "format": "date-time",
          "title": "Timestamp when pickup was abandoned (optional)"
        },
        "request_id": {
          "type": "string",
          "description": "the x-request-id header used in the ReserveCell API call. This is stored when the reservation is created and can be used for tracing and debugging."
        },
        "allocation_eta": {
          "type": "integer",
          "format": "int32",
          "description": "allocation_eta is the estimated time in seconds until a cell becomes available.\nThis field is only populated when queueing=true (no cells immediately available at reservation time).\nValue represents estimated seconds until a cell is expected to free up.\nExample: 300 means approximately 5 minutes until cell availability.\nWhen a cell is allocated immediately (queueing=false), this field is 0 or not set.\nThis field is set at reservation creation and may be updated if queue time estimates change."
        },
        "queueing": {
          "type": "boolean",
          "description": "Important constraints:\n- If require_immediate_allocation=true was used, queueing is ALWAYS false\n- If require_immediate_allocation=false (default) and no cells available, queueing=true\n\nOnce a cell is allocated, this field reflects the initial queuing status.\nCheck the cell field and status to determine current allocation state.",
          "title": "queueing indicates whether this reservation was queued waiting for cell availability at creation time.\n- false: Cell was allocated immediately at reservation time\n- true: No cells were available, reservation was queued"
        }
      },
      "required": [
        "reservation_id",
        "machine_id",
        "machine",
        "platform_order_id",
        "status",
        "created_at",
        "drop_off_code",
        "drop_off_qrcode",
        "drop_off_qrcode_url",
        "pickup_code",
        "pickup_code_qrcode",
        "pickup_code_qrcode_url"
      ]
    },
    "deliveryexternalv1Machine": {
      "type": "object",
      "properties": {
        "machine_id": {
          "type": "string",
          "description": "machine_id is the unique identifier of a machine. This is generated by KF delivery platform. Max length: 128 characters. It's guaranteed that different machines will have different machine_id. And if a machine has been moved to a different location, it will have a different machine_id."
        },
        "name": {
          "type": "string",
          "title": "machine name, e.g. \"Awesome Business Park - Waiting Area (South)\"\""
        },
        "location": {
          "type": "string",
          "title": "machine location, e.g. \"Benda, Tangerang City, Banten\""
        },
        "latitude": {
          "type": "number",
          "format": "float",
          "title": "latitude of the machine location, e.g. -6.125556"
        },
        "longitude": {
          "type": "number",
          "format": "float",
          "title": "longitude of the machine location, e.g. 106.655830"
        },
        "online": {
          "type": "boolean",
          "description": "If this machine is connected to KF platform currently."
        },
        "preferred_cells": {
          "type": "array",
          "items": {
            "type": "object",
            "$ref": "#/definitions/deliveryexternalv1CellInformation"
          },
          "description": "non-exhaustive, KF recommended cells for the request, it may include a blended flavour of cells (dimensions etc) with different sizes for your consideration."
        },
        "all_cells": {
          "type": "array",
          "items": {
            "type": "object",
            "$ref": "#/definitions/deliveryexternalv1CellInformation"
          },
          "description": "all cells in the machine, this is the full list of the cells that are configured to this machine."
        },
        "occupancy_information": {
          "$ref": "#/definitions/v1OccupancyStatus",
          "description": "occupancy information of the machine. This is realtime. The occupancy includes the reserved cells that have not yet been used for drop-off."
        }
      },
      "required": [
        "machine_id",
        "name",
        "location",
        "latitude",
        "longitude",
        "online",
        "all_cells",
        "occupancy_information"
      ]
    },
    "deliveryexternalv1MachineInfo": {
      "type": "object",
      "properties": {
        "machine": {
          "$ref": "#/definitions/deliveryexternalv1Machine"
        },
        "distance_in_metres": {
          "type": "integer",
          "format": "int32",
          "title": "distance to supplied location (latitude+longitude)"
        }
      },
      "required": [
        "machine",
        "distance_in_metres"
      ]
    },
    "deliveryexternalv1OpenDoorResponse": {
      "type": "object",
      "properties": {
        "accepted": {
          "type": "boolean",
          "title": "Request has been accepted and will be processed asynchronously\nTrue: Request accepted, door will be opened\nFalse: Request rejected (see error message for details)"
        },
        "cell": {
          "$ref": "#/definitions/deliveryexternalv1Cell",
          "title": "Cell that will be opened\nOnly populated when accepted=true"
        },
        "request_id": {
          "type": "string",
          "title": "Request ID for tracing and webhook correlation\nUse this to correlate the API call with the EVENT_TYPE_OPEN_DOOR_FULFILLED webhook\nThis is the X-Request-Id header value"
        },
        "platform_reference_id": {
          "type": "string",
          "title": "Echoed back from request for platform correlation\nMatches platform_reference_id from OpenDoorRequest"
        },
        "machine": {
          "$ref": "#/definitions/deliveryexternalv1Machine",
          "title": "Machine information where the door will be opened\nOnly populated when accepted=true"
        }
      },
      "required": [
        "accepted"
      ]
    },
    "deliveryexternalv1SearchMachinesRequest": {
      "type": "object",
      "properties": {
        "latitude": {
          "type": "number",
          "format": "float"
        },
        "longitude": {
          "type": "number",
          "format": "float"
        },
        "radius": {
          "type": "integer",
          "format": "int32",
          "title": "radius in meters"
        },
        "limit": {
          "type": "integer",
          "format": "int32",
          "title": "limit the number of machines returned"
        },
        "only_available_lockers": {
          "type": "boolean",
          "title": "default false, if true, only return machines that are currently available"
        },
        "packaging": {
          "$ref": "#/definitions/v1Packaging",
          "description": "if packaging is provided, we will only return lockers with those cells that are capable of holding the packaging. If only_available_lockers enabled, we will only return lockers that have free doors for this package."
        }
      },
      "required": [
        "latitude",
        "longitude",
        "radius"
      ]
    },
    "deliveryexternalv1SearchMachinesResponse": {
      "type": "object",
      "properties": {
        "machines": {
          "type": "array",
          "items": {
            "type": "object",
            "$ref": "#/definitions/deliveryexternalv1MachineInfo"
          }
        }
      }
    },
    "protobufAny": {
      "type": "object",
      "properties": {
        "@type": {
          "type": "string",
          "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n  value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n  URL, or have them precompiled into a binary to avoid any\n  lookup. Therefore, binary compatibility needs to be preserved\n  on changes to types. (Use versioned type names to manage\n  breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics."
        }
      },
      "additionalProperties": {},
      "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n    Foo foo = ...;\n    Any any;\n    any.PackFrom(foo);\n    ...\n    if (any.UnpackTo(\u0026foo)) {\n      ...\n    }\n\nExample 2: Pack and unpack a message in Java.\n\n    Foo foo = ...;\n    Any any = Any.pack(foo);\n    ...\n    if (any.is(Foo.class)) {\n      foo = any.unpack(Foo.class);\n    }\n    // or ...\n    if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n      foo = any.unpack(Foo.getDefaultInstance());\n    }\n\n Example 3: Pack and unpack a message in Python.\n\n    foo = Foo(...)\n    any = Any()\n    any.Pack(foo)\n    ...\n    if any.Is(Foo.DESCRIPTOR):\n      any.Unpack(foo)\n      ...\n\n Example 4: Pack and unpack a message in Go\n\n     foo := \u0026pb.Foo{...}\n     any, err := anypb.New(foo)\n     if err != nil {\n       ...\n     }\n     ...\n     foo := \u0026pb.Foo{}\n     if err := any.UnmarshalTo(foo); err != nil {\n       ...\n     }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n    package google.profile;\n    message Person {\n      string first_name = 1;\n      string last_name = 2;\n    }\n\n    {\n      \"@type\": \"type.googleapis.com/google.profile.Person\",\n      \"firstName\": \u003cstring\u003e,\n      \"lastName\": \u003cstring\u003e\n    }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n    {\n      \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n      \"value\": \"1.212s\"\n    }"
    },
    "rpcStatus": {
      "type": "object",
      "properties": {
        "code": {
          "type": "integer",
          "format": "int32",
          "description": "The status code, which should be an enum value of\n[google.rpc.Code][google.rpc.Code]."
        },
        "message": {
          "type": "string",
          "description": "A developer-facing error message, which should be in English. Any\nuser-facing error message should be localized and sent in the\n[google.rpc.Status.details][google.rpc.Status.details] field, or localized\nby the client."
        },
        "details": {
          "type": "array",
          "items": {
            "type": "object",
            "$ref": "#/definitions/protobufAny"
          },
          "description": "A list of messages that carry the error details.  There is a common set of\nmessage types for APIs to use."
        }
      },
      "description": "The `Status` type defines a logical error model that is suitable for\ndifferent programming environments, including REST APIs and RPC APIs. It is\nused by [gRPC](https://github.com/grpc). Each `Status` message contains\nthree pieces of data: error code, error message, and error details.\n\nYou can find out more about this error model and how to work with it in the\n[API Design Guide](https://cloud.google.com/apis/design/errors)."
    },
    "v1AbandonPickUpResponse": {
      "type": "object"
    },
    "v1CancelReservationResponse": {
      "type": "object"
    },
    "v1DropOffResponse": {
      "type": "object",
      "properties": {
        "cell": {
          "$ref": "#/definitions/deliveryexternalv1Cell",
          "title": "returns the same cell for all follow-up requests"
        }
      },
      "required": [
        "cell"
      ]
    },
    "v1GetReservationResponseReservationStatus": {
      "type": "string",
      "enum": [
        "RESERVATION_STATUS_UNSPECIFIED",
        "RESERVATION_STATUS_PENDING",
        "RESERVATION_STATUS_DROPPED_OFF",
        "RESERVATION_STATUS_PICKED_UP",
        "RESERVATION_STATUS_CANCELLED",
        "RESERVATION_STATUS_ABANDONED"
      ],
      "default": "RESERVATION_STATUS_UNSPECIFIED",
      "description": "- RESERVATION_STATUS_UNSPECIFIED: Default unspecified status\n - RESERVATION_STATUS_PENDING: Reservation created but package not yet dropped off\n - RESERVATION_STATUS_DROPPED_OFF: Package has been dropped off by rider/driver\n - RESERVATION_STATUS_PICKED_UP: Package has been picked up by consumer\n - RESERVATION_STATUS_CANCELLED: Reservation has been cancelled\n - RESERVATION_STATUS_ABANDONED: Pickup has been abandoned",
      "title": "Reservation status enum"
    },
    "v1ListOngoingReservationsResponse": {
      "type": "object",
      "properties": {
        "reservations": {
          "type": "array",
          "items": {
            "type": "object",
            "$ref": "#/definitions/ListOngoingReservationsResponseReservationInfo"
          },
          "title": "reservations is the list of ongoing reservations for the authenticated platform.\nResults are ordered by created_at in ascending order (oldest first).\nThe list may be empty if there are no ongoing reservations matching the filters.\nEach reservation in the list is guaranteed to be in one of these states:\n- PENDING: Waiting for drop-off\n- DROPPED_OFF: Waiting for pickup\n- PICKED_UP: Within grace period (consumer can still re-open door)"
        },
        "next_page_token": {
          "type": "string",
          "description": "next_page_token is used to retrieve the next page of results.\nIf empty or not present, this is the last page and there are no more results.\nIf present, pass this value as page_token in the next ListOngoingReservationsRequest.\n\nPagination consistency:\n- The page_token maintains query consistency even if reservations change state during pagination\n- A reservation that transitions to a terminal state during pagination may still appear in results\n- This ensures you don't miss reservations that were ongoing when the query started"
        },
        "total_count": {
          "type": "integer",
          "format": "int32",
          "description": "total_count is the approximate total number of ongoing reservations matching the query filters.\nThis count represents the total across all pages, not just the current page.\n\nImportant notes:\n- This is an approximate count and may change between pagination requests as reservations transition states\n- If created_after filter is used, this count only includes reservations created after that timestamp\n- Use this for displaying progress indicators or estimating total pages\n- Do not rely on this for exact counts in critical business logic due to eventual consistency"
        }
      },
      "description": "ListOngoingReservationsResponse contains the list of ongoing reservations and pagination information.\nAll reservations returned are in PENDING, DROPPED_OFF, or PICKED_UP (within grace period) state at query time.",
      "required": [
        "reservations"
      ]
    },
    "v1OccupancyStatus": {
      "type": "string",
      "enum": [
        "OCCUPANCY_STATUS_UNSPECIFIED",
        "OCCUPANCY_STATUS_LOW",
        "OCCUPANCY_STATUS_MEDIUM",
        "OCCUPANCY_STATUS_HIGH",
        "OCCUPANCY_STATUS_OVERLOADED"
      ],
      "default": "OCCUPANCY_STATUS_UNSPECIFIED",
      "title": "- OCCUPANCY_STATUS_UNSPECIFIED: Default unspecified status\n - OCCUPANCY_STATUS_LOW: Machine is essentially empty, occupancy rate less or equal to 30%\n - OCCUPANCY_STATUS_MEDIUM: Machine is partially occupied, occupancy rate between 31% to 70%\n - OCCUPANCY_STATUS_HIGH: Machine is almost full, occupancy rate is above 70%\n - OCCUPANCY_STATUS_OVERLOADED: Machine is overloaded, occupancy rate is above 95%"
    },
    "v1Packaging": {
      "type": "object",
      "properties": {
        "width": {
          "type": "integer",
          "format": "int32"
        },
        "height": {
          "type": "integer",
          "format": "int32"
        },
        "depth": {
          "type": "integer",
          "format": "int32"
        },
        "weight": {
          "type": "integer",
          "format": "int32",
          "title": "weight in grams"
        },
        "heating_required": {
          "type": "boolean",
          "description": "if heating is required, this is used for later upgraded unit."
        },
        "cooling_required": {
          "type": "boolean"
        }
      },
      "required": [
        "width",
        "height",
        "depth"
      ]
    },
    "v1PickUpResponse": {
      "type": "object",
      "properties": {
        "cell": {
          "$ref": "#/definitions/deliveryexternalv1Cell"
        }
      },
      "required": [
        "cell"
      ]
    },
    "v1RequestMaintenanceRequest": {
      "type": "object",
      "properties": {
        "reservation_id": {
          "type": "string",
          "description": "Optional reservation_id if issue is related to specific reservation.\nIncluding this helps operations team correlate the issue with delivery history."
        },
        "machine_id": {
          "type": "string",
          "description": "Machine ID - required to identify which locker has the issue.\nThis is the machine_id from GetMachine, SearchMachines, or ReserveCell responses."
        },
        "cell_id": {
          "type": "string",
          "description": "Cell ID - optional, specify if issue is with a specific cell.\nThis is the cell_id returned from DropOff or PickUp responses.\nIf not provided, the issue is assumed to be locker-level (not cell-specific)."
        },
        "notes": {
          "type": "string",
          "title": "Detailed description of the issue in free-text format.\nInclude as much detail as possible:\n- What went wrong (e.g., \"door won't close\", \"cell is dirty\", \"heating not working\")\n- When it happened (e.g., \"during dropoff at 2:30 PM\")\n- Who reported it (e.g., \"customer complained\", \"driver noticed\")\n- Any error messages if applicable\nMax length: 4096 characters"
        },
        "block_cell_immediately": {
          "type": "boolean",
          "description": "Whether the cell should be immediately blocked from accepting new reservations.\nThis is a RECOMMENDATION ONLY - the operations team will make the final decision\non whether to block the cell based on the severity of the issue described in notes.\n\nIf true, the platform is requesting immediate blocking due to critical issues\nthat could affect subsequent deliveries (e.g., door won't close, safety hazard,\ncell is damaged). The operations team will review and may block the cell.\n\nIMPORTANT: This field is IGNORED if cell_id is not provided (empty).\nYou must specify a cell_id to request cell blocking.\n\nDefault: false"
        },
        "platform_reference_id": {
          "type": "string",
          "title": "Platform's tracking reference for this request.\nUse this to correlate with your internal ticketing system.\nMax length: 256 characters"
        }
      },
      "required": [
        "machine_id",
        "notes"
      ]
    },
    "v1RequestMaintenanceResponse": {
      "type": "object",
      "properties": {
        "maintenance_request_id": {
          "type": "string",
          "description": "Unique identifier for the maintenance request.\nUse this ID to track the request status or reference it in communications."
        },
        "requested_at": {
          "type": "string",
          "format": "date-time",
          "title": "Timestamp when request was received and logged"
        },
        "cell_blocked": {
          "type": "boolean",
          "description": "Whether the cell was blocked as a result of this request.\nTrue if block_cell_immediately was requested AND the operations team/system blocked the cell.\nFalse if blocking was not requested, not approved, or the cell couldn't be blocked (e.g., cell_id not found).\nMay be absent if blocking decision is deferred to operations team review."
        },
        "message": {
          "type": "string",
          "title": "Human-readable acknowledgment message"
        }
      },
      "required": [
        "maintenance_request_id",
        "requested_at"
      ]
    },
    "v1ReserveCellRequest": {
      "type": "object",
      "properties": {
        "machine_id": {
          "type": "string",
          "description": "machine_id is the unique identifier of a machine."
        },
        "platform_order_id": {
          "type": "string",
          "description": "platform_order_id is used by delivery service provide to track an order in their own ERP system or online order system. We use it for reference. It is not required to be unique. This will be included in all callbacks with \"X-Platform-Order-Id\" header. Max length: 1024 characters."
        },
        "notes": {
          "type": "string",
          "description": "optional notes attached to the order. Used by operation team for debugging purpose. Max length: 1024 characters."
        },
        "webhook_url": {
          "type": "string",
          "description": "This webhook_url will be used for all callbacks from the delivery service provider.  If this is not provided, we will call global webhook url which is registered for new platform onboarding. If this is specified, we will use this URL for all callbacks related to this reservation instead of the global webhook URL."
        },
        "packaging": {
          "$ref": "#/definitions/v1Packaging",
          "description": "packaging is the packaging information of the package to be delivered. It is used to determine which cell can be used for the delivery. If not provided, we will use the default cell size."
        },
        "eta_minutes": {
          "type": "integer",
          "format": "int32",
          "description": "when are we expecting the delivery rider/driver to arrive at the machine in minutes at this moment. This field is not currently in use, and it's only for optimization purpose in the future."
        },
        "grace_period_pickup_in_seconds": {
          "type": "integer",
          "format": "int32",
          "description": "Grace period for pickup operations (in seconds).\n\nImportant: This is NOT a delay before state change. The state changes IMMEDIATELY on first PickUp.\n\nBehavior:\n- Default: 120 seconds if not specified\n- Timer starts: When consumer first successfully opens the door (state becomes PICKED_UP)\n- During grace period: Consumer can call PickUp API again to re-open the same door\n- Purpose: Helps consumers who accidentally closed the door after opening it\n- After grace period expires: Door can no longer be re-opened via API for this reservation\n\nState Transition:\n- First PickUp call: DROPPED_OFF → PICKED_UP (immediate, door opens)\n- Subsequent PickUp calls during grace period: State remains PICKED_UP (door re-opens)"
        },
        "grace_period_dropoff_in_seconds": {
          "type": "integer",
          "format": "int32",
          "description": "Grace period for drop-off operations (in seconds).\n\nImportant: This is NOT a delay before state change. The state changes IMMEDIATELY on first DropOff.\n\nBehavior:\n- Default: 120 seconds if not specified\n- Timer starts: When rider/driver first successfully opens the door (state becomes DROPPED_OFF)\n- During grace period: Rider/driver can call DropOff API again to re-open the same door\n- Purpose: Helps riders/drivers who accidentally closed the door after opening it\n- After grace period expires: Door can no longer be re-opened via API for drop-off\n\nState Transition:\n- First DropOff call: PENDING → DROPPED_OFF (immediate, door opens)\n- Subsequent DropOff calls during grace period: State remains DROPPED_OFF (door re-opens)"
        },
        "require_immediate_allocation": {
          "type": "boolean",
          "description": "require_immediate_allocation controls whether the reservation requires immediate cell allocation.\n\nRECOMMENDED: Use false (default) for better fulfillment rate and user experience.\n\nBehavior:\n- Default: false (RECOMMENDED - allows queueing if no cells available)\n- When true: Request FAILS if no cell is immediately available\n- When false: Request is queued if no cells available (queueing=true)\n\nWhy false is recommended:\n- Higher success rate: Even if cells are in sanitization, request can be queued\n- Queued requests are prioritized: System prioritizes queued requests over new ones\n- Better user experience: Avoids order failures during peak hours or maintenance\n- Automatic fulfillment: Platform receives webhook when cell is allocated\n\nResponse guarantees when require_immediate_allocation=true:\n- queueing will ALWAYS be false\n- cell will ALWAYS be populated with allocated cell information\n- allocation_eta will be 0 or not set\n- Request fails with error if no cells available (including sanitization)\n\nResponse guarantees when require_immediate_allocation=false (default):\n- If cell available: queueing=false, cell populated immediately\n- If no cells available: queueing=true, allocation_eta provides estimated wait time\n- Webhook notification sent when queued reservation gets cell allocated\n\nUse cases:\n- false (RECOMMENDED): Standard deliveries, allows queueing during sanitization/peak hours\n- true: Only for critical time-sensitive deliveries that cannot tolerate any wait"
        }
      },
      "required": [
        "machine_id",
        "platform_order_id",
        "packaging"
      ]
    },
    "v1ReserveCellResponse": {
      "type": "object",
      "properties": {
        "reservation_id": {
          "type": "string",
          "description": "reservation_id is the unique identifier of the reservation. It is used to track the order in our system. This is generated by KF delivery platform. Max length: 64 characters."
        },
        "machine_id": {
          "type": "string",
          "description": "machine_id is the unique identifier of a machine. This is generated by KF delivery platform. Max length: 128 characters. It's guaranteed that different machines will have different machine_id. And if a machine has been moved to a different location, it will have a different machine_id."
        },
        "machine": {
          "$ref": "#/definitions/deliveryexternalv1Machine"
        },
        "drop_off_code": {
          "type": "string",
          "description": "drop_off_code is the code used by the delivery rider/driver to unlock the door."
        },
        "drop_off_qrcode": {
          "type": "string"
        },
        "drop_off_qrcode_url": {
          "type": "string",
          "description": "full URL of the qrcode. Format: https://api.delivery.vendingontrack.com/qrcode/{ABCDEFGH}. Delivery platform can use the URL to show to rider/driver directly."
        },
        "pickup_code": {
          "type": "string",
          "description": "pickup_code is the code used by the consumer to unlock the door."
        },
        "pickup_code_qrcode": {
          "type": "string"
        },
        "pickup_code_qrcode_url": {
          "type": "string",
          "description": "full URL of the qrcode. Format: https://api.delivery.vendingontrack.com/qrcode/{ABCDEFGH}. Delivery platform can use the URL to show to consumers directly."
        },
        "request_id": {
          "type": "string",
          "description": "the x-request-id header used in the ReserveCell API call. This is stored when the reservation is created and can be used for tracing and debugging."
        },
        "cell": {
          "$ref": "#/definitions/deliveryexternalv1Cell",
          "description": "cell is the allocated cell information (e.g., \"A03\", \"B05\").\nThis field is populated when a cell is successfully allocated at reservation time.\n\nPopulation rules:\n- If require_immediate_allocation=true: ALWAYS populated (or request fails)\n- If require_immediate_allocation=false and queueing=false: Populated immediately\n- If require_immediate_allocation=false and queueing=true: Empty until allocation (webhook sent)\n\nNote: This represents a change from previous behavior where cells were allocated at drop-off time.\nWith this enhancement, cells are pre-allocated at reservation time when available."
        },
        "allocation_eta": {
          "type": "integer",
          "format": "int32",
          "description": "allocation_eta is the estimated time in seconds until a cell becomes available.\nThis field is only populated when queueing=true (no cells immediately available).\nValue represents estimated seconds until a cell is expected to free up.\nExample: 300 means approximately 5 minutes until cell availability.\nWhen a cell is allocated immediately (queueing=false), this field is 0 or not set."
        },
        "queueing": {
          "type": "boolean",
          "description": "Important constraints:\n- If require_immediate_allocation=true in request, queueing MUST be false\n- If require_immediate_allocation=false (default) and no cells available, queueing=true\n\nWhen queueing=true:\n  - allocation_eta provides estimated wait time\n  - cell field may be empty until allocation occurs\n  - Platform will receive webhook notification when cell is allocated\n\nWhen queueing=false:\n  - cell field is populated with allocated cell\n  - allocation_eta is 0 or not set",
          "title": "queueing indicates whether this reservation is queued waiting for cell availability.\n- false: Cell was allocated immediately, see cell field for details\n- true: No cells currently available, reservation is queued"
        }
      },
      "required": [
        "reservation_id",
        "machine_id",
        "machine",
        "drop_off_code",
        "drop_off_qrcode",
        "drop_off_qrcode_url",
        "pickup_code",
        "pickup_code_qrcode",
        "pickup_code_qrcode_url"
      ]
    }
  },
  "securityDefinitions": {
    "ApiKeyAuth": {
      "type": "apiKey",
      "name": "X-API-Key",
      "in": "header"
    }
  },
  "security": [
    {
      "ApiKeyAuth": []
    }
  ],
  "externalDocs": {
    "description": "VendingOnTrack API Documentation",
    "url": "https://github.com/vendingontrack/api"
  }
}
