> ## Documentation Index
> Fetch the complete documentation index at: https://ramps-docs-sync-20260721.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Sandbox Testing

> Drive deterministic card outcomes with the simulate endpoints

The card network can't reach into Sandbox to send real authorizations,
so Sandbox exposes three simulate helpers that drive the same internal
`authorize` and `reconcile` paths the issuer would call in production.
Production returns `404` on these paths.

```text theme={null}
POST /sandbox/cards/{id}/simulate/authorization
POST /sandbox/cards/{id}/simulate/authorization_advice
POST /sandbox/cards/{id}/simulate/balance_inquiry
POST /sandbox/cards/{id}/simulate/clearing
POST /sandbox/cards/{id}/simulate/credit_authorization
POST /sandbox/cards/{id}/simulate/credit_authorization_advice
POST /sandbox/cards/{id}/simulate/financial_authorization
POST /sandbox/cards/{id}/simulate/financial_credit_authorization
POST /sandbox/cards/{id}/simulate/return
POST /sandbox/cards/{id}/simulate/return_reversal
```

Outcomes are deterministic — driven by magic-value suffixes on the
relevant id. The same approach is used by
`/sandbox/internal-accounts/{id}/fund`.

## Issuance suffixes (platformCardId)

The last three characters of `platformCardId` (or `cardholderId` when
`platformCardId` is omitted) control how `POST /cards` resolves:

| Suffix    | Behavior                                                                         |
| --------- | -------------------------------------------------------------------------------- |
| `001`     | Stays `PROCESSING` indefinitely (test the polling path)                          |
| `002`     | Issuer provisioning rejected → `state: CLOSED`, `stateReason: "ISSUER_REJECTED"` |
| `005`     | Delayed activation (\~30s) before the `CARD.STATE_CHANGE` webhook fires          |
| any other | Instant activation → `state: ACTIVE`, `last4` deterministic from the suffix      |

## Funding-source suffixes (accountId)

Binding a funding source resolves based on the last three characters
of `accountId`:

| Suffix    | Behavior                                                 |
| --------- | -------------------------------------------------------- |
| `002`     | `FUNDING_SOURCE_INELIGIBLE` (insufficient balance check) |
| `003`     | `FUNDING_SOURCE_INELIGIBLE` (account closed)             |
| any other | Success                                                  |

## Authorization simulate

```bash theme={null}
curl -X POST "$GRID_BASE_URL/sandbox/cards/Card:019542f5-b3e7-1d02-0000-000000000010/simulate/authorization" \
  -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 1250,
    "currency": { "code": "USD" },
    "merchant": {
      "descriptor": "BLUE BOTTLE COFFEE SF",
      "mcc": "5814",
      "country": "US"
    }
  }'
```

Outcomes are controlled by the last three characters of
`merchant.descriptor`:

| Suffix    | Outcome                                                                                                  |
| --------- | -------------------------------------------------------------------------------------------------------- |
| `002`     | Decline — `INSUFFICIENT_FUNDS` (the pull on the funding source fails)                                    |
| `003`     | Decline — `CARD_PAUSED` (use against a `FROZEN` card to verify)                                          |
| `005`     | Delayed pull (\~30s) — exercises the `PENDING → CONFIRMED` path                                          |
| `006`     | Pull succeeds but the confirmation event reports `FAILED` — exercises the high-urgency `EXCEPTION` alert |
| any other | Approved                                                                                                 |

The response is the resulting `CardTransaction`.

## Clearing simulate

```bash theme={null}
curl -X POST "$GRID_BASE_URL/sandbox/cards/Card:019542f5-b3e7-1d02-0000-000000000010/simulate/clearing" \
  -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "cardTransactionId": "CardTransaction:019542f5-b3e7-1d02-0000-000000000100",
    "amount": 1500
  }'
```

* `amount > authorizedAmount` exercises the over-auth post-hoc pull
  path (restaurant tip / tip-on-top).
* `amount = 0` exercises `AUTHORIZATION_EXPIRY` — the auth expires
  with no clearing posted.

