# Test in the sandbox

> What you can try in the sandbox today, how to do it, which test values exist and what does not work yet.

You want to prove that your integration handles every flow before a real clinic is switched on. In the sandbox you create orders from your own code and play the patient yourself on a virtual payment device in the portal. This guide says honestly what that covers: card, Swish and invoice can be tried in different ways, `rivr trigger` gives a `Created` order and with `--complete` one paid by card or Swish or transferred to invoice, and a few things can't be tried at all yet. The checklist before the first clinic says what must be proven. This guide says how.

- Market: Sweden (`se`). Norway differs in currency, payment methods and what happens when nobody pays: https://developers.rivr.io/guides/testing.md?market=no
- Language: English (`en`). Svenska: https://developers.rivr.io/guides/testing.md?lang=sv
- 7 min read · 11 steps
- Page in the portal: https://developers.rivr.io/guides/testing

Every example targets the sandbox (`https://api.test.rivr.io`) and needs test credentials. A platform client's tokens come from `https://auth.test.rivr.io`, an organisation key's from `https://auth.test.rivr.tech`.

## 1. Everything is tried in the sandbox

*Journal system → Rivr*

The sandbox is Rivr's test environment: the same API as in production, with test clinics and no real money. You get tokens from the test environment's auth and list your clinics with `GET /api/public/merchants`. Rivr hands you the platform keys, you create your organisation's own keys under API keys in the portal, and test keys only work here.

An order you create in the sandbox is a real order in the test environment. It gets real webhooks, shows up in the API logs and on the Orders page and goes through the same payment paths as in production. What is simulated is the money.

**Postman.** There is a ready collection per surface, for example `/postman/rivr-api-public.postman_collection.json`, and an environment for the sandbox at `/postman/rivr-sandbox.postman_environment.json`. They are generated from the same specs as the reference, and the reference page has a button for the collection. Import the environment, fill in `clientId` and `clientSecret`, and send the token request first: its test script saves the token for every other request. The environment has only variable names and the sandbox's addresses, never a secret value.

**What your system does:** Follow the guide Connect as a platform if you don't have a token yet, and stay with the sandbox's addresses in all the code you try out.

## 2. Create test orders

*Journal system → Rivr*

There are three ways. The first is what you will use in production: `PUT /api/public/orders/{id}` from your own code. The second is the Orders page in the portal, with "Create test order". The third is `rivr trigger`, which creates an order of 250 kr (`--amount <minor>` changes the amount in minor units, `--merchant <id>` picks the clinic) with your relay URL as `callbackUrl`. With `rivr trigger --complete` the CLI also pays the order on your own virtual device, without a browser: by card by default, with Swish (`--method swish`) or by invoice (`--method invoice`). The CLI waits for `Completed` with card and Swish, and for `Pending` with invoice. `--outcome declined` or `--outcome aborted` gives a declined or aborted card payment and applies to card only. If the outcome is not the one you asked for, the CLI exits with an error code.

An order from `rivr trigger` and from the portal has one line and no customer: no personal number, no phone and no email. The exception is `--method invoice`, since an invoice needs a customer: that order carries the sandbox's test person (see the invoice step below). If you need those fields yourselves, for example for the patient to identify themselves on the device, create the order with your own call.

**From the terminal.** `rivr api <GET|POST|PUT> <path>` calls the sandbox's API as one of your clinics, and the portal sets the authorisation for you, so you handle no token. `--data '<json>'` or `--data @file.json` gives the body, `--merchant <id>` picks the clinic (the first in your organisation otherwise) and `--idempotency-key <key>` sends the `Idempotency-Key` header. The answer is formatted JSON with the status, the `Rivr-Request-Id` when the API sent one and the body, and the exit code is 1 for a 4xx or 5xx answer. Only paths under `/api/public` go through, and a write needs the same permission as the Orders page. `rivr orders get <id>` reads an order, and `rivr orders list` lists the newest. `/api/public` has no order list, so it is the list on the Orders page. That is for when you are signed in. In CI, where there is no browser to sign in with, set `RIVR_CLIENT_ID` and `RIVR_CLIENT_SECRET` to the `client_id` and `client_secret` of an organisation key: `rivr api`, `rivr orders` and `rivr whoami` then call the API directly with the key, and `--organization <id>` is the `Rivr-Organization` header. The secret is read from the environment only, never from an option.

