Skavio Payment Proof: acknowledge the transfer once, not every notification
Skavio Payment Proof provides payment history, PDF evidence and CSV exports for noncustodial USDC payments sent directly to a merchant’s wallet. Avoiding duplicate acknowledgement requires a separate operational rule: repeated evidence should lead back to the original payment record, not create another payment entry.
1. Separate the request, the notification and the transfer
A payment request describes what a business expects to receive. A notification reports an event. The on-chain transfer is the movement of tokens. These are related, but their identifiers serve different purposes. A reliable reconciliation workflow preserves all three rather than treating each incoming message as a new payment. The controls below are recommendations for the merchant’s own workflow—not a claim that Skavio automatically prevents every duplicate.
- Request or order reference: identifies the obligation against which a payment may be allocated.
- Notification event ID: identifies an event and helps recognize repeated delivery of that event.
- Transfer identity: identifies the specific on-chain token movement, regardless of how often someone submits its evidence.
2. Verify the token movement before acknowledging it
For a Base USDC example, check the selected network, the USDC contract against Circle’s official network-specific listing, the transaction receipt’s success status, and the relevant Transfer event’s recipient and exact amount. A successful transaction receipt alone does not establish that the intended USDC amount reached the merchant. For EVM-based reconciliation, a useful transfer key is the chain identifier plus transaction hash plus log index. This is an implementation recommendation derived from the receipt structure: one transaction can contain multiple transfer logs, so a transaction hash alone may be too broad. It is not a universal identifier for every blockchain. Keep pending or unverifiable claims unresolved. Retain the block reference and recheck whether the transfer remains on the canonical chain according to your acceptance policy, including when a chain reorganization creates uncertainty. Do not treat a temporary observation as a finality guarantee.
3. Retrieve the original acknowledgement instead of creating another
Maintain one shared merchant payment register so finance and support staff consult the same record. Before acknowledging a claim, search by the verified transfer key—not by the screenshot filename, ticket number or sender’s description. If the transfer already has an acknowledgement, reuse its reference, date and evidence link. A suitable reply is: “This transfer is already recorded under acknowledgement [reference]; here is the existing evidence.” Providing the evidence again should not create another payment entry or trigger fulfilment again. If the transfer is already associated with a different order, pause for reconciliation. Split payments and deliberate multi-invoice allocations need explicit allocation records, not silent reuse of the full transfer amount.
- Retain the transfer key, token contract, recipient, exact amount and block reference.
- Link the request or order reference, verification time, acknowledgement reference and evidence location.
- Keep transfer verification, business allocation and acknowledgement state distinct. A verified chain transfer alone does not establish a customer sale.
4. Deduplicate both webhook delivery and the business effect
Skavio’s published Payment Proof integration reference distinguishes payment.confirmed from invoice.paid. It states that a linked invoice can produce both events and explicitly warns against counting them as separate revenue. It also describes at-least-once webhook delivery with stable event IDs across retries, and says repeated watcher scans or PAID updates do not generate new events. These are documented behaviours, not independently verified deployment results. The reference marks implementation as pending independent verification and deployment. Do not interpret these descriptions as production-tested capabilities or an exactly-once processing guarantee. For a developer implementing the receiving workflow, event-ID deduplication is only the first layer. Two different event IDs can still describe the same underlying payment.
- Enforce event-ID uniqueness for delivery retries, maintain a unique transfer record, and guard the mapped request’s settlement transition. Keep legitimate payment allocations separate.
- Use database uniqueness constraints and transactional conflict handling rather than an unprotected “check, then insert.” PostgreSQL’s ON CONFLICT provides documented handling for unique conflicts.
- Commit the event ID and local business effect—or a local processing outbox—atomically before returning webhook success. Any external fulfilment action still needs its own retry-safe design.
5. Test that duplicates stop, while distinct transfers remain visible
Use fictional reconciliation records and controlled event fixtures to test the workflow before relying on it. The expected result is not simply fewer records: it is one canonical record per distinct transfer, with traceable acknowledgements and allocations. Uncertain evidence should remain an exception rather than being forced into a paid state.
- Submit the same transfer claim twice, then process two simultaneous acknowledgements. Both tests should resolve to one payment record without a second settlement effect.
- Deliver the same event twice, then deliver both payment.confirmed and invoice.paid for one underlying payment. Neither case should count that transfer again.
- Inspect two distinct transfer logs within one transaction. They must remain distinguishable rather than being collapsed solely because their transaction hash matches.
Review Skavio Payment Proof’s payment history and evidence workflow →