# Get account locations

`GET /v2/account/locations`

**Base URLs:**

- Production: `https://api.bobbox.co.za`

**Authentication:** Bearer token required (see the Authentication page).

## Example request

```bash
curl -X GET 'https://api.bobbox.co.za/v2/account/locations' \
  -H "Authorization: Bearer <API_KEY>"
```

Retrieve locker locations available to your account. This is the primary endpoint for external integrators (courier and delivery platforms) to list usable Bob Box locations — for example to show pickup and dropoff points on a map, or to check whether a location can fit a given parcel before creating a reservation.

Only active, non-hidden locker locations are returned by default.

Limits are imposed while an account is frozen — this endpoint then returns `403 Account is frozen`.

### Request

**Method:** GET
**URL:** `https://api.bobbox.co.za/v2/account/locations`

#### Query parameters

| Key | Description | Type | Required |
| --- | --- | --- | --- |
| id | One or more location IDs, passed as a JSON array (e.g. `[213]`). | array of integer | No |
| name | Case-insensitive partial match on the internal location name. Not an exact match. | string | No |
| search_name | Case-insensitive partial match on either the internal `name` or the `human_name`. | string | No |
| lat | Latitude to search near (used with `max_distance`). | float | No |
| lng | Longitude to search near (used with `max_distance`). | float | No |
| max_distance | Maximum distance in km from `lat`/`lng`. Leave it out and a per-location cap applies instead — see below. | float | No |
| order_closest | If true, order results by distance from `lat`/`lng`. | boolean | No |
| min_lat / max_lat / min_lng / max_lng | Bounding box filter, as an alternative to a radius search. | float | No |
| include_availability | If true, include a `compartment_availability` map showing which compartment sizes currently have space. Required to see availability at all. | boolean | No |
| show_hidden | If true, include locations normally hidden from listings. | boolean | No |
| parcel_length / parcel_width / parcel_height | Parcel dimensions in cm. Marks a size `false` unless the parcel fits it. Only has an effect together with `include_availability=true`. | float | No |
| volumetric_weight | Parcel volumetric weight in kg — `length × width × height ÷ 4000`, sides in cm. Used for fit checks when no dimensions are sent. | float | No |
| limit | Limit the number of records returned. Must be 0 or more. | integer | No |
| offset | The number of records to skip (for pagination). Must be 0 or more. | integer | No |
| order_by | Field name to sort by. Must be a valid location field. | string | No |
| order | Sort direction, `asc` or `desc`. | string | No |

**The dimensions and `include_availability` work as a pair.** `compartment_availability` is the only field the dimensions shape, and it is left out entirely unless `include_availability=true`. Send both, or neither.

- **Both sent** — a size is `true` when a compartment of that size is free **and** the parcel fits it.
- **`include_availability` alone** — `true` means only that a compartment of that size is free. No fit check runs.
- **Either way, dimensions never remove a location.** A location can come back with every size `false`. Filter those out yourself.

**What the map does and does not promise about `POST /bob-box/reservations` is documented once**, in the Workflows section under "Checking space before you reserve". Read it before you rely on this field.

**Sending `lat` and `lng` filters more than you asked for.** Two extra rules run whenever both coordinates are present:

- **A distance cap always applies.** Send `max_distance` and you get that radius. Leave it out and each location is capped by its own service range instead, falling back to a platform default. The list is trimmed before you ever see it. **Always send `max_distance`,** so the radius is one you chose.
- **A service-area check runs.** A location that defines a service area is dropped unless your point falls inside it. A location with no service area is always kept.

Together these mean a locker a few hundred metres away can be missing from the result. If you expect a specific locker and do not see it, fetch it by `id` instead of by coordinates.

### Response

**Status code:** 200 OK
**Content-Type:** application/json

**Response body example:**

