Skip to main content

Chaos engineering for payment flows

Project description

Carbon Layer

PyPI CI Python License

Chaos engineering for payment flows.

Every company processing payments tests the happy path — payment succeeds, order fulfilled — and ships. What breaks in production is everything else: dispute spikes your system doesn't respond to, refund storms that break reconciliation, gateway errors that leave orders stuck, webhook sequences your handlers were never tested against.

Carbon Layer lets you simulate these failure modes against your own integration before your customers encounter them. Run a scenario, point it at your webhook endpoint, and see exactly what your system handles and what it doesn't.


Installation

Option A: Quick start (no database needed)

pip install carbon-layer

Works out of the box. Carbon Layer uses SQLite by default — data is stored in ~/.carbon/carbon.db. Nothing else to install or configure.

Option B: With PostgreSQL (if you already have it)

pip install carbon-layer[postgres]

Then set your connection string via a .env file or environment variable:

# .env file in your project directory
DATABASE_URL=postgresql://postgres:yourpassword@localhost:5432/carbon

Or with Docker:

docker run -d --name carbon-pg \
  -e POSTGRES_PASSWORD=carbon \
  -e POSTGRES_DB=carbon \
  -p 5432:5432 postgres:15

# then set:
DATABASE_URL=postgresql://postgres:carbon@localhost:5432/carbon

Both options support all features. You can start with SQLite and switch to PostgreSQL anytime by installing the extra and setting DATABASE_URL.

Option C: With pipx (isolated install)

pipx install carbon-layer

Option D: With Docker

docker run ghcr.io/pritom14/carbon-layer run dispute-spike --provider mock

Quickstart

# List available scenarios
carbon scenarios-list

# Run your first scenario
carbon run dispute-spike --provider mock

# View the report (use the run_id from the output above)
carbon report --run-id <run_id>

No payment gateway account needed. The mock adapter simulates the full payment lifecycle locally.


Webhook Simulation

The real value of Carbon Layer is testing your webhook handlers. Point it at your endpoint and it fires provider-specific webhook events — payment.captured, payment_intent.succeeded, PAYMENT_SUCCESS_WEBHOOK, ORDER_SUCCEEDED, and more — after the scenario runs. Payloads are signed exactly like real webhooks from each provider (Razorpay, Stripe, Cashfree, Juspay).

carbon run dispute-spike --provider mock --webhook-url http://localhost:8000/webhooks

The report shows how your endpoint responded for each event type — 2xx, 4xx, 5xx, or timeout. No payment gateway account required.


Scenarios

Scenario What it tests
dispute-spike 15% dispute rate — does your system respond and submit evidence?
payment-decline-spike 30% payment failure rate — does your retry and order state logic hold?
refund-storm Mass refunds on captured payments — does reconciliation break?
flash-sale High order and payment volume — does throughput hold?
gateway-error-burst Intermittent gateway errors — are orders left in inconsistent state?
min-amount Minimum paise transactions — are edge-case amounts handled correctly?
max-amount Large-value transactions — are limits and approvals handled correctly?
upi-timeout UPI payments stuck without terminal status — does your reconciliation catch it?
vpa-not-found Invalid UPI VPA failures — does your handler distinguish VPA errors from general failures?
mandate-rejection UPI autopay mandate rejections — does your handler notify the customer?
settlement-delay Refunds on captured-but-unsettled payments — does reconciliation handle it?

Parameter Overrides

Override scenario parameters at runtime without editing YAML:

carbon run dispute-spike --provider mock --set baseline_orders=500 --set dispute_rate=0.3

Use --set multiple times for multiple parameters. Unknown keys are ignored with a warning.


HTML Reports

Export a shareable HTML report after any run:

carbon report --run-id <run_id> --format html

Writes carbon_report_<run_id>.html to the current directory. Self-contained, no external dependencies — safe to share with your team or attach to an incident report.


Webhook Resilience Testing

Test how your webhook handler behaves under real-world failure conditions.

Idempotency (duplicate webhooks)

Fire each webhook multiple times to test whether your handler processes duplicates:

carbon run dispute-spike --provider mock --webhook-url http://localhost:8000/webhooks --webhook-repeat 5

Out-of-order delivery

Gateways don't guarantee webhook order. Test with randomized or reversed delivery:

carbon run dispute-spike --provider mock --webhook-url http://localhost:8000/webhooks --webhook-order random

Options: sequence (default), reverse, random.

Signature verification

Test whether your handler actually validates webhook signatures:

# Missing signatures — should your handler reject these?
carbon run dispute-spike --provider mock --webhook-url http://localhost:8000/webhooks --webhook-signature missing

# Corrupted signatures
carbon run dispute-spike --provider mock --webhook-url http://localhost:8000/webhooks --webhook-signature corrupted

# Signed with wrong secret
carbon run dispute-spike --provider mock --webhook-url http://localhost:8000/webhooks --webhook-signature wrong_secret

Options: valid (default), missing, corrupted, wrong_secret.


Webhook Replay

Replay stored webhook payloads from any previous run. Useful for regression testing after code changes:

