Skip to main content
Understanding payment statuses is critical for properly handling charges and payouts. Every payment moves through a defined lifecycle with specific status transitions. Knowing when payments can be modified—or when they become unstoppable—directly impacts your application’s payment logic and user experience.

What This Reference Covers

This comprehensive guide provides everything you need to handle payment statuses correctly:
  • Status lifecycles: The complete flow from creation to terminal states
  • The pending threshold: Why pending status is the point of no return
  • Failed vs reversed: Critical distinction between pre-funding and post-funding failures
  • ACH return codes: All R-codes and S-codes with their meanings and timing
  • Status reasons: Complete catalog of failure reasons and their sources
  • Status/Source/Reason matrix: Valid combinations showing what actually occurs
  • Implementation patterns: Code examples for monitoring and handling status changes
Whether you’re building retry logic, handling disputes, or reconciling returns, this reference ensures you respond appropriately to every payment state.

Payment Lifecycle Overview

The happy path for payments follows this progression:
1

Created

Payment successfully created and awaiting verification
2

Scheduled

Payment passed verifications and risk scoring, queued for processing
3

Pending

Payment sent to network - CANNOT BE STOPPED
4

Paid

Payment successfully funded
Critical Understanding: Once a payment reaches pending status, it has been submitted to the payment network and cannot be stopped, held, or cancelled. The payment must complete its network processing.

Status Values

Complete Status Reference

*Only user-initiated holds can be released by the user; Watchtower holds require Straddle authorization
†Can still transition to reversed if return occurs post-funding

Understanding Failed vs Reversed

Status Sources

Sources identify where status changes originate:

Status/Source/Reason Matrix

Success States

Hold States

Failed States (Pre-Funding)

Reversed States (Post-Funding)

Cancelled States

Cancellation only occurs via user action in the dashboard or API

Resubmit Failed Payments

Retry any failed, reversed, or cancelled charge or payout by creating a new payment linked to the original. The new payment carries over the original bank information and payment details. Optional: provide a new payment_date, description, or external_id. Otherwise, Straddle generates these from the original payment. The new payment inherits the amount, paykey, currency, and metadata from the original. Each payment can only be resubmitted once, but if a resubmitted payment also fails, resubmit that one to create a chain. Resubmit a charge with an updated payment date and description.

Refund Paid Charges

Return funds to a customer for a paid charge directly from the dashboard or API. The refund is sent back to the customer’s original bank account using the same paykey as the source charge, so there’s no manual lookup or destination-account work. To issue a refund from the dashboard, see the step-by-step walkthrough in the help center. Each charge can be refunded once, full or partial. The refund amount must be greater than $0 and no more than the original charge amount. When you create a refund:
  • A new payout is created with payment_type: "payout" and a description of Refund for Charge ID: {id}. If you supplied your own description, it’s appended after the system prefix.
  • The original charge stays in Paid status. Refunds are tracked separately as payouts and linked through related_payments.
  • The new refund payout follows normal payout statuses (Pending → Paid).
After a refund, the original charge’s related_payments lists the new refund payout, and the refund payout’s related_payments lists the source charge. Each entry includes the linked payment’s id, relationship, and payment_type. Relationship values:
  • original: the linked payment is the source. Appears on the refund payout, pointing back to the charge.
  • refund: the linked payment is a refund. Appears on the original charge, pointing to the new refund payout.
Since a refund is created as a payout, the standard payout.* webhook events fire for the refund lifecycle. Existing payout handlers track refunds without changes.

When You Can’t Refund

  • The charge is not in paid status. Use Resubmit for failed, reversed, or cancelled charges.
  • The charge has already been refunded. Each charge can have one refund; check related_payments before retrying.
  • Two requests reach the API at the same time. Straddle uses optimistic concurrency to prevent duplicate refunds — one request succeeds, the other gets a 422 with a clear message.

Important: Same Reason, Different Sources

Some reason codes can originate from different sources depending on when they’re detected:

insufficient_funds

Key distinction:
  • Watchtower: Proactive check using real-time balance data — payment never leaves Straddle
  • Bank Decline: Reactive return from the ACH network after the payment was sent

Status Reasons

Active Reason Codes

These reason codes are actively used by the system:

ACH Return Codes

Standard ACH Returns (R-Codes)

Straddle Internal Codes (S-Codes)

Status Details Structure

Every payment includes detailed status information:

Handling Status Changes

Monitoring for Status Changes

Handling Specific Failure Reasons

Common Scenarios

Successful Payment Flow

  1. createdsystem / ok - Payment initialized
  2. scheduledsystem / ok - Verification passed, risk approved
  3. pendingsystem / ok - Sent to ACH network
  4. paidsystem / ok - Funds successfully transferred

Pre-Submission Balance Check Failure

  1. createdsystem / ok
  2. Balance check detects insufficient funds
  3. failedwatchtower / insufficient_funds
  4. No money moved, payment never sent to bank

NSF After Submission (ACH Return)

  1. createdscheduledpending
  2. Bank returns with R01
  3. failedbank_decline / insufficient_funds / code: R01
  4. No money moved (failed before funding)

Dispute After Funding

  1. createdscheduledpendingpaid
  2. Customer disputes with their bank
  3. Bank sends R10 return
  4. reversedcustomer_dispute / disputed / code: R10
  5. Money was moved, then returned

Risk Hold and Release

  1. createdsystem / ok - Payment initialized
  2. Watchtower flags for review
  3. on_holdwatchtower / risk_review
  4. Manual review in dashboard
  5. If approved: released → scheduled → normal flow
  6. If declined: → failed or cancelled

User-Initiated Hold

  1. createdsystem / ok
  2. User calls hold API
  3. on_holduser_action / user_request
  4. User can release when ready
  5. Released → continues processing

Best Practices

Monitor Pending Status

Once pending, payments cannot be stopped. Plan accordingly.

Check Both Source and Reason

The same reason can come from different sources with different implications.

Handle Failed vs Reversed

Different workflows for pre-funding failures vs post-funding reversals.

Track Return Codes

Log ACH return codes for reconciliation and pattern analysis.

Next Steps

Webhook Events

Set up real-time status notifications

Testing Statuses

Test various status scenarios in sandbox

Charges Guide

Learn about charge-specific flows

Payouts Guide

Understand payout-specific scenarios