Browse documentation

Server SDK — API/SDK advanced

Use the API/SDK advanced path from Node.js for custom attribution, billing and non-native integration workflows.

Updated August 3, 2026

Use API/SDK advanced when you need custom Checkout, non-Stripe billing, custom pre-Checkout attribution, custom discounts, trials or onboarding, or non-financial events. If Stripe is your payment source and a supported Payment Link fits your flow, use Stripe automatic instead.

@affihq/sdk works with Node.js 20 or later and does not depend on a specific framework. AffiHQ provides it as a compiled archive that you can keep in your private dependency workflow.

Install the SDK

Install the archive supplied by AffiHQ from your project directory:

pnpm add ./affihq-sdk-0.1.0.tgz

Create the client

import { createAffiHQ } from '@affihq/sdk/server'

const affihq = createAffiHQ({
  apiKey: process.env.AFFIHQ_API_KEY!,
  fingerprintKey: process.env.AFFIHQ_FINGERPRINT_KEY!,
  baseUrl: process.env.AFFIHQ_BASE_URL,
  timeoutMs: 1500,
})

Product API and fingerprint keys belong only in your server secret store for API/SDK advanced requests. Never use either key in browser code. Stripe automatic does not need these keys or this SDK; its connected Stripe deliveries are handled by AffiHQ. The default base URL is https://affihq.com and the default timeout is 2500 ms.

Fingerprint the customer

const customerFingerprint = affihq.customers.fingerprint(customerEmail)

The SDK normalizes the email and computes a product-scoped HMAC-SHA-256 digest locally. Send the digest; never put the email in an API payload, outbox message, exception or log.

Handle typed results

const result = await affihq.attributions.create(input)

if (result.status === 'accepted') {
  // Continue with result.data.
} else if (result.status === 'retryable_error') {
  // Keep the original message in the API/SDK advanced outbox for retry.
} else {
  // Record result.error.code for review without logging the payload.
}

Timeouts, network failures, 429 and 5xx responses are retryable. Stable business rejections are invalid. Bad local configuration throws before a request is sent.

Available clients

  • integration.get() checks credentials and capabilities;
  • references.validate(input) previews a reference;
  • attributions.create(input) locks the first qualified attribution;
  • attributions.discount(publicId, billingCycle) reads the frozen discount;
  • billingEvents.send(input) submits verified financial facts;
  • delivery.* creates and flushes API/SDK advanced outbox messages.