The public request form first asks what kind of job (pickup & delivery vs errand), then which addresses — including business-defined service locations (hostel, gate, landmark…).
Your bot / backend should do the same: call discovery endpoints before collecting fields, so you only ask questions that apply to this business.
Discover org settings
GET https://business.kiloapp.org/api/v1/capabilities
Authorization: Bearer sk_live_...
Returns (plan-clamped, same spirit as the public form):
| Field | Use it for |
|---|---|
enabledServiceKinds |
Only offer pickup_delivery and/or errand if listed |
defaultServiceKind |
Pre-select when the user has not chosen |
allowWarehouseDropoff |
Whether warehouse pickup mode is allowed |
errand.enabledModes |
at_place / link / photo for errands |
errand.curatedLinks |
Suggested shops/links for link-mode errands |
paymentCollection |
Which of cash / online checkout you may send |
pod.enabled |
Whether cash-to-collect (POD) is offered on pickup jobs |
features.serviceLocations |
Whether named campus/venue places exist for this plan |
Warehouses
GET https://business.kiloapp.org/api/v1/warehouses
Authorization: Bearer sk_live_...
Use when allowWarehouseDropoff is true and the user wants pickup from a warehouse.
Then create with deliveryMode: "warehouse" and warehouseId from the list. Fill pickupAddress / pickupCoords from the warehouse row (same as the public form).
Service locations (hostels, gates, landmarks)
GET https://business.kiloapp.org/api/v1/service-locations
Authorization: Bearer sk_live_...
Each place includes name, address, coords, category, and a unit config:
| `unit.mode` | Bot behavior |
|---|---|
none |
Use the place as-is |
free_text |
Ask for unit.label (e.g. Room) — required if unit.required |
list |
Offer options from unit.ranges + unit.values (expand ranges into concrete rooms); allow custom only if unit.allowCustom |
Compose the create address like the public form:
{name} — {address} — {unit}
and set pickupCoords / deliveryCoords from that place’s coords (required — do not invent or re-geocode the composed address string).
Coords contract
- Service location: use
coords.lng/coords.lat→{ "lng": …, "lat": … }on create. - Warehouse: use
longitude/latitudethe same way whendeliveryModeiswarehouse. - Free-form addresses: geocode with a real geocoder; never hardcode fake coordinates.
- Unit/room text only changes the address string — keep the same place pin (
coords) after the user picks a room.
Important: service locations are for pickup & delivery meeting points (sender/receiver at a known place). For errands, do not force the hostel/gate picker for the shop — follow errand.enabledModes instead (shop pin, curated link, or photo). The customer's dropoff *can* still use a service location if they live in a known hostel.
Conversation pattern (bots)
GET /capabilities(cache for the session).- If more than one service kind → ask which job (or infer clearly).
- If
pickup_delivery→ optionally load service locations + warehouses; match vague mentions (“Queen’s Hall”) to a place, then ask unit follow-ups. - If
errand→ ask errand mode fields; skip service-location flows for the shop side. - Only then
POST /deliverieswith a complete payload.