CreditKit Pro troubleshooting
Most CreditKit Pro tickets trace back to a trigger status that never fired, a module left switched off, an expiry setting that overrides what the customer was shown, or a webhook that retried itself into a disabled state. Each section below names the symptom, the cause and the fix. Every location refers to CreditKit Pro 2.2.0.
A customer paid for a bundle and no credits arrived
Credits are granted when an order transitions into the status named by Credit Addition Order Status on Credit System → Settings → Purchase Options, which defaults to completed. An order that never reaches that status never grants credits, and an order that already granted credits carries a _pcs_credits_processed flag blocking a second grant.
Compare the order’s current status with that setting, and switch the setting to processing if the store fulfils on processing. When a bundle line grants zero credits, CreditKit writes an order note beginning “WARNING: bundle line item(s) granted zero credits” that names the failing line.
A stored balance does not match the transaction log
Balance drift is repaired by reconciliation, not by the fraud tools. Open Credit System → Security → Credit Backups and use the Balance Reconciliation panel. Press “Scan for mismatches”, which compares every stored balance against the ledger and changes nothing, review the differences, then press “Fix all shown” or fix individual rows.
The same scan runs nightly as the pcs_daily_reconciliation job in PCS_Balance_Reconciliation, and a mismatch emits the balance.drift_detected webhook event. The “Run risk assessment now” button on the Fraud Detection tab scores accounts for fraud risk and touches no balance.
Credits expired sooner or later than the bundle promised
Global Credit Expiry Days on Credit System → Settings → General decides every expiry date written to the ledger. The per-bundle Expiry Days field is what the product page card and the [pcs_credit_bundles] grid display, and in 2.2.0 that per-bundle value never reaches the ledger. A bundle advertising 30 days on a store left at the default writes 365 days.
Set Global Credit Expiry Days to the number you intend to honour, then copy it into every bundle’s Expiry Days field so the advertised text matches. A global value of 0 means credits never expire.
The Groups & Budgets menu is not there
Groups & Budgets ships off. Tick Groups & Budgets on Credit System → Settings → Features and save, and the menu item appears immediately. While the module is off, CreditKit registers no menu item, no legacy redirect and no budget rollover cron job.
The menu also needs the manage_team_credits capability, granted on activation to the administrator role and to the Credit Manager, Credit Admin and Department Head roles. A custom role without that capability sees no menu item even when the module is on.
A customer’s balance dropped after I refunded a bundle order
That is the claw-back working as designed. When a money-paid order that granted credits is refunded, PCS_Refund_Clawback removes credits in proportion to the refunded amount, floored, and capped so the cumulative claw-back never exceeds what the order granted. A refund of half the order total removes half the granted credits, and the order gets a note recording the removal.
To exempt specific orders, return false from the pcs_should_clawback_bundle_refund filter, which receives the refund, the parent order and the first bundle product on the order. A vetoed refund is still marked as handled, so the hook stays idempotent.
The Issue store credit box is missing on an order
The box is hard-gated off on orders already paid in credits, because those orders return credits automatically. Refunding a credit-paid order with the normal WooCommerce refund button returns credits proportionally through PCS_Order_Admin::handle_credit_refund. Guest orders show the box with an explanation instead of a form, because there is no customer account to credit.
Pay with Credits does not appear at checkout
The gateway hides itself unless four conditions hold at once. Credit Payment must be enabled under WooCommerce → Settings → Payments. The shopper must be logged in. The cart must be one that will actually be paid in credits, meaning it holds a credits-only item, or every item is in either mode and the shopper flipped the cart toggle. The shopper must not be blocked or suspended by the security module. A balance shortfall does not hide the gateway. Credit Payment stays visible and prints how many more credits the shopper needs.
A webhook stopped delivering
CreditKit retries a failed delivery four times after the first attempt, waiting 1 minute, 5 minutes, 30 minutes and 2 hours. After 5 total failed attempts the subscription is auto-disabled, its status becomes disabled, and the recorded reason reads “Auto-disabled after 5 consecutive delivery failures”. The pcs_webhook_auto_disabled action fires at the same moment.
Fix the endpoint first, then open Credit System → API & Webhooks and press Enable on that row, which clears the disable markers. Press Test to confirm delivery, within a limit of 10 test deliveries per user per 5 minutes.
A webhook to a local or staging URL is rejected
Webhook URLs pass through wp_http_validate_url(), a server-side request forgery guard that rejects loopback addresses and private RFC1918 ranges. A URL such as http://localhost:3000/hook fails with unsafe_url. Use a public tunnel URL for local testing.
The REST API answers 429
Key-authenticated requests are capped at 100 requests per minute and 1,000 requests per hour, counted per API key. Exceeding either cap returns 429 with the error code rate_limit_exceeded, plus Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers. Honour Retry-After, and spread bulk work across several keys or across time.
Listing webhooks over REST returns 401
GET /wp-json/pcs/v1/webhooks is not a public route. It needs an API key sent as Authorization: Bearer pcs_… or X-API-Key: pcs_…, and the user who owns that key needs manage_options. A call with no key returns 401 with no_api_key, and a key belonging to a non-admin returns 403 with insufficient_permissions. Issue keys at Credit System → API & Webhooks → API Keys.
Blocked users, spending limits and backups are not in the menu
Those three screens were folded into Credit System → Security in 2.2.0, which carries seven tabs: Fraud Detection, Monitoring, Blocking Options, Security Alerts, Blocked Users, Spending Limits and Credit Backups. The old pcs-blocked-users, pcs-spending-limits and pcs-backups slugs still resolve as hidden redirects to the matching tab.
Scheduled jobs are not running
All 14 recurring CreditKit jobs are WP-Cron events registered in includes/class-pcs-cron.php, including pcs_check_expiring_credits, pcs_daily_reconciliation and the three backup jobs. List them with wp cron event list over WP-CLI, or with any WP-Cron viewer plugin. They do not appear under Tools → Scheduled Actions.
Action Scheduler handles exactly one CreditKit workload: webhook delivery and retry, queued in the pcs-webhooks group. Look there when a webhook is late, and at WP-Cron for everything else. A site with DISABLE_WP_CRON set needs a real system cron hitting wp-cron.php, otherwise expiry, reconciliation and backups stall.
The plugin will not activate
CreditKit Pro 2.2.0 declares Requires PHP 8.1, and WordPress refuses to activate a plugin whose PHP requirement exceeds the server, with the message “The plugin cannot be activated because it requires PHP version 8.1 or higher”. Upgrade PHP to 8.1 or newer at the host.
Activation also stops with an error page when WooCommerce is inactive. WooCommerce 7.0 is the floor: on anything older the plugin activates, loads nothing and shows an admin notice.
Still stuck
Set PCS_ENABLE_DIAGNOSTICS to true in wp-config.php to add a read-only WooCommerce → Credit Diagnostics screen listing the credit-data completeness of recent orders and the next-run time of every scheduled job. That screen exposes raw order metadata, so switch the constant back off afterwards. Otherwise send the symptom, the CreditKit version and the diagnostics output through the contact page.