API & Webhooks Reference
API & Webhooks Reference
Webhooks (Shopify → App)
These webhooks are registered when you install the app. They handle the order-to-payment lifecycle.
| Webhook | Event | What Happens |
|---|---|---|
orders/create |
New order | Runs rule engine → finds matching plan → creates OrderPayment with deposit link |
orders/cancelled |
Order cancelled | Voids OrderPayment → cancels/refunds captured Stripe charges |
orders/create
Fires when a new order is placed or a draft order is finalized. The handler:
- Extracts order data (products, totals, customer tags)
- Resolves collection membership via Admin GraphQL (for collection-based rules)
- Runs all enabled Plan Rules in priority order
- If a rule matches: creates an
OrderPaymentwith a uniquepayToken - If no rule matches (Growth/Pro): generates an
AIRecommendationfor merchant review
orders/cancelled
Fires when an order is cancelled. The handler:
- Looks up the
OrderPaymentbyorderGid - If a deposit was captured: cancels uncaptured intents, refunds captured ones
- Sets
OrderPayment.statustovoided
Webhooks (Stripe → App)
| Event | What Happens |
|---|---|
payment_intent.succeeded |
Records charge attempt, updates OrderPayment status, advances lifecycle |
payment_intent.payment_failed |
Records failed attempt, triggers dunning recovery |
Both webhooks are idempotent — duplicate events are detected by providerChargeId and skipped.
Public Endpoints
| Route | Purpose |
|---|---|
POST /pay/{token} |
Customer-facing payment page. Creates a Stripe Checkout Session for deposit or balance payment based on kind form field. Redirects to Stripe. |
The payToken is a crypto.randomUUID() — unguessable, no PII leakage.
Data Model Reference
PaymentPlan
| Field | Type | Description |
|---|---|---|
id |
UUID | Primary key |
title |
String | Plan name |
type |
Enum | deposit, preorder, deferred |
depositKind |
Enum | percent, fixed |
depositValue |
Decimal | Deposit % or amount |
installments |
Int | For deferred: number of installments |
autoChargeBalance |
Boolean | Auto-charge balance vs. manual invoice |
PlanRule
| Field | Type | Description |
|---|---|---|
conditionType |
Enum | product, collection, minOrderValue, customerTag |
action |
Enum | propose (auto-apply), require (manual review) |
priority |
Int | Lower = evaluated first |
threshold |
Decimal | For minOrderValue conditions |
OrderPayment
| Field | Type | Description |
|---|---|---|
status |
Enum | awaiting_deposit → deposit_paid → balance_paid / failed / voided |
payToken |
UUID | Public payment link identifier |
depositAmount |
Decimal | Amount collected upfront |
balanceDue |
Decimal | Remaining balance |
depositChargeId |
String | Stripe PaymentIntent ID for deposit |
balanceChargeId |
String | Stripe PaymentIntent ID for balance |
ChargeAttempt
| Field | Type | Description |
|---|---|---|
kind |
String | deposit or balance |
status |
Enum | pending, succeeded, failed |
providerChargeId |
String | Stripe PaymentIntent ID |
errorMessage |
String | Failure reason (if failed) |
DunningEvent
| Field | Type | Description |
|---|---|---|
stage |
Enum | reminder_1, reminder_2, final_notice, escalation |
channel |
String | app_notification (email integration planned) |
AIRecommendation
| Field | Type | Description |
|---|---|---|
suggestedDeposit |
Decimal | AI-suggested deposit amount |
confidence |
Float | 0-1 confidence score |
reason |
String | Human-readable explanation |
decision |
Enum | pending, approved, overridden, rejected |
appliedPlanId |
UUID | Plan used if merchant overrode the suggestion |