> ## Documentation Index
> Fetch the complete documentation index at: https://docs.paywise.de/llms.txt
> Use this file to discover all available pages before exploring further.

# Sandbox environment

> Build and rehearse an integration against api-sandbox.paywise.de with sandbox-only credentials, know which effects the sandbox deliberately does not produce, and fix the usual mix-ups fast.

The paywise sandbox is a full, separate installation of the platform for
**building and rehearsing an integration**. It runs the same code and the same
contracts as production against its own data.

## Sandbox versus production at a glance

| | Sandbox | Production |
| - | - | - |
| API host | `https://api-sandbox.paywise.de` | `https://api.paywise.de` |
| Portal host | `https://sandbox.paywise.de` | `https://app.paywise.de` |
| Key prefix | `pw_sbx_` | no environment prefix |
| `X-Paywise-Environment` response header | `sandbox` | `production` |
| Who issues keys | your developers, in the sandbox portal under *Für Entwickler* | your developers, in the production portal under *Für Entwickler* |
| Outbound mail and letters | captured in the mail log, never delivered | delivered to debtors and recipients |
| Money movement | none | real |
| Transfer to case management | never; you accept orders yourself | on acceptance by paywise |
| Bookkeeping integrations | cannot be connected | available |
| Reset available | yes — a pure wipe from the sandbox portal; nothing is re-created | no |

The base paths are unchanged: `/v2/` for the Case Management API,
`/partner/v2/` for the Partner API, `/mahnservice/v1/` for the
[Mahnservice API](/api-docs/mahnservice-api/introduction). Point your client at
the sandbox host and everything else in this documentation applies.

## Which entry path do I need?

| I want to… | Use | What it is for |
| - | - | - |
| Call the API from my code, a test suite, or Postman | a `pw_sbx_` key against `https://api-sandbox.paywise.de` | Everything the contract offers: submitting orders, following mandates, reporting payments, subscribing webhooks. The sandbox host serves exactly the production routes — nothing more. |
| Issue or revoke sandbox keys, read the request log or the mail log, inspect webhook deliveries, play the counterparty (accept an order, advance a case, book a debtor payment), apply example data, run a playbook, reset the sandbox | the sandbox portal, entered by single sign-on from the production portal (*Für Entwickler* → *Zur Sandbox*) | The operator's view of your sandbox: what your integration sent, what the sandbox suppressed, and the controls that exist only here — see the [sandbox drawer](#sandbox-drawer). |

