Waffo and Anyway subscriptions
Dashloom Cloud uses provider-hosted checkout. Card data never passes through Dashloom. The browser return URL never grants access; only a verified, idempotently recorded webhook can change workspace entitlements.
Cloud Free includes no managed AI credits and uses BYOK by default. Solo, Studio, and Agency include 5,000, 15,000, and 45,000 credits per paid billing period. They do not include a trial, and every checkout is validated against the server-owned price.
Server-owned catalog
The server catalog is Solo USD 9/month, Studio USD 29/month, and Agency USD 79/month. Permanent one-time packs are 5,000 credits for USD 12, 10,000 for USD 22, and 50,000 for USD 89. Product IDs, payment links, prices, and credit amounts are server-owned rather than browser input.
Waffo configuration: WAFFO_MODE, WAFFO_MERCHANT_ID, WAFFO_PRIVATE_KEY, WAFFO_PRODUCT_SOLO/STUDIO/AGENCY, and one-time products WAFFO_PRODUCT_CREDITS_5000/10000/50000. Its signed webhook endpoint is /api/billing/webhook/waffo.
Anyway subscription configuration uses ANYWAY_PAYMENT_LINK_SOLO/STUDIO/AGENCY and matching ANYWAY_PRODUCT_SOLO/STUDIO/AGENCY. Credit packs additionally require published product ANYWAY_PRODUCT_CREDITS and fixed one-time links ANYWAY_PAYMENT_LINK_CREDITS_5000/10000/50000. All flows share server-only ANYWAY_MERCHANT_API_KEY, ANYWAY_WEBHOOK_PUBLIC_KEY, and /api/billing/webhook/anyway.
Subscription credits are granted by a verified paid billing period and do not roll over. Purchased credits are stored in a separate non-expiring balance after Waffo order.completed or authoritative Anyway order.paid. Managed calls atomically reserve credits before contacting the model, then settle with ceil((inputTokens + 5 × outputTokens) / 1000) from provider-reported usage. Subscription credits are consumed first; purchased credits cover only the remainder. BYOK consumes no Dashloom credits.
Waffo checkout carries a server-created checkout ID in order metadata and uses provider-hosted sessions created from server-owned Product IDs. Waffo credit fulfillment validates the signed event's USD amount against the server catalog; refund.succeeded revokes a credited pack or paid subscription idempotently. Subscription refunds are resolved by authoritative Waffo order ID, so entitlement revocation does not depend on the original checkout metadata. Anyway redirects to the configured server-owned payment link with only the opaque checkout ID as merchant_reference; do not put secrets or personal data in payment-link query parameters. The redirect does not depend on a mutable product-read response. Fulfillment still fails closed unless the Merchant API confirms the paid order's product, amount, currency, refund/dispute state, and monthly subscription interval against the local checkout and server catalog.
Anyway Webhooks are verified with the configured Ed25519 public key and durably claimed by webhook-id before asynchronous processing. Order and subscription payloads are treated as notifications: the Worker reloads the authoritative order and subscription through the Merchant API before changing access. The canonical local identifier is Anyway's subscriptionId; renewal orders are related through subscriptionId and originalOrderId, not by assuming that every renewal repeats the initial merchant_reference.
The quarter-hourly Worker job reconciles Waffo and Anyway incomplete subscription checkouts, one-time credit checkouts, and live subscriptions against provider-authoritative state; Anyway additionally replays recoverable Webhooks. Waffo reconciliation detects successful subscription and credit-pack refunds even if a Webhook was delayed or lost. Any supported provider-reported refund or dispute suspends paid access until an operator resolves the billing state; this fail-closed policy also covers partial refunds. Merchant API and reconciliation failures are recorded without logging credentials or payment details. A daily remote catalog check verifies all configured Waffo versions and Anyway links against the server-owned product type, environment, amount, currency, billing period, and publication/activation rules.
Operations
Waffo webhook change effective 2026-09-06
In the merchant dashboard's Webhook settings, explicitly enable subscription.renewed alongside subscription.activated, subscription.payment_succeeded, subscription.uncanceled, subscription.updated, subscription.canceling, subscription.canceled, subscription.past_due, order.completed, and refund.succeeded. Renewal events are not delivered unless selected. First payments use activation plus payment events; only subsequent successful renewals emit subscription.renewed.
Payment success no longer supplies billingPeriod, currentPeriodStart, currentPeriodEnd, or orderStatus. The handler records payment ID, date, amount and currency without changing subscription state or granting credits. Activation and renewal validate and persist the monthly period, update access, and grant credits. Missing lifecycle period fields or an unresolved local checkout return a retryable error. Older lifecycle events retain history but cannot shorten a newer period or restore access after a newer refund event.
No schema migration is required. Historical periods are stored in audit_events with action billing.waffo_subscription_period; target_id is the order ID and metadata_json contains eventId, eventType, billingPeriod, currentPeriodStart, and currentPeriodEnd. Payment records use action billing.waffo_payment_succeeded and the same order ID, with paymentId and paymentDate when supplied. These records omit buyer details. Deduplicate audit exports by event ID because retries after partial processing can append another record. Associate the first payment with activation by order ID; subsequent payments require the order's cycle sequence and payment dates, since renewed events do not supply a payment ID.
Webhook deduplication uses event type plus business eventId (falling back to delivery id for older payloads). Lifecycle grants and current-state reconciliation share an order/period-end credit key. The existing database trigger prevents a repeated or older period from resetting an already consumed balance, including grants made under previous payment-ID keys.
Order queries return only the latest period. Reconciliation restores current entitlement, without assigning that period to a historical payment. For missing periods between September 6 and enabling renewed events, export affected payments and prefer retained lifecycle events. Otherwise use paymentDate plus the product interval only as an explicitly labelled estimate. For monthly plans, add one calendar month and clamp to the destination month's last day. Review duplicates, refunds and already granted cycles before any backfill; do not replay estimated history as new credit grants. This change performs no automatic historical backfill.
Rollout: deploy the handler, enable the event in each relevant Waffo test/prod webhook configuration, and verify signed activation and renewal in test mode. Check stored history, one grant per cycle, duplicate delivery, payment/lifecycle reordering and quarter-hourly reconciliation. Code deployment does not change the merchant dashboard's event selection.
General operations
Keep Waffo test/prod resources separate and use Anyway test-capable links where available. Configure both webhook endpoints only after the public Worker origin is final. For Waffo, create three one-time products priced at USD 12, 22, and 89, then subscribe the webhook to order.completed, refund.succeeded, and the implemented subscription lifecycle events. For Anyway, select all supported order.* and subscription.* events. Fetch https://api.anyway.sh/v1/webhooks/signing-key and cache its publicKey (whpk_...) field in ANYWAY_WEBHOOK_PUBLIC_KEY; during a key rotation, the value may temporarily contain comma-separated old and new public keys before the old key is removed.
Before enabling either provider in production, observe a successful daily catalog validation and quarter-hourly reconciliation. For Anyway, verify the three plan links are monthly Card / USD SUBSCRIPTION links and the credit links are fixed ONE_TIME links for USD 12, 22, and 89. Configure the credit-link success return as /dashboard/credits?billing=success, confirm Product IDs and prices, send a signed test event, and observe successful reconciliation. Automated catalog checks do not replace a provider test-mode transaction. Test both subscriptions and packs for success, failure, duplicate delivery, renewal, pause, cancellation, refund/dispute, delayed or out-of-order delivery, Merchant API outage, and webhook-before-return behavior.
Cancellation and refund forms create operator-review requests; they do not automatically mutate provider state. Use the provider dashboard for invoices, refunds, disputes, and account-level reconciliation. Do not enable real transactions until legal terms, tax handling, refund policy, support contact, and provider onboarding are complete.