Skip to content

Payment Management

Overview

Payment management handles post-processing operations including refunds, cancellations, disputes, retry logic, and transaction history. This guide covers the complete management lifecycle for payments after initial processing.

Breaking change - money fields are now structured objects

All monetary fields on payments are returned as structured objects, not plain numbers. See the Orders guide for the full format reference.

json
"amount": { "amount": 347.47, "cents": 34747, "currency": "USD", "formatted": "347.47 USD" }

Fields affected: amount, refunded_amount, refundable_amount.

Table of Contents

Refunding Payments

Full Refund

Endpoint: POST /api/v1/sales/payments/{payment}/refund

Authentication: Required (Bearer token)

Purpose: Issue full or partial refund for completed payment

Prerequisites:

  • Payment must be in completed status
  • Payment must not be fully refunded already
  • Refund must be within allowed timeframe (typically 180 days)

Request Body (Full Refund):

json
{
  "amount": 347.47,
  "refund_reason": "product_return",
  "reason_details": "Customer returned product - defective",
  "notify_customer": true,
  "refund_method": "original_payment_method"
}

Response (200 OK):

json
{
  "success": true,
  "message": "Payment refunded successfully",
  "data": {
    "id": "01hwxyz123abc456def789ghk7",
    "payment_number": "PAY-12345678",
    "status": "refunded",
    "amount": { "amount": 347.47, "cents": 34747, "currency": "USD", "formatted": "347.47 USD" },
    "refunded_amount": { "amount": 347.47, "cents": 34747, "currency": "USD", "formatted": "347.47 USD" },
    "refund": {
      "id": "01hwxyz123abc456def789ghm1",
      "refund_number": "REF-87654321",
      "amount": 347.47,
      "refund_reason": "product_return",
      "reason_details": "Customer returned product - defective",
      "refund_method": "credit_card",
      "processed_at": "2025-12-19T10:00:00Z",
      "expected_arrival": "2025-12-24"
    },
    "refunded_at": "2025-12-19T10:00:00Z",
    "customer_notified": true
  }
}

Partial Refund

Request Body:

json
{
  "amount": 100.00,
  "refund_reason": "partial_return",
  "reason_details": "Customer returned 1 of 2 items",
  "notify_customer": true
}

Response:

json
{
  "success": true,
  "message": null,
  "data": {
    "status": "partially_refunded",
    "amount": 347.47,
    "refunded_amount": 100.00,
    "remaining_amount": 247.47,
    "refund": {
      "id": "01hwxyz123abc456def789ghm1",
      "amount": 100.00,
      "refund_reason": "partial_return"
    }
  },
  "meta": {}
}

Refund Reasons

Standard Refund Reasons:

  • customer_request - Customer requested refund
  • product_return - Product returned
  • defective_product - Product defective or damaged
  • wrong_item_shipped - Incorrect item shipped
  • duplicate_charge - Duplicate payment processed
  • cancelled_order - Order cancelled
  • service_not_provided - Service not delivered
  • billing_error - Billing mistake
  • other - Other reason (provide details)

Viewing Refunds

Endpoint: GET /api/v1/sales/payments/{payment}/refunds

Response (200 OK):

json
{
  "success": true,
  "message": null,
  "data": [
    {
      "id": "01hwxyz123abc456def789ghm1",
      "refund_number": "REF-87654321",
      "amount": 100.00,
      "refund_reason": "partial_return",
      "refund_method": "credit_card",
      "status": "completed",
      "processed_at": "2025-12-19T10:00:00Z",
      "expected_arrival": "2025-12-24",
      "gateway_refund_id": "re_1234567890"
    }
  ],
  "meta": {
    "total_refunds": 1,
    "total_refunded": 100.00,
    "remaining_refundable": 247.47
  }
}

Canceling Payments

Cancel Payment

Endpoint: POST /api/v1/sales/payments/{payment}/cancel

Authentication: Required (Bearer token)

Purpose: Cancel payment before processing completes

Prerequisites:

  • Payment must be in pending or processing status
  • Payment not yet completed
  • Cancellation must be possible (not all gateways support mid-processing cancellation)

