Skip to main content
Commerce lets an agency charge its own clients through one of three payment processors. You connect a processor once, then every invoice can be paid on a hosted, branded pay page — and any card your client saves can be charged again on file for subscriptions and future invoices. All three processors implement the same internal gateway interface, so the pay page, stored-card, refund, and reconciliation flows work identically regardless of which one you pick. Connections are stored per account in crm_payment_integrations; the Payments UI is at /dashboard/commerce/payments, and you connect processors from /dashboard/commerce/settings.

The three processors

Hiveku Payments

White-label Stripe, onboarded inside Hiveku. Fastest to set up, no Stripe account of your own required. Hiveku charges a platform fee per transaction.

Your own Stripe

Link a Stripe account you already own via Connect OAuth. You keep your own Stripe dashboard and payouts. No Hiveku platform fee.

Authorize.Net

Bring your Authorize.Net merchant credentials. US / USD. Accept.js pay page plus CIM stored cards. No Hiveku platform fee.
You can have more than one processor connected, but a single active gateway (crm_payment_integrations.provider) is what new invoice charges route through. If the selected provider isn’t fully connected, Hiveku falls back to whichever one is — an account never hard-fails a charge because the column still reads the default. The default is Authorize.Net.

Connecting Hiveku Payments

Hiveku Payments is a fully white-labeled Stripe connected account that Hiveku creates and onboards for you. There’s no separate Stripe login — KYC and account management happen inside Hiveku via Stripe’s embedded Connect components.
1

Open payment settings

Go to /dashboard/commerce/settings and choose Hiveku Payments.
2

Complete embedded onboarding

Hiveku creates a connected account on first use and renders Stripe’s embedded onboarding. You submit business and bank details in-app; Stripe manages compliance and risk.
3

Wait for charges to enable

When Stripe marks the account charges_enabled, the connection flips to active. Until then, charges are refused with a clear “finish Stripe onboarding” message.
Hiveku Payments carries a blended platform fee of 3.9% + $0.60 per transaction, attached as Stripe’s application_fee_amount on every charge. This is one all-in rate — your client never sees a separate Stripe line, and Stripe’s own processing cost is deducted out of it. On a refund, Hiveku returns its fee proportionally so you aren’t left covering the refund and eating the fee.

Connecting your own Stripe

If you already have a Stripe account, link it with Connect OAuth. You keep your own Stripe dashboard, payouts, and pricing — Hiveku charges no platform fee on this connection.
1

Start the OAuth flow

From /dashboard/commerce/settings, choose Connect your existing Stripe. Hiveku redirects you to Stripe’s hosted authorize page with read_write scope.
2

Authorize on Stripe

Sign in to your Stripe account and approve the connection. Stripe redirects back to Hiveku’s OAuth callback, which exchanges the code for your connected account id (acct_…).
3

Confirm it's live

Hiveku reads your account’s live charges_enabled status and stores the link as a standard connection. Once charges are enabled and Authorize.Net isn’t also connected, Stripe is auto-selected as your active gateway.
You can’t link your own Stripe while a Hiveku Payments account is live — the flows use different account models and linking would orphan the Hiveku Payments account on Stripe. Disconnect Hiveku Payments first. Disconnecting a linked Stripe also revokes Hiveku’s OAuth grant on your Stripe account.

Connecting Authorize.Net

Authorize.Net is bring-your-own-credentials. It’s US / USD and uses Accept.js for the pay page plus CIM (Customer Information Manager) for stored cards.
1

Gather your credentials

From your Authorize.Net merchant account you’ll need four values: API Login ID, Transaction Key, Signature Key, and Public Client Key (the last one powers client-side Accept.js tokenization).
2

Enter them in settings

Go to /dashboard/commerce/settings, choose Authorize.Net, paste all four, and pick sandbox or production.
3

Hiveku verifies and stores

On save, Hiveku runs a no-charge authentication test against the gateway to confirm the keys are live, encrypts the secrets at rest, and records the connection with the verification result.
4

Webhooks self-register

