Quick check
Confirm the basics before going deeper.
- WooCommerce → Status → Webhooks lists a webhook pointing at
https://api.peptideclients.com/integrations/v1/webhook/woocommercewith status Active. - That webhook’s Delivery URL matches the URL above exactly (no trailing slash drift, no
http://, no staging domain). - The matching key in Settings → Connectors has
payload_format = woocommerceand is Active (not revoked). - The failing order’s WC status is one we map to a create (see WC status doesn’t trigger).
The request never reached us
The symptom
You placed an order in WC and waited a minute. No row in Orders, no row in Settings → Connectors → key → Request log.
Why it happens
One of three things:
- WC didn’t fire the webhook (it was disabled, suspended after 5 consecutive failures, or simply not configured).
- WC fired it but the URL is wrong (typo in the host, missing path segment, pointed at the wrong store).
- WC fired the right URL but a firewall / WAF on your network outbound is blocking it.
How to fix it
- Open WooCommerce → Status → Webhooks. Confirm the webhook exists and its status is Active. If it’s Disabled, WC auto-disabled it after 5 failed deliveries — toggle it back on after you’ve fixed whatever was failing.
- Click into the webhook and check Delivery URL. It must be
https://api.peptideclients.com/integrations/v1/webhook/woocommerce— nothing else. No store slug, no query string. - Open Delivery history on that webhook. If there are zero rows for the recent order, WC never fired (likely the topic / event setting is wrong — you want
Order createdat minimum, plusOrder updatedif you want status changes synced). - If there are delivery rows but they all show
Failed to connector DNS errors, your storefront host can’t reachapi.peptideclients.com. Some managed WP hosts block outbound HTTP — ask the host to allowlist.
Request reached us but rejected on signature
The symptom
The request log shows a row at path=/v1/webhook/woocommerce with status_code=401 and error_code=signature_invalid.
Why it happens
The HMAC over the body doesn’t match. The most common cause for a WC integration is that the secret in the WC webhook settings is not byte-identical to the signing secret on the key row.
How to fix it
Full walkthrough lives in Integration API → signature_invalid — including the hex-as-string vs hex-decoded gotcha that bites Woo integrators most often. Short version: rotate the signing secret in Settings → Connectors → key, paste the new value into the WC webhook’s Secret field, save both. Retry.
WC status doesn’t trigger a create
The symptom
The request log shows a 200 row at path=/v1/webhook/woocommerce but no row in Orders. Or the order is there but at invoiced, not paid.
Why it happens
WooCommerce sends a webhook for every order status change. We only map some of those to a create + payment.
| WC status | What we do | Our status |
|---|---|---|
pending | Create order, no payment | invoiced |
on-hold | Create order, no payment | invoiced |
failed | Create order, no payment | invoiced |
processing | Create order + inline payment | paid |
completed | Create order + inline payment | paid |
cancelled | Lookup or create, then cancel | cancelled |
refunded | Find payment, refund it | (payment marked refunded) |
So if your WC order is at pending (e.g. it’s a bank-transfer order awaiting payment), it imports as invoiced with no payment row — by design. The order shows up in PeptideClients; it just doesn’t show up as paid until WC transitions it to processing or completed.
How to fix it
- Look at the WC order’s current status (top-right of the order detail page in WC admin).
- Cross-reference the table above. If the order is at
pendingand you expectedpaid, the payment hasn’t happened on the WC side yet — this is correct behavior. - If you want to force the import to
paid, transition the order toprocessingin WC admin. The next webhook (which WC fires automatically) will create the payment row.
cancelled webhook for an order we never saw
The symptom
The request log shows a 200 row with response body {"cancelled":false,"skipped":true,"reason":"order_not_found_in_peptideclients"}. No order appears in PeptideClients.
Why it happens
WC fired a cancelled webhook for an order whose creation webhook never reached us. This commonly happens when you wire up the WC webhook after the order was already placed (the cancel runs but there’s nothing to cancel on our side), or when the create webhook was filtered out by an earlier signature error and never recovered.
WC’s cancelled payload often arrives without line_items (the order was cancelled, so WC doesn’t bother re-sending the items). Without lines, we can’t do a create-then-cancel safely — we’d be inventing an order whose contents we don’t know.
So we return a 200 no-op with the skipped:true, reason:'order_not_found_in_peptideclients' body. That tells WC the call succeeded (so it stops retrying) but documents that nothing was persisted.
The alternative was a 422 lines_required error, which made WC retry indefinitely against an impossible request. The 200 no-op is the new behavior shipped in integration-api v3.
How to fix it
- Make sure the WC webhook URL is configured before the order is placed. New webhook = new orders flow; existing orders before the webhook was wired will never backfill.
- If you need to import a historical cancelled order, create it in WC at
processingfirst (which will fire a create webhook and land an order on our side), then transition it tocancelled. The second webhook will find the existing row and mark it cancelled. - For one-off back-import, use the
POST /integrations/v1/ordersendpoint manually with the order data andexternal_id: "woo-. Then send the cancel webhook from WC and it will find the row."
WC is retrying forever (401)
The symptom
WC’s Delivery history for the webhook is a stack of 401 responses, retrying every few seconds. The PeptideClients request log shows the same row hitting us repeatedly. Eventually WC marks the webhook Disabled after 5 consecutive failures.
Why it happens
WC’s webhook retry policy treats any non-2xx as a transient failure and re-sends with exponential backoff. A signature_invalid 401 from our side looks identical to a temporary network hiccup — so WC tries again, fails again, marks the delivery a failure, and the loop continues until it crosses the 5-failure threshold and self-disables.
How to fix it
- Stop the bleeding: disable the WC webhook (toggle off in WC → Settings → Advanced → Webhooks) so it stops retrying while you fix the secret.
- Rotate the signing secret in Settings → Connectors → key → Rotate signing secret. Copy the new value.
- Paste the new value into the WC webhook’s Secret field. Save.
- Re-enable the WC webhook. Trigger a test order. The next request log row should be
200. - If 401s continue, walk through the four divergence cases in signature_invalid — specifically the hex-as-string vs hex-decoded gotcha for WC integrations.
Order imported but quantities or prices are wrong
The symptom
The order is in PeptideClients with the right number / customer / total — but a line item shows the wrong unit price, the wrong quantity, or a different total than WC.
Why it happens
WC’s order JSON has three overlapping fields per line item: price (the unit price after coupons), subtotal (the line subtotal before coupons), and total (the line total after coupons + taxes). They’re consistent for vanilla orders and diverge for orders with coupons, line-level taxes, or manual price overrides.
Our WC adapter reads price first, then falls back to total, then to subtotal — in that order. For an order with a 10% coupon applied at the cart level, price includes the discount but subtotal does not. That mismatch is what most operators see.
How to fix it
- Open the order detail in PeptideClients. Check the line item’s
metadata— we stamp the raw WCline_itemJSON in there at import time, so you can see exactly which fields we had to work with. - If the issue is coupon-related and you want pre-discount prices, change the WC store’s coupon model to per-line discounts (so
pricereflects the actual charged amount) and re-import. - For one-off fixes, edit the line item in the PeptideClients order detail — the import doesn’t fight you on subsequent edits.
- If you see this consistently across many orders, email {{CONTACT_EMAIL}} with the WC order id and the imported PeptideClients order id — we can correlate the raw
line_itemswe received against the rows we wrote.
Reading the diagnostics
Two places to look. Walk them in this order.
1. PeptideClients request log
Settings → Connectors → key → Request log. Filter to path = /v1/webhook/woocommerce. You should see a row for every WC webhook delivery.
| Column | What it tells you |
|---|---|
status_code | 200 = we accepted it. 401 = signature problem. 4xx/5xx = something else. |
error_code | Empty on success; otherwise jump to the matching section in Integration API troubleshooting. |
external_id | Should be woo-<order_id>. If it’s missing, the body didn’t parse far enough to extract it. |
| Response body | For cancelled-but-unseen orders look for {"skipped":true, "reason":"order_not_found_in_peptideclients"} — that’s the section above. |
If there’s no row at all for a given WC order, the request never reached us — jump to No request reached us.
2. WooCommerce delivery history
WC admin → WooCommerce → Status → Webhooks → your webhook → Delivery history. Each row shows the timestamp, response code we returned, response body, and the X-WC-Webhook-Delivery-ID.
- Response 200 from us, no row in PeptideClients: check the response body — if it’s the cancelled-skipped no-op, see cancelled webhook, no order.
- Response 401 from us: signature problem. See WC retrying forever (401).
- Response timeout / connection refused: your host can’t reach
api.peptideclients.com. - No delivery row at all: WC didn’t fire. Check the webhook is enabled and the order status change actually matches the webhook’s Topic setting.
When to write to support
Email {{CONTACT_EMAIL}} with:
- The WC order id from the WC admin URL.
- The delivery id from the WC webhook delivery history (
X-WC-Webhook-Delivery-ID). - The request log row from Settings → Connectors → Request log — click Copy as text.
- The response body WC saw (visible in WC’s delivery history) and the response body we logged (visible in our request log). They should be byte-identical; if they aren’t, a proxy is rewriting in flight.
- One sentence each on expected vs actual.
Related: Integration API feature guide · Integration API troubleshooting · Troubleshooting hub.