Refunds

Refunds are vendor-initiated and non-custodial. The vendor signs and broadcasts the refund transaction directly from their wallet to the consumer's wallet. APISettle tracks and validates the refund but never holds the funds.

How refunds work

  1. 1 Create intent — Vendor calls POST /refunds with the settlement ID and refund amount.
  2. 2 Sign and broadcast — Vendor signs a Solana transfer from their wallet to the consumer's wallet and broadcasts it.
  3. 3 Submit tx hash — Vendor submits the transaction hash to APISettle. The platform validates and records the refund.
Vendor pays tx fee: Since the vendor initiates and signs the refund transaction, the vendor's wallet pays the Solana network fee. APISettle does not intermediate the transfer.

Create a refund intent

POST /v1/refunds

Creates a refund intent tied to a specific settlement. You can refund the full amount or a partial amount. APISettle validates that the cumulative refund doesn't exceed the original payment.

create-refund.js
// Create a refund intent for a settled payment
const res = await fetch('https://api.apisettle.com/v1/refunds', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    settlement_id: 'stl_abc123',
    amount: '2000000',       // $2.00 — full or partial
    reason: 'Customer requested cancellation',
  }),
})

const refund = await res.json()
// {
//   id: "ref_...",
//   settlement_id: "stl_abc123",
//   amount: "2000000",
//   currency: "USDC",
//   status: "pending_vendor_submit"
// }

Refund parameters

Field Type Description
settlement_id string The settlement to refund. Must be redeemed.
amount string Refund amount in USDC micro-units. Must be positive.
reason string? Optional reason (max 500 characters).

Submit the refund transaction

POST /v1/refunds/:id/submit

After broadcasting the refund transfer on Solana, submit the transaction hash so APISettle can validate and record the refund.

submit-refund.js
// After signing and broadcasting the refund tx on-chain,
// submit the tx hash to APISettle for confirmation
const res = await fetch(
  `https://api.apisettle.com/v1/refunds/${refundId}/submit`,
  {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      refund_tx_hash: '5UzH3nPjK...',
    }),
  },
)

const result = await res.json()
// { id: "ref_...", status: "confirmed", confirmed_at: "..." }

Refund lifecycle

Status Meaning
pending_vendor_submit Intent created. Awaiting vendor's on-chain tx.
submitted Tx hash submitted. Awaiting on-chain confirmation.
confirmed Refund confirmed on-chain. Consumer received funds.
failed On-chain tx failed or validation error.
cancelled Vendor cancelled before submitting tx.
expired Vendor didn't submit tx within the allowed window.

Partial refunds

You can issue multiple partial refunds against the same settlement. APISettle tracks the cumulative refunded amount and rejects any refund that would exceed the original payment.

Example: A $10.00 settlement can be refunded as $3.00 + $4.00 + $3.00 (three separate refunds totaling $10.00). A fourth refund of any amount would be rejected.

Other refund operations

Action Endpoint
Cancel a pending refund POST /refunds/:id/cancel
Get refund details GET /refunds/:id
List all refunds GET /refunds