Configuration
Headcount can be configured via the control panel under Headcount → Settings, or by creating a config/headcount.php file. The config file always wins over CP settings, which makes per-environment configuration easy.
Config File
Create config/headcount.php to override settings per environment:
<?php
return [
'stripeSecretKey' => getenv('STRIPE_SECRET_KEY'),
'stripePublishableKey' => getenv('STRIPE_PUBLISHABLE_KEY'),
'stripeWebhookSecret' => getenv('STRIPE_WEBHOOK_SECRET'),
'paypalClientId' => getenv('PAYPAL_CLIENT_ID'),
'paypalClientSecret' => getenv('PAYPAL_CLIENT_SECRET'),
'paypalEnabled' => false,
'defaultCurrency' => 'USD',
'checkoutSuccessUrl' => '/membership/thank-you',
'checkoutCancelUrl' => '/membership/plans',
'loginUrl' => '/login',
'pricingUrl' => '/membership/plans',
// Wallet cards
'walletEnabled' => true,
'appleWalletEnabled' => true,
'applePassTypeIdentifier' => getenv('APPLE_PASS_TYPE_ID'),
'appleTeamIdentifier' => getenv('APPLE_TEAM_ID'),
'appleCertificatePath' => getenv('APPLE_PASS_CERT_PATH'),
'appleCertificatePassword' => getenv('APPLE_PASS_CERT_PASSWORD'),
'appleWwdrCertificatePath' => getenv('APPLE_WWDR_CERT_PATH'),
'googleWalletEnabled' => true,
'googleWalletIssuerId' => getenv('GOOGLE_WALLET_ISSUER_ID'),
'googleWalletServiceAccountPath' => getenv('GOOGLE_WALLET_KEY_PATH'),
];
Stripe
Headcount uses Stripe Checkout Sessions and the Stripe Customer Portal — cards never touch your server, so your site stays in PCI SAQ A scope.
| Setting | Description |
|---|---|
stripeSecretKey | Stripe secret API key (server-side) |
stripePublishableKey | Stripe publishable key (client-side) |
stripeWebhookSecret | Signing secret for the Stripe webhook endpoint (whsec_…). Required — without it every Stripe webhook is refused, because none can be verified. |
Stripe Webhook
Add a webhook endpoint in Stripe pointing to:
https://yoursite.com/actions/headcount/webhook/stripe
Subscribe to these events:
checkout.session.completedcustomer.subscription.createdcustomer.subscription.updatedcustomer.subscription.deletedinvoice.paidinvoice.payment_failedinvoice.payment_action_requiredcustomer.subscription.trial_will_end
PayPal (Optional)
To accept PayPal subscriptions, set paypalEnabled to true and provide your PayPal Business credentials.
| Setting | Description |
|---|---|
paypalEnabled | Enable the PayPal gateway |
paypalClientId | PayPal REST API client ID |
paypalClientSecret | PayPal REST API client secret |
paypalWebhookId | The ID PayPal gives your webhook. Required — without it every PayPal webhook is refused. |
PayPal cannot be used for season memberships — its Subscriptions API only bills on a cycle, so checkout refuses a PayPal season purchase rather than signing the member up to something recurring.
PayPal Webhook
Add a webhook in your PayPal developer dashboard pointing to:
https://yoursite.com/actions/headcount/webhook/paypal
Then copy the Webhook ID PayPal shows for it into Headcount's PayPal settings. Headcount asks PayPal to verify every event against that ID, and refuses events when it isn't set.
URLs & Defaults
| Setting | Default | Description |
|---|---|---|
defaultCurrency | USD | Three-letter ISO currency code |
checkoutSuccessUrl | /membership/thank-you | Where Stripe sends users after successful checkout |
checkoutCancelUrl | /membership/plans | Where Stripe sends users who cancel checkout |
loginUrl | /login | Where unauthenticated visitors are redirected when access is required |
pricingUrl | /membership/plans | Where gated content sends visitors with the “Redirect” behavior |
Wallet Cards
Apple Wallet and Google Wallet credentials live under Headcount → Settings → Wallet Cards. They are your own — an Apple Pass Type ID certificate and a Google Wallet issuer account — and every field accepts an environment variable. Keep the certificate and key files outside your web root. Full setup in the Wallet Cards guide.
| Setting | Description |
|---|---|
walletEnabled | Master switch for wallet cards |
walletImagePath | Directory holding icon.png and friends. Apple rejects a pass with no icon |
appleWalletEnabled | Issue Apple Wallet passes |
applePassTypeIdentifier | Your Pass Type ID, e.g. pass.com.yourclub.membership |
appleTeamIdentifier | Ten-character Apple Developer team ID |
appleCertificatePath | Path to the Pass Type ID certificate (.p12) |
appleCertificatePassword | Password the .p12 was exported with |
appleWwdrCertificatePath | Path to Apple’s WWDR intermediate certificate (.pem) |
applePassUpdatesEnabled | Run Apple’s pass web service so cards on a device update themselves. Needs HTTPS and curl with HTTP/2 |
googleWalletEnabled | Issue Google Wallet passes |
googleWalletIssuerId | Numeric issuer ID from the Google Pay & Wallet Console |
googleWalletServiceAccountPath | Path to the service account JSON key |
Outgoing Webhooks
Set a webhook URL in Headcount → Settings to receive POST notifications for subscription lifecycle events. Payloads are signed with HMAC-SHA256 in the X-Headcount-Signature header.
Events emitted:
subscription.createdsubscription.updatedsubscription.canceledsubscription.expiredmember.upgradedmember.downgraded
API Keys
Issue API keys from Headcount → Settings to authenticate REST API requests for non-session contexts (mobile apps, integrations). Pass the key in the X-Headcount-Api-Key header.
Every credential setting accepts an environment variable ($HEADCOUNT_API_KEY). A variable that doesn't resolve counts as unset — for the API key that means key access is off, and for the outgoing webhook secret it means nothing is sent — and the settings screen says so.
The ?apiKey= query parameter was removed in 5.2.0 — it leaked keys into web server logs, browser history, and the Referer header of outbound links. Any integration still using it must move to the header.