---
updatedAt: 2026-09-14T15:48:19.000Z
agentTools:
  projectIndex: https://docs.striga.com/llms.txt
---

# Sandbox Simulator

Trigger the events you cannot cause yourself in the sandbox - identity verification results, incoming bank payments, card activity and more.

Some of what happens in Striga starts outside your application: a verification provider reaches a decision, a bank payment arrives, a card is used at a till. The sandbox simulator lets you trigger those events on demand, so you can build and test every step of your integration end to end.

Simulator endpoints exist **only on the sandbox**, under `https://www.sandbox.striga.com/api/v1/simulate`. They are signed exactly like every other request (see [Authenticating with the API](authenticating-with-the-api)). They cause the same state changes and send the same webhooks as the real events they stand in for.

## At a glance

| Area           | Endpoint                                 | Simulates                                     |
| -------------- | ---------------------------------------- | --------------------------------------------- |
| Identity       | `PATCH /simulate/user/kyc`               | A consumer's identity verification result     |
| Identity       | `POST /simulate/kyc/share-token`         | A reusable-KYC share token                    |
| Identity       | `PATCH /simulate/business/kyb`           | A business's verification result              |
| Identity       | `POST /simulate/auth/2fa/reset/liveness` | A passed liveness check for a 2FA reset       |
| Money movement | `PATCH /simulate/accounts/deposit`       | An incoming SEPA payment to a EUR account     |
| Money movement | `PATCH /simulate/sepa`                   | The outcome of an outgoing SEPA payment       |
| Cards          | `PATCH /simulate/card/status`            | A physical card being dispatched or activated |
| Cards          | `POST /simulate/card/authorization`      | A card payment at a merchant or ATM           |
| Application    | `PATCH /simulate/payment-accounts`       | Turning Payment Accounts on or off            |
| Application    | `POST /simulate/payment-accounts/state`  | Reading your Payment Accounts settings        |
| Webhooks       | `POST /simulate/webhook/ping`            | A test webhook to your endpoint               |

## Identity verification

### Simulate a consumer's KYC result

`PATCH /simulate/user/kyc`

| Field          | Required | Description                                                                    |
| -------------- | -------- | ------------------------------------------------------------------------------ |
| `userId`       | yes      | The consumer's id                                                              |
| `status`       | yes      | `APPROVED`, `REJECTED` or `REJECTED_FINAL`                                     |
| `tier`         | no       | `1` or `2`, the verification tier to decide                                    |
| `rejectLabels` | no       | For rejections: an array of reasons, e.g. `["LOW_QUALITY", "SELFIE_MISMATCH"]` |
| `reusable`     | no       | `true` to simulate a reused verification, where no new documents are collected |

```json
{ "userId": "00000000-0000-0000-0000-000000000000", "status": "APPROVED", "tier": 1 }
```

The consumer must have verified their email and mobile first. Verification must also have been started with `POST /user/kyc/start`.

The call answers `200` as soon as the decision is recorded, and you receive a `KYC` webhook when the status changes. After an approval, Striga keeps provisioning in the background for a few more seconds: the consumer's default wallet and accounts, and their banking record. If your application has **automatic account enrichment**, accounts are enriched as part of that provisioning, and you don't need to call `POST /wallets/account/enrich` yourself during onboarding. Ask your Striga contact to enable it for your sandbox application.

### Create a reusable-KYC share token

`POST /simulate/kyc/share-token`

No body. Answers `{ "shareToken": "..." }`. Pass the token to `POST /user/kyc/start` on an application with reusable KYC enabled, then complete the verification with `PATCH /simulate/user/kyc`.

### Simulate a business's KYB result

`PATCH /simulate/business/kyb`

| Field        | Required | Description                                |
| ------------ | -------- | ------------------------------------------ |
| `businessId` | yes      | The business's id                          |
| `status`     | yes      | `APPROVED`, `REJECTED` or `REJECTED_FINAL` |

Answers `204`. On an approval, the business's default wallet and banking record are provisioned *before* the status is recorded. If provisioning fails, the business stays unapproved, and you can simply repeat the call.

### Pass liveness for a 2FA reset

`POST /simulate/auth/2fa/reset/liveness`

| Field     | Required | Description                                  |
| --------- | -------- | -------------------------------------------- |
| `resetId` | yes      | The id returned when the reset was initiated |

Answers `{ "resetId": "...", "status": "LIVENESS_PASSED" }`. You can then complete the reset. Resets that are already `COMPLETED`, `REJECTED` or `EXPIRED` are refused.

## Money movement

### Simulate an incoming EUR deposit

`PATCH /simulate/accounts/deposit`

Credits a simulated SEPA payment to an **enriched** EUR account.