Request Body:

json
{
  "cancellation_reason": "Customer requested cancellation before processing",
  "notify_customer": true,
  "release_invoice_hold": true
}

Response (200 OK):

json
{
  "success": true,
  "message": "Payment cancelled successfully",
  "data": {
    "id": "01hwxyz123abc456def789ghk7",
    "payment_number": "PAY-12345678",
    "status": "cancelled",
    "cancelled_at": "2025-12-18T10:30:00Z",
    "cancellation_reason": "Customer requested cancellation before processing",
    "invoice_updated": true,
    "customer_notified": true
  }
}

What Happens on Cancellation:

  1. Payment status changes to cancelled
  2. No funds transferred
  3. Invoice remains unpaid
  4. Customer notified if requested
  5. Payment cannot be reactivated

Error Response:

json
{
  "success": false,
  "message": "Payment already completed. Use refund endpoint instead.",
  "errors": {
    "status": ["Payment already completed. Use refund endpoint instead."]
  },
  "meta": {}
}

Voiding Authorizations

Void Authorized Payment

Endpoint: POST /api/v1/sales/payments/{payment}/void

Authentication: Required (Bearer token)

Purpose: Cancel payment authorization and release reserved funds

Prerequisites:

  • Payment must be in authorized status
  • Authorization must not be expired
  • Authorization must not be captured

Request Body:

json
{
  "void_reason": "Order cancelled - void authorization",
  "notify_customer": true
}

Response (200 OK):

json
{
  "success": true,
  "message": "Payment authorization voided successfully",
  "data": {
    "id": "01hwxyz123abc456def789ghk7",
    "payment_number": "PAY-12345678",
    "status": "voided",
    "voided_at": "2025-12-18T15:00:00Z",
    "void_reason": "Order cancelled - void authorization",
    "authorization_released": true,
    "funds_available_to_customer": true,
    "customer_notified": true
  }
}

Void vs Cancel vs Refund:

  • Void: Release authorization (funds never captured)
  • Cancel: Stop pending/processing payment (before completion)
  • Refund: Return captured funds (after completion)

Retrying Failed Payments

Retry Failed Payment

Endpoint: POST /api/v1/sales/payments/{payment}/retry

Authentication: Required (Bearer token)

Purpose: Retry failed payment with same or updated details

Prerequisites:

  • Payment must be in failed status
  • Failure reason must be retryable (not fraud/blocked)
  • Updated payment details available (if failure due to invalid data)

Request Body (Retry with Same Details):

json
{
  "retry_reason": "Temporary gateway error - retrying",
  "use_original_details": true
}

Request Body (Retry with Updated Details):

json
{
  "retry_reason": "Updated card details provided by customer",
  "use_original_details": false,
  "payment_method_token": "pm_new_token_9876",
  "billing_address": {
    "street": "456 New St",
    "city": "San Francisco",
    "state": "CA",
    "postal_code": "94105",
    "country": "US"
  }
}

Response (200 OK):

json
{
  "success": true,
  "message": "Payment retry initiated successfully",
  "data": {
    "id": "01hwxyz123abc456def789ghk7",
    "payment_number": "PAY-12345678",
    "status": "processing",
    "retry_count": 1,
    "previous_failure_reason": "insufficient_funds",
    "retry_initiated_at": "2025-12-19T11:00:00Z"
  }
}

Automatic Retry Logic: The system can automatically retry failed payments based on configuration:

  • Retry 1: After 1 hour
  • Retry 2: After 24 hours
  • Retry 3: After 72 hours
  • Max retries: 3 (configurable)

Non-Retryable Failures:

  • Stolen card
  • Fraud detected
  • Invalid card number
  • Expired card (unless updated)
  • Customer blocked
  • Payment method disabled

Dispute Management

Handling Disputed Payments (Chargebacks)

Endpoint: POST /api/v1/sales/payments/{payment}/dispute

Authentication: Required (Bearer token)

Purpose: Record and manage payment disputes/chargebacks

