Delivery Marketplace Troubleshooting Runbook
Operational runbook for diagnosing PedidosYa connection, webhook ingest, menu
sync, and outbound order-action failures in
apps/backend/src/delivery-marketplace/.
Pair with Delivery Marketplace Architecture.
Scope
Primary codepaths:
application/use-cases/connect-marketplace.use-case.tsapplication/use-cases/ingest-marketplace-order.use-case.tsapplication/marketplace-provider-registry.service.tsinterfaces/delivery-marketplace.controller.tsinterfaces/webhooks/pedidosya-plugin.controller.tsinterfaces/guards/pedidosya-ip-allowlist.guard.tsinfrastructure/pedidosya/*infrastructure/processors/marketplace-*.processor.ts
Runtime provider matrix:
| Provider | Registered adapter |
|---|---|
pedidosya | PedidosYaAdapter |
uber_eats | none — MarketplaceProviderNotConfiguredError |
1) Symptom triage
| Symptom | Likely layer |
|---|---|
Connect returns Unknown/not configured error | MarketplaceProviderRegistry (e.g. uber_eats) |
Connect returns 422 Invalid credentials or store not found | Adapter testConnection / wrong store id or credentials |
Connect returns 409 already exists | Non-disconnected connection for location+provider |
Webhook returns 401 IP not in PedidosYa allowlist | PEDIDOSYA_WEBHOOK_IP_ALLOWLIST / proxy IP forwarding |
Webhook returns 400 Invalid order payload | PedidosYa Zod schema mismatch |
| Ingest logs "No active connection" and returns 200 | Missing/inactive connection for store_id |
Ingested order stuck in pending_session | No open cash register session at connection location |
Ingested order status error / "Missing menu mappings" | Menu never pushed or mapping incomplete |
Menu push returns 409 already in progress | Redis lock marketplace:menu-push-lock:{connectionId} |
Accept returns 400 wrong status | Order not in received / pending_session |
Item availability 404 No marketplace mapping | Product not in menu mappings; run menu push |
| Provider never sees accept | Outbound BullMQ job failing / credentials decrypt / acceptance window |
| Duplicate webhook ignored | Expected dedup via insertIfNew |
2) Connection checks
Expected connect flow:
- Authenticated
POST /delivery-marketplace/connections?businessId=... - Credential test against PedidosYa
- Encrypt credentials, persist connection as
active
Verify:
providerispedidosya(not reserveduber_eats).externalStoreIdmatches the PedidosYa vendor / store id used in webhooks (payload.client.store_id).externalChainIdis set when the PedidosYa account is chain-scoped.- After disconnect (
DELETE), reconnect is allowed; an active duplicate is not.
Test an existing connection with
POST /delivery-marketplace/connections/:id/test?businessId=....
3) Webhook and ingest checks
Public routes under /marketplace/pedidosya:
- Confirm Cloud Run / reverse proxy preserves client IP or sets
X-Forwarded-Forcorrectly when the allowlist is enabled. - Hit
GET /marketplace/pedidosya/healthfor reachability. - For order dispatch failures, inspect backend logs around
PedidosYaPluginControllerandIngestMarketplaceOrderUseCase. - Confirm a connection exists for the webhook
store_id+pedidosya. - If
webhookSecretis set on the connection, ingest requires a matchingtokenparameter — the PedidosYa controller currently does not supply one. LeavewebhookSecretunset for PedidosYa unless token forwarding is implemented; rely on IP allowlisting.
Ingest outcome statuses to look for:
| Status | Meaning |
|---|---|
received → POS created | Happy path before/without accept |
pending_session | No open cash register session |
error | Mapping failure or POS create failure |
| (no new row) | Duplicate external order id |
Also inspect GET /delivery-marketplace/connections/:id/sync-log.
4) Menu push and 86
- Enqueue with
POST .../menu/push. Expect202/acceptedwithjobIdmenu-push:{connectionId}. - On
409, either wait for the Redis lock TTL (180s) or retry withforce: trueafter confirming no healthy worker is mid-push. - Confirm BullMQ workers for
marketplace-push-menuare running against the same Redis as the API. - For 86 failures, call
GET /delivery-marketplace/connections/:id/menu-mappingsand ensure the FlowPOS product id exists as entity typeitem. - Remember the request body field
externalItemIdmust be the FlowPOS product UUID despite the name.
5) Outbound accept / deny / status
Outbound work runs on queue marketplace-outbound-order-action.
- Manual accept enqueues
accept:manual:{ingestedOrderId}with no delay. - Auto-accept from ingest uses job id
accept:{ingestedOrderId}and delays bydefaultPrepTimeMinutesminutes. If PedidosYa rejects accepts as past the acceptance window, disable auto-accept or reduce that delay and retest. - Decrypt failures in the processor surface as job failures; check
ENCRYPTION_KEYconsistency across instances. - Repeated auth failures can mark connection health degraded — inspect
connection
lastError*fields and Sentry for the processor.
Kitchen → marketplace status fan-out depends on
MarketplaceOrderLifecycleListener. If POS kitchen updates never reach
PedidosYa:
- Confirm the restaurant order has a linked ingested marketplace order.
- Confirm outbound queue processing is healthy.
- Confirm status mapper supports the kitchen state being emitted.
6) FEL after marketplace ingest
Successful ingest enqueues marketplace-fel-retry with job id
fel:{ingestedOrderId}.
If invoices are missing:
- Confirm FEL is configured for the business/location.
- Inspect failed jobs on
marketplace-fel-retry. - Use existing FEL runbooks under
apps/docs/docs/dev/fel/for certifier / network failures; marketplace only schedules the retry worker.
7) Quick recovery checklist
- Provider registered? (
pedidosyaonly today) - Connection active for the webhook store id?
- Open cash register session at the location?
- Menu mappings present for ordered items?
- Redis + BullMQ workers up for all three marketplace queues?
- IP allowlist correct in staging/production?
- Auto-accept delay compatible with provider SLA?