Skip to main content

API Reference

Complete reference for all Delivery Locker API endpoints.

Base URL

https://api.delivery.kioskforce.com

Authentication

All endpoints require the X-API-Key header:

X-API-Key: YOUR_API_KEY

Endpoints

Echo

Test API connectivity and verify authentication.

POST /api/delivery/external/v1/echo

Request Body:

{
"message": "test"
}

Parameters:

  • message (body, optional): Echo message

Response:

{
"message": "test"
}

Search Machines

Find delivery lockers by location and criteria.

POST /api/delivery/external/v1/machines/search

Request Body:

{
"latitude": -6.125556,
"longitude": 106.655830,
"radius": 1000,
"limit": 10,
"only_available_lockers": true,
"packaging": {
"width": 300,
"height": 200,
"depth": 400,
"weight": 1500,
"heating_required": false,
"cooling_required": true
}
}

Parameters:

  • latitude (required): Latitude coordinate
  • longitude (required): Longitude coordinate
  • radius (required): Search radius in meters
  • limit (optional): Maximum number of results
  • only_available_lockers (optional): Only return machines with available cells
  • packaging (optional): Package requirements for optimal matching

Response:

{
"machines": [
{
"machine": {
"machine_id": "machine_123",
"name": "Awesome Business Park - Waiting Area (South)",
"location": "Benda, Tangerang City, Banten",
"latitude": -6.125556,
"longitude": 106.655830,
"online": true,
"preferred_cells": [
{
"width": 300,
"height": 300,
"depth": 300,
"heating": false,
"cooling": true,
"weight_sensor": true
}
]
},
"distance_in_metres": 150
}
]
}

Get Machine Details

Retrieve detailed information about a specific machine.

GET /api/delivery/external/v1/machines/{machine_id}

Parameters:

  • machine_id (path, required): Unique machine identifier

Response:

{
"machine": {
"machine_id": "machine_123",
"name": "Awesome Business Park - Waiting Area (South)",
"location": "Benda, Tangerang City, Banten",
"latitude": -6.125556,
"longitude": 106.655830,
"online": true,
"preferred_cells": [...]
}
}

Reserve Cell

Reserve a locker compartment for package delivery.

POST /api/delivery/external/v1/reservations

Request Body:

{
"machine_id": "machine_123",
"platform_order_id": "order_456",
"notes": "Fragile package - handle with care",
"webhook_url": "https://yourapi.com/webhooks/delivery",
"packaging": {
"width": 300,
"height": 200,
"depth": 400,
"weight": 1500,
"heating_required": false,
"cooling_required": true
},
"eta_minutes": 30,
"grace_period_pickup_in_seconds": 120,
"grace_period_dropoff_in_seconds": 120
}

Parameters:

  • machine_id (required): Target machine identifier
  • platform_order_id (required): Your internal order ID (max 1024 chars)
  • packaging (required): Package dimensions and requirements
  • notes (optional): Additional notes for operations team (max 1024 chars)
  • webhook_url (optional): Custom webhook URL for this reservation
  • eta_minutes (optional): Expected arrival time in minutes
  • grace_period_pickup_in_seconds (optional): Pickup grace period (default: 120)
  • grace_period_dropoff_in_seconds (optional): Drop-off grace period (default: 120)

Response:

{
"reservation_id": "res_789",
"machine_id": "machine_123",
"machine": { ... },
"drop_off_code": "1234",
"drop_off_qrcode": "DLV-DROP-res_789-1234",
"drop_off_qrcode_url": "https://api.delivery.kioskforce.com/qrcode/ABC123",
"pickup_code": "5678",
"pickup_code_qrcode": "DLV-PICK-res_789-5678",
"pickup_code_qrcode_url": "https://api.delivery.kioskforce.com/qrcode/DEF456"
}

Get Reservation

Retrieve the details of a specific reservation by its ID.

GET /api/delivery/external/v1/reservations/{reservation_id}

Parameters:

  • reservation_id (path, required): Reservation identifier

Response:

