Skip to Content
Payment Flow

Payment Flow

This page shows Payylo’s group-payment flow: how a single purchase is split into slots and paid by multiple participants, each covering their own slot.

Overview

Payylo coordinates the split between your backend, the checkout, the card provider, and each participant. The diagrams below walk through the end-to-end process from setup to capture.

The Group Payment Lifecycle

One purchase is split into slots; each participant pays one slot. Instead of repeating the same steps for every participant, the diagram shows the three phases — setup, one participant paying (looped), and completion:

The Three Phases in Detail

Multiple participants collaboratively pay for a single purchase, one slot each:

1. Setup (server-side)

  • Your backend creates a group payment with POST /v1/group-payments, passing total_amount (in currency units) and a distribution that defines the slots.
  • Payylo returns the group_payment, its payment_slots, and a shareable checkout_url.
  • You share that URL with participants — or embed the flow (see Embedded Checkout).

2. Each participant pays a slot

  • A participant opens the checkout, picks an available slot, and enters their card.
  • Payylo pre-authorises (holds) the funds with the card provider — it does not capture yet.
  • The group moves to partially_preauthorised (some slots held) and then preauthorised once every slot is held. No money has been captured at this point — if the group expires here, the holds are simply released.
  • Webhooks: payment_intent.preauthorised for that slot. group_payment.partially_paid is not sent for holds — it always means captured money.

3. Auto-capture & completion

  • Once every slot is authorised, Payylo automatically captures all of them.
  • Webhooks: payment_intent.captured, then group_payment.paid — your cue to fulfil the order / confirm the booking.

Group Payment States

While collecting, no money has been captured — only held. partially_paid appears only in the capture phase, when some captures have confirmed and the rest are still pending or failed and retrying; it always means real captured money, never just holds. Expiry only applies while collecting: the holds are released and nobody is charged.

Error Handling for Group Payments

Payylo provides comprehensive error handling for group payment scenarios:

Group Payment Creation Errors

  • Invalid total amount: Cart total doesn’t match sum of slot amounts
  • Slot configuration: Invalid item assignments or duplicate amounts
  • API validation: Missing required fields or invalid data

Individual Payment Errors

  • Payment declined: Individual user’s payment method declined
  • Insufficient funds: User doesn’t have enough balance
  • Slot already paid: User trying to pay for an already completed slot
  • Payment intent failures: PSP communication issues during payment processing

Group Completion Errors

  • Session expiry: Group payment session timed out before completion
  • Partial payments: Some slots paid but others remain incomplete
  • Webhook delivery: Issues sending completion notifications

Best Practices for Group Payments

  1. Set clear session timeouts to avoid indefinite waiting
  2. Implement real-time updates so users see slot status changes
  3. Handle partial failures gracefully with retry mechanisms
  4. Validate slot amounts match cart totals before creation
  5. Test group scenarios with multiple concurrent users

Integration Examples

Creating a group payment

Amounts are in currency units (e.g. 300.00), not cents. Slots come from the distributionequally across N slots, or custom amounts that sum to the total.

curl https://api.payylo.com/v1/group-payments \ -H "Authorization: Bearer $PAYYLO_SECRET_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: $(uuidgen)" \ -d '{ "group_name": "Office gear", "total_amount": 300.00, "currency": "EUR", "expires_at": "2026-06-22T18:00:00Z", "distribution": { "type": "custom", "slots": [ { "amount": 250.00, "metadata": { "item": "Laptop" } }, { "amount": 30.00, "metadata": { "item": "Wireless Mouse" } }, { "amount": 20.00, "metadata": { "item": "Mechanical Keyboard" } } ] } }'

Webhook handler for group payments

Verify the signature first (see Webhooks), then switch on the real event types:

app.post( '/webhooks/payylo', express.raw({ type: 'application/json' }), (req, res) => { // Verify req.header('Payylo-Signature') against the raw body — see /webhooks. const event = JSON.parse(req.body.toString('utf8')); switch (event.type) { case 'group_payment.partially_paid': // Some money has actually been CAPTURED (not just held) — e.g. while // captures confirm one by one, or after a partial capture failure. console.log('Partially paid:', event.data.group_payment_id); break; case 'group_payment.paid': // All slots paid — fulfil the order / confirm the booking here. console.log('Group payment paid:', event.data.group_payment_id); break; case 'group_payment.refunded': case 'group_payment.partially_refunded': console.log('Refund event:', event.type, event.data.group_payment_id); break; case 'payment_intent.failed': console.log('A payment intent failed:', event.data); break; } res.json({ received: true }); } );

Next Steps

Last updated on