How do you test a Stripe agent before production?
Start with Stripe test mode and test cards for the basics, then test the parts agents get wrong: refunds larger than the charge, duplicate charges on retries, webhook ordering, and idempotency keys. Those cases pass against mocks and fail against real Stripe.
Start with the official test environment
Stripe ships a genuinely good test mode with test cards and a full API that behaves like live mode. Use it. The Stripe test mode and test cards docs cover creating customers, charges, and subscriptions without moving real money.
Where agents actually break
The happy path is the easy part. An agent that can do the simple version of the task will still fall over on the cases below, and these are the ones worth building tests around:
- A refund larger than the original charge, which Stripe rejects but a mock approves
- A retry that fires a second charge because the agent did not send an idempotency key
- Webhooks that arrive out of order, so a
charge.succeededlands after acharge.refunded - A card decline or dispute mid-flow, where the agent should stop rather than continue
- Rate limits during a burst of charges, which change the timing the agent depends on
How to test it properly
Give the agent a realistic starting state, let it run the full task end to end, then check the state it left behind rather than the response it returned. Run the same scenario twice to confirm it does not duplicate work or corrupt state on a retry. Then deliberately inject a failure partway through, a rejected write or a rate limit, and confirm the agent recovers instead of charging ahead as if nothing happened.
Testing the duplicate-charge case
The bug that hurts most is a retry that charges twice. In Stripe test mode, drive the agent, then assert the customer was charged once. Passing the same idempotency key twice must return the same charge, not a new one:
pythonimport stripe # stripe.api_key is a test-mode key (sk_test_...)
def test_retry_does_not_double_charge():
customer = stripe.Customer.create(email="maria@example.com")
# simulate the agent retrying the same request (same idempotency key)
key = "order-1234-charge"
first = agent_charge(customer.id, 4200, idempotency_key=key)
retry = agent_charge(customer.id, 4200, idempotency_key=key)
assert first.id == retry.id # same charge returned, not a new one
charges = stripe.Charge.list(customer=customer.id)
assert len(charges.data) == 1 # exactly one charge exists
Without the idempotency key this test fails against real Stripe and silently passes against a naive mock, which is why the mock hides the bug.