# Choose a reporting strategy

Whether to ask this platform for payment data on a schedule, or to have it sent to you as it happens, and what each one costs you to run.

5 questions, 6 outcomes

## What does your reporting need from each payment?

https://devportal-simpay-sbx.winkpg.io/docs/decide/reporting-strategy/what-your-reporting-answers.md

Totals and individual payments come from different endpoints, so this is the fork that decides which half of the API you build against.

**Choose one**

- A periodic total. Counts and amounts over a day, a week, or a month. Nobody looks at an individual payment unless something is wrong. Leads to: How current do the totals have to be?.
- Every payment on its own, with its own detail. You show, store, or act on payments one at a time. Leads to: How soon after a payment do you need it?.

### How current do the totals have to be?

https://devportal-simpay-sbx.winkpg.io/docs/decide/reporting-strategy/how-current-the-totals-must-be.md

A figure computed on a schedule is one request. A figure that moves during the day is a stream you accumulate yourself.

**Choose one**

- A figure computed on a schedule answers the question. Yesterday's numbers this morning, or this month's at month end. Leads to: Read the summary reports on a schedule.
- Someone watches the number move through the day. An operations board, or an alert on the day's takings. Leads to: Keep your own totals, fed by webhooks.

#### Read the summary reports on a schedule

https://devportal-simpay-sbx.winkpg.io/docs/decide/reporting-strategy/poll-the-summary-reports.md

One request returns the figure you were going to compute, already computed.

**What to build**

Call the merchant summary report for totals over a period, and the payment type summary when the split by card, ACH, and the rest is what you are reporting. Run it on the cadence your report is published on. Don't build a webhook receiver for this: you would be accumulating a number this platform will hand you in one call.

**Worth knowing**

- Ask for a closed period. A total over a window that includes the current hour changes between two runs, which reads as a discrepancy in a report that's behaving correctly.
- Settlement, refunds, and chargebacks move a figure after the payment. Decide which of those your total is supposed to reflect before you compare two runs against each other.

**Where to go next**

