Safira Paydocs
Integration Guides

Sandbox Testing

Overview

The sandbox environment allows you to simulate different webhook scenarios without affecting real transactions. Use the X-Sandbox-Scenario header on any request to control the result of the received webhook.

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

How to Use

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

curl -X POST https://api.safirapay.com/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.safirapay.com/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.safirapay.com/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

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@safirapay.com 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