---
name: talvess-revenue
description: Connect verified payments and refunds to Talvess revenue analytics and link them to signup sources. Use when asked to set up Talvess revenue tracking or integrate a billing provider with Talvess.
---

# Talvess revenue tracking

Send verified, successful payments and refunds from the billing backend. Link payments to confirmed signups with an opaque account identifier so Talvess can report revenue from detected traffic sources, including identifiable AI referrals. Crawler activity is not a revenue source or proof of AI influence.

## Configuration

The setup prompt supplies `TALVESS_ORIGIN` and `WEBSITE_ID`. Ask for either if missing. The website ID is used only for optional signup browser context; the bearer key selects the website for server events.

Add `TALVESS_ORIGIN` and `TALVESS_REVENUE_KEY` to the project's server-only environment configuration. Leave the key empty in example env files; the user creates a dedicated website key in Talvess Profile and sets it privately. Never ask for it in chat, expose it to the browser, log it, or commit it. The key works with `/api/revenue` and `/api/events`; using a separate key isolates revenue's collection quota from other integrations. Each key permits 600 requests per minute across server endpoints, and bodies are limited to 4096 bytes.

## Find the verified billing path

Inspect the project's language, payment provider, and webhook or transaction handlers. Match the existing TypeScript or JavaScript conventions. Verify the provider's webhook signature using its required raw body and confirm that the transaction succeeded before scheduling collection. Do not change authentication, signature verification, billing state, or the provider's acknowledgement semantics.

Track settled money, not checkout page visits, button clicks, authorization holds, pending transactions, failed payments, or subscription creation alone. Select one canonical paid transaction per charge, including subscription renewals, so overlapping webhook types cannot double-count the same money. Use durable background jobs or the project's existing outbox; analytics delivery must not block or roll back payment processing, refunds, or signup. Do not rely on an unawaited fetch in a serverless handler.

## Send payments and refunds

Send `POST {TALVESS_ORIGIN}/api/revenue` with `Content-Type: application/json` and `Authorization: Bearer {TALVESS_REVENUE_KEY}`. The strict schema accepts only these fields:

```json
{
  "type": "payment",
  "paymentId": "provider:payment_123",
  "customerId": "account_123",
  "amountMinor": "29900",
  "currency": "USD",
  "occurredAt": "2026-10-11T10:00:00Z"
}
```

```json
{
  "type": "refund",
  "refundId": "provider:refund_123",
  "paymentId": "provider:payment_123",
  "amountMinor": "4900",
  "currency": "USD",
  "occurredAt": "2026-10-11T11:00:00Z"
}
```

Replace these sample values with the original verified transaction data:

- `paymentId`, `refundId`, and `customerId` are 1-128 characters, start with an ASCII letter or digit, and otherwise contain only letters, digits, `.`, `_`, `:`, or `-`. Use provider-prefixed stable transaction identifiers. Do not use random webhook delivery IDs, emails, names, or other personal data. Refunds use the same canonical `paymentId` as the original payment and do not include `customerId`.
- `customerId` is the application's opaque account identifier, identical to the one sent at signup. Resolve a provider customer to that account; do not use the provider's customer ID unless signup uses the identical value. Do not invent a customer identifier when that mapping is missing.
- `amountMinor` is a positive base-10 integer string, without decimals, signs, or leading zeros, no greater than `9223372036854775807`. Send amounts excluding tax and before provider fees. Use exact provider minor-unit values or precise integer arithmetic, not floating-point conversion. USD 299.00 is `"29900"`; JPY 299 is `"299"`. A refund's amount is the refunded portion of the same tax-exclusive payment measure. Do not assume all currencies have two decimal places or convert currencies for collection.
- `currency` is a supported uppercase ISO currency code. Refund currency must match the payment. Talvess keeps currency totals separate.
- `occurredAt` is the original transaction time as ISO 8601 with a timezone. It is optional in the API but should be supplied for reliable retries and attribution. Times must be within the last 30 days and no more than five minutes ahead. Do not replace an old transaction date with the current time to bypass this limit.
- Send the payment before its refunds. Each refund has its own stable `refundId` and original time, cannot precede the payment, and cumulative refunds cannot exceed the payment amount.
- Do not add `websiteId`, browser context, provider metadata, IP addresses, cookies, or request bodies to revenue payloads.

