> ## Documentation Index
> Fetch the complete documentation index at: https://docs.paywithsoap.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Refund a Charge

> Refund a succeeded card charge in full

Refund a succeeded card charge. The full amount is returned to the customer's card — partial refunds are not supported. The charge must belong to the merchant whose API key is used; otherwise the API responds with a 422 indistinguishable from "not found", by design.

<Note>
  Refunds are currently supported for **card charges processed via the NMI gateway**. Requests for other charges return a 422 with an explanatory error.
</Note>

## Behavior

* The request takes **no body** — the full charge amount is always refunded.
* On success the charge transitions to the terminal `refunded` status and the response is the **same charge object returned by [Retrieve a Charge](/api-reference/api-v1/charges/show)**, with `status: "refunded"`.
* A charge can only be refunded once; a second attempt fails because the charge is no longer in the `succeeded` status.
* If you subscribe to the opt-in [`checkout.refunded`](/api-reference/api-v1/webhooks/checkout-refunded) webhook, it fires when the charge transitions.

## Settlement timing

Card transactions settle in a daily batch, typically the next business day. The processor cannot refund a transaction before it settles — a same-day refund attempt fails with a 422 whose `responsetext` carries the processor's decline reason. Retry after the settlement batch.

<RequestExample>
  ```bash Curl theme={null}
  curl -X POST "https://api-sandbox.paywithsoap.com/api/v1/charges/ch_pQsQ4kz3Af6Mb9rCupnWj6VFzxJsmkYK/refund" \
    -H "Authorization: Bearer YOUR_API_KEY"
  ```

  ```ruby Ruby theme={null}
  require 'net/http'
  require 'uri'

  charge_id = 'ch_pQsQ4kz3Af6Mb9rCupnWj6VFzxJsmkYK'
  uri = URI.parse("https://api-sandbox.paywithsoap.com/api/v1/charges/#{charge_id}/refund")

  http = Net::HTTP.new(uri.host, uri.port)
  http.use_ssl = true

  request = Net::HTTP::Post.new(uri.request_uri)
  request['Authorization'] = 'Bearer YOUR_API_KEY'

  response = http.request(request)
  puts response.body
  ```

  ```javascript JavaScript theme={null}
  const axios = require('axios');

  const refundCharge = async (chargeId) => {
    try {
      const response = await axios.post(
        `https://api-sandbox.paywithsoap.com/api/v1/charges/${chargeId}/refund`,
        {},
        {
          headers: {
            'Authorization': 'Bearer YOUR_API_KEY'
          }
        }
      );

      console.log(response.data);
    } catch (error) {
      console.error(error);
    }
  };

  refundCharge('ch_pQsQ4kz3Af6Mb9rCupnWj6VFzxJsmkYK');
  ```
</RequestExample>

<ResponseExample>
  ```json Error (not yet settled) theme={null}
  {
    "error": "Refund failed",
    "responsetext": "Transaction can not be refunded because it has not settled"
  }
  ```

  ```json Error (unknown charge) theme={null}
  {
    "error": "Unable to refund charge.",
    "hint": "Please verify the charge_id is correct. \n charge_id: ch_pQsQ4kz3Af6Mb9rCupnWj6VFzxJsmkYK"
  }
  ```
</ResponseExample>


## OpenAPI

````yaml POST /api/v1/charges/{id}/refund
openapi: 3.1.0
info:
  title: Soap API
  description: >-
    API documentation for Soap - AI-native payments infrastructure for complex,
    compliance-heavy payment flows
  license:
    name: MIT
  version: 1.4.0
servers:
  - url: https://api-sandbox.paywithsoap.com
security:
  - bearerAuth: []
paths:
  /api/v1/charges/{id}/refund:
    post:
      tags:
        - Charges
      summary: Refund a charge
      description: >-
        Refund a succeeded NMI card charge in full. Takes no request body — the
        entire charge amount is refunded. On success the charge transitions to
        the terminal `refunded` status and the response is the same charge
        object as GET /api/v1/charges/{id}. The processor cannot refund a
        transaction before it settles (daily batch, typically the next business
        day); pre-settlement attempts return a 422 whose `responsetext` carries
        the processor's decline reason.
      parameters:
        - name: id
          in: path
          required: true
          description: Unique identifier of the charge to refund.
          schema:
            type: string
            example: ch_pQsQ4kz3Af6Mb9rCupnWj6VFzxJsmkYK
      responses:
        '200':
          description: >-
            The refund succeeded. Returns the charge in the same shape as GET
            /api/v1/charges/{id}, with status "refunded".
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Charge'
        '422':
          description: >-
            The refund could not be processed — unknown charge or wrong merchant
            (opaque error), charge not refundable (not a succeeded NMI card
            charge, or already refunded), or the processor declined the refund
            (e.g. not yet settled).
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: Refund failed
                  responsetext:
                    type: string
                    description: >-
                      The processor's decline reason, when the gateway rejected
                      the refund.
                    example: Transaction can not be refunded because it has not settled
                  hint:
                    type: string
                    description: Present on lookup/ownership failures.
      security:
        - bearerAuth: []
components:
  schemas:
    Charge:
      type: object
      properties:
        id:
          type: string
          example: ch_pQsQ4kz3Af6Mb9rCupnWj6VFzxJsmkYK
        amount_cents:
          type: integer
          description: Charge amount in cents.
          example: 2999
        transaction_type:
          type: string
          description: >-
            Direction of the charge: `credit` for deposits (money into the
            customer balance), `debit` for withdrawals (money out).
          enum:
            - credit
            - debit
          example: debit
        currency:
          type: string
          example: USD
        status:
          type: string
          description: >-
            Current state of the charge. Not every value is reachable on every
            flow or processor: `held` occurs on withdrawals that place a hold;
            `voided` and `returned` follow a settled charge that the processor
            later reversed; `cancelled` applies to bank-transfer payments
            cancelled while still `pending`; `refunded` is set by a full refund
            of a settled NMI card charge via POST /api/v1/charges/{id}/refund or
            the dashboard, and emits the opt-in `checkout.refunded` event.
            `cancelled` emits no webhook. See the charge lifecycle for the full
            transition map and which webhook each transition emits.
          enum:
            - created
            - pending
            - succeeded
            - failed
            - held
            - voided
            - returned
            - refunded
            - cancelled
          example: succeeded
        failure_code:
          type: string
          nullable: true
          description: >-
            Machine-readable failure code; only present when `status` is
            `failed`.
          example: null
        failure_message:
          type: string
          nullable: true
          description: >-
            Human-readable failure reason; only present when `status` is
            `failed`.
          example: null
        created_at:
          type: string
          format: date-time
          example: '2026-05-31T10:30:00.000Z'
        updated_at:
          type: string
          format: date-time
          example: '2026-05-31T10:30:05.000Z'
        customer:
          type: object
          properties:
            id:
              type: string
              example: cus_pQsQ4kz3Af6Mb9rCupnWj6VFzxJsmkYK
            first_name:
              type: string
              example: Sarah
            last_name:
              type: string
              example: Johnson
        payment_method:
          type: object
          description: >-
            Payment method used for the charge. Exactly one of `card`,
            `bank_account`, or `crypto_wallet` is populated, matching
            `payment_type`.
          properties:
            id:
              type: string
              example: pm_pQsQ4kz3Af6Mb9rCupnWj6VFzxJsmkYK
            payment_type:
              type: string
              enum:
                - card
                - bank_account
                - crypto_wallet
              example: card
            created_at:
              type: string
              format: date-time
              example: '2026-05-31T10:30:00.000Z'
            updated_at:
              type: string
              format: date-time
              example: '2026-05-31T10:30:05.000Z'
            saved:
              type: boolean
              description: >-
                Whether the customer chose to save this payment method for
                future use.
              example: true
            fingerprint:
              type: string
              description: >-
                Stable SHA-256 fingerprint of the underlying instrument. Useful
                for de-duplicating payment methods across charges.
              example: 9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08
            card:
              type: object
              nullable: true
              description: Present when `payment_type` is `card`.
              properties:
                last_four:
                  type: string
                  example: '4242'
                card_brand:
                  type: string
                  example: visa
                card_expiration_month:
                  type: integer
                  example: 12
                card_expiration_year:
                  type: integer
                  example: 2027
                card_issuer_country:
                  type: string
                  example: US
                name_on_card:
                  type: string
                  example: Sarah Johnson
                card_type:
                  type: string
                  example: credit
                first_name:
                  type: string
                  example: Sarah
                last_name:
                  type: string
                  example: Johnson
                zip:
                  type: string
                  example: '10001'
                google_pay:
                  type: boolean
                  example: false
                apple_pay:
                  type: boolean
                  example: false
                bin:
                  type: string
                  example: '424242'
            bank_account:
              type: object
              nullable: true
              description: Present when `payment_type` is `bank_account`.
              properties:
                last_four:
                  type: string
                  example: '1234'
                bank_brand:
                  type: string
                  example: chase
                bank_account_type:
                  type: string
                  example: checking
                bank_account_name:
                  type: string
                  example: Alice Brown
                first_name:
                  type: string
                  example: Alice
                last_name:
                  type: string
                  example: Brown
            crypto_wallet:
              type: object
              nullable: true
              description: Present when `payment_type` is `crypto_wallet`.
              properties:
                crypto_wallet_address:
                  type: string
                  example: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb5'
        avs_result:
          type: string
          nullable: true
          description: >-
            Address Verification System result from the processor. Card charges
            only.
          example: null
        cvv_result:
          type: string
          nullable: true
          description: CVV verification result from the processor. Card charges only.
          example: null
        network_authorization_code:
          type: string
          nullable: true
          description: Authorization code returned by the card network. Card charges only.
          example: null
        processor_charge_id:
          type: string
          nullable: true
          description: External processor's identifier for this charge. Card charges only.
          example: null
        threeds:
          type: object
          nullable: true
          description: >-
            3D Secure verification details. Only present for card charges where
            3DS was performed.
          properties:
            eci:
              type: string
              example: '05'
            version:
              type: string
              example: 2.2.0
            liability_shifted:
              type: boolean
              example: true
            failure_reason:
              type: string
              nullable: true
              example: null
            status:
              type: string
              example: success
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: >-
        Bearer token authentication using your API key (key_...). Used for every
        endpoint except POST /api/v1/device_pings.

````