Portal Community

Example 1: Payment Success — Provision Service

Trigger: payment_intent.succeeded or charge.succeeded. When Stripe confirms a payment, automatically provision access to the purchased service and send a receipt.

Node settings:

WebhookSecret: whsec_your_signing_secret_here
AllowedEventTypes: payment_intent.succeeded,charge.succeeded
RequireKnownCustomer: true
EnableIdempotencyCheck: true

Output fields used downstream:

{{ nodes.stripeTrigger.output.event_type }}         // "payment_intent.succeeded"
{{ nodes.stripeTrigger.output.customer_id }}        // "cus_PqRsTuVwXy"
{{ nodes.stripeTrigger.output.payment_intent_id }}  // "pi_3NxK..."
{{ nodes.stripeTrigger.output.amount }}             // 4900 (cents)
{{ nodes.stripeTrigger.output.currency }}           // "usd"
{{ nodes.stripeTrigger.output.metadata }}           // { "order_id": "ORD-421", "plan": "pro" }
{{ nodes.stripeTrigger.output.receipt_email }}      // "customer@example.com"
{{ nodes.stripeTrigger.output.livemode }}           // true

Workflow steps after trigger:

  1. IfCondition — verify livemode == true before provisioning to avoid test events touching production systems
  2. MongoDB (findOne) — look up the customer record using customer_id and the order_id from metadata
  3. MongoDB (update) — update order status to paid and store payment_intent_id
  4. HTTP Request (provisioning API) — activate the customer's account or deliver the purchased service
  5. Email (SMTP) — send a payment confirmation receipt to receipt_email with the amount (divide by 100) and order reference from metadata
  6. Slack — notify #payments channel of the successful transaction
Expected outcome: Service is provisioned within seconds of payment confirmation. Customer receives a receipt email. The payment record is updated in the database. EnableIdempotencyCheck prevents double-provisioning if Stripe retries the delivery.

Example 2: Payment Failure — Retry and Notify

Trigger: payment_intent.payment_failed. When a payment attempt fails, send a personalised recovery message to the customer based on the specific failure reason.

Node settings:

WebhookSecret: whsec_your_signing_secret_here
AllowedEventTypes: payment_intent.payment_failed

Output fields used downstream:

{{ nodes.stripeTrigger.output.customer_id }}                  // for DB lookup
{{ nodes.stripeTrigger.output.last_payment_error_code }}      // "card_declined", "insufficient_funds"
{{ nodes.stripeTrigger.output.last_payment_error_message }}   // human-readable reason
{{ nodes.stripeTrigger.output.amount }}                       // attempted amount
{{ nodes.stripeTrigger.output.currency }}
{{ nodes.stripeTrigger.output.metadata }}                     // order/subscription reference

Workflow steps after trigger:

  1. MongoDB (findOne) — look up the customer record and email address using customer_id
  2. Switch — branch on last_payment_error_code:
    • card_declined or insufficient_funds — send "your payment was declined" email with a payment update link
    • expired_card — send "your card has expired" email with a card update link
    • do_not_honor — escalate to billing team in Slack for manual review
  3. MongoDB (update) — increment failed_payment_count on the customer record
  4. IfCondition — if failed_payment_count >= 3, flag the account for review and notify the billing team
  5. Delay — wait 3 days
  6. Email (SMTP) — send a follow-up reminder if payment has not been updated
Note: Stripe automatically retries failed subscription payments on its Smart Retries schedule. This workflow provides a customer communication layer on top of Stripe's automated retries — personalised messaging based on the specific decline reason reduces involuntary churn.

Example 3: Refund — Update Order Status

Trigger: charge.refunded. When Stripe issues a refund, update the order record, reverse any provisioned access if it is a full refund, and send a confirmation to the customer.

Node settings:

WebhookSecret: whsec_your_signing_secret_here
AllowedEventTypes: charge.refunded
EnableIdempotencyCheck: true

Output fields used downstream:

{{ nodes.stripeTrigger.output.charge_id }}        // "ch_3NxK..."
{{ nodes.stripeTrigger.output.payment_intent_id }} // to look up the order
{{ nodes.stripeTrigger.output.amount_refunded }}   // total refunded in cents
{{ nodes.stripeTrigger.output.amount }}            // original charge amount
{{ nodes.stripeTrigger.output.refund_reason }}     // "requested_by_customer"
{{ nodes.stripeTrigger.output.customer_id }}
{{ nodes.stripeTrigger.output.currency }}