Request Body:

json
{
  "dispute_reason": "fraudulent",
  "dispute_amount": 347.47,
  "dispute_date": "2025-12-25",
  "dispute_id": "DIS-123456789",
  "evidence_required": true,
  "evidence_due_date": "2026-01-08",
  "notes": "Customer claims unauthorized charge"
}

Response (200 OK):

json
{
  "success": true,
  "message": "Payment dispute recorded successfully",
  "data": {
    "id": "01hwxyz123abc456def789ghk7",
    "payment_number": "PAY-12345678",
    "status": "disputed",
    "disputed_at": "2025-12-25T00:00:00Z",
    "dispute": {
      "id": "DIS-123456789",
      "reason": "fraudulent",
      "amount": 347.47,
      "dispute_date": "2025-12-25",
      "evidence_due_date": "2026-01-08",
      "status": "open"
    },
    "funds_held": true,
    "action_required": "submit_evidence"
  }
}

Dispute Reasons

Common Dispute Reasons:

  • fraudulent - Customer claims unauthorized charge
  • unrecognized - Customer doesn't recognize charge
  • duplicate - Customer charged twice
  • product_not_received - Product never delivered
  • product_unacceptable - Product defective/not as described
  • credit_not_processed - Refund not received
  • subscription_cancelled - Charged after cancellation
  • other - Other reason

Viewing Failed Payments

Endpoint: GET /api/v1/sales/payments/failed

Response (200 OK):

json
{
  "success": true,
  "message": null,
  "data": [
    {
      "id": "01hwxyz123abc456def789ghm2",
      "payment_number": "PAY-12345680",
      "status": "failed",
      "amount": 299.00,
      "method": "credit_card",
      "failure_reason": "insufficient_funds",
      "failed_at": "2025-12-18T11:00:00Z",
      "retry_count": 2,
      "can_retry": true,
      "customer": {
        "id": "01hwxyz123abc456def789ghm3",
        "company_name": "Beta Corp"
      }
    }
  ],
  "meta": {
    "total_failed": 1,
    "total_failed_amount": 299.00,
    "retryable_count": 1
  }
}

Viewing Disputed Payments

Endpoint: GET /api/v1/sales/payments/disputed

Response (200 OK):

json
{
  "success": true,
  "message": null,
  "data": [
    {
      "id": "01hwxyz123abc456def789ghk7",
      "payment_number": "PAY-12345678",
      "status": "disputed",
      "amount": 347.47,
      "dispute_reason": "fraudulent",
      "disputed_at": "2025-12-25T00:00:00Z",
      "evidence_due_date": "2026-01-08",
      "days_to_respond": 14,
      "requires_urgent_action": false
    }
  ],
  "meta": {
    "total_disputed": 1,
    "total_disputed_amount": 347.47,
    "evidence_required": 1,
    "urgent_disputes": 0
  }
}

Payment Transactions

View Transaction History

Endpoint: GET /api/v1/sales/payments/{payment}/transactions

Authentication: Required (Bearer token)

Purpose: View complete transaction history for a payment

Response (200 OK):

json
{
  "success": true,
  "message": null,
  "data": [
    {
      "id": "01hwxyz123abc456def789ghm4",
      "type": "authorization",
      "amount": 347.47,
      "status": "succeeded",
      "gateway_transaction_id": "auth_1234567890",
      "created_at": "2025-12-18T09:00:00Z"
    },
    {
      "id": "01hwxyz123abc456def789ghm5",
      "type": "capture",
      "amount": 347.47,
      "status": "succeeded",
      "gateway_transaction_id": "ch_1234567890",
      "created_at": "2025-12-18T14:30:00Z"
    },
    {
      "id": "01hwxyz123abc456def789ghm6",
      "type": "refund",
      "amount": -100.00,
      "status": "succeeded",
      "gateway_transaction_id": "re_1234567890",
      "created_at": "2025-12-19T10:00:00Z"
    }
  ],
  "meta": {
    "total_transactions": 3,
    "net_amount": 247.47
  }
}

Transaction Types

