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 processor is what new charges go through. Choose it with Make active processor. If the active one isn’t fully connected, Hiveku falls back to whichever one is. A card already saved keeps being charged on the processor it was saved under, but the client portal lists only the active processor’s cards.
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 Commerce > Settings and click Set up 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
In Commerce > Settings, click Connect your existing Stripe account. Hiveku sends you to Stripe to approve the connection.
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.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
In Commerce > Settings, under Authorize.Net, paste all four. Sandbox mode starts switched on: switch it off for your live (production) keys. Then click Save credentials. When you save again later, a key field left blank keeps the key Hiveku already holds, so enter only the keys that changed. A new API Login ID (another Authorize.Net account) needs its own Signature Key.
3
Hiveku verifies and stores
On save, Hiveku runs a no-charge authentication test against the gateway to confirm the keys work, encrypts the secrets at rest, and records the connection with the verification result.
4
Webhooks register themselves
When verification succeeds, Hiveku registers a webhook with Authorize.Net (settlement, refund, void and fraud events), so you don’t paste a URL into the Authorize.Net dashboard. The settings page doesn’t show whether this worked. If it didn’t, Hiveku asks Authorize.Net again every day, and when Authorize.Net refuses (usually because the account has no Signature Key yet), an urgent item in your Commerce inbox says so and what to do. After you fix it at Authorize.Net, save your keys in Hiveku again (fields left blank keep the saved keys): the item closes at Hiveku’s next daily check once Authorize.Net has agreed at a save. If Authorize.Net’s notices reach Hiveku but fail the check against the Signature Key saved in Hiveku, a different urgent item says so: in the Authorize.Net Merchant Interface create a new Signature Key, then enter it in Hiveku and save (the other fields can stay blank). That item closes on the first notice that passes. Payments made through Hiveku update invoices either way; refunds and voids made in the Authorize.Net dashboard reach Hiveku only through the webhook.
The pay page
Sending an invoice emails your client a link to its hosted, branded pay page; no sign-in is needed. The link works for 60 days, and sending the invoice again makes a fresh one. The page shows your agency’s logo, brand color and the invoice’s template design, the line items and the balance due, and, when a processor is connected, a Pay $X panel:- Stripe (Hiveku Payments or your own) shows a Stripe card form with a **Pay 0.50. When the client’s bank asks for a 3-D Secure check, the page shows the bank’s own step and finishes the same payment once it’s passed. If the client’s connection drops right after the check, the payment still counts: the next payment attempt on that invoice, or its automatic charge on the due date, finds it and records it instead of charging the card again. If a payment was recorded on the invoice in the meantime, Hiveku doesn’t record it, because that payment may be this one or a different one. Instead it stops the next charge once so the client isn’t charged twice, and an urgent item in your Commerce inbox asks you to check. A payment refunded in Stripe is left alone.
- Authorize.Net shows an Accept.js card form with Pay X without saving. The browser turns the card into a token, and only that token reaches Hiveku.
Stored cards and charge-on-file
A saved card is stored at the processor, never the card number itself; Hiveku keeps only a reference and the card’s brand, last four digits and expiry. Cards get saved in a few ways:- Paying an invoice on Authorize.Net. The client clicks Pay $X and save card.
- The client portal. On any processor, clients add cards under Payment methods.
- A card-update link. You send it from a subscription, an invoice or a contact. It lasts 7 days and charges nothing.
- A subscription payment page. Signing up keeps the card for renewals.
- Your team. On Authorize.Net, your team can add a card from the contact’s record.
The cardholder’s name on Authorize.Net
When a card is saved on Authorize.Net, Hiveku sends the cardholder’s name with it: the name typed on the card form, or else the payer’s or the client’s name. This applies wherever a card is saved, including payment pages, invoice payments, the client portal, the card-update link and cards your team adds.- A name Authorize.Net can store. Authorize.Net keeps only Western European letters and turns any other letter into a question mark. Hiveku sends the closest name it can keep: accents it can’t store come off (“Łukasz” becomes “Lukasz”), ligatures are spelled out, curly apostrophes are straightened, and digits, symbols and emoji are left out. A name written only in another alphabet (Cyrillic or Chinese, for example) is still sent, and Authorize.Net shows it as question marks.
- One-word names fill both the first and the last name field (“Teller Teller”).
- Each card keeps its own name. When a client saves a card they already have on file (the same last four digits), Hiveku sends exactly the name it was saved with, so Authorize.Net recognizes the card instead of storing a second copy. A different card gets its own name.
- Imported cards keep the name Authorize.Net holds for them.
On Stripe, a subscription sign-up on a payment page can’t complete yet for a card whose bank asks for 3-D Secure verification. The payer is asked to try a different card and nothing is charged. Authorize.Net has no such limit.
Refunds
Open the payment under Commerce > Payments and click Refund, for all of it or part of it. The money goes back to the original card at the processor. After a partial refund the invoice stays paid and shows the amount refunded; a full refund marks it Refunded. Either way, the client isn’t billed again.- Stripe
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.
Reconciliation
- Automatic — a payment is recorded the moment the client pays. Processor webhooks are a backstop that also carry later signals (settlement, refunds made in the processor’s dashboard, onboarding completion), and a repeated webhook can’t record a payment twice.
- Manual — for money received outside a processor (a check, a wire, ACH or cash), use Collect payment > Record a payment on the invoice, or Record offline payment under Commerce > Payments.
Unconfirmed charges
Now and then a processor doesn’t answer whether a charge went through. In Commerce > Settings, on the Defaults tab, Unconfirmed charges sets what Hiveku does then:- Re-send the charge automatically (recommended). It retries at 15 minutes, 1 hour and 4 hours, re-sending the exact same transaction, so the processor rejects it if the first attempt already went through. Anything still unresolved is held for review.
- Always hold for review. Nothing is retried, and the invoice is flagged straight away for someone to check the processor.
Importing from your processor
Import existing data, on the Payment processor tab of Commerce > Settings, brings in the customers, saved cards and past transactions already in a connected processor account.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.Under the hood
Data model, routes, env vars, and webhooks (for developers)
Data model, routes, env vars, and webhooks (for developers)
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.
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 tohttps://app.hiveku.com).
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 byevent.account. Verified with HMAC-SHA256 over${timestamp}.${rawBody}usingSTRIPE_CONNECT_WEBHOOK_SECRET(thestripe-signatureheader). - 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 (thex-anet-signatureheader), 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).
- 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 onhttps://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
Stripe shows connected but charges fail
Stripe shows connected but charges fail
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.Can't link my own Stripe
Can't link my own Stripe
Linking your own Stripe is blocked while a Hiveku Payments account is live (it would orphan that account on Stripe). Disconnect Hiveku Payments first, then run the OAuth flow.
A refund won't go through
A refund won't go through
On Authorize.Net, a charge that hasn’t settled can only be voided in full. Wait for it to settle (about two days) to refund part of it. 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?
Create and Send an Invoice
Build an invoice, save or send it, then record what the client pays.
Subscriptions
Recurring billing on saved cards and dunning.
Client Portal
Where clients view invoices and pay.
Reports & Analytics
Cash collected, transaction volume, and refunds.