Triagic docs
Playbooks

Example: Checkout & Orders

A playbook for the buyer-facing half of payments — declines, failed checkouts, and orders that did not appear.

The customer could not pay, or paid and got nothing. The mirror image of Payments & Payouts: money coming in rather than going out.

These tickets are more likely to be genuinely systemic — a card issuer declining a whole BIN range, a gateway timing out — so this playbook is scoped to see aggregate signal as well as individual records.

Fields

Name

Checkout & Orders

Description

Tickets where a buyer could not complete a purchase, or completed one that did not
appear: payment declined, checkout errors, cart failures, duplicate charges, missing
orders after a successful payment.

Routing hints

checkout, "payment failed", "card declined", declined, "can't pay", "won't let me
order", cart, "order missing", "charged twice", duplicate charge, "no confirmation
email", gateway, 3DS, CVV

Triage instructions

Two distinct shapes hide behind these tickets, and they diverge immediately:

A. The payment did not go through — a decline or a checkout error.
B. The payment went through and the order did not materialize.

Determine which from the ticket before touching any system.

For shape A (decline / checkout error):
1. MySQL: orders and payment_attempts for this store around the reported time. Read
   the decline codes — an issuer decline is not our failure and should be reported as
   such.
2. Check whether this is one buyer or many. Look at the decline rate for the store in
   the same window. One buyer with an issuer decline is a customer-service answer; a
   spike across buyers is an incident.
3. Prometheus: checkout_payment_declined_total for this store against its own
   baseline. A clear spike from a 0-1 baseline is the strongest systemic signal
   available.
4. Sentry and the app-checkout-* logs for gateway exceptions and timeouts in the same
   window.

For shape B (paid, no order):
1. MySQL: does the payment record exist? Does an order row exist for it?
2. Redis: check for a stuck or expired cart/session key for this buyer — an expired
   session between authorization and order creation is a known cause.
3. app-checkout-* logs for the order-creation step, filtered on the payment id.

Known causes, most to least common:
- issuer-side declines, often clustered by card BIN — not our bug, but say so clearly
- expired cart session between payment authorization and order creation
- gateway timeout where the payment authorized and the callback was lost, which is
  what produces "charged but no order"
- 3DS challenge abandoned by the buyer

Conclusions:
- Always state whether this affected one buyer or many. That single distinction
  decides whether support replies or engineering is paged.
- For an issuer decline, say so plainly and give the decline code. Do not describe it
  as a platform failure.
- If a payment authorized without an order, flag it explicitly as needing
  reconciliation — this is a money-affecting state, not a cosmetic one.

Data sources

org-mysql, org-redis, org-prometheus, org-sentry, org-opensearch

Visibility

Everyone in the organization.

Why it is scoped this way

Wider than the payouts playbook, on purpose. Checkout failures are frequently systemic, and the ability to compare one buyer against the store's aggregate decline rate is what separates "reply to the customer" from "page someone".

Prometheus earns its place here specifically for that comparison. Redis earns its place for session and cart state, which is the only way to explain the paid-but-no-order case.

Tuning it

If the agent keeps reporting individual issuer declines as incidents, strengthen the instruction to check the aggregate first — that is an ordering problem, not a data problem.

On this page