Authorization:

  • Reserves funds
  • Does not transfer money
  • Expires after hold period

Capture:

  • Transfers reserved funds
  • Completes payment
  • Creates settlement

Refund:

  • Returns funds to customer
  • Reverses capture
  • May have fees

Void:

  • Cancels authorization
  • Releases reserved funds
  • No money transferred

Chargeback:

  • Customer dispute
  • Funds held/reversed
  • Requires evidence

Payment Reconciliation

Payment Statistics

Endpoint: GET /api/v1/sales/payments/statistics

Query Parameters:

  • from_date (date) - Start date
  • to_date (date) - End date
  • method (string) - Filter by payment method
  • status (string) - Filter by status

Response (200 OK):

json
{
  "success": true,
  "message": null,
  "data": {
    "period": {
      "from": "2025-12-01",
      "to": "2025-12-31"
    },
    "payment_counts": {
      "total": 1247,
      "completed": 1156,
      "failed": 45,
      "disputed": 3,
      "refunded": 23,
      "pending": 20
    },
    "financial_metrics": {
      "total_processed": 1245678.90,
      "total_refunded": 23456.78,
      "total_fees": 34567.89,
      "net_revenue": 1187654.23,
      "average_transaction": 998.87
    },
    "method_breakdown": {
      "credit_card": {
        "count": 856,
        "amount": 876543.21,
        "percentage": 70.4
      },
      "bank_transfer": {
        "count": 234,
        "amount": 234567.89,
        "percentage": 18.8
      },
      "paypal": {
        "count": 157,
        "amount": 134567.80,
        "percentage": 10.8
      }
    },
    "success_metrics": {
      "success_rate": 96.2,
      "failure_rate": 3.6,
      "dispute_rate": 0.2,
      "average_processing_time_seconds": 4.5
    }
  }
}

Payment Activities

Endpoint: GET /api/v1/sales/payments/{payment}/activities

Response (200 OK):

json
{
  "success": true,
  "message": null,
  "data": [
    {
      "id": "01hwxyz123abc456def789ghm7",
      "type": "payment_refunded",
      "description": "Partial refund issued - $100.00",
      "user": {
        "id": "01hwxyz123abc456def789ghi9",
        "name": "Jane Manager"
      },
      "metadata": {
        "refund_amount": 100.00,
        "refund_reason": "partial_return"
      },
      "created_at": "2025-12-19T10:00:00Z"
    },
    {
      "id": "01hwxyz123abc456def789ghm8",
      "type": "payment_completed",
      "description": "Payment processed successfully",
      "user": {
        "id": null,
        "name": "System"
      },
      "metadata": {
        "gateway": "stripe",
        "transaction_id": "ch_1234567890"
      },
      "created_at": "2025-12-18T14:30:00Z"
    },
    {
      "id": "01hwxyz123abc456def789ghm9",
      "type": "payment_authorized",
      "description": "Payment authorized",
      "user": {
        "id": "01hwxyz123abc456def789ghl3",
        "name": "John Sales"
      },
      "metadata": {
        "authorization_code": "AUTH-456789"
      },
      "created_at": "2025-12-18T09:00:00Z"
    }
  ],
  "meta": {}
}

Best Practices

  1. Refund Promptly: Process refunds quickly to maintain customer satisfaction

  2. Document Everything: Record detailed reasons for refunds, cancellations, and disputes

  3. Monitor Dispute Rate: High dispute rates may indicate fraud or customer service issues

  4. Retry Intelligently: Use exponential backoff for automatic payment retries

  5. Track Transaction History: Maintain complete audit trail for compliance

  6. Respond to Disputes Quickly: Submit evidence before deadline to avoid automatic loss

  7. Reconcile Daily: Match payment records with gateway settlements daily

  8. Handle Partial Refunds Carefully: Ensure accounting properly reflects partial refunds

  9. Test Refund Flows: Verify refund processing in test environment before production

  10. Notify Customers: Always inform customers of refunds, cancellations, and disputes

Documentation for SynthesQ CRM/ERP Platform