{
"reservation_id": "res_789",
"machine_id": "machine_123",
"machine": { ... },
"platform_order_id": "order_456",
"notes": "Fragile package - handle with care",
"status": "RESERVATION_STATUS_DROPPED_OFF",
"created_at": "2025-07-10T10:00:00Z",
"drop_off_code": "1234",
"drop_off_qrcode": "DLV-DROP-res_789-1234",
"drop_off_qrcode_url": "https://api.delivery.kioskforce.com/qrcode/ABC123",
"pickup_code": "5678",
"pickup_code_qrcode": "DLV-PICK-res_789-5678",
"pickup_code_qrcode_url": "https://api.delivery.kioskforce.com/qrcode/DEF456",
"cell": {
"description": "A03"
},
"dropped_off_at": "2025-07-10T10:30:00Z"
}

Status Values:

  • RESERVATION_STATUS_PENDING - Reservation created but package not yet dropped off
  • RESERVATION_STATUS_DROPPED_OFF - Package has been dropped off by rider/driver
  • RESERVATION_STATUS_PICKED_UP - Package has been picked up by consumer
  • RESERVATION_STATUS_CANCELLED - Reservation has been cancelled
  • RESERVATION_STATUS_ABANDONED - Pickup has been abandoned

List Ongoing Reservations

Retrieve all ongoing (not finished) reservations for your platform with pagination support.

GET /api/delivery/external/v1/reservations

Query Parameters:

  • page_size (optional): Maximum number of reservations per page (default: 100, max: 1000)
  • page_token (optional): Token for retrieving next page of results
  • created_after (optional): Unix timestamp to filter reservations created after this time (exclusive)

Ongoing States: Reservations are considered "ongoing" if they are in one of these states:

  • PENDING - Cell reserved but package not yet dropped off
  • DROPPED_OFF - Package dropped off, waiting for consumer pickup
  • PICKED_UP - Package picked up but still within grace period (consumer can re-open door)

Grace Period Behavior:

  • A reservation in PICKED_UP state remains in the list only if: (current_time - picked_up_at) <= grace_period_pickup_seconds
  • This allows tracking reservations where consumers can still re-access the cell
  • After grace period expires, the reservation is excluded from this list

Response:

{
"reservations": [
{
"reservation_id": "res_789",
"machine_id": "machine_123",
"platform_order_id": "order_456",
"status": "RESERVATION_STATUS_DROPPED_OFF",
"created_at": "2025-11-11T10:00:00Z",
"dropped_off_at": "2025-11-11T10:30:00Z",
"cell": {
"description": "A03"
}
}
],
"next_page_token": "token_abc123",
"total_count": 150
}

Response Fields:

  • reservations - Array of ongoing reservations, ordered by creation time (oldest first)
  • next_page_token - Token for next page (empty if no more results)
  • total_count - Approximate total number of ongoing reservations

Pagination Example:

# First page
GET /api/delivery/external/v1/reservations?page_size=50

# Next page
GET /api/delivery/external/v1/reservations?page_size=50&page_token=token_abc123

Filtering by Time:

# Get reservations created after timestamp 1699999999
GET /api/delivery/external/v1/reservations?created_after=1699999999

Use Cases:

  • Monitor active deliveries in progress
  • Track packages waiting for consumer pickup
  • Identify reservations needing attention (e.g., long wait times)
  • Build real-time dashboard showing current delivery status
  • Implement incremental sync workflows

Drop Off Package

Open locker door for package drop-off by driver/rider.

POST /api/delivery/external/v1/reservations/{reservation_id}/dropoffs

Parameters:

  • reservation_id (path, required): Reservation identifier

Response:

{
"cell": {
"description": "A03"
}
}

⚠️ State Transition Behavior:

  • The API call opens the locker door immediately
  • The reservation state does NOT change to DROPPED_OFF until the door is closed by the driver/rider
  • This allows the driver to ensure the package is properly placed before the state changes
  • Once the door closes, the state transitions to DROPPED_OFF and the dropoff webhook is sent (if configured)

Pick Up Package

Open locker door for package pickup by consumer.

POST /api/delivery/external/v1/reservations/{reservation_id}/pickups

Parameters:

  • reservation_id (path, required): Reservation identifier

Response:

{
"cell": {
"description": "A03"
}
}

⚠️ State Transition Behavior:

  • The API call opens the locker door immediately
  • The reservation state changes immediately to PICKED_UP when the door opens successfully
  • This is different from dropoff - pickup state changes on door open, not door close
  • The pickup webhook is sent immediately when the door opens (if configured)
  • The grace period starts from this moment, allowing the consumer to re-open the door if needed