| Field         | Required | Description                                                               |
| ------------- | -------- | ------------------------------------------------------------------------- |
| `accountId`   | yes      | The 32-character EUR account id                                           |
| `amount`      | yes      | Amount in cents, as a string without decimals, e.g. `"10000"` for €100.00 |
| `senderName`  | no       | Up to 70 characters                                                       |
| `senderIban`  | no       | A valid IBAN                                                              |
| `senderBic`   | no       | A valid BIC                                                               |
| `reference`   | no       | Up to 129 characters                                                      |
| `paymentType` | no       | `SEPA` (default) or `SEPA_INSTANT`                                        |

```json
{ "accountId": "00000000000000000000000000000000", "amount": "10000", "reference": "Sandbox top-up" }
```

A successful call answers `200`, and the credit arrives on the account like a real incoming payment.

Every refusal is HTTP `400`, and its code tells you whether repeating the request can succeed:

| `errorCode` | `message`                                   | What to do                                                                                                 |
| ----------- | ------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| `31002`     | Account must be active and enriched         | The account has no bank account yet. Enrich it, then repeat.                                               |
| `31122`     | Account not found                           | No account has this `accountId`. Repeating cannot succeed.                                                 |
| `31123`     | Only EUR deposits can be simulated          | The account is not a EUR account. Repeating cannot succeed.                                                |
| `31124`     | Account holder banking record is not set up | Repeating cannot succeed. Contact support with the `accountId`.                                            |
| `31125`     | Deposit simulation failed                   | The banking provider refused the deposit, or it failed unexpectedly. Contact support with the `accountId`. |
| `00002`     | Invalid fields                              | A field failed validation; `errorDetails` names it.                                                        |

### Simulate the outcome of an outgoing SEPA payment

`PATCH /simulate/sepa`

| Field           | Required | Description                                      |
| --------------- | -------- | ------------------------------------------------ |
| `transactionId` | yes      | The id of an outgoing SEPA payment you initiated |
| `accountId`     | yes      | The EUR account it was sent from                 |
| `status`        | yes      | `COMPLETED` or `FAILED`                          |

Answers `200`. The payment settles or fails exactly as a real one would, with the same balance changes and webhooks.

## Cards

### Dispatch or activate a physical card

`PATCH /simulate/card/status`

| Field    | Required | Description              |
| -------- | -------- | ------------------------ |
| `cardId` | yes      | The card's id            |
| `status` | yes      | `DISPATCHED` or `ACTIVE` |

Activating a card also enrols it in 3-D Secure. Cards that are already active or blocked are refused.

### Simulate a card payment

`POST /simulate/card/authorization`

| Field            | Required | Description                                                                             |
| ---------------- | -------- | --------------------------------------------------------------------------------------- |
| `cardId`         | yes      | The card's id                                                                           |
| `amountEURCents` | yes      | Whole euro cents, from `0` to `1500000`                                                 |
| `mcc`            | no       | A merchant category code, e.g. `"5812"`. Use `"ATM"` or `"6011"` for a cash withdrawal. |

```json
{ "cardId": "00000000-0000-0000-0000-000000000000", "amountEURCents": 1234, "mcc": "5812" }
```

Answers `200` with the simulated transaction and `"response": "APPROVED"` or `"DECLINED"`. The decision is made exactly as for a real payment: against the balance of the account linked to the card, the card's limits and its status. So fund the linked account first, with `PATCH /simulate/accounts/deposit`. The reason for a decline is delivered in the card transaction webhook.

## Application settings

### Turn Payment Accounts on or off

`PATCH /simulate/payment-accounts`

| Field     | Required | Description       |
| --------- | -------- | ----------------- |
| `enabled` | yes      | `true` or `false` |

Changes the setting for **your** application. Enabling it also grants the consent endpoints' permissions; disabling it leaves those permissions in place, inert. Answers:

```json
{ "paymentAccountsEnabled": true, "consentPermissionsGranted": true }
```

### Read your Payment Accounts settings

`POST /simulate/payment-accounts/state`

No body. Answers:

```json
{ "paymentAccountsEnabled": true, "effective3pSepaPayoutsEnabled": true }
```

`effective3pSepaPayoutsEnabled` is whether third-party SEPA payouts are actually permitted for your application.

## Webhooks

### Send a test webhook

`POST /simulate/webhook/ping`

| Field     | Required | Description     |
| --------- | -------- | --------------- |
| `payload` | yes      | Any JSON object |

Delivers `payload` to your application's webhook URL as a `TEST` webhook. It is signed like every live webhook, with a `uid` and a `ts` added. Use it to check that your endpoint verifies signatures and responds.

The call answers `200` once delivery has been attempted, even if your endpoint did not accept it. Confirm receipt on your side.

## Putting it together: from a new consumer to a card payment

1. Create the consumer, then verify their email and mobile.
2. `POST /user/kyc/start`, then `PATCH /simulate/user/kyc` with `"status": "APPROVED"`.
3. Enrich the EUR account with `POST /wallets/account/enrich`, unless your application enriches accounts automatically.
4. Fund it with `PATCH /simulate/accounts/deposit`.
5. Create a card linked to that account, and pay with it using `POST /simulate/card/authorization`.