Reversing Donations and Canceling Recurring Profiles

This API lets you refund donations and cancel recurring donation profiles through the same REST endpoints used to fetch them.

A reversal on an order or transaction calls the payment processor to request a refund or void. A cancel on a recurring profile stops future charges but does not refund anything that has already been charged.

Warning

Reversals are permanent. Once a charge has been reversed at the processor there is no way to undo it — the donor’s card has been credited and the transaction is marked reversed in ActionKit. If you want the donation back, the donor has to make a new one.

The staff account you authenticate with must have permission to manage donations.

Background: Orders, Transactions, and Recurring Profiles

Before reversing a donation it helps to know how the three relevant resources relate:

  • /rest/v1/order/ (core_order) — one row per donation action. For a recurring donation there is exactly one order per recurring profile, not one order per charge.

  • /rest/v1/transaction/ (core_transaction) — one row per processor interaction (sale, credit, etc.) attached to an order. A recurring profile’s single order accumulates multiple transaction rows over time, one per successful or failed charge.

  • /rest/v1/orderrecurring/ (core_orderrecurring) — the recurring profile (schedule, account, status, etc).

This means a recurring donation has one order, one orderrecurring, and many transactions. When picking which endpoint to use, read the next two sections.

To do this

Use

Refund a one-time donation

POST /rest/v1/order/<order_id>/reverse/

Refund a specific recurring charge

POST /rest/v1/transaction/<transaction_id>/reverse/

Stop a recurring profile

POST /rest/v1/orderrecurring/<orderrecurring_id>/cancel/

Reverse An Order

POST to /rest/v1/order/<order_id>/reverse/ to reverse the order’s initial payment. The request body is ignored.

$ curl -i -u user:password -X POST \
    https://docs.actionkit.com/rest/v1/order/12345/reverse/
HTTP/1.1 202 ACCEPTED

After a successful reversal the order’s status becomes reversed and the underlying transaction’s status becomes reversed. If the order has already been reversed the endpoint returns 400 Bad Request:

{ "order_id": "Order has already been reversed." }

Note

Don’t use this endpoint for recurring donations. If you want to reverse payments, reverse the specific transaction instead — see Reverse A Transaction. If you want to stop future payments, see Cancel A Recurring Profile.

When you GET an order whose status is completed, the response includes a "reverse" URL pointing at this endpoint, so clients can discover the action without hard-coding the URL pattern:

{
    "id": 12345,
    "status": "completed",
    "reverse": "/rest/v1/order/12345/reverse/",
    ...
}

Reverse A Transaction

POST to /rest/v1/transaction/<transaction_id>/reverse/ to reverse a specific transaction. This is the right endpoint for refunding one charge in a recurring series. The request body is ignored.

Note

<transaction_id> is the ActionKit primary key (core_transaction.id), not the processor’s transaction ID (core_transaction.trans_id). This is a common mistake.

$ curl -i -u user:password -X POST \
    https://docs.actionkit.com/rest/v1/transaction/98765/reverse/
HTTP/1.1 202 ACCEPTED

After a successful reversal the transaction’s status becomes reversed. If the transaction has already been reversed the endpoint returns 400 Bad Request:

{ "order_id": "Transaction has already been reversed." }

Note

Only full reversals are supported through the API. Partial refunds must be issued through the admin interface.

As with orders, completed transactions include a discoverable "reverse" URL in their GET response.

To find the transactions attached to an order, filter the transaction list by order:

GET /rest/v1/transaction/?order=12345

Cancel A Recurring Profile

POST to /rest/v1/orderrecurring/<orderrecurring_id>/cancel/ to cancel a recurring profile. This stops future charges but does not refund anything that has already been charged. To refund past charges, reverse the relevant transactions (see Reverse A Transaction). The request body is ignored.

$ curl -i -u user:password -X POST \
    https://docs.actionkit.com/rest/v1/orderrecurring/4567/cancel/
HTTP/1.1 202 ACCEPTED

The profile must be in an active state (active, pending, or past_due). If it is already in a terminal state the endpoint returns 400 Bad Request with the current status:

{ "orderrecurring_id": "OrderRecurring is not active: Canceled by user" }

When you GET an active recurring profile, the response includes a "cancel" URL pointing at this endpoint.

Note

This is the operational cancel endpoint, which talks to the payment processor. If you instead need to record a cancellation that already happened in an external system (an import stub workflow), see Cancellations Of Existing Profiles in the Donation Push API.