Workflow steps after trigger:

  1. MongoDB (findOne) — find the order by payment_intent_id from metadata
  2. IfCondition — check if this is a full refund: amount_refunded == amount
  3. Full refund branch:
    • MongoDB (update) — set order status to refunded
    • HTTP Request (access API) — revoke service access for the customer
  4. Partial refund branch:
    • MongoDB (update) — add a refund record to the order's refund history, keep status as partially_refunded
  5. Email (SMTP) — send refund confirmation: "Your refund of {{ amount_refunded / 100 | currency }} has been processed. Please allow 5–10 business days for it to appear on your statement."
Expected outcome: Order records are kept accurate for both full and partial refunds. Full refunds trigger immediate access revocation. Customers receive a clear confirmation with the exact refund amount and processing timeline.

Example 4: Dispute — Pause Account and Alert Team

Trigger: charge.dispute.created. When a customer opens a dispute (chargeback) with their bank, immediately pause their account and alert the billing team with full context.

Node settings:

WebhookSecret: whsec_your_signing_secret_here
AllowedEventTypes: charge.dispute.created,charge.dispute.closed
IncludeFullEventObject: true

Output fields used downstream:

{{ nodes.stripeTrigger.output.event_type }}         // "charge.dispute.created" or "charge.dispute.closed"
{{ nodes.stripeTrigger.output.dispute_id }}         // "dp_..."
{{ nodes.stripeTrigger.output.dispute_reason }}     // "product_not_received", "fraudulent", etc.
{{ nodes.stripeTrigger.output.dispute_status }}     // "needs_response"
{{ nodes.stripeTrigger.output.amount }}             // disputed amount in cents
{{ nodes.stripeTrigger.output.currency }}
{{ nodes.stripeTrigger.output.customer_id }}
{{ nodes.stripeTrigger.output.evidence_due_by }}    // Unix timestamp — evidence deadline
{{ nodes.stripeTrigger.output.charge_id }}

Workflow steps after trigger:

  1. Switch — branch on event_type:
    • charge.dispute.created — continue with the dispute response steps below
    • charge.dispute.closed — branch on dispute_status: if won, restore account; if lost, write off the amount and update records
  2. MongoDB (findOne) — find customer by customer_id
  3. HTTP Request (account API) — set account status to under_review to prevent further charges
  4. MongoDB (update) — record the dispute with dispute_id, reason, amount, and evidence deadline
  5. DataMapping — convert evidence_due_by Unix timestamp to a readable date
  6. Slack — post to #billing-disputes: "DISPUTE OPENED — Customer: {{ customer_id }} | Amount: {{ amount / 100 | currency }} | Reason: {{ dispute_reason }} | Evidence due: {{ evidence_due_date }} | Dispute ID: {{ dispute_id }}"
  7. Email (SMTP) — send a case summary to the billing team with full dispute context and the Stripe Dashboard link
Evidence deadline: The evidence_due_by timestamp is critical. Use a DataMapping node to convert it from Unix to a readable date and include it prominently in the Slack alert. Missing the evidence deadline means automatically losing the dispute regardless of its merits.

Example 5: Wildcard Filter for All Charge Events

Configuration: Use a single Stripe node with a wildcard filter to receive all charge lifecycle events, then route each type to its own workflow branch using a Switch node.

Node settings:

WebhookSecret: whsec_your_signing_secret_here
AllowedEventTypes: charge.*
AllowedCurrencies: usd,gbp
MinimumAmount: 100
EnableIdempotencyCheck: true

This catches all 5 charge events: charge.succeeded, charge.failed, charge.refunded, charge.dispute.created, charge.dispute.closed.

Switch node downstream — branch on event_type:

// Switch node condition expressions:
Case 1: {{ nodes.stripeTrigger.output.event_type }} == "charge.succeeded"
  → Provision service branch

Case 2: {{ nodes.stripeTrigger.output.event_type }} == "charge.failed"
  → Failure notification branch

Case 3: {{ nodes.stripeTrigger.output.event_type }} == "charge.refunded"
  → Refund processing branch

Case 4: {{ nodes.stripeTrigger.output.event_type }} == "charge.dispute.created"
  → Dispute response branch

Case 5: {{ nodes.stripeTrigger.output.event_type }} == "charge.dispute.closed"
  → Dispute closure branch
MinimumAmount filter: The MinimumAmount: 100 setting (= $1.00 / £1.00) filters out test charges and micro-transactions below 1 currency unit. Adjust this value to match the minimum meaningful transaction amount for your business. AllowedCurrencies ensures only USD and GBP transactions trigger this workflow — EUR or other currency events are discarded.