The short answer
Authorize.net runs a full sandbox with its own endpoint, and its accepted test cards are a fixed list. Drop these into a sandbox transaction and they pass format and Luhn checks:
- Visa: 4007000000027
- Visa: 4012888818888
- Mastercard: 5424000000000015
- American Express: 370000000000002
- Discover: 6011000000000012
- JCB: 3566002020360505
- Diners Club: 38000000000006
- Visa decline card: 4222222222222
Use any expiration date in the future, and a card code whose length matches the brand: three digits for Visa, Mastercard, Discover and Diners, four for American Express. The first seven numbers are built to get an approval. The decline number is there so you can watch your error handling path run without touching a real account.
Test cards are not a mode switch
This is the part that confuses people coming from other processors. Authorize.net does not have a "test": true flag you set on a request. You point the same API call at a different host and sign it with a different set of credentials. Sandbox traffic goes to the test endpoint, live traffic goes to the production endpoint, and the API Login ID and Transaction Key from your sandbox account will not authenticate on the live side. If one of the numbers above comes back as an error, check the host and credentials before you blame the card. Most of the time the request is quietly hitting production with test keys, or the sandbox keys are pasted into a live config file.
What these numbers actually exercise
A sandbox approval returns the same response codes you see in production: 1 for approved, 2 for declined, 3 for an error, 4 for held for review. That makes the sandbox useful for testing the boring parts of an integration, which are usually the parts that break: how you parse the response, how you store the transaction ID, what your UI shows when the gateway says declined, and how you handle a timeout.
Address Verification and Card Code responses in the sandbox come from the values you submit rather than from a bank, so you can drive specific AVS and CVV result codes by following the mapping in the developer documentation instead of guessing. Test card codes are frequently not validated at all, which means a CVV mismatch test that passes locally can behave differently once real issuer responses are in play.
Things that break a test run
- Fraud filters. Advanced Fraud Detection Suite rules like velocity limits, card code mismatch and suspicious amount thresholds will happily hold or reject a well-known test number. Check the filter settings on the sandbox account before you assume the code is wrong.
- The duplicate window. Sending the same card, amount and invoice number again within the window, two minutes by default, returns a duplicate transaction error. Vary the invoice number when you loop a test.
- Expiration format. The modern API wants YYYY-MM, for example 2026-12. Older integrations and hosted form code sometimes use MMYY or MM/YY. A correctly formatted date in the wrong style fails before it reaches the card.
- Zero amounts. Some accounts and processors reject a 0.00 authorization. Use a small nonzero amount unless you are deliberately testing an auth-only plus void flow.
- Brand mismatch. An American Express card number with a three digit card code, or a card type field that contradicts the number, can trip validation inside your own code before Authorize.net ever sees it.
Keep test numbers out of production
Test numbers are flagged. Sending one to the live gateway gets you a decline at best, and repeated attempts can draw attention from the risk team on your merchant account, since running test transactions through a live account is not permitted under the merchant agreement. Keep the sandbox credentials and the test card list in your development config, use environment variables so the two never mix, and never let real cardholder data land in a test database. If you need to reproduce a production issue, reproduce the shape of the data, not the data itself.
One last note on validation: all of the numbers above pass the Luhn check, so Luhn validation alone will never tell you a card is a test card. If you want to block them, you need a BIN range check, and that list needs maintenance because issuers reassign ranges over time.