Avistadocs
Integration Guides

Sandbox Testing

What is Sandbox?

The sandbox is a testing mode for your account — not a separate environment. It uses the same API, same base URL, and same endpoints as production. The difference is that your sandbox account is connected to a simulated banking provider: transactions are processed instantly, no real funds are transferred, and no PIX is sent to BACEN.

Sandbox and production are separate accounts, each with their own credentials (certificate, clientId, clientSecret). Your certificate may be shared between both accounts depending on your setup — check with your account manager.

Your code doesn't change between sandbox and production. When you're ready to go live, just switch to your production account credentials. No endpoint changes, no code changes.

Sandbox vs Production

SandboxProduction
Base URLSame (https://api.avista.global)Same
AccountDedicated sandbox accountDedicated production account
CredentialsOwn certificate + clientId/clientSecretOwn certificate + clientId/clientSecret
BalanceSimulated (fictitious)Real funds
TransactionsSimulated (persisted — queryable via API)Real PIX via BACEN
WebhooksSimulated (~1s delivery), same payload structureReal, delivery depends on provider
X-Sandbox-ScenarioSupported (control webhook outcomes)Returns 400 Bad Request
DocumentationSame as production — all API Reference pages applySame

Getting Started with Sandbox

Contact your account manager or suporte@avista.global to request a sandbox account.

You will receive a certificate and OAuth credentials (clientId + clientSecret) for the sandbox account.

Register your webhook URL via POST /api/webhooks so you can receive simulated webhook events.

In the dashboard, go to Settings to confirm your account is configured in sandbox mode.

Authenticate, make API calls, and use the X-Sandbox-Scenario header to simulate different outcomes.


Overview

The X-Sandbox-Scenario header allows you to control the webhook outcome for any transaction. Without it, the sandbox always returns success webhooks. Use it to test error handling, delays, and edge cases.

Without the X-Sandbox-Scenario header, the sandbox always returns success webhooks. To test error scenarios (insufficient funds, invalid key, etc.), you must explicitly send the header on each request.

This feature works only in sandbox. In production, the header is ignored and the behavior is determined by the actual transaction result.

How It Works

The X-Sandbox-Scenario does not alter the HTTP response -- the API always returns 201 Created with status: "PENDING". The simulated scenario only affects the asynchronous webhook that arrives at your callback URL.

┌─────────────┐         ┌──────────────┐         ┌─────────────────┐
│   Your App  │──POST──▶│   Avista API  │──────▶  │  Mock Provider  │
│             │◀──201───│              │         │                 │
│             │         │              │         │  Processes the  │
│             │         │              │         │  scenario from  │
│             │         │              │         │  the header     │
│             │◀────────│──webhook─────│◀────────│                 │
│             │         │              │         │  ~1s later      │
└─────────────┘         └──────────────┘         └─────────────────┘
      │                                                  │
      │              HTTP Response: always 201           │
      │              Webhook: success OR error            │
      │              (depends on the header)              │
RequestHTTP ResponseReceived Webhook
Without X-Sandbox-Scenario201 PENDINGCONFIRMED (success)
With X-Sandbox-Scenario: success201 PENDINGCONFIRMED (success)
With X-Sandbox-Scenario: error:insufficient-funds201 PENDINGERROR with errorCode
With X-Sandbox-Scenario: delayed:5s201 PENDINGCONFIRMED after 5s extra

How to Use

Add the X-Sandbox-Scenario header to any Cash-In, Cash-Out, or Refund request:

curl -X POST https://api.avista.global/api/pix/cash-out \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-Sandbox-Scenario: error:insufficient-funds" \
  -H "Content-Type: application/json" \
  -d '{
    "value": 150.00,
    "details": {
      "key": "recipient@email.com",
      "keyType": "EMAIL",
      "name": "Recipient Name",
      "document": "39284918812"
    },
    "externalId": "test-error-001"
  }'
const response = await axios.post(
  'https://api.avista.global/api/pix/cash-out',
  {
    value: 150.00,
    details: {
      key: 'recipient@email.com',
      keyType: 'EMAIL',
      name: 'Recipient Name',
      document: '39284918812',
    },
    externalId: 'test-error-001',
  },
  {
    headers: {
      Authorization: `Bearer ${token}`,
      'X-Sandbox-Scenario': 'error:insufficient-funds',
    },
  }
);
response = requests.post(
    "https://api.avista.global/api/pix/cash-out",
    json={
        "value": 150.00,
        "details": {
            "key": "recipient@email.com",
            "keyType": "EMAIL",
            "name": "Recipient Name",
            "document": "39284918812",
        },
        "externalId": "test-error-001",
    },
    headers={
        "Authorization": f"Bearer {token}",
        "X-Sandbox-Scenario": "error:insufficient-funds",
    },
)

Available Scenarios

Error Scenarios

Simulate different types of webhook failures:

