Modes of failure
What can go wrong, what you'll see when it does, and what Strimz does about it automatically.
Things break. Network calls fail, customers cancel mid-flow, on-chain transactions get stuck. This page lists the failure modes Strimz already handles, what surfaces in each case, and where the automatic recovery stops.
A subscription charge fails
The contract emits SubscriptionChargeSkipped(subId, attemptId, outcome) instead of reverting. The outcomes that count as a payment failure are:
InsufficientFunds. Payer's balance was below the charge amount.RevokedApproval. Payer's allowance to the contract is too low.TransferFailed. The token transfer failed, for example because the token blocklisted the payer.MerchantInactive. The merchant is not active in the registry.
The indexer projects these into SubscriptionCharge(status: failed, outcome: <enum>), fires subscription.charge_failed, and flips the Subscription to at_risk. The scheduler retries after 15m, 1h, 3h, 6h, 12h, then every 24h. The agent's recovery capability (if enabled) emails the customer per your recoveryStrategy. If no charge succeeds within 48 hours of the period end, the scheduler's hourly subscription-lapsed cron flips the sub to lapsed and fires subscription.lapsed.
Other outcomes are recorded but change nothing: Cancelled (already cancelled), NotDue (charged before nextChargeAt), Duplicate (attempt id already used), Ended and Unknown.
You'll see this in:
GET /v1/subscriptions?status=at_risksubscription.charge_failedwebhooksubscription.lapsedwebhook (after grace)- The agent activity log under
recovery_notification_sent
A webhook delivery fails
Strimz POSTs the event to your URL with a 10-second timeout. Anything other than 2xx, including network errors, counts as a failure.
After permanent failure:
- Strimz emails the merchant with the delivery ID, last response, and last error.
- If the same endpoint has had 5+ permanent failures in 24 hours, the endpoint auto-disables (status:
disabled) and a separate notice goes out. You re-enable from the dashboard. - The delivery row stays in your
WebhookDeliverytable withstatus='permanently_failed'andlastErrorfor triage. You can manually replay viaPOST /v1/webhook-deliveries/:id/replay.
The on-chain payment is broadcast but doesn't confirm
Arc has deterministic sub-second finality, so a confirmed transaction is not reorged away. The indexer projects after CONFIRMATIONS blocks; the setting is required and 1 is recommended. If a batchCharge broadcast fails or never lands, the worker releases the lock and the next sweep tries again. If the earlier attempt did land, the contract skips the repeat with outcome Duplicate (or NotDue once the period has moved on), so the payer is not charged twice.
A customer cancels their subscription on-chain (without telling you)
The contract emits SubscriptionCancelled(subId, by). The indexer projects Subscription.status = cancelled and cancellationReason = 'on-chain cancel by 0x… in tx 0x…'. No subscription.cancelled webhook fires for an on-chain cancel today, so check GET /v1/subscriptions/:id if your records disagree.
A refund tx is signed but never broadcast
The merchant created a refund (status: awaiting_signature) but didn't sign and send it. The refund stays in awaiting_signature until manually voided (cancel via dashboard) or the merchant does eventually broadcast.
If they broadcast but submit the wrong tx hash to
POST /v1/refunds/:id/signature, the indexer's ERC-20 matcher
finds no corresponding Transfer event and the row sits in
submitted. Re-submit the correct hash to fix it; the row updates
idempotently.
API key leaks
Strimz does not scan for leaked keys. If a key leaks, revoke it on the API keys page and create a new one. A revoked key returns authentication_error immediately.
What's not currently automated
These are real failure modes you should still build for:
- Customer's wallet permanently loses access (lost seed phrase, hardware wallet bricked). Their subscription will keep failing until they re-create a wallet and re-subscribe. There's no Strimz-side way to "transfer" a subscription to a new wallet. The on-chain authorisation is gone.
- Strimz API is down. Strimz is a single hosted service today. Outage equals downtime, and no plan carries an uptime SLA today. The on-chain layer keeps working. Payments via direct contract calls still settle.
- Arc network outage. Same idea: this is a chain-level event. Strimz inherits Arc's availability.
For anything not on this page, open an issue. New failure modes and their recovery get documented here as they come up.