Both paths lead to the same tenant. A key issued in the sandbox portal calls
the sandbox API; what that call did is visible in the same portal's request
log — each API keeps its own: *Für Entwickler → Case Management API →
API-Monitoring → Request-Log* for Case calls, the equivalent Partner API page
for Partner calls, and *Mahnservice → Für Entwickler → API-Monitoring* for
Mahnservice calls. The docked [sandbox drawer](#sandbox-drawer)'s
*Request-Log* tab shows the most recent calls of every API together in one
place.

## Credentials

Sandbox API keys are issued **in the sandbox portal**, under *Für Entwickler*,
exactly as production keys are issued in the production portal. They carry the
prefix `pw_sbx_`, so a mixed-up key is recognizable at a glance:

```http theme={null}
GET /v2/info/ HTTP/1.1
Host: api-sandbox.paywise.de
Authorization: Bearer pw_sbx_0123456789abcdef0123456789abcdef01234567
```

Sandbox and production credentials are **not interchangeable**. A `pw_sbx_` key
sent to `api.paywise.de` is rejected with `401`, and a production key sent to
the sandbox host is rejected the same way. Never infer the environment from a
key or from a response field — infer it from the host you configured, and keep
the two configurations apart.

There is no separate signup on the sandbox host. Sign in to the production
portal and enter the sandbox through single sign-on (*Für Entwickler* → *Zur
Sandbox*). No separate sandbox admission or setup by paywise is required.
Case Management and Mahnservice access are fully self-serve. Partner API
controls become available after you submit the *Partner-API anfragen* form
under *Für Entwickler* → *Partner werden* and receive paywise sign-off; issuing
Partner keys is self-serve after that.

## Set up Mahnservice without production checkout

Mahnservice configuration is sandbox-native and is not copied from production.
To create your sandbox default flow, open *Mahnservice* → *Erste Schritte* → *Mahnlauf einrichten*
in the sandbox portal. At step 4 (*Speichern*), choose **Mahnlauf speichern**. This
creates the default dunning configuration without buying a subscription,
entering a payment method, or connecting bookkeeping. Saving and activating
are separate: API release creates a `pending` process until the flow is
activated. After saving, choose *Weiter*, then *Mahnlauf prüfen und aktivieren*
on *Erste Schritte*. The [Mahnservice quickstart](/api-docs/mahnservice-api/quickstart)
then walks through submitting invoices through the API and checking document
scanning before release.

Production payment setup is not a prerequisite for this sandbox rehearsal.
If you configure a production Mahnlauf, it is saved before checkout, and
leaving checkout keeps that configuration for resuming later; actual
production use still requires the subscription and payment setup.

## What the sandbox does

* **The same contracts.** Same routes, same request and response shapes, same
  typed errors, same idempotency and pagination rules.
* **Your own configuration.** Entering the sandbox copies your company profile,
  the entering user's membership, the company's notification recipients, and
  that user's own notification recipients.
  Mahnservice configuration is sandbox-native; the sandbox grants a synthetic
  entitlement independently of whether you purchased the product in production.
* **Real lifecycles.** Orders can be submitted and accepted, mandates followed,
  invoices held, corrected and released, dunning ladders advanced, payments
  reported, webhooks delivered to your endpoint.
* **Records are labelled.** Companies and users carry a read-only
  `sandbox_origin`: `sandbox_native` for something created inside the sandbox,
  `production_mirror` for something copied from your production tenant.
* **Reset.** The sandbox portal can wipe your sandbox back to empty, so a
  rehearsal can be repeated from a known starting point. Apply a seed pack
  afterward if you want example data back.

## Fixed behaviour you can rely on

These are not side effects of the current build; they are the sandbox's
contract, and a test suite can depend on them:

* **Mail is captured, not lost.** The sandbox sends no e-mail to debtors or
  other third parties. Mahnservice mail and the invitation and setup mails of
  your company's users are recorded in the sandbox mail log, with recipient,
  template, delivery or suppression reason, and timestamp. Their content and
  open invitation links are visible to your company's administrators only.
  Password-reset mail never appears there.
* **Real HTTPS webhook delivery.** Register a public HTTPS receiver in the
  sandbox portal or API. For a disposable receiver, use the unique URL from
  [webhook.site](https://webhook.site/). The sandbox signs and sends real HTTP
  requests; destinations follow the same public-address and no-redirect rules
  as production. See [Test a sandbox delivery](/api-docs/essentials/webhooks#test-a-sandbox-delivery).
* **Reset is a pure wipe and clears the request log.** After a reset your
  sandbox company is empty and the request log and mail log are empty — every
  API's own Request-Log page and the drawer's Request-Log tab alike; nothing
  is re-created. API keys and webhook subscriptions survive. Apply a seed pack
  (below) to get example data back. Read the request log before you reset if
  you are diagnosing a failed call — open the specific API's own page
  (Case, Partner or Mahnservice), since that is what has the row you're
  looking for.
* **Orders are never auto-accepted.** In production, paywise reviews and
  accepts a submitted order. The sandbox waits for you: accept the order in
  the sandbox drawer (*Kontext* → *Auftrag annehmen*), as shown in
  [quickstart step 4](/api-docs/case-management-api/quickstart#4-accept-the-order-in-the-sandbox).
* **Unknown paths answer JSON.** A path that does not exist on the sandbox
  host answers the surface's ordinary JSON `404 not_found` — the same envelope
  as production, with an `X-Paywise-Request-Id` and a row in the request log.
  The request log stores what you sent, with two escapes: a NUL byte is
  stored as U+FFFD and a lone surrogate as its `\uXXXX` escape. The query
  parameters `q`, `search`, and `email` are left out of the stored query
  string. Sandbox request-log rows are kept for 30 days, or until a reset.

## Sandbox drawer

The counterparty side of a rehearsal — everything paywise or a debtor would
normally do — is simulated in the sandbox portal, never through the API. The
portal's docked **sandbox drawer** (the amber *Sandbox-Tools* button at the
lower right of every account page, or `Alt+S`) has three tabs:

* **Kontext** follows the page you are on. On an order it offers *Auftrag
  annehmen*, *Auftrag ablehnen* (with a reason the client sees), and
  *Rückfrage* (a request to the client with the answer types it allows). On a
  mandate it offers *Nächste Mahnstufe*, *Verfahrenswahl* (the
  procedure-choice request a negative credit report raises), *Zahlung des
  Schuldners an paywise* — the full open balance or a partial amount,
  optionally issuing a statement — *Rückfrage*, and the closing actions
  (withdrawn, cancelled, expired, transfer failed, activated). On the order
  and mandate lists a picker hosts the same panel for any listed case. Each
  panel ends with a *Playbook* section (below).
* **Werkzeuge** holds *Beispieldaten* (example data), *Playbooks*, *Sandbox
  leeren* (reset), *Webhooks ausprobieren*, which opens a disposable
  [webhook.site](https://webhook.site/) receiver, and the *E-Mail-Log* of
  captured Mahnservice mail and user invitations.
* **Request-Log** is a live, condensed view of the most recent public-API calls
  this company made in the sandbox, with a link to the full request log.

Every action simulates what the counterparty would do: the page behind the
drawer updates in place, and the same webhooks fire as the real event would
fire in production. An action that does not fit the case's current state
changes nothing and says why — an order still in draft cannot be accepted, a
closed case (cancelled, archived, or ended, including ended by an earlier
full payment) takes no further payment or request to client, and a payment
larger than the open balance is refused. Rehearse a late payment on the open
case, before you close it.

### Example data (seed packs)

A sandbox company starts **empty** — entering the sandbox does not copy in
any demonstration cases. *Werkzeuge → Beispieldaten* applies one of two
opt-in packs:

* **Referenzdaten** — four fixed cases with stable references
  (`SBX-CLAIM-0001` to `0003`, `SBX-ORDER-0004`): active with an open request,
  settled with a statement, in dunning, and one pending order. For a partner
  company, applying it also fills the seeded reference client with the same
  four cases.
* **Beispielportfolio** — about twenty generated cases: every playbook
  (below) run three times with varied amounts and debtors, plus two pending
  orders. Use it for lists, filters, and pagination.

Applying a pack is idempotent: an already-applied pack shows its counts
instead of creating anything a second time. Seeding never fires a webhook,
unlike a playbook run (below) — it is example data appearing in your
sandbox, not simulated counterparty activity.

### Playbooks

A playbook is a named scenario that drives a case through the simulation
actions above, so you do not have to click every stage yourself. Seven are
available:

* **Schnellzahler** — accepted, first dunning letter, then the debtor pays
  paywise in full and a statement is issued.
* **Ratenzahler** — accepted, then three partial payments to paywise across
  two dunning stages until settled.
* **Mahnverfahren** — accepted, then the whole dunning ladder up to the
  court dunning order.
* **Negative Bonität** — accepted, two dunning stages, then a negative credit
  report raises the procedure-choice request; ends awaiting your answer.
* **Rückfrage** — accepted, then paywise raises a request to the client;
  ends awaiting your answer.
* **Abgelehnt** — paywise rejects the order with a reason.
* **Erfolglos** — accepted, two dunning stages, then paywise closes the
  case as uncollectible.

Under *Werkzeuge → Playbooks*, *Starten* creates a fresh debtor, order, and
invoice and runs the whole scenario; *Schrittweise* runs only its first
step, for a consumer that wants to observe one webhook at a time. The
*Playbook* section at the end of an order's or mandate's *Kontext* panel
attaches a scenario to that existing case instead: it shows which steps the
case already satisfies and runs only the remaining ones — one at a time with
*Nächster Schritt*, or all with *Alle ausführen*. Progress is derived from
the case's state on every read, so manual actions in between are picked up.
The result lists every step and its outcome; a step the case's state refuses
stops the run there with an explanation rather than an error, and a
completed run links to the created order or mandate.

Playbooks fire every webhook a real case passing through the same stages
would — they are simulated counterparty activity, not the silent example
data a seed pack applies.

### Reset the sandbox

A reset (*Werkzeuge → Sandbox leeren*, confirmed by typing the confirmation
phrase) is a **pure wipe**: it deletes every order, mandate, claim, payment,
and statement belonging to your company, its persisted webhook events (the
rows behind its event feed), and clears its request log and mail log. Partner-owned event
rows are not touched by a client's reset; they go with the Partner's own
reset. Nothing is re-created — a partner's seeded reference client is not
deleted by a reset, but it is emptied like every other managed client and
loses its mirrored partner memberships; its company row and fixed user
survive. API keys and webhook subscriptions survive. Apply a seed pack
(above) afterward if you want example data back.

A reset takes the sandbox company's write lock. Wait for the reset to finish
before you send commands for that company: a command that commits before the
wipe is wiped with everything else, and one that commits after it keeps its
data. There is no dedicated error for the overlap.

<Warning>
  A reset clears the request log and does not re-create anything, seeded
  reference client included. Read the log before you reset if you are
  diagnosing a failed call — afterward there is nothing left to read. Apply
  a seed pack after resetting if your rehearsal needs example data.
</Warning>

## Partner keys in the sandbox

A Partner key uses `X-On-Behalf-Of-Company` in the sandbox exactly as in
production, for a managed client whose sandbox it has Case access to. The
Partner API treats a company mirrored from production as source-managed:
`PATCH /partner/v2/companies/{id}/`, `release`, and every membership command
on such a company answer `403 sandbox_source_managed`. Only
`POST /partner/v2/companies/` mints a sandbox-native test company, and those
companies accept every write. A capability refusal raised inside a keyed
command is the ordinary `403` envelope (`sandbox_source_managed` or
`sandbox_feature_unavailable`, with `translation_key`) and releases the
`Idempotency-Key`, so you can retry with the same key once the cause is
fixed.

### Simulate on your clients

Simulation runs only in the drawer of a signed-in portal session and acts on
that session's company; there is no API for it. As a Partner you simulate in
two places:

* **The reference client.** Applying the *Referenzdaten* pack in your Partner
  company creates the seeded reference client and makes every member of your
  Partner company an administrator there. Switch to it in the portal and use
  the drawer.
* **A client you created through the Partner API.** Your Partner users are
  not members of the companies you create. Open the one-time `setup_url` of
  one of that company's users — from the create or resend response, or the
  invite link the sandbox shows on your partner page — set a sandbox
  password, sign in as that user, and use the drawer there. Use a second
  browser session, such as a private window, so that your own session stays
  signed in. Later invitations for that company appear with their link in its
  sandbox mail log.

The sandbox adds no memberships for this, so the Partner API responses you
test are those of production.

## What the sandbox does not do

* **Nothing leaves the building.** No e-mail or letter reaches a debtor, no
  money moves, and nothing is transferred to the debt-collection system. A
  dunning notice that the sandbox suppresses is still recorded as sent and the
  ladder still advances, so the sequence you are integrating against behaves
  normally; the message itself is captured instead of delivered. Captured
  mail — Mahnservice notices and your company's user invitations — is readable
  in the sandbox drawer under *Werkzeuge → E-Mail-Log* and in the Mahnservice
  sandbox portal under *E-Mail-Log* (`/mahnservice/sandbox/email-log`). The
  *Test-Mahnung* dialog opens the latter through *Erfasste E-Mails ansehen*.
* **No purchasing and no billing.** Subscriptions cannot be bought, renewed or
  cancelled in the sandbox. Not owning a product in production does not stop
  you integrating against it here.
* **No bookkeeping integrations.** Lexware Office, sevDesk, WISO MeinBüro,
  orgaMAX and the others cannot be connected in the sandbox. This is why the
  [Mahnservice API](/api-docs/mahnservice-api/introduction) is the only way to
  get invoices into a sandbox Mahnservice — seeded demo rows are for looking
  at, not an intake path.
* **No client reporting.** The client statistics report is computed by the
  collection back office and is permanently empty in the sandbox, so it is
  hidden rather than shown blank.
* **No production data changes.** Mirrored company profiles, memberships,
  company-level notification recipients, and the entering user's own recipients
  remain protected. Sandbox setup creates its own
  Mahnlauf configuration; nothing
  is written back to production. Sandbox activity never appears in your
  production account, in invoices, or in usage.
* **Not a trial.** The sandbox is for development and rehearsal by an existing
  or contracted customer's developers, not for evaluating the product.

Anything the sandbox refuses on purpose answers with an explicit, typed
error rather than failing silently, and the portal marks the surface as
unavailable in the sandbox instead of offering a control that cannot work.

## Confirm the environment from the API

Read back the credential context before a rehearsal that writes, and fail
closed if it is not the tenant you expected:

* [GET `/v2/info/`](/api-docs/case-management-api/reference/info/get-case-credential-context)
  for a direct Case key.
* [GET `/partner/v2/info/`](/api-docs/partner-api/reference/meta/get-partner-token-info)
  for a Partner key, which additionally reports the authoritative environment.
* [GET `/mahnservice/v1/info/`](/api-docs/mahnservice-api/reference/info/get-token-info)
  for the Mahnservice API: its `environment` field and
  `X-Paywise-Environment` identify the installation. A modern sandbox key
  intentionally has `access_mode: "production"`; this compatibility data lane
  does not indicate a production installation or enable production effects.

## Troubleshooting

| Symptom | Likely cause | Fix |
| - | - | - |
| `401` although the key is fresh | A `pw_sbx_` key was sent to `api.paywise.de`, or a production key to `api-sandbox.paywise.de`. Credentials only work on their own host. | Pair host and key from the same environment; call `GET /v2/info/` and check `X-Paywise-Environment`. |
| HTML page or a redirect instead of JSON | The request went to the portal host (`sandbox.paywise.de` or `app.paywise.de`) instead of the API host. | Use `api-sandbox.paywise.de` (or `api.paywise.de`) as the base URL; the portal hosts serve the web application and are not API endpoints. |
| Webhook does not arrive | The subscription was created in the other environment, does not include the event, or points at a destination the sandbox cannot reach. | Check the subscription and its delivery log in the sandbox portal; register a public HTTPS test receiver such as webhook.site to confirm the sandbox is sending; see [Webhook troubleshooting](/api-docs/essentials/webhooks#troubleshooting). |
| Nothing changes after a drawer action | The case is not in the state the action needs — the order is still a draft, or the mandate is already closed. | The drawer explains every refusal inline. Finalize the order first, then accept it; rehearse payments on the open case before closing it. |

## Before you go live

1. Run your integration end to end in the sandbox, including the failure paths:
   ambiguous retries, rejected writes, and webhook redelivery.
2. Check that your environment configuration — host **and** key — is switched
   as one unit, and that nothing derives the environment from a hostname
   substring or a response field.
3. Repeat the rehearsal after a sandbox reset, so first-run and repeat-run
   behaviour are both proven.
4. Issue production credentials yourself in the production portal under
   *Für Entwickler* — there is no review step by paywise — and switch host and
   key together to the production pair. Confirm the switch with the
   credential-info call before the first write.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.