Browse documentation

Billing events — API/SDK advanced

Forward authenticated payments, refunds and disputes for the API/SDK advanced path with exact amounts and stable identities.

Updated August 3, 2026

This merchant webhook verification and forwarding flow is only for API/SDK advanced. Verify the payment-provider webhook on your server before sending its billing event to AffiHQ. Do not send payment events from a browser callback.

With Stripe automatic, AffiHQ receives, verifies, checks the Stripe mode, retries and processes native Stripe Connect deliveries. Do not forward those same Stripe events from your application or duplicate them through the API. For a native setup issue, see the troubleshooting guide.

Successful payment

await affihq.billingEvents.send({
  type: 'payment.succeeded',
  provider: 'stripe',
  providerEventId: stripeEvent.id,
  customerId: merchantCustomerId,
  paymentId: invoice.id,
  billingCycle: 'monthly',
  currency: 'USD',
  amounts: {
    collectedMinor: 2500,
    taxMinor: 0,
    discountMinor: 500,
    commissionableMinor: 2000,
  },
  occurredAt: stripeEvent.createdAt,
})

All monetary values use the currency’s minor unit. commissionableMinor cannot exceed the collected amount minus tax. Exclude non-commissionable lines before submitting the event.

Refunds and disputes

Send payment.refunded, payment.disputed and payment.dispute_resolved events with the original paymentId. A correction before payout reduces what is due. A correction after payout becomes a negative balance against future commissions.

Events before attribution

Billing events can arrive before the matching attribution. AffiHQ retains them as unattributed and replays the match when the attribution is locked.

Idempotency

The SDK sends provider:providerEventId as the idempotency key. An identical replay is accepted as a duplicate. If AffiHQ returns idempotency_conflict, compare the financial data with the original event before sending it again.