Skip to main content
More Stripe documentation

Stripe Integration Troubleshooting

Fix common ERPClaw Stripe integration issues. API key errors, sync failures, webhook signature errors, payout reconciliation gaps, ASC 606 imbalances, MRR misreports.

Pick the symptom that matches.

“Stripe API authentication failed”

Either the API key is wrong, the key was rotated in the Stripe Dashboard, or you are using a pk_ key (publishable, client-side) instead of rk_ (restricted, server-side) or sk_ (secret).

Verify by listing your accounts:

erpclaw stripe-list-accounts

If your account shows but sync fails, rotate the key in Stripe Dashboard, store the new key, and check it:

erpclaw set-credential --integration stripe --from-stdin --user-confirmed
erpclaw stripe-test-connection --stripe-account-id <id>

Sync stalls or returns 429

Stripe rate-limits at 100 read requests per second in live mode. If ERPClaw is mid-sync of a very large account and you also have other processes hammering Stripe, you will see 429s. ERPClaw does not retry on its own: the sync job is marked failed with the error. Pause the other processes and run the sync again.

If sync is stuck, check the sync job:

erpclaw stripe-list-sync-jobs --stripe-account-id <id> --status running
erpclaw stripe-get-sync-status --sync-job-id <id>

Cancel and retry:

erpclaw stripe-cancel-sync --sync-job-id <id>
erpclaw stripe-start-full-sync --stripe-account-id <id>

Webhook returns 400 Bad Request

ERPClaw’s stripe-process-webhook does not check signatures, so a signature rejection comes from the receiver you host in front of it. Either the webhook secret it uses is wrong (key rotated, accidentally pasted the wrong one) or the request is being modified in transit (unusual proxy, MITM testing).

Compare the secret in your receiver with the endpoint’s signing secret in the Stripe Dashboard (Developers > Webhooks). If you keep a copy on the ERPClaw account, update it too:

erpclaw stripe-update-account --stripe-account-id <id> --webhook-secret whsec_NEW_SECRET

Webhook returns 200 but journal entries are missing

Check that the events arrived:

erpclaw stripe-list-webhook-events --stripe-account-id <id> --processed 1 --limit 20

Processing an event re-syncs the object it concerns into ERPClaw’s Stripe tables; it does not post journal entries. Post whatever is not yet posted:

erpclaw stripe-bulk-post-gl --stripe-account-id <id>

Custom routing rules for a transaction type are listed with stripe-list-gl-rules --stripe-account-id <id> --transaction-type charge. Without a custom rule, posting uses the account’s default GL mapping.

Payout reconciliation does not balance

Run the three-layer reconciliation:

erpclaw stripe-run-reconciliation --stripe-account-id <id> --date-from 2026-04-01 --date-to 2026-04-30

The run checks Layer 1 (each balance transaction to its source charge, refund, or payout), Layer 2 (charges to mapped customers), and Layer 3 (each payout to the transactions it contains).

Common causes of imbalance:

  • A bank deposit was manually entered with a different amount than the actual Stripe payout
  • A transaction was posted manually before sync caught it (causing a duplicate)
  • A test-mode transaction got posted in live mode (or vice versa)
  • A refund was posted but the original charge sync was missed

Review what is still open with stripe-list-unreconciled, then match the stragglers with stripe-match-charge or stripe-reconcile-payout, or reverse the duplicate journal entry and resync.

Clearing balance does not match Stripe Dashboard

Stripe’s “Available balance” minus “Pending balance” should equal your Stripe Clearing GL account. If it doesn’t:

  • Run erpclaw stripe-verify-gl-balance --stripe-account-id <id> and note the value
  • Check the Stripe Dashboard’s Balance overview
  • Difference is usually pending payouts not yet recorded in your bank

Force a fresh payout sync:

erpclaw stripe-start-sync --stripe-account-id <id> --object-type payout

ASC 606 deferred revenue does not balance

If the Stripe Unearned Revenue account does not match the sum of unrecognized subscription periods, compare the two:

erpclaw stripe-rev-rec-status --stripe-account-id <id>

It lists, per subscription, the contract value, revenue recognized to date, and the deferred balance remaining; compare the total with the Unearned Revenue account balance.

Common causes:

  • A plan change that was not recorded with stripe-handle-subscription-change
  • A charge posted before the subscription’s schedule was created (it did not go to Deferred Revenue)
  • A discounted plan whose schedule still carries the full plan price
  • Refund of a partially-recognized subscription
  • Multi-currency subscriptions (we support USD only in v1)
  • Billing intervals outside the standard month/year patterns

MRR report shows wrong number

ERPClaw computes MRR from your synced subscription data, not from your revenue. If MRR looks wrong:

  • Trialing subscriptions are included (and counted separately)
  • Paused, past-due, and canceled subscriptions are excluded
  • The amount is the first item’s unit price: quantity, discounts, and extra items are not applied
  • Annual plans are divided by twelve; plans billed every N months are read by their interval only

Check the report and the subscriptions behind it:

erpclaw stripe-mrr-report --stripe-account-id <id>
erpclaw stripe-list-subscriptions --stripe-account-id <id> --status active

Where to get help