## Link revenue to signup sources

Update future events from the existing confirmed-signup sender at `POST {TALVESS_ORIGIN}/api/events` to include `customerId`. Preserve its original stable `eventId`, occurrence time, optional browser context, and delivery behaviour; do not install a second signup sender. When replaying previously attempted events, reuse their exact original fields rather than adding or changing a customer ID on a saved receipt. This endpoint may use the existing signup key or the dedicated revenue key, provided it belongs to the same website.

```json
{
  "name": "signup",
  "eventId": "signup:account_123",
  "customerId": "account_123",
  "occurredAt": "2026-10-11T09:00:00Z",
  "context": {
    "websiteId": "<WEBSITE_ID>",
    "visitorId": "<visitor UUID>",
    "sessionId": "<session UUID>"
  }
}
```

Only send signup after a new account was successfully created. Browser context comes from `window.talvess?.getContext(WEBSITE_ID)` and is forwarded through the application's own backend. Validate and omit missing or invalid context; `sessionId` is optional. Missing tracking context must never block account creation. If signup tracking does not exist yet, implement this confirmed-signup path without replacing the application's auth or OAuth protections.

A payment without a matching signup remains **Unlinked**. A linked signup without a recognized referral does not establish measured AI attribution. Preserve detected referrals, unknown or direct traffic, and optional self-reported sources as separate concepts. Do not synthesize historical signup events, infer AI influence from crawls, or send personal data to fill missing attribution.

## Delivery and verification

Serialize and persist the original outgoing payload once, then reuse it unchanged for all deliveries. Use a short fetch timeout such as 5000 ms, reject redirects, and handle network errors inside the delivery worker. A timeout can happen after collection succeeded; stable identifiers make the next delivery safe.

- `201` means a new receipt; `200` means an identical retry. Both require a valid `transaction.id` receipt, not just a success status or HTML response. Signup collection uses an `event.id` receipt; `202 { "ignored": true }` there means tracking is disabled and nothing was recorded. Report that configuration state without retrying it automatically.
- Retry network failures, `408`, `429`, `500`, `502`, `503`, and `504` with bounded exponential backoff and jitter. Honor `Retry-After` in seconds or as an HTTP date. For a refund's `409` with code `PAYMENT_NOT_FOUND`, ensure the original payment has been delivered, then retry the same refund.
- Keep each delivery invocation bounded. The setup examples use at most four attempts, five seconds per request and response body read, and a 25-second total budget. If the retry delay exceeds that budget, leave the job for later delivery rather than ignoring `Retry-After` or holding a serverless invocation open. The host must allow the chosen budget; a post-response hook such as `after()` is not a durable queue.
- Other `4xx` responses and permanent `5xx` such as `501` or `505` need investigation, not an automatic retry. `TRANSACTION_CONFLICT` means an identifier was reused with different data. Never work around it by inventing a new identifier. Invalid or revoked keys need replacement by the user. Preserve failed jobs for correction rather than dropping money silently or retrying indefinitely. Replay only original authoritative transaction records and payloads, preserving identifiers, currency, amount, and occurrence time within the API's 30-day window.
- Log only safe status or error codes and job references, never authorization headers or full provider payloads.

Use mocked provider and Talvess requests to test signature rejection, successful payment selection, exact amounts, signup linkage, duplicate deliveries, partial and full refunds, refund ordering, timeouts, rate limits, and permanent failures. Run the project's relevant checks. Do not create real charges, refunds, or production Talvess events without explicit authorization. For an authorized test integration, verify `201`, an identical retry returning `200`, and receipt in Talvess's Track revenue sheet; reports refresh every 15 seconds.

Finish with the files changed, the billing and signup hooks used, the environment variables the user must set, and the verification steps. State any missing provider-to-account mapping or source context rather than claiming attribution that cannot be measured.