Suffix-driven outcomes on the parent transaction's id govern whether
the post-hoc pull succeeds — use them with the
[merchant descriptor suffixes](#authorization-simulate) above to
construct deterministic exception scenarios.

## Return simulate

```bash theme={null}
curl -X POST "$GRID_BASE_URL/sandbox/cards/Card:019542f5-b3e7-1d02-0000-000000000010/simulate/return" \
  -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "cardTransactionId": "CardTransaction:019542f5-b3e7-1d02-0000-000000000100",
    "amount": 1500
  }'
```

A full refund flips the parent to `REFUNDED`; a partial refund keeps
it `SETTLED` with a non-zero `refundedAmount`.

## Authorization advice simulate

Re-sizes an existing open authorization to a new total amount:

```bash theme={null}
curl -X POST "$GRID_BASE_URL/sandbox/cards/Card:019542f5-b3e7-1d02-0000-000000000010/simulate/authorization_advice" \
  -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "cardTransactionId": "CardTransaction:019542f5-b3e7-1d02-0000-000000000100",
    "amount": 2000
  }'
```

The `amount` is the new *total* authorized amount. The parent
transaction must be in `AUTHORIZED` or `PARTIALLY_SETTLED` state.

## Balance inquiry simulate

Simulates a balance-inquiry authorization (always a zero-amount auth):

```bash theme={null}
curl -X POST "$GRID_BASE_URL/sandbox/cards/Card:019542f5-b3e7-1d02-0000-000000000010/simulate/balance_inquiry" \
  -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "merchant": {
      "descriptor": "SHELL OIL 12345678",
      "mcc": "5541",
      "country": "US"
    }
  }'
```

## Credit authorization simulate

Simulates an inbound credit authorization (a merchant-initiated credit
to the card, e.g. a refund pushed as an authorization):

```bash theme={null}
curl -X POST "$GRID_BASE_URL/sandbox/cards/Card:019542f5-b3e7-1d02-0000-000000000010/simulate/credit_authorization" \
  -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 2500,
    "currency": { "code": "USD" },
    "merchant": {
      "descriptor": "ACME MARKETPLACE",
      "mcc": "5942",
      "country": "US"
    }
  }'
```

Uses the same [merchant descriptor suffixes](#authorization-simulate)
for outcome control.

## Credit authorization advice simulate

Re-sizes an existing credit authorization:

```bash theme={null}
curl -X POST "$GRID_BASE_URL/sandbox/cards/Card:019542f5-b3e7-1d02-0000-000000000010/simulate/credit_authorization_advice" \
  -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "cardTransactionId": "CardTransaction:019542f5-b3e7-1d02-0000-000000000100",
    "amount": 3000
  }'
```

## Financial authorization simulate

Simulates a single-message financial authorization (an authorization
that clears in the same message, e.g. an ATM withdrawal):

```bash theme={null}
curl -X POST "$GRID_BASE_URL/sandbox/cards/Card:019542f5-b3e7-1d02-0000-000000000010/simulate/financial_authorization" \
  -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 8000,
    "currency": { "code": "USD" },
    "merchant": {
      "descriptor": "ATM WITHDRAWAL 24TH ST",
      "mcc": "6011",
      "country": "US"
    }
  }'
```

Uses the same [merchant descriptor suffixes](#authorization-simulate)
for outcome control.

## Financial credit authorization simulate

Simulates a single-message financial credit (a credit that clears in
the same message, e.g. an ATM deposit or push credit):

```bash theme={null}
curl -X POST "$GRID_BASE_URL/sandbox/cards/Card:019542f5-b3e7-1d02-0000-000000000010/simulate/financial_credit_authorization" \
  -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 4000,
    "currency": { "code": "USD" },
    "merchant": {
      "descriptor": "ACME PAYOUTS",
      "mcc": "6012",
      "country": "US"
    }
  }'
```

Uses the same [merchant descriptor suffixes](#authorization-simulate)
for outcome control.

## Return reversal simulate

Reverses a previously settled return:

```bash theme={null}
curl -X POST "$GRID_BASE_URL/sandbox/cards/Card:019542f5-b3e7-1d02-0000-000000000010/simulate/return_reversal" \
  -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "cardTransactionId": "CardTransaction:019542f5-b3e7-1d02-0000-000000000100"
  }'
```

The parent transaction must be in `REFUNDED` state.

## End-to-end happy path

A simple Sandbox loop that exercises issue → activate → auth → clear
→ refund:

```bash theme={null}
# 1. Issue (suffix not in the magic set → instant activation)
curl -X POST "$GRID_BASE_URL/cards" \
  -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "cardholderId": "Customer:...",
    "platformCardId": "card-test-happy",
    "form": "VIRTUAL",
    "fundingSources": ["InternalAccount:..."]
  }'

# 2. Simulate auth — any non-magic descriptor approves
curl -X POST "$GRID_BASE_URL/sandbox/cards/Card:.../simulate/authorization" \
  -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{ "amount": 1250, "currency": {"code":"USD"}, "merchant": {"descriptor":"BLUE BOTTLE COFFEE SF"} }'

# 3. Clear the auth
curl -X POST "$GRID_BASE_URL/sandbox/cards/Card:.../simulate/clearing" \
  -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{ "cardTransactionId": "CardTransaction:...", "amount": 1500 }'

# 4. Refund the cleared transaction
curl -X POST "$GRID_BASE_URL/sandbox/cards/Card:.../simulate/return" \
  -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{ "cardTransactionId": "CardTransaction:...", "amount": 1500 }'
```

At each step you'll see `CARD.STATE_CHANGE` or
`CARD.FUNDING_SOURCE_CHANGE` webhooks plus transaction webhooks for
the simulated authorization, clearing, and return — wire those into
your local webhook handler to validate end-to-end.
