---
title: "Refund a paid charge."
method: POST
path: "/v1/charges/{id}/refund"
tags: ["Charge"]
---

# Refund a paid charge.

`POST /v1/charges/{id}/refund`

## Request

- Base URL: `https://sandbox.straddle.com`
- URL: `https://sandbox.straddle.com/v1/charges/{id}/refund`
- Auth: HTTP bearer

Issue a refund for a successfully paid charge. The refund is created as a new payout linked to the original charge through `related_payments`. The customer receives the funds back at the bank account they paid from. Each charge can be refunded once; partial and full refunds are both supported.

## Path parameters

- `id` string, uuid, required

## Headers

- `Straddle-Account-Id` string, uuid
- `Request-Id` string
- `Correlation-Id` string
- `Idempotency-Key` string

## Request body

- RefundChargeV1Request
  - `amount` integer, nullable, required: The refund amount in cents. Must be greater than 0 and no more than the original charge amount.
  - `description` string, nullable: Optional reason recorded on the refund payout. Appended to the system-generated description `Refund for Charge ID: {id}`.
  - `external_id` string, nullable: Optional unique identifier for this refund, used to correlate with your internal records. Defaults to a new value if not specified.
  - `payment_date` string, date, nullable: The date on which to submit the refund for processing. Defaults to today if not specified.
  - `metadata` object, nullable: Optional key-value pairs for storing additional structured data. Keys and values must be strings.

## Response `201`

Created