> **Warning.** In the standard flow a text with a payment link is sent at once to the number in the order. Use your own number, or send the `disableNotifications` hint with the value `"true"` and neither text nor reminder goes out. The invoice step still runs if the order stays unpaid.

**Order status:** `Created` · **The journal shows:** Unpaid

**Request:** `PUT /api/public/orders/7b1e7c3a-2f4d-4a51-9c7e-5d0a6b8e2c14` · Merchant token · [Reference](https://developers.rivr.io/reference/api-public/createOrder.md)

```bash
curl -X PUT https://api.test.rivr.io/api/public/orders/7b1e7c3a-2f4d-4a51-9c7e-5d0a6b8e2c14 \
  -H "Authorization: Bearer $MERCHANT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "id": "7b1e7c3a-2f4d-4a51-9c7e-5d0a6b8e2c14",
  "merchantId": "MERCHANT_ID",
  "reference": "visit-48213",
  "personalNumber": "195001182046",
  "phone": "+46701740605",
  "email": "patient@example.com",
  "currencyCode": "SEK",
  "orderLines": [
    {
      "description": "Samtal 45 min",
      "quantity": 1,
      "unitPriceExclVat": 950,
      "vatPercentage": 0,
      "discountExclVat": 0
    }
  ],
  "callbackUrl": "https://journal.example.com/webhooks/rivr",
  "metadata": { "bookingId": "48213" }
}'
```

**In the portal:** [Create a test order on the Orders page](https://developers.rivr.io/orders)

## 3. Test data: never real people

*Journal system → Rivr*

Use only made-up details for patients in the sandbox. Real patients' personal numbers, names, phone numbers and email addresses don't belong there, and neither does your own personal number. Your own phone number or email address is fine when you want to see a message arrive.

- **Swedish personal numbers:** Skatteverket's published test personal numbers. They are blocked and never assigned to anyone. A few examples: `195005050975`, `196503184589`, `197205169266`, `198005032399`, `198805012393`, `199505012394`, `200105012389` and `201005022387`. The whole list is published by Skatteverket as open data (Testpersonnummer).
- **Norwegian identity numbers:** only synthetic numbers, that is reserved test persons (month + 65) and test numbers from Test-Norge or Tenor (month + 80). Never an F-, D- or H-number: Norwegian health care gives H-numbers to real patients.
- **Phone:** the Swedish regulator's series for fictional use, `070-1740605` to `070-1740699`, or your own number if you want to see the text message.
- **Email:** an address at `example.com`, or your own.
- **Card:** the virtual device's simulated card reader, or Adyen's published test cards in the web checkout.

**Sandbox clinics** that Rivr sets up for you accept only test identities. Any other personal number is refused with 422 and the code `personal_number_not_test_identity` before anything is created, for an order as well as a subscription.

**Why:** The customer is a shared record per personal number in the test environment. An order with a real personal number can bring back details someone else stored about that person, and then you have read personal data you shouldn't have.

## 4. See the webhooks on your own machine

*Rivr → Journal system*

Rivr delivers to `callbackUrl` on the order, and in the sandbox the portal can be the receiver. Install the CLI with `curl -fsSL https://developers.rivr.io/cli/install.sh | sh` on macOS and Linux or `irm https://developers.rivr.io/cli/install.ps1 | iex` in PowerShell on Windows; it needs Node.js 18 or later. `rivr login` approves the CLI in the browser, and `rivr listen --forward-to http://localhost:4000` prints a relay URL that is yours and does not change. Set it as `callbackUrl` on your test orders and every delivery is forwarded to your machine byte for byte, with `Rivr-Signature` untouched. Deliveries that arrive while nothing listens are kept, the last 50 for at most an hour, and replayed when you connect. `rivr serve --secret <key>` is a throwaway receiver that verifies the signature for you. `rivr verify --url <address>` instead probes your own receiver with eight checks in signed test deliveries (a correct one, a duplicate with the same `Rivr-Webhook-Id`, one with a wrong signature, one with a `t` that is too old, one with no `Rivr-Signature`, a second, different event, one whose `Reference` and `metadata` have å, ä and ö as JSON escapes, and one order sent as `Completed` before `Created`) and tells you for each whether the receiver answered as it should: `2xx` for the correct one, for the duplicate, for the second event, for the escaped delivery and for both deliveries of the order, all within five seconds, and `4xx` (preferably `401`) for the three that should be refused. Five of the checks are the ones that most often fail: idempotency (the duplicate must be acknowledged with `2xx`, not refused, since Rivr resends with the same id), an expired signature (a `t` older than 300 seconds must be refused, or a recorded delivery can be sent again), a quick answer (answer within five seconds and do the work afterwards), the raw bytes (the signature is computed over the bytes that came, not over JSON that has been parsed and written again, since Rivr writes characters outside ASCII as JSON escapes) and the order (`Completed` can arrive before `Created`, so both must get `2xx`). The last line, which is printed only when all eight passed, and `checks` in `--json` name the checks that ran. The secret is read from `RIVR_WEBHOOK_SECRET`, nothing goes to Rivr, and the exit code is 1 when a probe fails, so the command runs in CI.

**One order at a time.** `rivr send <status> --url <address>` sends a single test delivery of an order event (`created`, `pending`, `completed`, `cancelled` or `refunded`) with the body Rivr writes for that status, and prints the order's id: `--order <id>` makes the next `send` an event about the same order, with the same `merchantId` and `CreatedDate`. `rivr verify --sequence <name> --url <address>` runs, instead of the eight checks, a sequence of events about one order (`invoice-paid`, `refund`, `cancel`, `out-of-order`, `late-duplicate`, where the first `Completed` comes again with the same `Rivr-Webhook-Id` after `Refunded`, and `same-status`, where `Completed` comes twice with different ids), checks that every delivery gets `2xx` and says at the end which status the order should have in your journal, which the CLI cannot see. That holds for a receiver that takes the status from the webhook: one that fetches the order from Rivr finds none for the invented ids (`/api/public` answers `204`) and keeps no row, which is right. Neither goes to Rivr: the deliveries are signed with your own secret in `RIVR_WEBHOOK_SECRET` and are not deliveries from Rivr.

The Webhooks page shows the deliveries and attempts per order. For your organisation's own endpoints "Send test" sends a correctly signed test delivery and shows that your receiver answers `2xx` to it. The test delivery stores nothing. Whether a wrong, a missing and an old signature are refused is what `rivr verify` checks. Verify `Rivr-Signature` before you recognise a test delivery by `Rivr-Webhook-Test: true`: the deliveries from `rivr verify` that should be refused carry the marker too. A firewall or limit that shuts out a sender after a few `401`s can stop Rivr's real deliveries too. A `Rivr-Signature` comes along on the `callbackUrl` path only when a signing key exists for the clinic or the platform.

**The patient journey as a test suite.** `rivr journey --forward-to <your receiver>` runs five scenarios from a clinic's day with a real test order each: the patient pays by card, the card is declined, the patient pays with Swish, takes an invoice, and the clinic cancels before the patient pays. Every webhook Rivr sends for the order goes on to your receiver with the same bytes, `Rivr-Signature` and `Rivr-Webhook-Id`, and the CLI says for every check whether it is Rivr's side (the payment ended right and the webhooks came, signed) or yours (the receiver answered `2xx` within five seconds to every signed delivery, and to the same delivery once more as Rivr retries it, which needs every key Rivr signs with in `RIVR_WEBHOOK_SECRET`, separated by commas). The exit code is 1 when your receiver fails, 2 when only Rivr's side did (the line says whether to run it again, what to set up, such as a signing key, or that Rivr sent a webhook it should not have) and 3 when the journey could not run. It runs with your sign-in to the portal, not with an organisation key. `rivr journey --list` shows the scenarios.

**What your system does:** Verify the signature, answer `2xx` within five seconds and deduplicate on `Rivr-Webhook-Id`, as in the guides Receive webhooks and Verify the webhook signature.

**Order status:** `Created` · **The journal shows:** Unpaid

**Webhook to you** (`Created`)

```http
POST /webhooks/rivr
Content-Type: application/json
Rivr-Signature: t=1789640080,v1=5f2b0c…

{
  "id": "7b1e7c3a-2f4d-4a51-9c7e-5d0a6b8e2c14",
  "type": "Order",
  "merchantId": "MERCHANT_ID",
  "status": "Created",
  "data": {
    "CreatedDate": "2026-09-17T09:12:03Z",
    "Reference": "visit-48213",
    "Metadata": { "bookingId": "48213" }
  }
}
```

**In the portal:** [See the deliveries](https://developers.rivr.io/webhooks)

## 5. Play the patient on the virtual device

*Patient → Rivr*

A payment is completed by a patient, and in the sandbox that patient is you. Under Test there is the virtual device, a Rivr payment device in your browser. It registers against the test environment, sends heartbeats, receives real orders and starts real payments. It shows up in `GET /api/public/devices`, so `POST /api/public/orders/{id}/send-to-device` or the `device` hint from your own code makes the order appear on the screen.

Or tap "Betala besök" (pay for a visit) and key in the personal number on the order: the device looks up the unpaid orders. The rocket on the start screen creates a demo order for the device, and it exists only in the test environment. Which payment methods the device shows depends on the clinic's settings and market, as in the guide Payment at the clinic.

> **Warning.** The virtual device is only driven from a signed-in browser session in the portal, and it requires permission to create orders. A CLI token and the organisation's API keys are not let in on its routes. From the CLI it works by card, Swish and invoice, through `rivr trigger --complete` on your own device. From code there is no way to complete a payment.

**Request:** `POST /api/public/orders/7b1e7c3a-2f4d-4a51-9c7e-5d0a6b8e2c14/send-to-device` · Merchant token · [Reference](https://developers.rivr.io/reference/api-public/sendOrderToDevice.md)

```bash
curl -X POST https://api.test.rivr.io/api/public/orders/7b1e7c3a-2f4d-4a51-9c7e-5d0a6b8e2c14/send-to-device \
  -H "Authorization: Bearer $MERCHANT_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{ "deviceId": "DEVICE_ID" }'
```

**In the portal:** [Open the virtual device](https://developers.rivr.io/device)

## 6. Pay by card: the simulated card reader

*Patient → Rivr*

The virtual device has no physical card reader, so it gets a simulated one: "Attach a simulated card reader" creates a simulated terminal and attaches it to the device. Beside the screen you choose what the next card payment gives: `Approved` (the default), `Declined`, `Aborted` or `Timeout`. The choice applies to the next payment only, and then the reader is back on `Approved`.

The outcome arrives about two seconds after you pick card, through the same handlers as a real terminal. `Approved` makes the order `Completed`, and the webhook arrives. `Declined` gives the declined screen and no `Completed`. `Aborted` closes the payment attempt without anything being approved. `Timeout` publishes nothing: the order is left untouched and the screen waits.

**What your system does:** Try all four outcomes against your receiver. `Timeout` is the one most often forgotten: the order stays unpaid and no webhook comes, so the journal must not change anything.

> **Note.** No card number is ever needed here, and there are no test card numbers that decide the outcome. The outcome is chosen in the panel. The sandbox's web checkout runs against Adyen's test environment and takes Adyen's test numbers for online payments, for example Visa 4111 1111 4555 1142 and Mastercard 5555 3412 4444 1115, with expiry 03/30 and CVC 737. A physical test terminal takes Adyen's test cards: Visa 4111 1100 0392 0001 (03/30) and Mastercard 5413 3300 8909 9999 (02/28), CVC 737 and PIN 1234.

**Order status:** `Completed` · **The journal shows:** Paid

**Webhook to you** (`Completed`)

```http
POST /webhooks/rivr
Content-Type: application/json
Rivr-Signature: t=1789640080,v1=5f2b0c…

{
  "id": "7b1e7c3a-2f4d-4a51-9c7e-5d0a6b8e2c14",
  "type": "Order",
  "merchantId": "MERCHANT_ID",
  "status": "Completed",
  "data": {
    "CreatedDate": "2026-09-17T09:12:03Z",
    "Reference": "visit-48213",
    "CompletedDate": "2026-09-17T09:14:40Z",
    "PaymentMethod": "Card",
    "Metadata": { "bookingId": "48213" }
  }
}
```

## 7. Swish and the payment link

*Patient → Rivr*

Swish on the device gives a real QR code from the API. Which provider carries Swish is a setting per platform in Rivr's configuration, Rivr or Adyen, and the device follows it. How the payment gets paid depends on the provider.

**Rivr's own Swish.** Outside production it talks to Swish's simulator, with Swish's test certificate and a test account as the payee. The simulator does the paying: it sends a simulated result to Rivr's callback on its own, and nobody needs to pay the QR code. The order then becomes `Completed` with `PaymentMethod: "Swish"`. That path, which the device and the CLI use, has not been measured in TEST yet. The measurement where `PAID` arrived four seconds after the payment was created was made in another of Rivr's Swish integrations.

**Swish through Adyen.** The payment goes to Adyen's test environment. We have not documented how it gets paid there.

**From the CLI.** `rivr trigger --method swish` creates an order, pays it with Rivr's own Swish on your own virtual device and waits for the simulator to make it `Completed`. If no answer comes in time, the CLI answers `no_payment_outcome` and exits with an error code, and the order may still be `Created`. If Adyen carries Swish for the clinic, the CLI answers `method_not_completable` before any order is created, since how the payment gets paid in Adyen's test environment is not established. An order in another currency than SEK gets the same answer, since Swish takes SEK only.

Swish errors can't be provoked. Rivr builds the message sent to Swish, and a partner can't set it, so `Declined` and `Cancelled` from Swish can't be produced in the sandbox.

The payment link is the patient's web checkout in the test environment, at `/o/{shortId}` on the sandbox's site. It opens from "Betala online" (pay online) on the device or as the order's checkout link on the Orders page. Vipps, for Norwegian clinics, gives a QR code that points to Rivr's payment page in test. We have not documented what it takes to complete it in Vipps' test environment.

**Order status:** `Completed` · **The journal shows:** Paid

**Webhook to you** (`Completed`)

```http
POST /webhooks/rivr
Content-Type: application/json
Rivr-Signature: t=1789640080,v1=5f2b0c…

{
  "id": "7b1e7c3a-2f4d-4a51-9c7e-5d0a6b8e2c14",
  "type": "Order",
  "merchantId": "MERCHANT_ID",
  "status": "Completed",
  "data": {
    "CreatedDate": "2026-09-17T09:12:03Z",
    "Reference": "visit-48213",
    "CompletedDate": "2026-09-17T09:14:40Z",
    "PaymentMethod": "Swish",
    "Metadata": { "bookingId": "48213" }
  }
}
```

## 8. Invoice and instalments

*Patient → Rivr*

**Invoice.** If you choose Invoice on the device and key in an email and a phone number, the order becomes `Pending` ("transferred to invoice"), and the `Pending` webhook arrives. The order becomes `Completed` only when the invoice is paid, and in the sandbox there is no function that marks an invoice paid. You can therefore try `Pending`, but not what comes after it.

**From the CLI.** `rivr trigger --method invoice` does the same without a browser. An invoice needs a customer with a name and a personal number, so that order carries the test person `195001182046`: one of Skatteverket's test personal numbers, and the same one the demo order from the device's rocket uses. The test environment gives the person a made-up name. The device keys in `demo@example.com` and `070-1740607`, and the order carries the `disableNotifications` hint, so no payment link is sent. The CLI waits until the order is `Pending` and shows the delivery of the `Pending` webhook to your relay URL. If the order does not offer Rivr's own invoice, for example only Avarda invoice, the CLI answers `invoice_not_offered`.

**Avarda invoice (30 or 90 days) and instalments.** They run a credit check on the personal number in the order. If the check is declined the device shows a screen of its own, and the patient can choose another payment method. We have not documented any personal number that gives an approved check in the sandbox, so don't count on being able to complete these payment methods there yet.

> **Rule.** For `Completed` after `Pending` you have to try your receiver with a delivery of your own. The body is in the guide Receive webhooks, and signed examples exist as test vectors in the guide Verify the webhook signature. Never move the receivable on `Pending`.

**Order status:** `Pending` · **The journal shows:** Unpaid — invoice sent

**Webhook to you** (`Pending`)

```http
POST /webhooks/rivr
Content-Type: application/json
Rivr-Signature: t=1789640080,v1=5f2b0c…

{
  "id": "7b1e7c3a-2f4d-4a51-9c7e-5d0a6b8e2c14",
  "type": "Order",
  "merchantId": "MERCHANT_ID",
  "status": "Pending",
  "data": {
    "CreatedDate": "2026-09-17T09:12:03Z",
    "Reference": "visit-48213",
    "Metadata": { "bookingId": "48213" }
  }
}
```

## 9. Cancel, refund and the clock

*Journal system → Rivr*

`Cancelled` and `Refunded` you get from your own code: `POST /api/public/orders/{id}/cancel` on an unpaid order and `POST /api/public/orders/{id}/refund` on a paid one, with an `Idempotency-Key`. Both also work on the Orders page, and from the terminal with `rivr orders cancel <id>` and `rivr orders refund <id>`. They send a new `Idempotency-Key` unless you give one with `--idempotency-key`, and print it, so you can repeat the call with the same key. The refund is for the whole order: the API has no partial refund, so the command takes no amount. See the guide Cancel and refund.

The clock cannot be shortened. The standard flow sends a text with a payment link at once, a reminder after 1,440 minutes (24 hours) and the invoice step after 1,800 minutes (30 hours). The times are the clinic's configuration, not a parameter of the call, and nothing in the API or the portal shortens them. Settlements are created at 00:00 and payouts at 04:00: if you pay during the day you fetch the settlement the next day.

**Request:** `POST /api/public/orders/7b1e7c3a-2f4d-4a51-9c7e-5d0a6b8e2c14/refund` · Merchant token · [Reference](https://developers.rivr.io/reference/api-public/refundOrder.md)

```bash
curl -X POST https://api.test.rivr.io/api/public/orders/7b1e7c3a-2f4d-4a51-9c7e-5d0a6b8e2c14/refund \
  -H "Authorization: Bearer $MERCHANT_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)"
```

## 10. Connect a sandbox clinic without BankID

*Journal system → Rivr*

The account connection can be tried without a real sign-in. The staff at sandbox clinics are test identities who can't sign in with BankID, so the sandbox has a simulated approval: `POST https://test.rivr.io/api/clinic-connect/sandbox/approve`, server to server, with `request` from the answer to `GET /oauth/authorize`, the sandbox clinic's `merchantId`, `clientId` and the client's secret in `clientSecret`. The answer is `redirectUrl`, with the code and your `state`, and everything after that is the real flow: your code exchange, `merchant_token` and the disconnection.

The approval exists in the sandbox only, and there is no test panel on Rivr's page. It needs Rivr to have registered your address and switched the connection on for your test platform. A real BankID sign-in also works, if Rivr adds your developer as staff on a sandbox clinic. A test clinic that isn't a sandbox clinic can only be picked once it is ready to take payments. The whole flow is in the guide Connect a clinic that already has a Rivr account.

**In the portal:** [The guide on the account connection](https://developers.rivr.io/guides/connect-clinic-account)

## 11. What does not work yet

*Rivr → Journal system*

**Choosing the outcome in the call itself.** There are no magic card numbers and no outcome to send in the `PUT`. The outcome for card is chosen at the virtual device or with `rivr trigger --complete --outcome …`, and it is the only outcome you can control.

**Paying from code, and with some payment methods from the CLI.** From your own code there is no way to complete a payment. `rivr trigger --complete` pays a `Created` order by card or with Rivr's own Swish, or transfers it to Rivr's own invoice. Swish through Adyen, Avarda invoice, instalments and Vipps still need the virtual device in a browser.

**Going from `Pending` to `Completed`** with an invoice, or getting an approved credit check for Avarda invoice and instalments.

**Shortening or winding the clock forward:** the reminder, the invoice step and the settlement.

**Payment methods without a route on the virtual device:** Trustly, Apple Pay and Google Pay, and Medical Finance are not shown there. Vipps can be started but is not documented as completable.

**Trying an onboarding with an invented signatory.** See the guide Connect a clinic from your system.

**What your system does:** Plan what can't be tried here together with Rivr, and write down what you have proven and how. What remains is proven with the pilot clinic.

## Common pitfalls

- Letting test orders send texts. The standard flow sends a text with a payment link at once to the number in the order. Use your own number, or the `disableNotifications` hint.
- Reading a `Timeout` as a bug in your code. The simulated card reader publishes nothing then: the order is unchanged, and no webhooks come.
- Forgetting that the outcome is one-shot. After a `Declined` the card reader is back on `Approved`, so the next payment goes through unless you choose again.
- Expecting more than `Created` from `rivr trigger` without `--complete`. The rest of the lifecycle needs a payment: add `--complete`, or pay on the virtual device.
- Expecting `Completed` from `rivr trigger --method invoice`. The invoice makes the order `Pending`, and it becomes `Completed` only when the invoice is paid, which nobody does in the sandbox.
- Waiting to pay the Swish QR yourself in a Swish app. With Rivr's own Swish in TEST, Swish's simulator does the paying, after a few seconds. How a Swish through Adyen gets paid in Adyen's test environment is not documented.
- Retrying `rivr orders cancel` or `rivr orders refund` without the key from the first run. Every run gets a new `Idempotency-Key`, so a retry without it is a new call: give the printed key with `--idempotency-key`.

## Next guide

- [The checklist before the first clinic](https://developers.rivr.io/guides/go-live.md): What must be proven in test before a real clinic is switched on.
- [Cancel and refund](https://developers.rivr.io/guides/cancel-refund.md): Cancel an unpaid order, pay back a paid one — and wait for the webhook.
