Introduction
The BillionCore API is a high-performance REST API for BIN (Bank Identification Number) lookup. Given the first 6–8 digits of a payment card, it returns the issuing bank's country, card brand, card type, and transaction routing rules — in under 20 microseconds.
The engine is written in Go and operates entirely in-memory with zero database hops. All responses are JSON. No SDK is required — any HTTP client works.
Quick start
- 1. Register and copy your API key from the dashboard.
- 2. Send a
GETrequest to https://engine.billioncore.tech/api/bin/lookup - 3. Pass your key in the
X-API-Keyheader.
Try it now — no signup
Copy this and run it. It uses a shared public demo key (rate-limited per IP), so you get a real 200 before you register — then grab your own free key for production.
# No signup — this shared public demo key works right now (rate-limited per IP) curl "https://engine.billioncore.tech/api/bin/lookup?bin=453998&country=US&profile=affiliate&price=49.99" \ -H "X-API-Key: bc_demo_BillionCoreStressTest2024"
Authentication
All requests require an API key. Keys are prefixed with bc_live_ and are generated instantly when you register.
Pass the key using either the X-API-Key header or as a Bearer token in the Authorization header.
GET /api/bin/lookup?bin=453998&country=US HTTP/1.1 Host: engine.billioncore.tech X-API-Key: bc_live_yourkey
Keep your API key secret — treat it like a password. Never expose it in client-side code or public repositories.
Base URL
All API requests are made over HTTPS to the following base URL. HTTP is not supported.
Endpoints
BillionCore exposes two main endpoints: a GET single-BIN lookup and a POST batch endpoint for up to 10,000 BINs in a single request. On the single-BIN endpoint, omit country to receive all configured country rules in one response.
BIN + Country lookup
GETReturns a single routing rule for a specific BIN + country combination. This is the fastest path — one atomic load plus two map lookups, returning in under 1ms.
| Parameter | Type | Required | Description |
|---|---|---|---|
| bin | string | required | First 6–8 digits of the card number. The engine accepts both 6- and 8-digit BINs — if an 8-digit BIN is not yet in the dataset, it automatically falls back to the 6-digit prefix. |
| country | string | optional | ISO 3166-1 alpha-2 code (e.g. US, GB) |
| profile | string | optional | Customer lens — retail (fraud/approval: approve·review·decline) or affiliate (traffic/rebill: force·keep·avoid). Omit for raw rules/action. When set, adds the analytics block (see Decision analytics). |
| vertical | string | optional | Traffic vertical that tunes the LTV horizon and chargeback cost: nutra, gambling, dating, vod, ecom, crypto. Requires profile. |
| price | float | optional | Your rebill price in USD. Unlocks LTV in analytics.economics. Falls back to the BIN's configured rebill price when omitted. |
| payout | float | optional | Your acquisition cost (CPA) in USD. Unlocks ROI, EV and breakeven in analytics.economics. |
Request
curl "https://engine.billioncore.tech/api/bin/lookup?bin=453998&country=US" \ -H "X-API-Key: bc_live_yourkey" # Add a decision lens + economics — risk, recommendation and projected LTV/ROI curl "https://engine.billioncore.tech/api/bin/lookup?bin=453998&country=US&profile=affiliate&vertical=nutra&price=49.99&payout=20" \ -H "X-API-Key: bc_live_yourkey"
Response
{
"success": true,
"data": {
"bin": "411111",
"country": "US",
"action": "FORCE",
"trial_price": 3.00,
"trial_period": 3,
"rebill_price": 39.74,
"rebill_period": 30,
"x_sell_status": "FORCE",
"configured": true,
"bin_performance": {
"gross_profit": 68.2,
"lead_u": 72.5,
"first_rebill": 88.0,
"rebill": 41.3,
"tc40_safe": 1.2,
"cb": 0.8,
"refund": 1.1,
"risk_score": 8
},
"issuer": {
"card_brand": "visa",
"card_type": "credit",
"issuer_name": "Jpmorgan Chase Bank, N.a.",
"country": "us"
}
},
"timestamp": "2026-06-02T20:00:00Z"
}BIN-only lookup (all country rules)
GETOmit the country parameter to receive all configured routing rules for a given BIN in a single response. Useful for admin tooling, data exploration, or when you want to see all market configurations at once.
| Parameter | Type | Required | Description |
|---|---|---|---|
| bin | string | required | First 6–8 digits of the card number |
Request
curl "https://engine.billioncore.tech/api/bin/lookup?bin=453998" \ -H "X-API-Key: bc_live_yourkey"
Response
{
"success": true,
"data": {
"bin": "411111",
"rules": {
"US": {
"action": "FORCE",
"trial_price": 3.00,
"trial_period": 3,
"rebill_price": 39.74,
"rebill_period": 30,
"x_sell_status": "FORCE"
},
"GB": {
"action": "DISABLE",
"trial_price": 0,
"trial_period": 0,
"rebill_price": 0,
"rebill_period": 0,
"x_sell_status": "DISABLE"
}
},
"bin_performance": {
"gross_profit": 68.2,
"lead_u": 72.5,
"first_rebill": 88.0,
"rebill": 41.3,
"tc40_safe": 1.2,
"cb": 0.8,
"refund": 1.1,
"risk_score": 8
},
"issuer": {
"card_brand": "visa",
"card_type": "credit",
"issuer_name": "Jpmorgan Chase Bank, N.a.",
"country": "us"
}
},
"timestamp": "2026-06-02T20:00:00Z"
}Batch lookup
POSTProcess up to 10,000 BINs in a single request. Each item in the batch counts as one API call toward your plan usage. Country is optional per item — with a country code the response contains a single routing rule; without a country code it returns all configured country rules for that BIN.
10,000 BINs processed in under 300ms. Each item in the batch counts as one API call toward your plan usage.
| Field | Type | Required | Description |
|---|---|---|---|
| lookups | array | required | Array of lookup items (max 10,000) |
| lookups[].bin | string | required | First 6–8 digits of the card |
| lookups[].country | string | optional | ISO 3166-1 alpha-2. Omit for all-country rules |
| lookups[].weight | float | optional | Traffic volume for this BIN. Weights the portfolio roll-up so high-volume BINs dominate the blended figures. Defaults to 1. |
Add ?profile=affiliate (with optional vertical/price/payout) to the batch URL and the response gains per-item analytics plus a top-level portfolio summary — see Decision analytics.
Request
# Plain batch — routing rules only
curl "https://engine.billioncore.tech/api/bin/batch" \
-X POST \
-H "X-API-Key: bc_live_yourkey" \
-H "Content-Type: application/json" \
-d '{"lookups":[{"bin":"453998","country":"US"},{"bin":"411111","country":"GB"},{"bin":"516793"}]}'
# Affiliate analytics + portfolio — add ?profile (and optional vertical/price/
# payout). Optional per-item "weight" = traffic volume for the portfolio roll-up.
curl "https://engine.billioncore.tech/api/bin/batch?profile=affiliate&vertical=nutra&price=49.99" \
-X POST \
-H "X-API-Key: bc_live_yourkey" \
-H "Content-Type: application/json" \
-d '{"lookups":[{"bin":"453998","country":"US","weight":5},{"bin":"516793","country":"US","weight":2}]}'Response
{
"success": true,
"count": 3,
"results": [
{
"bin": "679196",
"country": "NL",
"action": "FORCE",
"trial_price": 3,
"trial_period": 3,
"rebill_price": 90,
"rebill_period": 30,
"x_sell_status": "FORCE",
"issuer": {
"card_brand": "maestro",
"card_type": "debit"
},
"configured": true
},
{
"bin": "679835",
"country": "ES",
"action": "DISABLE",
"trial_price": 3,
"trial_period": 3,
"rebill_price": 33,
"rebill_period": 14,
"x_sell_status": "DISABLE",
"issuer": {
"card_brand": "maestro",
"card_type": "debit"
},
"configured": true
},
{
"bin": "453998",
"country": "US",
"action": "FORCE",
"x_sell_status": "FORCE",
"bin_performance": {
"gross_profit": 51.6,
"lead_u": 45.1,
"first_rebill": 85,
"rebill": 38.6,
"tc40_safe": 3.82,
"refund": 2.78,
"risk_score": 14
},
"issuer": {
"card_brand": "visa",
"card_type": "credit",
"issuer_name": "Cartasi S.p.a.",
"country": "it"
},
"configured": false,
"inference": {
"score": 100,
"signals": [
{ "key": "card_type", "value": "credit", "impact": 20, "label": "Credit card — best for recurring billing" },
{ "key": "risk_score", "value": 14, "impact": 20, "label": "Clean BIN — low fraud history" },
{ "key": "first_rebill_rate", "value": 85, "impact": 15, "label": "Strong first rebill rate" },
{ "key": "gross_profit", "value": 51.6, "impact": 10, "label": "Profitable BIN historically" }
]
}
}
],
"timestamp": "2026-06-03T19:48:23Z"
}Response fields
All successful responses follow the shape { success: true, data: {...} }. The fields inside data are described below.
Common (both endpoints)
| Field | Type | Description |
|---|---|---|
| bin | string | The BIN prefix (6–8 digits) |
| issuer | object? | Card issuer metadata — present when known |
| issuer.card_brand | string? | Payment network: visa, mastercard, amex, discover… |
| issuer.card_type | string? | credit, debit, prepaid, or charge |
| issuer.issuer_name | string? | Issuing bank name (best-effort, may lag rebrands) |
| issuer.country | string? | ISO 3166-1 alpha-2 country of the issuing bank |
| bin_performance | object? | Historical performance metrics — present when available |
| bin_performance.gross_profit | float | Average gross profit % for this BIN |
| bin_performance.lead_u | float | Lead conversion rate % |
| bin_performance.first_rebill | float | First rebill success rate % |
| bin_performance.rebill | float | Ongoing rebill success rate % |
| bin_performance.tc40_safe | float | TC40/SAFE fraud indicator % |
| bin_performance.cb | float | Chargeback rate % |
| bin_performance.refund | float | Refund rate % |
| bin_performance.risk_score | int | Pre-computed risk score 0–100 (0 = clean, 100 = critical) |
BIN + Country response
| Field | Type | Description |
|---|---|---|
| country | string | ISO 3166-1 alpha-2 country code |
| action | string | FORCE | DISABLE | INHERIT — routing decision for this card |
| trial_price | float | Trial period charge in USD |
| trial_period | int | Trial length in days |
| rebill_price | float | Recurring charge in USD |
| rebill_period | int | Recurring interval in days |
| x_sell_status | string | Cross-sell eligibility flag |
| configured | bool | true if action came from an explicit rule; false if derived by smart inference |
| inference | object? | Present only when configured=false — explains how the action was derived |
| inference.score | int | 0–100 confidence score (≥65→FORCE, 35–64→INHERIT, <35→DISABLE) |
| inference.signals | array | Contributing factors with key, value, impact (pts), and human-readable label |
| recommendation | object? | Present only when profile is set. Segment-specific decision. |
Recommendation object
| Field | Type | Description |
|---|---|---|
| profile | string | retail | affiliate |
| decision | string | retail: approve·review·decline · affiliate: force·keep·avoid |
| reasons | array | human-readable factors behind the decision |
Action values
| Value | Meaning |
|---|---|
| FORCE | Process this card — use the defined trial/rebill pricing |
| DISABLE | Block this card in this country — do not process |
| INHERIT | No country-specific rule — fall back to the global default |
Decision analytics
profileAdd ?profile=retail or ?profile=affiliate and the response gains an analytics block: projected rebill economics, peer-segment benchmarks, a confidence rating, and routing hints. The universal response is unchanged when no profile is requested. On the batch endpoint a portfolio-level portfolio summary is added alongside the per-item analytics.
Economics are modeled estimates, not settled results. When a BIN has no measured history the figures are inferred from its peer segment and estimated is true; always read confidence alongside the numbers. approval_likelihood is a modeled planning figure, not a measured authorisation rate.
analytics object
| Field | Type | Description |
|---|---|---|
| profile | string | retail | affiliate |
| estimated | bool | true when performance came from a peer-segment prior, not this BIN |
| confidence | object | How much to trust the figures (see below) |
| economics | object | Projected money + profit grade (see below) |
| benchmarks | array | Percentile rank of each metric vs the peer segment |
| routing | object? | Operational hints — present when relevant |
economics object
| Field | Type | Description |
|---|---|---|
| vertical | string | Resolved vertical (default unless ?vertical= given) |
| assumed_rebill_price | float | Price used for $ projections (from ?price= or the BIN rule) |
| projected_rebills | float | Expected successful rebills per approved customer over the vertical horizon |
| approval_likelihood | float | Modeled 0–1 authorisation probability (planning estimate, not measured) |
| profit_grade | string | A–F grade from the rate signals (price-independent) |
| ltv_per_approved | float? | Net projected $ over the rebill chain — needs a price |
| roi_pct | float? | Return on the payout — needs ?payout= |
| ev_per_approved | float? | ltv − payout — needs ?payout= |
| breakeven_payout | float? | Max CPA to break even (= ltv) — needs a price |
confidence object
| Field | Description |
|---|---|
| level | high | medium | low |
| basis | bin (own data) | segment_prior | global |
| segment | Peer segment used, e.g. visa/credit/US |
| samples | Peer BINs backing an estimate |
benchmarks & routing
| Field | Description |
|---|---|
| benchmarks[].metric | first_rebill, rebill, gross_profit, cb, refund, risk |
| benchmarks[].percentile | 0–100 vs peer segment — higher is always better |
| routing.recommend_3ds | Step-up authentication advised |
| routing.retry_strategy | e.g. retry_after_payday for debit |
| routing.note | Plain-language routing tip |
portfolio object (batch only)
| Field | Type | Description |
|---|---|---|
| bins / bins_with_data | int | Total BINs and how many could be scored |
| weighted_first_rebill | float | Volume-weighted first-rebill % across the batch |
| weighted_risk_score | float | Volume-weighted average risk score |
| blended_chargeback | float | Volume-weighted chargeback % |
| avg_projected_ltv | float | Average projected LTV per approved customer |
| chargeback_ceiling | float | Scheme monitoring threshold % (Visa VAMP ≈ 0.9) |
| ceiling_used_pct | float | How much of the ceiling the blended chargeback uses |
| compliance_status | string | healthy | watch | critical |
| top_issuer_country | string? | Most-concentrated issuer country |
| concentration_pct | float | Share of volume in the top issuer country |
| best / worst | array | Ranked BINs to keep/scale or review/cut |
Portfolio response (batch with ?profile=affiliate)
"portfolio": {
"bins": 3,
"bins_with_data": 3,
"weighted_first_rebill": 72.42,
"weighted_risk_score": 18.1,
"blended_chargeback": 0.1,
"blended_refund": 8.34,
"avg_projected_ltv": 48.73,
"chargeback_ceiling": 0.9,
"ceiling_used_pct": 11.11,
"compliance_status": "healthy",
"top_issuer_country": "IT",
"concentration_pct": 50,
"best": [ { "bin": "453998", "grade": "B", "risk_score": 14 } ],
"worst": [ { "bin": "411111", "grade": "F", "risk_score": 33 } ]
}Error codes
Errors always have success: false and a human-readable error string. The HTTP status code mirrors the error type.
| Status | Meaning |
|---|---|
| 401 | Missing or invalid API key |
| 400 | Missing required bin parameter |
| 500 | Internal server error — contact support |
Error responses
{
"success": false,
"error": "Unauthorized"
}Code examples
Full working examples for the most common languages and frameworks. All examples use the BIN + Country endpoint — omit &country=US to get all country rules instead.
curl
The fastest way to test your key. Works in any terminal.
# Single country curl "https://engine.billioncore.tech/api/bin/lookup?bin=453998&country=US" \ -H "X-API-Key: bc_live_yourkey" # All country rules curl "https://engine.billioncore.tech/api/bin/lookup?bin=453998" \ -H "X-API-Key: bc_live_yourkey"
PHP (vanilla)
Uses cURL extension, available in every PHP installation.
<?php
function billioncore_lookup(string $bin, string $country = ''): array
{
$url = 'https://engine.billioncore.tech/api/bin/lookup?bin=' . urlencode($bin);
if ($country !== '') {
$url .= '&country=' . urlencode($country);
}
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'X-API-Key: ' . $_ENV['BILLIONCORE_API_KEY'],
'Accept: application/json',
],
CURLOPT_TIMEOUT => 5,
]);
$body = curl_exec($ch);
curl_close($ch);
return json_decode($body, true);
}
// Usage
$result = billioncore_lookup('453998', 'US');
if ($result['success']) {
$data = $result['data'];
echo "Action: " . $data['action'] . PHP_EOL; // "FORCE"
echo "Trial: $" . $data['trial_price'] . " / " . $data['trial_period'] . " days" . PHP_EOL;
echo "Rebill: $" . $data['rebill_price'] . " / " . $data['rebill_period'] . " days" . PHP_EOL;
echo "Brand: " . ($data['issuer']['card_brand'] ?? 'unknown') . PHP_EOL;
echo "Bank: " . ($data['issuer']['issuer_name'] ?? 'unknown') . PHP_EOL;
echo "Risk: " . ($data['bin_performance']['risk_score'] ?? 'n/a') . "/100" . PHP_EOL;
}Laravel
Recommended pattern: store the key in config, use the HTTP facade.
<?php
return [
// ...
'billioncore' => [
'key' => env('BILLIONCORE_API_KEY'),
'base_url' => env('BILLIONCORE_BASE_URL', 'https://engine.billioncore.tech'),
],
];JavaScript / Node.js
Works in the browser and Node.js. Uses the native fetch API.
const BILLIONCORE_KEY = process.env.BILLIONCORE_API_KEY;
const BILLIONCORE_BASE = 'https://engine.billioncore.tech';
async function lookupBin(bin, country) {
const url = new URL('/api/bin/lookup', BILLIONCORE_BASE);
url.searchParams.set('bin', bin);
if (country) url.searchParams.set('country', country);
const res = await fetch(url.toString(), {
headers: { 'X-API-Key': BILLIONCORE_KEY },
});
if (!res.ok) {
const err = await res.json();
throw new Error(err.error ?? 'BillionCore error');
}
return res.json().then(r => r.data);
}
// Usage
const data = await lookupBin('453998', 'US');
if (data.action === 'FORCE') {
console.log('Trial: $' + data.trial_price + ' / ' + data.trial_period + ' days');
console.log('Brand:', data.issuer?.card_brand); // "visa"
console.log('Risk: ', data.bin_performance?.risk_score); // 8
}Python
Uses the requests library. Compatible with Django, FastAPI, Flask.
import os
import requests
from typing import Optional
BILLIONCORE_KEY = os.environ["BILLIONCORE_API_KEY"]
BILLIONCORE_BASE = "https://engine.billioncore.tech"
def lookup_bin(bin: str, country: Optional[str] = None) -> dict:
params = {"bin": bin}
if country:
params["country"] = country
resp = requests.get(
f"{BILLIONCORE_BASE}/api/bin/lookup",
params=params,
headers={"X-API-Key": BILLIONCORE_KEY},
timeout=5,
)
resp.raise_for_status()
return resp.json()["data"]
data = lookup_bin("453998", "US")
if data["action"] == "FORCE":
print(f"Trial: {data['trial_price']{'}'} / {'{'}data['trial_period']{'}'} days")
print(f"Brand: {'{'}data.get('issuer', {'{}'}).get('card_brand', 'n/a'){'}'}")
print(f"Risk: {'{'}data.get('bin_performance', {'{}'}).get('risk_score', 'n/a'){'}'}/100")Go
Zero external dependencies — uses the standard library only.
package billioncore
import (
"context"
"encoding/json"
"fmt"
"net/http"
"net/url"
"os"
"time"
)
type Client struct {
apiKey string
baseURL string
http *http.Client
}
type LookupData struct {
Bin string `json:"bin"`
Country string `json:"country,omitempty"`
Action string `json:"action"`
TrialPrice float64 `json:"trial_price"`
TrialPeriod int `json:"trial_period"`
RebillPrice float64 `json:"rebill_price"`
RebillPeriod int `json:"rebill_period"`
XSellStatus string `json:"x_sell_status"`
Performance *BinPerformance `json:"bin_performance,omitempty"`
Issuer *Issuer `json:"issuer,omitempty"`
Rules map[string]Rule `json:"rules,omitempty"`
}
type Rule struct {
Action string `json:"action"`
TrialPrice float64 `json:"trial_price"`
RebillPrice float64 `json:"rebill_price"`
}
type BinPerformance struct {
GrossProfit float64 `json:"gross_profit"`
RiskScore int `json:"risk_score"`
}
type Issuer struct {
CardBrand string `json:"card_brand"`
CardType string `json:"card_type"`
IssuerName string `json:"issuer_name"`
Country string `json:"country"`
}
func NewClient() *Client {
return &Client{
apiKey: os.Getenv("BILLIONCORE_API_KEY"),
baseURL: "https://engine.billioncore.tech",
http: &http.Client{Timeout: 5 * time.Second},
}
}
func (c *Client) Lookup(ctx context.Context, bin, country string) (*LookupData, error) {
u, _ := url.Parse(c.baseURL + "/api/bin/lookup")
q := u.Query()
q.Set("bin", bin)
if country != "" {
q.Set("country", country)
}
u.RawQuery = q.Encode()
req, _ := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil)
req.Header.Set("X-API-Key", c.apiKey)
resp, err := c.http.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
var errResp struct{ Error string `json:"error"` }
json.NewDecoder(resp.Body).Decode(&errResp)
return nil, fmt.Errorf("billioncore: %s", errResp.Error)
}
var result struct {
Data LookupData `json:"data"`
}
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return nil, err
}
return &result.Data, nil
}