---
title: "Simulate a payment"
method: POST
path: "/v1/payments/{paymentId}/simulate"
tags: ["Payments"]
---

# Simulate a payment

`POST /v1/payments/{paymentId}/simulate`

Drive a sandbox payment to a terminal status immediately, whatever its amount and payment method. Sandbox only: a production API key and a production payment id are both rejected with 403. `REFUNDED` marks the payment paid if it is not already and then issues a full refund; `DISPUTED` marks it paid if it is not already and then moves it to `CHARGEBACK`, which is a chargeback and not a MED.

## Path parameters

- `paymentId` string, uuid, required

## Headers

- `X-Idempotency-Key` string

## Request body

- SimulatePaymentRequest
  - `status` 'PAID' | 'CANCELLED' | 'EXPIRED' | 'REFUNDED' | 'DISPUTED' — Terminal outcome to apply. Defaults to `PAID` when the body is empty or omitted.

## Response `200`

The payment after the simulated transition.

- object
  - `payment` Payment
    - `id` string, uuid
    - `txId` string — YuvexPay transaction ID.
    - `amount` number — Merchant-requested base amount, in BRL. This is the seller's intended receivable.
    - `feeAmount` number — YuvexPay platform fee, in BRL. When `feePassedToPayer` is true, this equals `payerFeeAmount` and is charged on top of `amount`. When false, this is deducted from `amount` to produce `netAmount`.
    - `netAmount` number — Merchant's net receivable, in BRL. Equals `amount` when `feePassedToPayer` is true; equals `amount - feeAmount` otherwise.
    - `feePassedToPayer` boolean — Resolved decision (after applying the per-payment override, company default, and sub-R$1 forced passthrough) on whether the fee was added on top for the payer.
    - `payerFeeAmount` number, nullable — Fee amount added to the payer's total charge. Null when `feePassedToPayer` is false. When true, payer-charged total = `amount + payerFeeAmount`.
    - `status` 'NEW' | 'PENDING_METHOD_SELECTION' | 'PROCESSING' | 'CONFIRMED' | 'PAID' | 'CANCELLED' | 'EXPIRED' | 'REFUNDED' | 'PARTIAL_REFUND' | 'CHARGEBACK' | 'MED_FROZEN' — Possible payment statuses.
    - `paymentMethod` 'PIX' | 'CARD' | 'BOLETO' — Available public payment methods.
    - `currency` 'BRL' — Supported currencies.
    - `description` string
    - `metadata` object
    - `expiresAt` string, date-time
    - `createdAt` string, date-time
    - `methodData` object — Payment method-specific data (QR code for PIX, barcode for boleto, etc.).
      - `type` 'PIX' | 'CARD' | 'BOLETO' — Available public payment methods.
    - `paidAt` string, date-time, nullable — Timestamp when the payment was confirmed paid. Null until paid.
    - `payer` object, nullable — Payer (debtor) identity captured from the PIX network once the charge is paid. Provider-agnostic. Null for historical records or open-payer charges where no payer data was captured.
      - `name` string, nullable — Payer full name.
      - `document` string, nullable — Payer CPF or CNPJ, as digits. Some PIX participants report the document masked (for example `***405566**`); when that is all the network gave us, the masked string is what this field carries — a full document wins whenever one is on file. `null` when no document of either kind was captured, which for an open-payer charge is common. Match on `*` before parsing the value as a CPF or CNPJ.
      - `documentType` 'CPF' | 'CNPJ' | 'null', nullable — Payer document type. `null` when the network did not say which kind of document it reported, which is the usual case alongside a masked `document`.
      - `institutionName` string, nullable — Payer bank/institution name.
      - `institutionIspb` string, nullable — Payer bank ISPB (Banco Central participant identifier).

## Other responses

- `400` — Validation error.
- `401` — Missing or invalid authentication token.
- `403` — The API key is a production key. Only sandbox API keys can simulate.
- `404` — Resource not found.
- `409` — Idempotency conflict, raised by the idempotency middleware. `IDEMPOTENCY_PAYLOAD_MISMATCH` means the key was already used with a different request body, at any point in the 24-hour window, including by a request still in flight. `IDEMPOTENCY_CONFLICT` means a request with the same key and the same body is still being processed. Both use the **flat** envelope: `error` is the HTTP reason phrase and the machine-readable code is the top-level `code`. Note that `IDEMPOTENCY_CONFLICT` raised later by the withdrawal service on an idempotency-key collision uses the nested `Error` envelope instead.

## Changes

- **2026-09-01** `746526879975` — 1 info
  - endpoint added

[Change history](https://skmtc.dev/yuvexpay/apis/yuvexpay-api/changes/v1/payments/:paymentId/simulate/post.md)

---

[API](https://skmtc.dev/yuvexpay/apis/yuvexpay-api.md) · [All operations](https://skmtc.dev/yuvexpay/apis/yuvexpay-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/yuvexpay/yuvexpay-api/revisions/746526879975/schema)