When verification succeeds, Hiveku auto-registers a per-tenant webhook with Authorize.Net (settlement, refund, void, and fraud events) so payments reconcile without you pasting a URL into the Authorize.Net dashboard. If auto-registration fails, the settings UI tells you to register it manually.
Sandbox credentials only work against the sandbox endpoint and production credentials only against production — a mismatch fails verification. The API Login ID is case-sensitive; paste it with no trailing whitespace.

The pay page

Every invoice can be shared as a tokenized link that opens a hosted, branded pay page at /pay/{token}. The page renders your agency’s logo, brand color, and the invoice’s template design, shows the line items and balance due, and — when a processor is connected and the link allows payment — presents a Pay now panel:
  • Stripe (Hiveku Payments or your own) renders a Stripe.js card element. The browser tokenizes the card into a PaymentMethod (pm_…); only that id reaches Hiveku.
  • Authorize.Net renders an Accept.js form. The browser tokenizes the card into an opaque token; only that token reaches Hiveku.
Either way the raw card number never touches Hiveku’s servers. On success the page shows a confirmation and transaction id, and the invoice balance updates. A read-only link (or a fully paid / voided invoice) shows the invoice without a pay form.
The pay page is the same code path for both the public token link and the authenticated client portal, so a payment behaves identically wherever the client starts.

Stored cards and charge-on-file

When a client opts to save a card, Hiveku stores it at the processor — never the card number itself — and keeps only a reference:
  • Stripe — the card is attached to a Stripe Customer as a PaymentMethod. Stored charges confirm a PaymentIntent off_session against that customer + payment method.
  • Authorize.Net — a CIM customer profile holds the payment profile. Hiveku snapshots the card’s brand, last four, and expiry into crm_customer_profiles.stored_payment_profiles so the UI can list saved cards without round-tripping the gateway on every read.
A saved card can be charged again on file — this is what powers subscription renewals and one-click repeat payments. For recurring billing and failed-payment dunning, see Subscriptions.

Refunds

Refund from the invoice’s payment record. Both full and partial refunds go back to the original payment method at the processor, which is the source of truth; Hiveku reflects the result and updates the invoice’s refunded amount and balance.
Hiveku issues a refund against the original charge. For Hiveku Payments, the platform fee is refunded proportionally so you don’t cover the refund and lose the fee. For your own Stripe, there’s no Hiveku fee to return.
Refunds appear on the client’s statement on the processor’s own timeline (typically several business days for cards). Refunds older than the processor’s window may have to be handled in the processor’s dashboard directly.

Reconciliation

  • Automatic — the synchronous pay flow records the payment immediately, and processor webhooks are an idempotent backstop that also carry async signals (settlement, dashboard-initiated refunds, onboarding completion). Duplicate webhook deliveries can’t create duplicate ledger rows.
  • Manual — for money received outside a processor (a check or wire), record it against the invoice with Mark as Paid (POST /api/crm/invoices/{id}/record-payment).

Keeping card data off Hiveku’s servers

Both rails tokenize the card in the browser (Stripe.js or Accept.js) and send Hiveku only a token — no card number, CVC, or expiry reaches Hiveku. Saved cards live at the processor (Stripe Customers or Authorize.Net CIM profiles), and Hiveku persists only references. This keeps card entry fully outsourced to the processor.
Don’t defeat the tokenization flow by taking card numbers over the phone, emailing them, or storing them in a spreadsheet. Always direct clients to the pay page.

Under the hood

Provider resolutionThe gateway for an account is resolved in src/lib/billing/providers/index.ts (resolveProviderName / getPaymentProvider). It honors crm_payment_integrations.provider ('stripe' or 'authorize_net') when that provider is connected, and otherwise falls back to whichever one is. Default: authorize_net. Both Stripe modes share the stripe provider value and the stripe_account_id column — they’re distinguished by stripe_connection_mode ('hiveku_payments' vs 'standard').Where connection state livescrm_payment_integrations (one row per account) holds:
  • Authorize.Net: api_login_id_encrypted, transaction_key_encrypted, signature_key_encrypted, public_client_key (a merchant identifier, stored plaintext), sandbox, merchant_id, webhook_endpoint_id.
  • Stripe: stripe_account_id, stripe_connection_mode, stripe_connect_status, stripe_charges_enabled.
  • Shared: provider, connected_at, last_verified_at, last_error.