Cancel Reservation

Cancel a reservation before package drop-off.

POST /api/delivery/external/v1/reservations/{reservation_id}/deletes

Parameters:

  • reservation_id (path, required): Reservation identifier

Response:

{}

Note: This only works if the package hasn't been dropped off yet. Use "Abandon Pick Up" if the package is already in the locker.


Abandon Pick Up

Mark a package as abandoned when consumer cannot/will not pick it up.

POST /api/delivery/external/v1/reservations/{reservation_id}/abandons

Parameters:

  • reservation_id (path, required): Reservation identifier

Response:

{}

Note: Use this when the consumer has requested to abandon the package. The operations team will be notified for cleanup.


Request Maintenance

Report cell or locker issues that require operations team attention.

POST /api/delivery/external/v1/maintenances

Request Body:

{
"cell_id": "cell_unique_id_123",
"machine_id": "machine_123",
"description": "Door mechanism not opening properly - requires inspection",
"severity": "HIGH",
"block_cell_immediately": true
}

Parameters:

  • cell_id (optional): Unique identifier of the problematic cell
  • machine_id (optional): Machine identifier for machine-level issues
  • description (required): Detailed description of the issue
  • severity (optional): Issue severity (LOW, MEDIUM, HIGH, CRITICAL)
  • block_cell_immediately (optional): If true, blocks the cell from further reservations

Response:

{
"maintenance_ticket_id": "maint_456",
"created_at": "2025-11-13T10:00:00Z",
"status": "OPEN"
}

Use Cases:

  • Report broken doors or mechanisms
  • Flag cells with hardware issues after failed operations
  • Escalate repeated failure patterns
  • Request proactive maintenance

Open Door (Out-of-Band)

Open locker door for customer support and troubleshooting without changing reservation state.

POST /api/delivery/external/v1/reservations/{reservation_id}/open-door

Request Body:

{
"reason": "Customer support request - customer unable to open door with code",
"platform_reference_id": "support_ticket_789"
}

Parameters:

  • reservation_id (path, required): Reservation identifier
  • reason (body, optional): Explanation for opening the door
  • platform_reference_id (body, optional): Your internal ticket/reference ID

Response:

{
"request_id": "req_xyz789",
"accepted_at": "2025-11-13T15:30:00Z"
}

⚠️ Async Operation:

  • The request is accepted immediately and processed asynchronously
  • A webhook event EVENT_TYPE_OPEN_DOOR_FULFILLED will be sent when the operation completes
  • Use the X-Request-ID header to correlate the API call with the webhook event

Time Window Constraints: The door can be opened during these periods:

  1. Cell Allocation Period: From when cell is allocated until drop-off begins
  2. Drop-off Grace Period: From first DropOff call through grace period (default: 120s)
  3. Awaiting Pickup Period: From drop-off completion until pickup begins (DROPPED_OFF state)
  4. Pickup Grace Period: From first PickUp call through grace period (default: 120s)
  5. Extended Window: Even after grace period expires, until cell is reallocated

Error Handling:

  • Immediate errors (in response): Invalid reservation, auth failure, time window violation, device offline
  • Deferred errors (via webhook): Hardware failure, door mechanism issues

Use Cases:

  • Customer support assistance when codes don't work
  • Verify door mechanism is functioning
  • Emergency access situations
  • Troubleshooting pickup issues

Example Webhook Correlation:

# 1. Make API call with X-Request-ID header
curl -X POST "https://api.delivery.kioskforce.com/api/delivery/external/v1/reservations/res_789/open-door" \
-H "X-API-Key: YOUR_API_KEY" \
-H "X-Request-ID: req_xyz789" \
-H "Content-Type: application/json" \
-d '{
"reason": "Customer support ticket #456",
"platform_reference_id": "ticket_456"
}'

# 2. Receive immediate response
{
"request_id": "req_xyz789",
"accepted_at": "2025-11-13T15:30:00Z"
}

# 3. Later, receive webhook when operation completes
# See Webhooks documentation for EVENT_TYPE_OPEN_DOOR_FULFILLED details

State Transition Timing

Asymmetric Behavior: Dropoff vs Pickup

The API has different state transition timing for dropoff and pickup operations:

