AnnouncementsIntroducing Arkoren

    Menu

    Payment Refunds

    Request explicit refund amounts and read the refund's own progress without confusing acceptance with completion.

    What's on this page
    1. Request an explicit positive refund amount with its own durable operation key.
    2. Read independent refund progress without treating pending acceptance as returned funds.
    3. Preserve provider-specific resource handles and avoid duplicate uncertain refunds.
    On this page

    A refund is a separate resource whose progress can outlast the request that created it. Use a configured client named payments, caller context ctx, and the original financial payment ID saved against your order. Import arkoren.dev/core/service/payment for the request and status types.

    Choosing Amounts

    Authorize the refund against the saved order/account and select its persisted merchant and test/live environment. Do not accept an arbitrary provider ID from the caller. Calculate the refund under your server-side policy and keep its currency equal to the original payment’s currency.

    For EUR 5.00 of an existing EUR payment, construct an exact positive amount:

    refundAmount, err := payment.NewMoney("EUR", 500)

    A full refund also requires an explicit positive amount. Zero does not mean “the remainder.” The provider enforces the remaining refundable balance, including concurrent requests; a locally calculated balance is not a reservation.

    Submitting Refunds

    Give this logical refund its own durable operation key, distinct from checkout and completion keys. Save the immutable request, original payment ID, and merchant/environment before dispatch:

    request := payment.NewRefundRequest(paymentID, refundAmount, "book-184-refund-1")

    Reuse that key only for the identical request within the provider’s documented scope and retention. A second intended partial refund is a different operation; it must not become a way to repeat an unresolved first refund.

    A failed refund reply can follow an accepted refund. Keep the original request/key and any returned refund references even with an error. A later rejection or read failure does not settle that earlier attempt. Follow Payment Recovery rather than issuing a fresh-key refund.

    Submit the saved request:

    refund, err := payments.RefundPayment(ctx, request)

    Record the result before telling the buyer it completed. An accepted RefundStatusPending is normal provider progress, not returned money and not an outcome-unknown error. The facade does not perform a hidden balance lookup or post-mutation read; a driver can document a required currency preflight.

    Reading Progress

    Save the entire refund.ID, not a token extracted from its value. To obtain a later observation, read the saved refundID without resubmitting the refund:

    observed, err := payments.GetRefund(ctx, refundID)

    After a successful read, reconcile the returned identity, expected amount, and any observed payment relationship against your saved operation. Missing relationships remain absent rather than being guessed.

    Status Interpretation
    RefundStatusSucceeded The provider confirms refund success.
    RefundStatusPending The refund is not finalized.
    RefundStatusRequiresAction Further action is required; funds are not confirmed returned.
    RefundStatusFailed A known unsuccessful refund outcome.
    RefundStatusCanceled Canceled before success.
    RefundStatusUnknown No mapped state; do not treat it as success.

    Your application chooses when to read and how to notify the buyer. Provider notifications can repeat or arrive out of order, so persist reconciliation idempotently. Refunding a payment does not cancel a recurring agreement; subscription cancellation is separate.

    Provider Limits

    Stripe checks the PaymentIntent’s currency before submitting an explicit refund. PayPal refunds Payments v2 captures only; subscription sale lookup/refund returns ErrUnsupported. A sale ID cannot be substituted for a capture ID.

    Mollie’s opaque compound refund handle carries the parent payment needed for lookup. Preserve it verbatim. Its queued/pending/processing states remain pending; only refunded succeeds. Mollie caches POST replies for one hour per exact credential, so credential rotation or replay after expiry can duplicate an unresolved refund. Its classic callback carries a payment ID, not this compound handle: read the refund IDs already saved by your application.

    Use Testing to script pending, succeeded, and uncertain replies without financial effects. For request and result types, see the payment API.

    Open a bulk documentation archive?

    This file contains every guide in its scope, not API declarations. Loading it all into an agent can exhaust its context window and increase processing time and cost. For coding tasks, start with the index and read only the relevant pages.

    Use the full archive for offline indexing, bulk processing, or deliberate large-context use.

    Browse the index instead
    Open archive