carbon replay <run_id> --webhook-url http://localhost:8000/webhooks

CI/CD Integration

Use --ci to fail the build if any webhook returned 5xx or timed out:

carbon run dispute-spike --provider mock \
  --webhook-url http://localhost:8000/webhooks \
  --ci

Use --callback-url to POST a JSON run summary to your pipeline:

carbon run dispute-spike --provider mock \
  --webhook-url http://localhost:8000/webhooks \
  --callback-url http://localhost:8000/carbon/results \
  --ci

The callback payload includes pass/fail status, findings summary, and webhook delivery counts.

JSON output

Pipe results to jq, Datadog, Slack, or any tool:

carbon run dispute-spike --provider mock --webhook-url http://localhost:8000/webhooks --output json

Returns structured JSON with run status, findings, webhook delivery stats, and overall pass/fail.

Example GitHub Actions workflow

See examples/github-actions.yml for a copy-paste workflow that runs Carbon Layer on every PR.


Supported Payment Gateways

Carbon Layer generates provider-specific webhook payloads with correct signing for each gateway.

Provider Webhook Format Signing CLI Flag
Mock Razorpay-format HMAC-SHA256 --provider mock
Razorpay X-Razorpay-Signature HMAC-SHA256 --provider razorpay
Stripe Stripe-Signature: t=...,v1=... HMAC-SHA256 --provider stripe
Cashfree x-webhook-signature Base64(HMAC-SHA256) --provider cashfree
Juspay Authorization: Basic ... Basic Auth --provider juspay

Razorpay

carbon run dispute-spike \
  --provider razorpay \
  --api-key your_test_key \
  --api-secret your_test_secret \
  --webhook-url https://your-app.com/webhooks

Or set RAZORPAY_API_KEY and RAZORPAY_API_SECRET as environment variables.

Stripe

carbon run dispute-spike \
  --provider stripe \
  --stripe-key sk_test_xxx \
  --webhook-url https://your-app.com/webhooks

Or set STRIPE_API_KEY as an environment variable.

Cashfree

carbon run dispute-spike \
  --provider cashfree \
  --cashfree-id your_app_id \
  --cashfree-secret your_secret_key \
  --webhook-url https://your-app.com/webhooks

Or set CASHFREE_CLIENT_ID and CASHFREE_CLIENT_SECRET as environment variables.

Juspay

carbon run dispute-spike \
  --provider juspay \
  --juspay-key your_api_key \
  --juspay-merchant-id your_merchant_id \
  --webhook-url https://your-app.com/webhooks

Or set JUSPAY_API_KEY and JUSPAY_MERCHANT_ID as environment variables.

Mock (no credentials needed)

carbon run dispute-spike --provider mock --webhook-url http://localhost:8000/webhooks

Mock mode simulates the full payment lifecycle locally. Use this if you don't have test credentials — all 11 scenarios work out of the box.


Carbon Layer Pro (coming soon)

The open-source CLI covers 11 scenarios, 5 payment gateways, and webhook resilience testing. We're building a hosted Pro tier for teams that need more:

  • Scheduled runs — run scenarios on a cron, get notified when your handlers regress
  • PDF reports — export compliance-ready reports for audits and stakeholders
  • Compliance dashboards — track webhook handler reliability over time
  • Pro scenarios — RBI compliance checks, PCI readiness suite, 10k TPS load tests, multi-gateway failover, settlement reconciliation
  • Team management — shared runs, role-based access, audit logs

The free CLI stays free and open-source (Apache 2.0). Pro is a separate hosted product.

Join the waitlist: pritom14.github.io/carbon-layer/waitlist


License

Apache 2.0 — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

carbon_layer-0.6.1.tar.gz (48.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

carbon_layer-0.6.1-py3-none-any.whl (55.0 kB view details)

Uploaded Python 3

File details

Details for the file carbon_layer-0.6.1.tar.gz.

File metadata

  • Download URL: carbon_layer-0.6.1.tar.gz
  • Upload date:
  • Size: 48.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.6

File hashes

Hashes for carbon_layer-0.6.1.tar.gz
Algorithm Hash digest
SHA256 ab35284dc5ca94cd58a0b78a51c9f457b2509fca41529e8ba24a660f1f88504d
MD5 93b9338d4399b4e616fa6fa46dc8d1c1
BLAKE2b-256 9239da317123c7f82749dbb28708a52ccf1068c96f11f092c930b85ea334ea86

See more details on using hashes here.

File details

Details for the file carbon_layer-0.6.1-py3-none-any.whl.

File metadata

  • Download URL: carbon_layer-0.6.1-py3-none-any.whl
  • Upload date:
  • Size: 55.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.6

File hashes

Hashes for carbon_layer-0.6.1-py3-none-any.whl
Algorithm Hash digest
SHA256 2e222b8356a5eb4ba9f80090ae23ba1f1a169afecac4bc9805f4d970f916daab
MD5 866d5c532b3e9b9ff613d51e547c5183
BLAKE2b-256 e59a449a31b63430f9d5993ffe83776d4f36c3d8b4487ce729b1aa9acafad146

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page