OperationDoor OpensState ChangesWebhook SentReason
Dropoff✅ Immediately⏳ When door closes⏳ When door closesAllows driver to verify package placement
Pickup✅ Immediately✅ Immediately✅ ImmediatelyConsumer has retrieved the package

Dropoff Flow

1. Call /dropoffs API → Door opens immediately (state: PENDING)
2. Driver places package
3. Driver closes door → State changes to DROPPED_OFF + webhook sent

Why? The dropoff state transition is delayed until door closure to ensure the driver has successfully placed the package. If the door closes before the driver is ready, they can re-open it within the grace period.

Pickup Flow

1. Call /pickups API → Door opens immediately → State changes to PICKED_UP + webhook sent
2. Consumer retrieves package
3. Consumer closes door

Why? The pickup state transition is immediate because the act of opening the door means the consumer has accessed the package. The grace period allows re-opening if needed (e.g., if the door accidentally closes).

Important Implications

  1. Monitoring Dropoffs: Don't assume a dropoff is complete immediately after calling the API - wait for the webhook or check the reservation status
  2. Monitoring Pickups: The pickup is considered complete as soon as the door opens successfully
  3. Grace Periods: Both operations allow re-opening the door within their respective grace periods, but the state has already changed for pickup
  4. Webhook Timing: Dropoff webhooks are delayed until door closure, while pickup webhooks are sent immediately

Error Responses

All endpoints may return these error status codes:

  • 403 - Unauthorized (invalid API key)
  • 404 - Resource not found
  • 500 - Server error

Error response format (rpcStatus):

{
"code": 5,
"message": "Resource not found",
"details": []
}

Common Error Codes:

  • 3 - Invalid argument
  • 5 - Not found
  • 7 - Permission denied
  • 13 - Internal server error
  • 16 - Unauthenticated

Notes

QR Code Fields

The API returns QR code data in two formats for both drop-off and pickup operations:

  1. QR Code Text (drop_off_qrcode, pickup_code_qrcode): Plain text string that should be encoded into a QR code by your application

    • Allows you to generate QR codes with your own branding, colors, and styling
    • Can be embedded directly into emails, mobile apps, or printed materials
    • Gives you full control over the QR code appearance and presentation
  2. QR Code URL (drop_off_qrcode_url, pickup_code_qrcode_url): A URL that displays the QR code as an image

    • Provides a ready-to-use QR code image
    • Useful when you need a quick solution without implementing QR code generation

The QR code URL is constructed by appending the QR code text to the base URL. For example:

  • If drop_off_qrcode is "DLV-DROP-res_789-1234"
  • Then drop_off_qrcode_url will be "https://api.delivery.kioskforce.com/qrcode/DLV-DROP-res_789-1234"

This URL can be:

  • Displayed directly in an <img> tag in web applications
  • Downloaded and printed for physical distribution
  • Shared via messaging apps or email

The same pattern applies for pickup QR codes.

Data Models

Machine

{
"machine_id": "string",
"name": "string",
"location": "string",
"latitude": "float",
"longitude": "float",
"online": "boolean",
"preferred_cells": [CellInformation],
"all_cells": [CellInformation],
"occupancy_information": "OccupancyStatus"
}

Fields:

  • preferred_cells - Non-exhaustive, KF-recommended cells with blended sizes for consideration. Only includes cells with status IDLE at the time of query (not reserved or occupied).
  • all_cells - Complete inventory of all cells configured for this machine
  • occupancy_information - Real-time occupancy status (includes reserved cells)

OccupancyStatus

Enum indicating the current occupancy level of a machine:

  • OCCUPANCY_STATUS_LOW (1) - Machine is essentially empty (≤30% occupied)
  • OCCUPANCY_STATUS_MEDIUM (2) - Machine is partially occupied (31-70% occupied)
  • OCCUPANCY_STATUS_HIGH (3) - Machine is almost full (>70% occupied)
  • OCCUPANCY_STATUS_OVERLOADED (4) - Machine is overloaded (>95% occupied)

CellInformation

{
"width": "int32", // millimeters
"height": "int32", // millimeters
"depth": "int32", // millimeters
"heating": "boolean",
"cooling": "boolean",
"weight_sensor": "boolean"
}

Packaging

{
"width": "int32", // millimeters
"height": "int32", // millimeters
"depth": "int32", // millimeters
"weight": "int32", // grams
"heating_required": "boolean",
"cooling_required": "boolean"
}