> For the complete documentation index, see [llms.txt](https://refkit.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://refkit.gitbook.io/docs/integrate-refkit/api-revenue.md).

# Report revenue with the API

Use API reporting when your backend should send normalized payments, refunds, and disputes to RefKit.

## Before reporting revenue

Complete [capture and identify](/docs/integrate-refkit/manual-setup.md). Persist the returned `customer_id` and `program_id` with your Customer or billing record.

## Report a payment

```bash
curl https://app.refkit.net/v1/transactions \
  -H "Authorization: Bearer $REFKIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "payment_id": "invoice_123",
    "customer_id": "rcus_...",
    "program_id": "prg_...",
    "amount": 2900,
    "currency": "usd"
  }'
```

* `payment_id` must be stable and unique for the payment.
* `amount` is a non-negative integer in minor units. `2900` means USD 29.00. A zero-value payment records history without commission.
* `currency` is a lowercase three-letter ISO currency.
* Report every successful renewal as a new payment with its own stable ID.
* A test key creates isolated, non-payable test activity.
* The key mode must match the Affiliate attribution mode established during identify. RefKit rejects mixed Test and Live attribution.

The same request can be retried safely. A replay returns `200`; a new payment returns `201`.

## Report a refund

```bash
curl https://app.refkit.net/v1/transactions/refunds \
  -H "Authorization: Bearer $REFKIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "refund_id": "refund_123",
    "payment_id": "invoice_123",
    "amount": 1450
  }'
```

Use a stable `refund_id` for one parent payment. Reusing it for another payment returns a conflict, even when the amount is the same. Cumulative refunds plus disputes that are opened or lost cannot exceed the original payment.

## Report a dispute

Use one stable `dispute_id` for the full lifecycle. Report each status change:

```bash
curl https://app.refkit.net/v1/transactions/disputes \
  -H "Authorization: Bearer $REFKIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "dispute_id": "dispute_123",
    "payment_id": "invoice_123",
    "status": "opened",
    "amount": 2900
  }'
```

Supported statuses:

* `opened`: hold approved commission.
* `won` or `withdrawn`: release the hold.
* `lost`: append a proportional commission reversal.
* `funds_reinstated`: append the matching reinstatement after a loss.

The dispute amount is a positive integer in minor units. Refunds plus disputes in `opened` or `lost` cannot exceed the parent payment. Won, withdrawn, and reinstated disputes no longer consume that balance. Overlapping open disputes keep the commission held until all of them resolve.

Repeat the request with the same `dispute_id`, `payment_id`, and `amount` when the status changes. A terminal outcome can arrive before `opened`; a delayed `opened` event cannot move it backward. Conflicting terminal outcomes return a conflict.

## Delivery order, retries, and corrections

* Report the parent payment before its refund or dispute. If the parent is missing, retry after the payment is accepted.
* Exact payment, refund, and dispute requests are safe to retry. A replay returns `200`.
* Payment, refund, and dispute IDs are isolated by App and Test or Live mode.
* Accepted identity details are immutable. Correct a payment by reporting a new refund and, when needed, a replacement payment with new stable IDs.
* Do not report subscription cancellation or a failed payment attempt as revenue.
* Report provider events only after they are successful or complete. Retry timeouts and server errors with the same stable identity. Treat validation and identity conflicts as terminal until the payload or integration is fixed.

## Rules

* Do not attach RefKit metadata to Stripe objects for this revenue path.
* Do not send API revenue to an App configured for Stripe.
* The payment currency must match the Program currency.
* Unattributed payments remain in history and create no commission. They also raise the setup alarm so the missing identify or metadata flow can be investigated.
* Test activity and zero-value live history do not lock the App revenue source. The first positive live payment does.

See [REST API](/docs/reference/rest-api.md) for endpoint and error details.