- PayoutV1ItemResponse
  - `meta` ResponseMetadata, required: Metadata about the API request, including an identifier and timestamp.
    - `api_request_id` string, uuid, required: Unique identifier for this API request, useful for troubleshooting.
    - `api_request_timestamp` string, date-time, required: Timestamp for this API request, useful for troubleshooting.
  - `response_type` 'object' | 'array' | 'error' | 'none', required: Indicates the structure of the returned content. - "object" means the `data` field contains a single JSON object. - "array" means the `data` field contains an array of objects. - "error" means the `data` field contains an error object with details of the issue. - "none" means no data is returned.
  - `data` PayoutV1, required
    - `id` string, uuid, required: Unique identifier for the payout.
    - `paykey` string, required: Value of the `paykey` used for the payout.
    - `description` string, nullable, required: An arbitrary description for the payout.
    - `payment_rail` 'ach': The payment rail used for the charge or payout.
    - `customer_details` CustomerDetailsV1: Information about the customer associated with the charge or payout.
      - `id` string, uuid, required: Unique identifier for the customer
      - `name` string, required: The name of the customer
      - `customer_type` 'individual' | 'business', required
      - `email` string, required: The customer's email address
      - `phone` string, required: The customer's phone number in E.164 format
    - `paykey_details` PaykeyDetailsV1
      - `id` string, uuid, required: Unique identifier for the paykey.
      - `customer_id` string, uuid, required: Unique identifier for the customer associated with the paykey.
      - `label` string, required: Human-readable label that combines the bank name and masked account number to help easility represent this paykey in a UI
      - `balance` integer, nullable: The most recent balance of the bank account associated with the paykey in dollars.
    - `amount` integer, required: The amount of the payout in cents.
    - `currency` string, required: The currency of the payout. Only USD is supported.
    - `payment_date` string, date, required: The desired date on which the payment should be occur. For payouts, this means the date you want the funds to be sent from your bank account.
    - `device` DeviceInfoV1, required
      - `ip_address` string, ipv4, required: The IP address of the device used when the customer authorized the charge or payout. Use `0.0.0.0` to represent an offline consent interaction.
    - `external_id` string, required: Unique identifier for the payout in your database. This value must be unique across all payouts.
    - `config` PayoutConfigurationV1, required
      - `sandbox_outcome` 'standard' | 'paid' | 'on_hold_daily_limit' | 'cancelled_for_fraud_risk' | 'cancelled_for_balance_check' | 'failed_insufficient_funds' | 'reversed_insufficient_funds' | 'failed_customer_dispute' | 'reversed_customer_dispute' | 'failed_closed_bank_account' | 'reversed_closed_bank_account' | 'failed_not_authorized' | 'reversed_not_authorized': Payment will simulate processing if not Standard.
      - `auto_hold` boolean, nullable: Defines whether to automatically place this charge on hold after being created.
      - `auto_hold_message` string, nullable: The reason the payout is being automatically held on creation.
    - `created_at` string, date-time, nullable: The time the payout was created.
    - `updated_at` string, date-time, nullable: The time the payout was last updated.
    - `processed_at` string, date-time, nullable: The time the payout was processed by Straddle and originated to the payment rail.
    - `effective_at` string, date-time, nullable: The actual date on which the payment occurred. For payouts, this is the date the funds were sent from your bank account.
    - `status` 'created' | 'scheduled' | 'failed' | 'cancelled' | 'on_hold' | 'pending' | 'paid' | 'reversed' | 'validating', required: The current status of the `charge` or `payout`.
    - `status_details` StatusDetailsV11, required
      - `message` string, required: A human-readable description of the current status.
      - `reason` 'insufficient_funds' | 'closed_bank_account' | 'invalid_bank_account' | 'invalid_routing' | 'disputed' | 'payment_stopped' | 'owner_deceased' | 'frozen_bank_account' | 'risk_review' | 'fraudulent' | 'duplicate_entry' | 'invalid_paykey' | 'payment_blocked' | 'amount_too_large' | 'too_many_attempts' | 'internal_system_error' | 'user_request' | 'ok' | 'other_network_return' | 'payout_refused' | 'cancel_request' | 'failed_verification' | 'require_review' | 'blocked_by_system' | 'watchtower_review' | 'validating' | 'auto_hold', required
      - `source` 'watchtower' | 'bank_decline' | 'customer_dispute' | 'user_action' | 'system', required
      - `changed_at` string, date-time, required: The time the status change occurred.
      - `code` string, nullable: The status code if applicable.
    - `status_history` StatusHistoryV1[], required: History of the status changes for the payout.
      - `reason` 'insufficient_funds' | 'closed_bank_account' | 'invalid_bank_account' | 'invalid_routing' | 'disputed' | 'payment_stopped' | 'owner_deceased' | 'frozen_bank_account' | 'risk_review' | 'fraudulent' | 'duplicate_entry' | 'invalid_paykey' | 'payment_blocked' | 'amount_too_large' | 'too_many_attempts' | 'internal_system_error' | 'user_request' | 'ok' | 'other_network_return' | 'payout_refused' | 'cancel_request' | 'failed_verification' | 'require_review' | 'blocked_by_system' | 'watchtower_review' | 'validating' | 'auto_hold', required
      - `source` 'watchtower' | 'bank_decline' | 'customer_dispute' | 'user_action' | 'system', required
      - `message` string, required: A human-readable description of the status.
      - `code` string, nullable: The status code if applicable.
      - `changed_at` string, date-time, required: The time the status change occurred.
      - `status` 'created' | 'scheduled' | 'failed' | 'cancelled' | 'on_hold' | 'pending' | 'paid' | 'reversed' | 'validating', required: The current status of the `charge` or `payout`.
    - `metadata` object, nullable: Up to 20 additional user-defined key-value pairs. Useful for storing additional information about the payout in a structured format.
    - `funding_ids` string[], required: Funding Ids
    - `trace_ids` object, required: Trace Ids.
    - `related_payments` RelatedPaymentV1[], nullable: Related payments.
      - `id` string, uuid, required: The ID of the related payment.
      - `relationship` 'original' | 'resubmit' | 'refund', required
      - `payment_type` 'charge' | 'payout', required: The type of payment.
    - `is_refund` boolean, required: Is the payout a refund of an original charge.
    - `is_resubmit` boolean, required: Is the payout a resubmit of an original payout.
    - `has_resubmit` boolean, required: Has the payout been resubmitted.
    - `documents` DocumentV1[], nullable: Documents uploaded for this payout (e.g. proof of authorization), in the order they were uploaded.
      - `document_id` string, uuid, required: Unique identifier for this document.
      - `document_name` string, required: The file name of this document as uploaded.
      - `document_type` 'payment_authorization', required
      - `document_size` integer, required: The size of this document in bytes.
      - `uploaded_at` string, date-time, required: The UTC timestamp when this document was uploaded.

## Other responses

- `400`: Bad Request
- `401`: Unauthorized
- `403`: Forbidden
- `422`: Validation Failed
- `500`: Server Error

## Changes

- **2026-10-16** `de39a60c562e`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/straddleio/apis/straddle-api/changes/v1/charges/:id/refund/post.md)

---

[API](https://skmtc.dev/straddleio/apis/straddle-api.md) - [All operations](https://skmtc.dev/straddleio/apis/straddle-api/llms.txt) - [OpenAPI document](https://skmtc.dev/straddleio/apis/straddle-api/revisions/7317fef4a9b0?raw)
