# Getting started

There are two ways in, and which one you want depends on whether Bob Go should
know about your orders.

**Ship directly.** Rate a parcel, book the rate you want, follow the shipment.
You do not need an order in Bob Go first.

**Push orders first.** Create the order in Bob Go, then fulfil it. You get the
rest of the platform with it: packing slips, rates at checkout, bulk
fulfilment, waybills, the order history in the dashboard. This is the route to
take when you are integrating a sales channel Bob Go does not support natively.
See [Orders](../6_Orders/README.md).

Either way the shipping half is the same three calls: rates, shipment, waybill.

## 1. Set up

1. Create an API key in the Bob Go dashboard (see [Authentication](../2_Authentication/README.md)).
   The key decides which account every request acts on, so there is no account
   id to send.
2. Point at Sandbox (`https://api.sandbox.bobgo.co.za/v2`) while you build.

In this Bruno collection, select the **Sandbox** environment and fill in
`api_key`. Every request picks it up automatically.

## 2. Get rates

`POST /v2/rates` takes a collection address, a delivery address and one or more
parcels, and asks every courier enabled on your account what they would charge.

The call is synchronous: it waits for the couriers to answer, up to `timeout`
milliseconds. Couriers that fail or time out come back with a status on their
own entry rather than failing the whole request, so always read `status` per
provider before using a rate.

**Send `timeout` on every call.** The maximum is 25 000 and the default is 0:
leave it out and Bob Go checks once, after a fifth of a second, so most rates
come back still `pending`. Send `25000` to wait as long as the API allows,
which is about 20 seconds of polling once the response budget is deducted.

Keep the `id` from the response. If you would rather not hold the connection
open, pass a short `timeout` and fetch the rates afterwards with
[`GET /v2/rates?id=…`](../8_Rates/rate_request.md).

See [Rates](../8_Rates/rates.md).

## 3. Create the shipment

`POST /v2/shipments` books the courier. You pick a rate from the previous
response and pass its `provider_slug` and `service_level_code`, along with the
same addresses and parcels and a contact name for each end.

Only send a `provider_slug` and `service_level_code` that came back in a rate
request. Not every courier serves every address, and booking a service level
that is not available for the lane fails: the shipment is still created, then
ends in `submission_status: "no-rates"`.

Pass `selected_rate_request_id` (the `id` from the rates response) so Bob Go can
tie the booking back to the quoted rate, and check the account has funds for
that rate before it books anything.

Bob Go submits the shipment to the courier asynchronously. The response returns
immediately, and `submission_status` tells you where the submission has got to:

| `submission_status` | Meaning |
| --- | --- |
| `pending-rates` | Queued, waiting for rates. |
| `pending-submission` | Rated, waiting to be sent to the courier. |
| `success` | The courier accepted the shipment. |
| `no-rates` | No rate was available for the service level requested. |
| `failed-will-retry` | The courier call failed; Bob Go will try again. |
| `failed-indefinitely` | The submission failed for good. `failed_reason` says why. |

Treat this as asynchronous state, not a return value. Subscribe to the
`shipment_submission_status/updated` webhook rather than polling, and record the
shipment `id` and `tracking_reference` as soon as you have them.

See [Shipments](../9_Shipments/shipment_create.md).

## 4. Print the waybill

Once `submission_status` is `success`, ask for the label from
[`GET /v2/shipments/waybill`](../9_Shipments/shipment_waybill.md), or a sticker
label from
[`GET /v2/shipments/sticker-waybill`](../9_Shipments/shipment_sticker_waybill.md).

Neither returns the file. You get a JSON envelope with a `download_url` to
fetch, or, for a large batch or a ZPL sticker, instructions to poll or the
label content inline. Check `waybills_ready` before assuming a label exists: a
shipment whose submission has not landed yet has no waybill to print.

Once the courier has accepted it, the shipment's `status` is
`pending-collection`, or `awaiting-dropoff` if you hand it in at a pickup point,
until the courier scans it.

## 5. Follow the shipment

Poll [`GET /v2/tracking`](../10_Tracking%20events/tracking.md) for the
shipment's events, or better, subscribe to
[webhooks](../11_Webhooks/README.md) so Bob Go pushes them to you as they
happen.

If plans change, [`POST /v2/shipments/cancel`](../9_Shipments/shipment_cancel.md)
cancels the booking, as long as the courier has not collected the parcel yet.

## Addresses that rate well

Rating quality depends almost entirely on address quality. Send structured
fields rather than one long string:

```json
{
  "type": "residential",
  "company": "",
  "street_address": "5 Long Street",
  "local_area": "Cape Town City Centre",
  "city": "Cape Town",
  "zone": "Western Cape",
  "country": "ZA",
  "code": "8001"
}
```

- `type` is `business`, `residential` or `locker`, and it affects both price and
  which service levels are available. Leave it out and it is `unknown`.
- `zone` is the province; `code` is the postal code.
- `country` must be `ZA` (or `South Africa`). Bob Go ships domestically.
- Include `lat` / `lng` if you have them and skip our geocoding step.