Authorize.Net secrets are encrypted at rest via src/lib/crypto/encrypt.ts (encryptApiKey / decryptApiKey) and cached per account for 5 minutes. Stripe never stores merchant secrets in this table — charges run on the platform secret key with a Stripe-Account header scoping each call to the connected account (Connect direct charges).The payment ledger is crm_payments, unique on (account_id, gateway, gateway_transaction_id) — that constraint is what makes webhook replays idempotent. Import/migration runs are tracked in crm_payment_migrations.Settings routes (the /settings/* rows are gated by the crm.invoicing permission — read to view status, create/manage to onboard or switch, delete to disconnect; the public pay endpoint is token-scoped, not permission-gated):Server env vars
  • STRIPE_SECRET_KEY + NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY — required for any Stripe flow (stripeConfigured()).
  • STRIPE_CONNECT_CLIENT_ID — required for BYO Stripe Connect OAuth.
  • STRIPE_CONNECT_WEBHOOK_SECRET — signing secret for the platform Connect webhook.
  • NEXT_PUBLIC_BUILDER_URL — app origin used to build OAuth redirect URIs and the Authorize.Net webhook URL (defaults to https://app.hiveku.com).
There is no env-var toggle for the platform fee — it’s hardcoded in src/lib/billing/stripe/platform-fee.ts (PLATFORM_FEE_BPS = 390, PLATFORM_FEE_FLAT_CENTS = 60, PLATFORM_FEE_LABEL = '3.9% + $0.60').Webhook endpoints
  • Stripe — one platform endpoint, POST /api/webhooks/stripe/connect, receives events for every connected account and routes by event.account. Verified with HMAC-SHA256 over ${timestamp}.${rawBody} using STRIPE_CONNECT_WEBHOOK_SECRET (the stripe-signature header).
  • Authorize.Net — per-tenant endpoint, POST /api/webhooks/authorize-net/{accountId}. The account id in the path is a routing hint only; trust comes from HMAC-SHA512 over the raw body using that account’s Signature Key (the x-anet-signature header), plus a 5-minute timestamp window. Auto-registered on connect via Authorize.Net’s REST API (/rest/v1/webhooks, HTTP Basic auth = API Login ID : Transaction Key).
Gateway endpoints
  • Stripe REST: https://api.stripe.com (charges via /v1/payment_intents, refunds via /v1/refunds, stored cards via /v1/customers + /v1/payment_methods); Connect OAuth on https://connect.stripe.com (/oauth/authorize, /oauth/token, /oauth/deauthorize).
  • Authorize.Net transaction API: https://api.authorize.net/xml/v1/request.api (production) / https://apitest.authorize.net/xml/v1/request.api (sandbox).

Troubleshooting

A connected Stripe account can’t charge until charges_enabled is true. Finish Stripe onboarding (or clear any verification requirements Stripe placed on the account) and re-check the status on the settings page, which re-reads it live.
Re-copy the API Login ID and Transaction Key without trailing whitespace, and confirm you selected the matching environment — sandbox credentials don’t authenticate against production and vice versa.
The settings response tells you whether reconciliation webhooks were registered. If not, register the URL shown in settings manually in your Authorize.Net dashboard. The synchronous charge path still updates invoices without webhooks; webhooks add settlement/refund/void reconciliation.
An Authorize.Net refund of a settled transaction needs the original card’s last four. A very old transaction may fall outside the processor’s refund window and has to be refunded from the processor’s own dashboard.

What’s next?

Send Your First Invoice

End-to-end, including connecting a processor.

Subscriptions

Recurring billing on saved cards and dunning.

Client Portal

Where clients view invoices and pay.

Reports & Analytics

Cash collected, transaction volume, and refunds.