Header ValueDescriptionWebhook Status
error:insufficient-fundsAccount without sufficient balanceERROR
error:invalid-pix-keyPIX key does not exist in DICTERROR
error:document-mismatchDocument does not match the key holderERROR
error:account-blockedDestination account blocked or closedERROR
error:duplicate-idDuplicate submission IDERROR

Success Scenario

Header ValueDescriptionWebhook Status
successForces success (default behavior)CONFIRMED
(no header)Default sandbox behaviorCONFIRMED

Delay Scenarios

Simulate slow processing to test timeouts and retry:

Header ValueDescriptionWebhook Status
delayed:5sSuccess after 5 extra secondsCONFIRMED
delayed:30sSuccess after 30 extra secondsCONFIRMED
delayed:60sSuccess after 60 extra secondsCONFIRMED

The maximum allowed delay is 120 seconds. Values above will be automatically capped.

Received Webhook Examples

Success Webhook (default)

{
  "event": "CashOut",
  "status": "CONFIRMED",
  "transactionType": "PIX",
  "movementType": "DEBIT",
  "transactionId": "12345",
  "externalId": "test-success-001",
  "endToEndId": "E17745159XI4QA0EGFU",
  "feeAmount": 0.50,
  "originalAmount": 150.00,
  "finalAmount": 150.50,
  "processingDate": "2026-03-26T10:00:00.000Z",
  "errorCode": null,
  "errorMessage": null,
  "counterpart": {
    "name": "Recipient Name",
    "document": "*.284.918-**",
    "bank": {}
  },
  "metadata": {}
}

Error Webhook (error:insufficient-funds)

{
  "event": "CashOut",
  "status": "ERROR",
  "transactionType": "PIX",
  "movementType": "DEBIT",
  "transactionId": "12345",
  "externalId": "test-error-001",
  "endToEndId": null,
  "feeAmount": 0.50,
  "originalAmount": 150.00,
  "finalAmount": 150.50,
  "processingDate": "2026-03-26T10:00:00.000Z",
  "errorCode": "INSUFFICIENT_FUNDS",
  "errorMessage": "Conta sem saldo",
  "counterpart": {
    "name": null,
    "document": null,
    "bank": {}
  },
  "metadata": {}
}

When the status is ERROR, the endToEndId field will be null (since the PIX was never confirmed by the Central Bank) and the errorCode and errorMessage fields describe the failure reason.

Compatible Endpoints

The X-Sandbox-Scenario header works with all transactional endpoints:

EndpointMethodDescription
/api/pix/cash-inPOSTGenerate PIX charge (QR Code)
/api/pix/cash-outPOSTPIX payment by key
/api/pix/cash-out/qrcodePOSTPIX payment by QR Code
/api/pix/refund-inPOSTRefund request

MED Scenarios

The MED module (Special Refund Mechanism) cannot be tested directly via X-Sandbox-Scenario. MEDs depend on integration with BACEN and with the configured PIX provider (Woovi, Hyperwallet, etc.), so they cannot be simulated by the sandbox mock provider.

To validate your integration with MED webhooks (MedCreated, MedAccepted, MedRejected):

Use POST /api/webhooks/{id}/resend to resend an existing MED webhook from your account to the configured URL. Useful for debugging the handler locally after changes.

Use GET /api/med to list MEDs associated with the account, filter by status, and reconcile with your local transactions.

If you need to simulate an end-to-end MED flow (opening, analysis, approval/rejection), contact suporte@avista.global to request access to the staging environment.

MED webhooks use the same authentication (Basic Auth) and retry structure as other events. The full payload is documented in MedCreated, MedAccepted, and MedRejected.

Behavior

The API processes the request normally and returns 201 Created with status PENDING. The header does not alter the immediate response -- only the subsequent webhook.

After ~1 second (or more, if using delayed:), the webhook is sent to the configured URL with the simulated scenario.

Your system receives the webhook with the status corresponding to the scenario (CONFIRMED or ERROR) and should process it accordingly.

Important: The X-Sandbox-Scenario header controls only the webhook. The HTTP response from the endpoint always returns success (201 Created) with status: "PENDING", regardless of the chosen scenario. The final result (success or error) arrives via webhook.

Restrictions

The X-Sandbox-Scenario header works exclusively with accounts configured in sandbox mode. If your account is configured with a production provider and you send the header, the API will return an error:

{
  "statusCode": 400,
  "message": "X-Sandbox-Scenario header is only supported in sandbox mode. This account is not configured with a sandbox provider."
}

Make sure your account is in sandbox mode before using this feature. If you receive this error, contact suporte@avista.global to verify your account configuration.

Best Practices

Test all scenarios

Implement handling for each webhook status (CONFIRMED, PENDING, ERROR) before going to production.

Validate error fields

When status is ERROR, use errorCode and errorMessage to determine the appropriate action (retry, notify user, etc.).

Test with delay

Use delayed: scenarios to verify that your system handles webhooks that take longer to arrive correctly.

Idempotency

Use transactionId as an idempotency key. The same webhook may be resent in case of delivery failure.

On this page