- [Merchant summary report](https://devportal-simpay-sbx.winkpg.io/docs/api/transactionSummaryGetMerchantSummary.md)
- [Payment type summary report](https://devportal-simpay-sbx.winkpg.io/docs/api/transactionSummaryGetPaymentTypeSummary.md)
- [Transaction lifecycle and settlement](https://devportal-simpay-sbx.winkpg.io/docs/guides/transaction-lifecycle-and-settlement.md)
- [Getting started with the API](https://devportal-simpay-sbx.winkpg.io/docs/guides/api-getting-started.md)

#### Keep your own totals, fed by webhooks

https://devportal-simpay-sbx.winkpg.io/docs/decide/reporting-strategy/keep-your-own-totals-from-webhooks.md

Subscribe to the payment events, add each one to a figure you hold, and check that figure against the summary report.

**What to build**

Register a webhook destination, subscribe to the transaction events, and accumulate the amounts as they arrive. Then reconcile against the merchant summary report on a schedule, because a running total assembled from a stream is the one number nothing else in your system can check.

**Worth knowing**

- Delivery is at least once. Record the event id you have already handled and ignore a repeat, because a retry after a slow acknowledgement is an ordinary event rather than a fault.
- Acknowledge within five seconds. Put the raw body on a queue and process it after you have answered, because slow handling is retried and a retry is a duplicate you then have to discard.
- Reconcile at least daily. A total that has drifted is still a number, and it keeps being displayed until something compares it with the report.

**Where to go next**

- [Quickstart: webhooks](https://devportal-simpay-sbx.winkpg.io/docs/guides/quickstart-webhooks.md)
- [Blueprint: receive and verify webhooks](https://devportal-simpay-sbx.winkpg.io/docs/blueprints/receive-and-verify-webhooks.md)
- [Merchant summary report, to reconcile against](https://devportal-simpay-sbx.winkpg.io/docs/api/transactionSummaryGetMerchantSummary.md)

### How soon after a payment do you need it?

https://devportal-simpay-sbx.winkpg.io/docs/decide/reporting-strategy/how-soon-each-payment-is-needed.md

This is the question that rules polling in or out. Nothing you poll on a schedule arrives sooner than the schedule.

**Choose one**

- A scheduled run is soon enough. Minutes or hours later is fine. A nightly load, or a report someone runs when they need it. Leads to: How many payments a day are you reporting on?.
- Within seconds of the payment. Something of yours has to act on the payment, not just record it. Leads to: Where do these payments end up on your side?.

#### How many payments a day are you reporting on?

https://devportal-simpay-sbx.winkpg.io/docs/decide/reporting-strategy/how-many-payments-a-day.md

Reading the same window back on every run is cheap at low volume, and stops being cheap well before it stops working.

**Choose one**

- Tens or low hundreds a day. A filtered request returns the whole window in a page or two. Leads to: Query the transactions list.
- Thousands a day or more. Re-reading the window on every run costs more than it returns. Leads to: Take webhooks, and reconcile each window on a schedule.

##### Query the transactions list

https://devportal-simpay-sbx.winkpg.io/docs/decide/reporting-strategy/query-the-transactions-list.md

Ask for the payments you want, when you want them, with the filters on the list endpoint.

**What to build**

Call the transactions list with the filters that describe your window, and page through the result. Run it on a schedule for a periodic load, or on demand when somebody opens a report. At this volume there is nothing a webhook receiver would buy you that a filtered request doesn't already give you, without an endpoint to deploy, secure, and keep available.

**Worth knowing**

- Filter on a closed window and page to the end of it. Paging is by continuation token, so follow the token rather than asking for a page number.
- A payment's state moves after it's created. Decide whether your load is reading new payments or re-reading recent ones for their current state, because a window that only looks at creation time never sees the second.
- Polling counts against your rate allowance like any other call. A tight loop over a quiet window spends it on responses that repeat the last one.

**Where to go next**

- [List transactions](https://devportal-simpay-sbx.winkpg.io/docs/api/transactionsGetList.md)
- [Transaction lifecycle and settlement](https://devportal-simpay-sbx.winkpg.io/docs/guides/transaction-lifecycle-and-settlement.md)
- [Rate limits and your allowance](https://devportal-simpay-sbx.winkpg.io/docs/guides/rate-limiting.md)
- [Getting started with the API](https://devportal-simpay-sbx.winkpg.io/docs/guides/api-getting-started.md)

##### Take webhooks, and reconcile each window on a schedule

https://devportal-simpay-sbx.winkpg.io/docs/decide/reporting-strategy/webhooks-with-a-scheduled-reconciliation.md

The stream carries the payments, and a scheduled query proves the window is complete instead of assuming it.

**What to build**

Subscribe to the transaction events and load each one as it arrives, then run a filtered query over the closed window on your reporting cadence and insert anything the stream didn't deliver. At this volume the stream is what makes the load affordable, and the sweep is what makes it trustworthy: a receiver that was down for an hour loses that hour, and only a query notices.

**Worth knowing**

- Delivery is at least once. Record the event id you have already handled and ignore a repeat, because a retry after a slow acknowledgement is an ordinary event rather than a fault.
- Acknowledge within five seconds. Put the raw body on a queue and process it after you have answered, because slow handling is retried and a retry is a duplicate you then have to discard.
- Sweep a window that has already closed, and overlap it slightly with the one before. A sweep that reaches into the current window keeps finding payments that were about to arrive anyway.
- Make the load idempotent on the payment id. The sweep and the stream will hand you the same payment, which is the design working rather than failing.

**Where to go next**

- [Quickstart: webhooks](https://devportal-simpay-sbx.winkpg.io/docs/guides/quickstart-webhooks.md)
- [Blueprint: receive and verify webhooks](https://devportal-simpay-sbx.winkpg.io/docs/blueprints/receive-and-verify-webhooks.md)
- [List transactions, for the reconciliation sweep](https://devportal-simpay-sbx.winkpg.io/docs/api/transactionsGetList.md)
- [Webhook integration](https://devportal-simpay-sbx.winkpg.io/docs/guides/webhook-integration.md)

#### Where do these payments end up on your side?

https://devportal-simpay-sbx.winkpg.io/docs/decide/reporting-strategy/where-a-live-feed-lands.md

A stream you act on and a store you have to keep complete are different obligations, and only the second one needs a way to notice a gap.

**Choose one**

- In a reporting system of ours that has to hold every payment. A warehouse, a ledger, or anything you reconcile against. Leads to: Take webhooks, and backfill what the stream missed.
- Nowhere lasting. We act on each payment and move on. A confirmation email, a fulfilment job, or a notification. Leads to: Subscribe to webhooks.

##### Take webhooks, and backfill what the stream missed

https://devportal-simpay-sbx.winkpg.io/docs/decide/reporting-strategy/webhooks-with-a-backfill-sweep.md

Webhooks keep the system of record current, and a backfill sweep keeps it complete.

**What to build**

Subscribe to the transaction events and write each one into your system of record as it arrives, then run a periodic query for the window you have already covered and insert anything missing. Check the delivery log when a gap shows up, because it says whether the delivery was never attempted or was attempted and refused, and those have different fixes on your side.

**Worth knowing**

- Delivery is at least once. Record the event id you have already handled and ignore a repeat, because a retry after a slow acknowledgement is an ordinary event rather than a fault.
- Acknowledge within five seconds. Put the raw body on a queue and process it after you have answered, because slow handling is retried and a retry is a duplicate you then have to discard.
- Store the event id alongside the payment. It's what lets you tell a redelivery from a second payment, and what the delivery log is searchable by when you are reconciling one.
- Verify the signature before you trust the body. A system of record is exactly the thing worth writing a forged event into.

**Where to go next**

- [Webhook integration](https://devportal-simpay-sbx.winkpg.io/docs/guides/webhook-integration.md)
- [Blueprint: receive and verify webhooks](https://devportal-simpay-sbx.winkpg.io/docs/blueprints/receive-and-verify-webhooks.md)
- [Webhook delivery log](https://devportal-simpay-sbx.winkpg.io/docs/api/notificationsGetWebhookEvents.md)
- [List transactions, for the backfill sweep](https://devportal-simpay-sbx.winkpg.io/docs/api/transactionsGetList.md)

##### Subscribe to webhooks

https://devportal-simpay-sbx.winkpg.io/docs/decide/reporting-strategy/subscribe-to-webhooks.md

Each payment reaches you as it happens, and you act on it rather than storing it.

**What to build**

Write a receiver, register it as a destination, and subscribe to the events you act on. Nothing here needs a reconciliation sweep, because you aren't keeping a record whose completeness anyone will later depend on. If that changes, and it usually does, come back to this guide: the answer moves to the sweep rather than away from webhooks.

**Worth knowing**

- Delivery is at least once. Record the event id you have already handled and ignore a repeat, because a retry after a slow acknowledgement is an ordinary event rather than a fault.
- Acknowledge within five seconds. Put the raw body on a queue and process it after you have answered, because slow handling is retried and a retry is a duplicate you then have to discard.
- Verify the signature on every delivery, and reject anything that fails. Your endpoint is on the public internet and the signature is what makes an event yours.
- Watch the delivery log while you are building. It tells you whether a delivery you never saw was refused by your endpoint or never sent.

**Where to go next**

- [Quickstart: webhooks](https://devportal-simpay-sbx.winkpg.io/docs/guides/quickstart-webhooks.md)
- [Webhook integration](https://devportal-simpay-sbx.winkpg.io/docs/guides/webhook-integration.md)
- [Blueprint: receive and verify webhooks](https://devportal-simpay-sbx.winkpg.io/docs/blueprints/receive-and-verify-webhooks.md)
- [Webhook delivery log](https://devportal-simpay-sbx.winkpg.io/docs/api/notificationsGetWebhookEvents.md)

- [Decision guides](https://devportal-simpay-sbx.winkpg.io/docs/decide.md): every decision guide this instance publishes.

## See also

- [All documentation](https://devportal-simpay-sbx.winkpg.io/llms.txt): the machine-readable index of every public page on this site.
