Quick check

Confirm the basics before going deeper.

  • WooCommerce → Status → Webhooks lists a webhook pointing at https://api.peptideclients.com/integrations/v1/webhook/woocommerce with 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 = woocommerce and 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

  1. 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.
  2. 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.
  3. 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 created at minimum, plus Order updated if you want status changes synced).
  4. If there are delivery rows but they all show Failed to connect or DNS errors, your storefront host can’t reach api.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 statusWhat we doOur status
pendingCreate order, no paymentinvoiced
on-holdCreate order, no paymentinvoiced
failedCreate order, no paymentinvoiced
processingCreate order + inline paymentpaid
completedCreate order + inline paymentpaid
cancelledLookup or create, then cancelcancelled
refundedFind 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

  1. Look at the WC order’s current status (top-right of the order detail page in WC admin).
  2. Cross-reference the table above. If the order is at pending and you expected paid, the payment hasn’t happened on the WC side yet — this is correct behavior.
  3. If you want to force the import to paid, transition the order to processing in 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.

This is intentional, not a bug

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

  1. 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.
  2. If you need to import a historical cancelled order, create it in WC at processing first (which will fire a create webhook and land an order on our side), then transition it to cancelled. The second webhook will find the existing row and mark it cancelled.
  3. For one-off back-import, use the POST /integrations/v1/orders endpoint manually with the order data and external_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

  1. Stop the bleeding: disable the WC webhook (toggle off in WC → Settings → Advanced → Webhooks) so it stops retrying while you fix the secret.
  2. Rotate the signing secret in Settings → Connectors → key → Rotate signing secret. Copy the new value.
  3. Paste the new value into the WC webhook’s Secret field. Save.
  4. Re-enable the WC webhook. Trigger a test order. The next request log row should be 200.
  5. 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

  1. Open the order detail in PeptideClients. Check the line item’s metadata — we stamp the raw WC line_item JSON in there at import time, so you can see exactly which fields we had to work with.
  2. If the issue is coupon-related and you want pre-discount prices, change the WC store’s coupon model to per-line discounts (so price reflects the actual charged amount) and re-import.
  3. For one-off fixes, edit the line item in the PeptideClients order detail — the import doesn’t fight you on subsequent edits.
  4. 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_items we 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.

ColumnWhat it tells you
status_code200 = we accepted it. 401 = signature problem. 4xx/5xx = something else.
error_codeEmpty on success; otherwise jump to the matching section in Integration API troubleshooting.
external_idShould be woo-<order_id>. If it’s missing, the body didn’t parse far enough to extract it.
Response bodyFor 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:

  1. The WC order id from the WC admin URL.
  2. The delivery id from the WC webhook delivery history (X-WC-Webhook-Delivery-ID).
  3. The request log row from Settings → Connectors → Request log — click Copy as text.
  4. 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.
  5. One sentence each on expected vs actual.

Related: Integration API feature guide · Integration API troubleshooting · Troubleshooting hub.