Documentation
Revenue

Generic revenue API

Send revenue commands through the generic API.

Send payments and refunds from any processor FounderHQ has no connection for. One request per money event.

Before you start

You need a secret key (fhq_sk_XXXX) that is scoped to one brand and may write events. A publishable key is rejected. A key with no brand is rejected.

Endpoint

POST https://i.getfounderhq.com/api/revenue
authorization: Bearer fhq_sk_XXXX
content-type: application/json

FounderHQ answers 202 as soon as the command is stored. Normalization, matching, and attribution happen after that, so a slow ledger never slows your checkout.

Using the Node SDK? events.captureRevenue(command) posts the same body and retries for you.

Example

curl -X POST https://i.getfounderhq.com/api/revenue \
  -H "authorization: Bearer fhq_sk_XXXX" \
  -H "content-type: application/json" \
  -d '{
    "idempotencyKey": "acme:payment:pay_ABC123",
    "transactionId": "pay_ABC123",
    "transactionRefType": "payment_intent",
    "kind": "payment",
    "amountMinor": "4900",
    "currency": "USD",
    "occurredAt": "2026-05-23T09:15:00.000Z",
    "paymentRail": "razorpay",
    "environment": "live",
    "customerEmail": "jane@acme.com",
    "checkoutVisitorId": "6b1f0d64-1f0e-4e5a-9a2a-6b0f1d8c2e77",
    "providerCustomerId": "cust_42",
    "providerSubscriptionId": "sub_42",
    "subscription": {
      "status": "active",
      "interval": "P1M",
      "currentPeriodEnd": "2026-06-23T09:15:00.000Z",
      "plan": "growth"
    }
  }'

Response

{
  "ok": true,
  "deliveryId": "DELIVERY_ID",
  "status": "QUEUED",
  "created": true
}
FieldMeaning
okAlways true on a 202.
deliveryIdFounderHQ's ID for this command. Log it.
statusQUEUED, PROCESSING, PROCESSED, or FAILED.
createdtrue for a new command. false when you replayed one FounderHQ already had.

Idempotency

idempotencyKey identifies the delivery. Reuse the same key on every retry of the same money event.

  • Same key, same body: FounderHQ returns 202 with created: false. Nothing is counted twice.
  • Same key, different body: FounderHQ returns 409. Pick a new key, or send the body you sent the first time.
  • Different key, same transactionId, transactionRefType, and kind: FounderHQ still counts the money once. The transaction is what dedupes the economics.

Keys are scoped to the API key you send them with.

Fields

FieldTypeRequiredMeaning
idempotencyKeystring, 1–512yesStable ID for this delivery. Retries reuse it.
transactionIdstring, 1–512yesThe processor's transaction ID. FounderHQ dedupes the money by it.
transactionRefTypeenumno, default transactionWhat transactionId points at: payment_intent, charge, invoice_payment, refund, transaction, order, dispute, credit_note.
kindenumno, default paymentpayment, refund, dispute_lost, or credit_note.
amountMinorinteger, string or numberyesAmount in minor units. 4900 is $49.00. Never 0. Signed or unsigned: FounderHQ normalizes the sign from kind.
currency3 lettersyesThe charged currency, for example USD.
taxMinorintegernoTax inside the amount.
feeMinorintegernoThe processor's fee.
settlementAmountMinorintegernoWhat actually reached your bank.
settlementCurrency3 lettersnoThe currency of that settlement.
reportingCurrency3 lettersnoThe currency you want this payment reported in.
fxRatedecimal, string or numbernoThe rate used to reach the reporting currency.
occurredAtISO 8601 datetimenoWhen the money moved. Without it, FounderHQ uses the time it received the command, and marks the date as a fallback. Send it.
providerRevisionAtISO 8601 datetimenoWhen the processor last revised this record. FounderHQ uses it to decide which correction is newer.
providerRevisionKeystring, 1–512noYour ID for that revision. Defaults to the idempotency key.
paymentRailstring, 1–64no, default genericThe processor this money moved on, for example razorpay.
merchantAccountIdstring, 1–256noYour merchant or account ID with that processor.
environmentstring, 1–32no, default liveThe environment this money moved in. FounderHQ stores it on the payment, so test money stays labelled as test.
originalTransactionIdstring, 1–512required for reversalsThe payment this refund, lost dispute, or credit note cancels.
originalRefTypeenumno, default transactionWhat originalTransactionId points at: payment_intent, charge, invoice_payment, transaction, order.
checkoutVisitorIdstring, 1–400noThe fhq_anonymous_id your checkout captured. This is what ties the payment to a channel.
checkoutAccountContextstring, 1–2048noThe fhq_account_context token, when the buyer paid on behalf of an account.
providerCustomerIdstring, 1–512noThe processor's customer ID. It binds renewals to the same contact.
providerSubscriptionIdstring, 1–512noThe processor's subscription ID. Required when you send subscription.
customerEmailemailnoThe payer's email. FounderHQ uses it to find the contact when no visitor ID is present.
historicalImportbooleanno, default falseMarks a backfilled payment. The amount counts, but with no touch it stays unmatched instead of counting as direct traffic.
metadataobjectnoYour own keys. Stored with the payment.
attributionWindowDays30, 60, 90, or 180no, default 90How far back FounderHQ looks for the touches that earn this payment.
subscriptionobjectnoRecurring state. See below.

subscription

Send this block on a recurring payment and FounderHQ drives MRR from it, the same way a connected provider does.

FieldTypeRequiredMeaning
statusenumno, default activetrialing, active, past_due, paused, canceled, or expired.
priceMinorintegernoThe plan price in minor units. Defaults to amountMinor on a payment.
intervalISO 8601 period, or nullnoP1M for monthly, P1Y for yearly. Without it, MRR is 0 and the period stays unknown.
currentPeriodEndISO 8601 datetime, or nullnoWhen this paid period ends.
quantityinteger, 1–10000no, default 1Seats or units.
planstring, 1–200, or nullnoYour plan name, for example growth.

Rules FounderHQ enforces

RuleWhy
amountMinor must not be 0A zero amount is not a money event.
A refund, lost dispute, or credit note must carry originalTransactionIdA reversal has to say what it reverses.
A payment must not carry originalTransactionIdA payment reverses nothing.
subscription requires providerSubscriptionIdMRR needs a subscription to attach to.

Errors

StatusMeaning
400The body failed a rule. The message names the first field that failed.
401The key is missing, wrong, or not a secret key.
403The key is not scoped to a brand, or cannot write events.
409This idempotency key already exists with a different body.

Verify

  1. Send a test payment with "environment": "test".
  2. Confirm the response is 202 with "created": true.
  3. Send the same body again. The response says "created": false.
  4. In FounderHQ, open Revenue. The payment shows your amount, and the channel that brought the customer when you sent checkoutVisitorId.

AI agent or LLM? Read this page as markdown

On this page