```json
{
    "bob_box_locations": [
        {
            "id": 213,
            "name": "sandton_city",
            "human_name": "Sandton City",
            "type": "bob-box-locker",
            "description": "Ground floor, near the west entrance.",
            "structured_address": {
                "entered_address": "83 Rivonia Rd, Sandhurst, Sandton, 2196",
                "company": null,
                "street_address": "83 Rivonia Rd",
                "local_area": "Sandhurst",
                "city": "Sandton",
                "zone": "Gauteng",
                "code": "2196",
                "country": "ZA",
                "lat": -26.107567,
                "lng": 28.05304
            },
            "address": "83 Rivonia Rd, Sandhurst, Sandton, 2196",
            "structured_trading_hours": {
                "monday": { "start_time": "09:00", "end_time": "21:00" },
                "tuesday": { "start_time": "09:00", "end_time": "21:00" },
                "wednesday": { "start_time": "09:00", "end_time": "21:00" },
                "thursday": { "start_time": "09:00", "end_time": "21:00" },
                "friday": { "start_time": "09:00", "end_time": "21:00" },
                "saturday": { "start_time": "09:00", "end_time": "18:00" },
                "sunday": { "start_time": "09:00", "end_time": "18:00" },
                "holidays": { "start_time": "", "end_time": "" }
            },
            "trading_hours": "Mon-Fri 09:00-21:00, Sat-Sun 09:00-18:00",
            "compartment_availability": { "Small": true, "Medium": true, "Large": false },
            "s3_image_url": "https://images.bob.co.za/locations/213/main.jpg",
            "s3_image_urls": ["https://images.bob.co.za/locations/213/main.jpg"],
            "status": "active",
            "hidden": false,
            "time_created": "2023-05-02T06:00:00.000000Z",
            "time_modified": "2026-01-10T07:00:00.000000Z"
        }
    ],
    "count": 1
}
```

#### Response fields

| Key | Description | Type |
| --- | --- | --- |
| bob_box_locations | Array of location objects matching the query. | array |
| count | Total number of locations matching the query, ignoring `limit` and `offset`. | integer |

**Location fields:**

| Key | Description | Type |
| --- | --- | --- |
| id | Unique identifier for the location. | integer |
| name | Internal location name. Not a URL slug — both `name` and `search_name` perform case-insensitive partial matches. | string |
| human_name | Display name for the location. Use this in customer-facing UI. | string |
| type | Always the exact string `bob-box-locker` on this endpoint. | string |
| description | Free-text description, e.g. where in the building it is. | string |
| structured_address | Structured address fields. See the table below. | object |
| address | Human-readable address string. | string |
| structured_trading_hours | Per-day opening and closing times (`monday`…`sunday`, `holidays`). Empty start/end time means closed that day. | object |
| trading_hours | Human-readable trading hours string. | string |
| compartment_availability | Map of compartment size to whether space is currently available. Keys are capitalised: `Small`, `Medium`, `Large`. Only present when `include_availability=true`. | object |
| s3_image_url | Primary location image URL. | string |
| s3_image_urls | All location image URLs. | array of string |
| status | `active` or `decommissioning`. | string |
| decommissioning_date | When the location will be decommissioned. ISO 8601 UTC timestamp, only present when `status` is `decommissioning`. See "Decommissioning locations" below. | string (datetime) |
| hidden | Whether this location is excluded from default listings. | boolean |
| time_created | When the location was created. | string (datetime) |
| time_modified | When the location was last modified. | string (datetime) |

**Structured address fields:**

| Key | Description | Type |
| --- | --- | --- |
| entered_address | The address as it was captured, unparsed. | string |
| company | Company or building name at the address. Often `null`. | string or null |
| street_address | Street number and street name. | string or null |
| local_area | Suburb or local area. | string or null |
| city | City or town. | string or null |
| zone | Province. | string or null |
| code | Postal code. | string or null |
| country | Two-letter country code, e.g. `ZA`. | string or null |
| lat | Latitude. | float |
| lng | Longitude. | float |

Every field except `entered_address`, `lat`, and `lng` can come back `null`, so guard before you render.

### Decommissioning locations

The `decommissioning_date` is an ISO 8601 UTC timestamp and is only present on locations with the status `decommissioning`.

When a location is decommissioning:

- Reservations are still allowed up until the `decommissioning_date`.
- Once the `decommissioning_date` has been reached, reservations will no longer be allowed at the location. `POST /bob-box/reservations` then returns `400 location is being decommissioned and is no longer accepting new reservations`.

It is up to the integrator to decide how far in advance of the `decommissioning_date` they would like to stop making reservations to the location. Allow enough lead time for parcels to still be dropped off and collected before the locker is removed.

**This endpoint only ever returns lockers.** `type` is always the exact string `bob-box-locker` — not `locker`. The other location type, `bob-box-counter`, exists in the system but is filtered out here, so you never have to handle it.
