Sandbox and testing
The sandbox is a separate Delivr environment to build and test against. It behaves like production, with three differences:
- No real SMS. Recipient messages are recorded, not sent. Use any valid Norwegian phone number, such as
+4791234567, and open the order’strackingUrlto see what the recipient sees. - Robo drivers. Test drivers deliver your on-demand orders in about two minutes.
- Test data only. Never send real customers’ names, phones or addresses.
| Base URL | https://driver-staging-api.delivr.no |
| Tracking pages | https://tracking-stage.delivr.no |
| Keys | Sandbox keys (dmk_…), see Get sandbox access. They never work in production. |
Get sandbox access
Section titled “Get sandbox access”Ask your Delivr contact for a sandbox merchant. Send:
- your company name and organization number, and the market (Norway),
- who should receive the key,
- the scope you need:
ordersto book deliveries, orquotesfor a backend that only prices them (see Scopes), - your webhook URL, if you want webhooks (public HTTPS),
- the fallback policy you want to test, if not the default
recipient_choice.
Delivr creates a sandbox merchant and sends you the API key and, with a webhook URL, its signing secret (whsec_…). Each is shown once, so store them in a secret manager.
Pick a webhook URL that stays the same
Section titled “Pick a webhook URL that stays the same”Only Delivr can change your webhook URL, so use one that does not change:
- a tunnel with a fixed name, such as an ngrok static domain or a Cloudflare named tunnel, to reach your laptop,
- or a request inspector such as webhook.site, to look at events before you have a handler.
A free ngrok URL changes every time you restart it. Until your endpoint is set up, test your handler locally.
Getting set up
Section titled “Getting set up”- Add your stores with
POST /v1/merchant/locations. Robo drivers park at a new store within a minute. - Check your webhook endpoint with
GET /v1/merchant/webhook(409 conflictmeans none is set up yet). - Send a test event with
POST /v1/merchant/webhooks/test, thenGET /v1/merchant/webhooks/deliveriesto see what your server answered.
Robo drivers
Section titled “Robo drivers”Robo drivers park outside sandbox stores, online. Because they are nearby, quotes for your store offer on_demand, and when an order’s goods are released one of them accepts it.
A robo driver behaves like a real driver using the Delivr driver app:
| Step | Takes | Status and webhook |
|---|---|---|
| Accepts the offer | A few seconds after the search starts | driver_assigned, order.driver_assigned |
| Drives to the store | About 45 seconds | |
| Arrives and loads, with a pickup photo | 5 to 20 seconds | picked_up, order.picked_up |
| Drives to the recipient | About 45 seconds | |
| Delivers, with a drop-off photo | delivered, order.delivered with proofOfDelivery |
The recipient’s tracking page shows the robo driver moving on the map, just as a shopper would see a real one.
Where robo drivers park
Section titled “Where robo drivers park”The sandbox is shared by every integrator, and so are its robo drivers:
- Stores are grouped into cells of about 100 m. Stores of different merchants at the same address share a cell.
- Two robo drivers park in each of the 30 newest cells, counted across all integrators. They return there after each delivery.
- Robo drivers only take Merchant API orders.
So two things can happen:
- Both drivers of your cell are busy, for example because another integrator uses the same address. A quote then has no
on_demandoption until one is back. Wait a few minutes, or use a store at another address below. - Your store has dropped out of the 30 newest cells because others added stores since. Its quotes stop offering
on_demand. Add a new location (a newexternalStoreId) at another address, and robo drivers park there within a minute. Locations cannot be removed, so give test stores clear names.
Test addresses
Section titled “Test addresses”These Oslo addresses are in the national address register, so they work without coordinates. Each store address is in its own cell.
| Use as a store | Use as a delivery address |
|---|---|
| Akersgata 45, 0158 Oslo | Karl Johans gate 22, 0026 Oslo |
| Storgata 1, 0155 Oslo | Møllergata 20, 0179 Oslo |
| Pilestredet 48, 0167 Oslo | Dronning Eufemias gate 16, 0191 Oslo |
| Hegdehaugsveien 31, 0352 Oslo | |
| Bogstadveien 50, 0366 Oslo | |
| Grønlandsleiret 25, 0190 Oslo |
An address that is not in the register answers 422 invalid_address. Check the postal code: Karl Johans gate 22 is 0026, not 0159.
Testing failure paths with directives
Section titled “Testing failure paths with directives”Real drivers read pickup.note. Robo drivers do too, and they follow directives written there. Put one anywhere in the note of the order you place:
{ "quoteId": "…", "option": "on_demand", "externalRef": "test-no-driver-1", "pickup": { "note": "sandbox:no_driver" }, "delivery": { "…": "…" }}| Directive | What the robo driver does | What you can test |
|---|---|---|
| (none) | Accepts and delivers. | The happy path and every status webhook. |
sandbox:no_driver |
Every robo driver declines, and the search ends within seconds instead of after 15 minutes. | failed with reason no_driver, and your fallback policy. |
sandbox:hand_back |
The first driver accepts, sets off and gives the job back. Another driver then delivers it. | A driver handing a job back. For assisted checkout, sale.driver shows reassigning. |
sandbox:stop_en_route |
Accepts and stays on the way to the store. | Cancelling at the driver_en_route fee. |
sandbox:stop_at_pickup |
Accepts, arrives at the store and waits there. | Cancelling at the driver_arrived fee, and goods that are not ready when the driver arrives. |
Directives are not case-sensitive and can sit next to normal text, like "Ask for Kari. sandbox:stop_at_pickup". A store’s pickupInstructions work too, which is handy for a store you only use to test one path. In production, directives are ordinary text that drivers ignore.
A held driver (stop_*) gives the job back after an hour if you do nothing. The order then searches again, and the next robo driver reads the same directive and holds it too. Cancel the order to end the test.
Timings
Section titled “Timings”These are the defaults. A market’s price list or your agreement can set others.
| What | Default |
|---|---|
Quote offered (expiresAt) |
5 minutes |
| Quote grace when you place after expiry | 10 minutes |
| On-demand driver search | 15 minutes, then failed with no_driver |
Ready grace after readyBy |
15 minutes, then failed with goods_not_ready |
| Checkout budget (assisted checkout) | 10 minutes from the driver’s accept |
| Recipient’s window choice (fallback) | 30 minutes (choiceDeadline) |
More things to test
Section titled “More things to test”| Scenario | How |
|---|---|
| Goods not ready | Set your store’s readySignal to required, place an order with a readyBy 5 minutes ahead, and send no ready or processing. You get order.ready_overdue at readyBy, then the order fails with goods_not_ready after the ready grace (15 minutes by default). |
| Packing time | Send POST /orders/{id}/processing {readyAt} a few minutes ahead. The driver search starts so that the driver arrives at about readyAt. |
| Price changes | Place an order on a quote more than 15 minutes old (validity plus grace). Delivr quotes again: you get the order at no more than the quoted price, or 409 price_changed. |
| Free cancellation | Place an order and cancel it before you send ready, while it is still awaiting_goods, with maxFeeMinor: 0. |
| Cancellation fees | Place with sandbox:stop_en_route or sandbox:stop_at_pickup, send ready, wait for driver_assigned, then check GET /orders/{id}/cancellation and cancel. |
| Fallback as recipient | Place with sandbox:no_driver and send ready. Under recipient_choice, open the failed order’s trackingUrl and choose a window, as the recipient would. |
| Webhook retries | Answer 500 from your endpoint, then look at GET /v1/merchant/webhooks/deliveries for the retry schedule. Replay an event with POST /v1/merchant/webhooks/events/{id}/replay. |
| Assisted checkout | Place with sale: "pending", poll until sale.driver is assigned, then complete with POST /orders/{id}/sale. |
Window orders
Section titled “Window orders”Window orders can be quoted, placed, rescheduled and cancelled in the sandbox. Robo drivers do not run window routes, so a window order usually stays scheduled. If you need to see picked_up and delivered on a window order, ask your Delivr contact to run one for you.
Limits and data
Section titled “Limits and data”- The same rate limits apply as in production.
- The sandbox is shared by every integrator, and Delivr may reset its data. Do not depend on old orders being there.
- Prices come from a sandbox agreement and are not your production prices.