---
title: "How to review and validate Rewards using the Events API (REST)"
url: "https://docs.aklamio.com/en/article/how-to-edit-a-reward-copy"
language: "en"
last_updated: "2026-08-17T10:41:35.911Z"
---

# How to review and validate Rewards using the Events API (REST)

**Platform:** Developers - **Quick Summary:** Use the Events API's sales endpoints to list incoming sales, check the details of an individual sale, correct its line items, and confirm or reject it before a reward is paid out.

| 💡 Full OpenAPI documentation is available on our [Developers' page.](https://developers.aklamio.com/openapi/v3-events-sales/index.html) |
| --- |

## Why use this

Every sale your integration sends to Aklamio is a potential reward for one of your customers. Before that reward get paid out, you need a reliable way to validate it, and decide whether it should go ahead. The Events API gives you that control programmatically: list and inspect sales as they arrive, fix a sale's line items if something's off, and confirm or reject it, all without leaving your own systems or dashboards.

This article walks through the core review and validation flow: **list sales**, **get a single sale**, **update a sale**, **confirm a sale**, **reject a sale**, and **create a sale** directly when you need to submit one on demand.

> A quick note on terminology: in the API, a sale moves through the states `unmatched`, `open`, `confirmed`, `rejected`, and `closed`. `Open` is the state you'll review and act on; `confirmed` and `rejected` are the outcomes of that review.

## Before you start

You'll need:

-   An **Api-Secret** key, provisioned by Aklamio for your brand. Every request must include it in the `Api-Secret` header. Ask your AKlamio Integration Manager for your **Api-Secre** or generate one directly from the PIFC if you have sufficient platform permissions. 
-   Your **promotionUid**, the identifier for the incentive program whose sales you want to work with. Your API key is scoped to your brand and works across all programs / promotions in that brand, but every request still needs a `promotionUid` to tell the API which promotion to look at.
-   A tool to send HTTP requests: curl, Postman, or your own backend code all work. The examples below use curl.

All requests go to `https://api.aklamio.com/v3/events/sales`.

## Step-by-step guide

### 1\. List sales to see what's come in

Start by pulling the sales for a promotion so you can see what needs review.

```plaintext
GET /v3/events/sales?promotionUid=<promotion_uid>
```

```plaintext
curl -X GET \
  -H 'Api-Secret: <api_key>' \
  'https://api.aklamio.com/v3/events/sales?promotionUid=<promotion_uid>'
```

By default, this returns every sale for the promotion, including ones that haven't been matched to a customer yet (`status: unmatched`). If you only want sales that are ready for a decision, filter down:

-   Add `status=open` to see only sales awaiting review.
-   Add `hasSalesRequest=true` to exclude unmatched, event-only entries entirely.
-   Add `createdAtFrom` and `createdAtTo` to narrow to a date range.
-   Add `orderId` if you're looking for one specific order.

The response is paginated. Use the `nextToken` returned in `meta.page` as the `pageToken` on your next request to keep moving through the list.

```plaintext
{
  "data": [
    {
      "id": "4f91cc9f-6e9f-4d72-b9f7-3f4e2a1d4f90",
      "orderId": "ORD-2026-001",
      "status": "open",
      "hasSalesRequest": true,
      "followerEmail": "joh***@***mple.com",
      "recommenderEmail": "jan***@***mple.com",
      "lineItems": [
        { "sku": "SKU-001", "name": "Premium Widget", "category": "electronics", "price": 9999 }
      ],
      "hasFile": true
    }
  ],
  "meta": { "page": { "nextToken": "nxt_...", "pageSize": 25 } }
}
```

**What to look for:** each item's `id` is what you'll use as the `saleId` in every other step below. `hasFile: true` tells you a receipt was attached, useful to know before you decide whether you need to look at it.

### 2\. Get a single sale for the full picture

Once you've spotted a sale that needs a closer look, whether from the list, from an order ID your support team gave you, or from your own records, fetch its full detail.

```plaintext
GET /v3/events/sales/{saleId}?promotionUid=<promotion_uid>
```

```plaintext
curl -X GET \
  -H 'Api-Secret: <api_key>' \
  'https://api.aklamio.com/v3/events/sales/4f91cc9f-6e9f-4d72-b9f7-3f4e2a1d4f90?promotionUid=<promotion_uid>'
```

This is the only place you'll get a **downloadable receipt file**, if one was attached, along with the full line items, request type (referral or cashback), sales channel, and any custom fields you sent at creation. The download URL in `file.downloadUrl` expires after one hour; if it's expired, just call this endpoint again to get a fresh one.

If the `saleId` doesn't exist or isn't accessible to your account, you'll get a `404` with `resource_not_found`.

### 3\. Update a sale if the line items need correcting

If you spot an error, a wrong price, a missing item, before you confirm, you can correct it. Updating replaces the sale's line items entirely.

```plaintext
PATCH /v3/events/sales/{saleId}?promotionUid=<promotion_uid>
```

```plaintext
{
  "lineItems": [
    { "sku": "SKU-001", "name": "Premium Widget v2", "category": "electronics", "price": 8999 }
  ]
}
```

```plaintext
curl -X PATCH \
  -H 'Api-Secret: <api_key>' \
  -H 'Content-Type: application/json' \
  -d '{"lineItems":[{"sku":"SKU-001","name":"Premium Widget v2","category":"electronics","price":8999}]}' \
  'https://api.aklamio.com/v3/events/sales/4f91cc9f-6e9f-4d72-b9f7-3f4e2a1d4f90?promotionUid=<promotion_uid>'
```

The sale keeps the same `id`, so anything you've already linked to it in your own systems stays valid. Only sales in `open` or `rejected` state can be updated; you'll get a `422` if the sale has already moved to `confirmed` or `closed`, or if it's an unmatched, event-only sale with nothing to update yet.

### 4\. Confirm a sale to approve the reward

Once a sale checks out, confirm it so the reward can move forward.

```plaintext
POST /v3/events/sales/confirm
```

```plaintext
{
  "promotionUid": "<promotion_uid>",
  "ids": ["4f91cc9f-6e9f-4d72-b9f7-3f4e2a1d4f90"]
}
```

```plaintext
curl -X POST \
  -H 'Api-Secret: <api_key>' \
  -H 'Content-Type: application/json' \
  -d '{"promotionUid":"<promotion_uid>","ids":["4f91cc9f-6e9f-4d72-b9f7-3f4e2a1d4f90"]}' \
  'https://api.aklamio.com/v3/events/sales/confirm'
```

You can confirm up to 1,000 sales in a single call by listing multiple IDs. If some succeed and others don't, you'll still get a `200 OK`; check the `failures` array for anything that didn't go through, and `summary` for the overall count. IDs not listed under `failures` were confirmed successfully.

Before confirming, the API checks that your account has enough balance to cover the reward. If it doesn't, the whole batch is rejected with a `422` and the response tells you how much you need versus what's available.

### 5\. Reject a sale to decline the reward

If a sale doesn't hold up, a duplicate, invalid, doesn't meet program terms, reject it instead.

```plaintext
POST /v3/events/sales/reject
```

```plaintext
{
  "promotionUid": "<promotion_uid>",
  "ids": ["4f91cc9f-6e9f-4d72-b9f7-3f4e2a1d4f90"]
}
```

```plaintext
curl -X POST \
  -H 'Api-Secret: <api_key>' \
  -H 'Content-Type: application/json' \
  -d '{"promotionUid":"<promotion_uid>","ids":["4f91cc9f-6e9f-4d72-b9f7-3f4e2a1d4f90"]}' \
  'https://api.aklamio.com/v3/events/sales/reject'
```

This works the same way as confirming: batch up to 1,000 IDs, get partial success back in `failures` and `summary`.

### 6\. Create a sale directly, when you're not relying on tracking

Most sales arrive automatically through your tracking integration. But if you need to submit one directly, from a backoffice tool, a CSV import, or a manual entry, you can create it yourself.

```plaintext
POST /v3/events/sales
```

```plaintext
{
  "mode": "direct",
  "promotionUid": "<promotion_uid>",
  "orderId": "ORD-2026-002",
  "trackedAt": "2026-03-18T14:00:00Z",
  "recommenderEmail": "recommender@example.com",
  "followerEmail": "buyer@example.com",
  "lineItems": [
    { "sku": "SKU-001", "name": "Premium Widget", "category": "electronics", "price": 9999 }
  ]
}
```

```plaintext
curl -X POST \
  -H 'Api-Secret: <api_key>' \
  -H 'Content-Type: application/json' \
  -d '{"mode":"direct","promotionUid":"<promotion_uid>","orderId":"ORD-2026-002","trackedAt":"2026-03-18T14:00:00Z","recommenderEmail":"recommender@example.com","followerEmail":"buyer@example.com","lineItems":[{"sku":"SKU-001","name":"Premium Widget","category":"electronics","price":9999}]}' \
  'https://api.aklamio.com/v3/events/sales'
```

Set `mode` to `"direct"` and it's created and returned immediately as `201 Created`, ready to review through the same steps above. You'll need either `recommenderEmail` and `followerEmail`, or a tracking identifier like `aid` or `coupon` to resolve them automatically. If you're submitting tracking data instead and want Aklamio to match it to a recommender for you, use `mode: "tracking"` instead; that returns a `200 OK` acknowledgment while matching happens in the background, and the sale shows up in your next list call.

## 💡Best practices

-   **Filter your list calls.** Pulling every sale for a large promotion is slower and noisier than it needs to be. Use `status=open` for your day-to-day review queue, and reach for the full unfiltered list only when you need visibility into unmatched, event-only sales.
-   **Use** `**orderId**` **to reconcile.** If you created a sale in `tracking` mode, the fastest way to check whether it landed is to list sales filtered by `orderId`, rather than polling `GET` on a `saleId` you don't have yet.
-   **Batch your confirms and rejects.** If you're processing a queue of reviewed sales, send them in one call (up to 1,000 IDs) instead of one request per sale. It's faster and it's what partial success in the response is designed for.
-   **Check** `**failures**` **even on a** `**200 OK**`**.** A successful response for confirm and reject doesn't mean every sale in your batch went through; it means the batch was processed. Always check `summary.failed` before assuming everything succeeded.
-   **Log the** `**requestId**`**.** Every response includes an `X-Request-Id` header, echoed as `requestId` in the body. Hold onto it; it's the fastest way for Aklamio support to trace a specific request if something looks wrong.

## Troubleshooting / FAQ

**Why can't I update or confirm a sale I just fetched?** Only sales in the `open` state can be updated, and only `open` sales can be confirmed or rejected. If a sale is `unmatched` (no linked sales request yet), it isn't ready for any of these actions until matching has completed. Check the `status` field on the sale before acting on it.

**I got a 422 when confirming, what does "insufficient balance" mean?** Your account doesn't have enough available balance to cover the rewards for the sales in that batch. The error response includes `requiredAmount` and `availableBalance` so you can see the gap. Top up your balance or reduce the batch, then retry.

**Why did my confirm or reject request return partial results?** Confirm and reject support partial success by design. If some IDs in your batch are already confirmed, rejected, or otherwise not in a valid state, those specific IDs appear in `failures` while the rest still go through. You don't need to resubmit the whole batch, just retry the failed IDs after checking why they failed.

**Where do I find the receipt file for a sale?** Only on the single-sale `GET` endpoint, not on the list. The list only tells you `hasFile: true/false` to keep list calls fast. Call `GET /v3/events/sales/{saleId}` to get the actual `downloadUrl`.

**What's the difference between confirming and rejecting?** Confirming approves the sale, which moves the linked reward toward payout. Rejecting declines it, no reward will be issued for that sale. Both are final actions on an open sale, so review the sale's details before deciding.

## 🔗 Related articles

[Find your way around Reward Management](https://docs.aklamio.com/en/article/find-your-way-around-reward-management)

[How to validate Rewards](https://docs.aklamio.com/en/article/how-to-validate-rewards)
