BIN Lookup API for C#: Integration Guide
This guide walks you through integrating BINLookupAPI into your C#/.NET application. From creating your account to writing production-ready code, we’ll assist you with proper error handling and modern .NET patterns.
- ✓ Look up BIN information for any payment card
- ✓ Handle all error cases gracefully
- ✓ Work with async/await patterns throughout
- ✓ Look up thousands of BINs in one request with the batch endpoint
- ✓ Validate cards in a real payment flow
Prerequisites
- .NET 6.0 or higher
- Visual Studio 2022, VS Code, or JetBrains Rider
- Basic familiarity with async/await in C#
No additional NuGet packages are required for basic usage. The built-in System.Net.Http and System.Text.Json namespaces provide everything you need.
# Create a new console project to follow along
dotnet new console -n BinLookupDemo
cd BinLookupDemo
Step 1: Create Your Account
First, you’ll need a BINLookupAPI account to get your API key.
- 1 Go to app.binlookupapi.com/sign-in
- 2 Sign in with your Google account
- 3 An organisation is created automatically for you
You’ll start on the free tier which includes 10 real lookups per day — no credit card required, so you can try the API before subscribing.
Step 2: Create an API Key
Once logged in:
- 1 Navigate to API Keys in the dashboard
- 2 Click Create Key
- 3 Give it a name (e.g., "C# Development")
- 4 Copy the key immediately — it's only shown once
Your API key will look something like: blapi_live_xxxxxxxxxxxxxxxxxxxx
Store your API key securely. Never commit API keys to version control. Use environment variables or a secrets manager.
Step 3: Your First BIN Lookup
Let’s start with a simple example to verify everything works:
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
const string ApiKey = "your_api_key_here";
const string ApiUrl = "https://api.binlookupapi.com/v1/bin";
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", ApiKey);
var requestBody = JsonSerializer.Serialize(new { number = 42467101 });
var content = new StringContent(requestBody, Encoding.UTF8, "application/json");
var response = await client.PostAsync(ApiUrl, content);
response.EnsureSuccessStatusCode();
var json = await response.Content.ReadAsStringAsync();
Console.WriteLine(json);
Expected response:
{
"data": {
"bin": "42467101",
"scheme": "visa",
"funding": "debit",
"brand": "VISA",
"category": "CLASSIC",
"country": {
"code": "PL",
"name": "POLAND"
},
"issuer": {
"name": "ING BANK SLASKI SA",
"website": null,
"phone": null
},
"currency": "PLN",
"prepaid": false,
"commercial": false
}
}
Step 4: Production-Ready Code with Error Handling
The basic example above doesn’t handle errors properly. Here’s a production-ready implementation:
using System.Net;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace BinLookup;
#region Exceptions
/// <summary>
/// Base exception for all BIN lookup errors.
/// </summary>
public class BinLookupException : Exception
{
public BinLookupException(string message) : base(message) { }
public BinLookupException(string message, Exception inner) : base(message, inner) { }
}
/// <summary>
/// Raised when the BIN format is invalid.
/// </summary>
public class InvalidBinException : BinLookupException
{
public InvalidBinException(string message) : base(message) { }
}
/// <summary>
/// Raised when the API key is invalid, missing, or lacks permissions.
/// </summary>
public class AuthenticationException : BinLookupException
{
public AuthenticationException(string message) : base(message) { }
}
/// <summary>
/// Raised when the daily quota has been exceeded.
/// </summary>
public class QuotaExceededException : BinLookupException
{
public QuotaExceededException(string message) : base(message) { }
}
/// <summary>
/// Raised when the BIN is not found in the database.
/// </summary>
public class BinNotFoundException : BinLookupException
{
public BinNotFoundException(string message) : base(message) { }
}
/// <summary>
/// Raised when the API service encounters an error.
/// </summary>
public class ServiceException : BinLookupException
{
public ServiceException(string message) : base(message) { }
public ServiceException(string message, Exception inner) : base(message, inner) { }
}
#endregion
#region Models
/// <summary>
/// Represents issuer (bank) information.
/// </summary>
public sealed record Issuer(
[property: JsonPropertyName("name")] string? Name,
[property: JsonPropertyName("website")] string? Website,
[property: JsonPropertyName("phone")] string? Phone
);
/// <summary>
/// Represents country information.
/// </summary>
public sealed record Country(
[property: JsonPropertyName("code")] string Code,
[property: JsonPropertyName("name")] string Name
);
/// <summary>
/// Represents BIN information returned by the API.
/// </summary>
public sealed record BinInfo(
[property: JsonPropertyName("bin")] string Bin,
[property: JsonPropertyName("scheme")] string Scheme,
[property: JsonPropertyName("funding")] string Funding,
[property: JsonPropertyName("brand")] string? Brand,
[property: JsonPropertyName("category")] string? Category,
[property: JsonPropertyName("country")] Country Country,
[property: JsonPropertyName("issuer")] Issuer Issuer,
[property: JsonPropertyName("currency")] string? Currency,
[property: JsonPropertyName("prepaid")] bool Prepaid,
[property: JsonPropertyName("commercial")] bool Commercial
);
/// <summary>
/// API response wrapper.
/// </summary>
internal sealed record ApiResponse(
[property: JsonPropertyName("data")] BinInfo Data
);
/// <summary>
/// API error response.
/// </summary>
internal sealed record ApiErrorResponse(
[property: JsonPropertyName("message")] string? Message
);
/// <summary>
/// Quota information from response headers.
/// </summary>
public sealed record QuotaInfo(
int Limit,
int Remaining,
long ResetTimestamp
);
#endregion
#region Client
/// <summary>
/// Client for the BINLookupAPI service.
/// </summary>
public sealed class BinLookupClient : IDisposable
{
private const string BaseUrl = "https://api.binlookupapi.com/v1/bin";
private readonly HttpClient _httpClient;
private readonly JsonSerializerOptions _jsonOptions;
private bool _disposed;
/// <summary>
/// Initialize the client with an API key.
/// </summary>
/// <param name="apiKey">Your BINLookupAPI key. If null, reads from BINLOOKUP_API_KEY environment variable.</param>
/// <param name="httpClient">Optional HttpClient instance (for IHttpClientFactory usage).</param>
public BinLookupClient(string? apiKey = null, HttpClient? httpClient = null)
{
var key = apiKey ?? Environment.GetEnvironmentVariable("BINLOOKUP_API_KEY");
if (string.IsNullOrWhiteSpace(key))
{
throw new ArgumentException(
"API key required. Pass it directly or set BINLOOKUP_API_KEY environment variable.",
nameof(apiKey)
);
}
_httpClient = httpClient ?? new HttpClient();
_httpClient.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", key);
_httpClient.Timeout = TimeSpan.FromSeconds(10);
_jsonOptions = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
};
}
/// <summary>
/// Look up information for a BIN.
/// </summary>
/// <param name="binNumber">The BIN to look up (6-11 digits).</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>BinInfo object with card details.</returns>
/// <exception cref="InvalidBinException">If the BIN format is invalid.</exception>
/// <exception cref="AuthenticationException">If the API key is invalid.</exception>
/// <exception cref="QuotaExceededException">If the daily quota is exceeded.</exception>
/// <exception cref="BinNotFoundException">If the BIN is not found.</exception>
/// <exception cref="ServiceException">If the API service has an error.</exception>
public async Task<BinInfo> LookupAsync(long binNumber, CancellationToken cancellationToken = default)
{
// Validate input
if (binNumber < 100000 || binNumber > 99999999999)
{
throw new InvalidBinException(
$"BIN must be between 100000 and 99999999999, got: {binNumber}"
);
}
HttpResponseMessage response;
try
{
var requestBody = JsonSerializer.Serialize(new { number = binNumber });
var content = new StringContent(requestBody, Encoding.UTF8, "application/json");
response = await _httpClient.PostAsync(BaseUrl, content, cancellationToken);
}
catch (TaskCanceledException ex) when (ex.InnerException is TimeoutException)
{
throw new ServiceException("Request timed out. Please try again.", ex);
}
catch (HttpRequestException ex)
{
throw new ServiceException("Could not connect to API. Check your network.", ex);
}
// Handle error responses
var statusCode = (int)response.StatusCode;
switch (response.StatusCode)
{
case HttpStatusCode.BadRequest: // 400
var errorJson = await response.Content.ReadAsStringAsync(cancellationToken);
var errorResponse = JsonSerializer.Deserialize<ApiErrorResponse>(errorJson, _jsonOptions);
throw new InvalidBinException(errorResponse?.Message ?? "Invalid BIN");
case HttpStatusCode.Unauthorized: // 401
throw new AuthenticationException("Invalid API key. Check your credentials.");
case HttpStatusCode.Forbidden: // 403
throw new AuthenticationException("API key lacks required permissions.");
case HttpStatusCode.NotFound: // 404
throw new BinNotFoundException($"BIN {binNumber} not found in database.");
case (HttpStatusCode)429: // Too Many Requests
throw new QuotaExceededException("Daily quota exceeded. Resets at midnight UTC.");
case HttpStatusCode.BadGateway: // 502
throw new ServiceException("API gateway error. Please try again later.");
}
if (statusCode >= 500)
{
throw new ServiceException(
$"API service error (HTTP {statusCode}). Please try again later."
);
}
if (!response.IsSuccessStatusCode)
{
throw new BinLookupException($"Unexpected error: HTTP {statusCode}");
}
// Parse successful response
var json = await response.Content.ReadAsStringAsync(cancellationToken);
var apiResponse = JsonSerializer.Deserialize<ApiResponse>(json, _jsonOptions);
return apiResponse?.Data ?? throw new BinLookupException("Invalid API response format");
}
/// <summary>
/// Get quota information from the API.
/// </summary>
public async Task<QuotaInfo?> GetQuotaInfoAsync(CancellationToken cancellationToken = default)
{
try
{
var requestBody = JsonSerializer.Serialize(new { number = 42467101 });
var content = new StringContent(requestBody, Encoding.UTF8, "application/json");
var response = await _httpClient.PostAsync(BaseUrl, content, cancellationToken);
if (!response.Headers.TryGetValues("X-Quota-Limit", out var limitValues) ||
!response.Headers.TryGetValues("X-Quota-Remaining", out var remainingValues) ||
!response.Headers.TryGetValues("X-Quota-Reset", out var resetValues))
{
return null;
}
return new QuotaInfo(
int.Parse(limitValues.First()),
int.Parse(remainingValues.First()),
long.Parse(resetValues.First())
);
}
catch
{
return null;
}
}
public void Dispose()
{
if (!_disposed)
{
_httpClient.Dispose();
_disposed = true;
}
}
}
#endregion
Step 5: Using the Client
Here’s how to use the production-ready client:
using BinLookup;
// Initialize with API key from environment
using var client = new BinLookupClient();
// Or pass the key directly
using var clientWithKey = new BinLookupClient(apiKey: "your_api_key_here");
// Look up a BIN
try
{
var info = await client.LookupAsync(42467101);
Console.WriteLine($"Card Network: {info.Scheme}");
Console.WriteLine($"Card Type: {info.Funding}");
Console.WriteLine($"Issuer: {info.Issuer.Name}");
Console.WriteLine($"Country: {info.Country.Name}");
Console.WriteLine($"Is Prepaid: {info.Prepaid}");
}
catch (InvalidBinException ex)
{
Console.WriteLine($"Invalid BIN: {ex.Message}");
}
catch (AuthenticationException ex)
{
Console.WriteLine($"Auth error: {ex.Message}");
// Check your API key
}
catch (QuotaExceededException ex)
{
Console.WriteLine($"Quota exceeded: {ex.Message}");
// Wait until midnight UTC or upgrade your plan
}
catch (BinNotFoundException ex)
{
Console.WriteLine($"BIN not found: {ex.Message}");
// This BIN isn't in the database
}
catch (ServiceException ex)
{
Console.WriteLine($"Service error: {ex.Message}");
// Retry with exponential backoff
}
catch (BinLookupException ex)
{
Console.WriteLine($"Unexpected error: {ex.Message}");
}
The exception hierarchy lets you catch specific errors or use the base BinLookupException to handle all API-related errors at once.
Step 6: Using IHttpClientFactory (Recommended)
For ASP.NET Core applications, use IHttpClientFactory for proper connection management:
// In Program.cs or Startup.cs
builder.Services.AddHttpClient<BinLookupClient>(client =>
{
client.BaseAddress = new Uri("https://api.binlookupapi.com/v1/");
client.Timeout = TimeSpan.FromSeconds(10);
});
builder.Services.AddSingleton(sp =>
{
var httpClient = sp.GetRequiredService<IHttpClientFactory>()
.CreateClient(nameof(BinLookupClient));
var apiKey = builder.Configuration["BinLookupApi:ApiKey"];
return new BinLookupClient(apiKey, httpClient);
});
Configuration in appsettings.json:
{
"BinLookupApi": {
"ApiKey": "your_api_key_here"
}
}
Using IHttpClientFactory prevents socket exhaustion issues and properly manages the lifetime of HttpClient instances in long-running applications.
Step 7: Batch Lookups — Up to 2,000 BINs per Request
If you’re enriching a transaction export or backfilling card metadata, calling /v1/bin in a loop means one HTTP round trip per BIN. The batch endpoint (POST /v1/bins — note the plural) accepts 1 to 2,000 BINs in a single request:
{
"numbers": [400062, "400597", 99999999]
}
Each entry follows the same rules as a single lookup: 6–11 digits, as an integer or a digit string. The response returns one result per submitted number, in the same order:
{
"mode": "live",
"results": [
{
"number": 400062,
"data": {
"bin": "400062",
"scheme": "visa",
"funding": "debit",
"country": { "code": "AE", "name": "UNITED ARAB EMIRATES" },
"issuer": { "name": "EMIRATES NBD BANK (P.J.S.C.)" }
},
"meta": { "longer_bin_available": true }
},
{
"number": "400597",
"data": {
"bin": "400597",
"scheme": "visa",
"funding": "credit",
"category": "BUSINESS",
"country": { "code": "US", "name": "UNITED STATES" },
"issuer": { "name": "FIRST ELECTRONIC BANK" },
"commercial": true
},
"meta": { "longer_bin_available": true }
},
{
"number": 99999999,
"error": "NOT_FOUND",
"message": "BIN not found"
}
]
}
Notice the third entry: per-item failures don’t affect the rest of the batch. Each result has either a data object or an error code (NOT_FOUND or BAD_REQUEST) with a message. The whole request only fails for request-level problems — malformed JSON, a missing or oversized numbers array, authentication, or quota.
Let’s extend the BinLookupClient from Step 4. First, the response models:
/// <summary>
/// Per-item metadata in a batch response.
/// </summary>
public sealed record BatchResultMeta(
[property: JsonPropertyName("longer_bin_available")] bool LongerBinAvailable
);
/// <summary>
/// One result in a batch response. Contains either Data (success)
/// or Error + Message (per-item failure).
/// </summary>
public sealed record BatchResultItem(
[property: JsonPropertyName("number")] JsonElement Number,
[property: JsonPropertyName("data")] BinInfo? Data,
[property: JsonPropertyName("meta")] BatchResultMeta? Meta,
[property: JsonPropertyName("error")] string? Error,
[property: JsonPropertyName("message")] string? Message
);
/// <summary>
/// Batch API response wrapper.
/// </summary>
internal sealed record BatchApiResponse(
[property: JsonPropertyName("mode")] string Mode,
[property: JsonPropertyName("results")] IReadOnlyList<BatchResultItem> Results
);
Number is a JsonElement because the API echoes each value back exactly as you submitted it — an integer stays a JSON number, a string stays a string. Now add the batch method to BinLookupClient:
private const string BatchUrl = "https://api.binlookupapi.com/v1/bins";
/// <summary>
/// Look up multiple BINs in one or more batch requests.
/// Lists larger than 2,000 are split into sequential requests automatically.
/// </summary>
/// <param name="numbers">The BINs to look up (6-11 digits each).</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>One result per submitted number, in the same order.</returns>
/// <exception cref="InvalidBinException">If the request itself is malformed.</exception>
/// <exception cref="AuthenticationException">If the API key is invalid.</exception>
/// <exception cref="QuotaExceededException">If the batch exceeds remaining quota.</exception>
/// <exception cref="ServiceException">If the API service has an error.</exception>
public async Task<IReadOnlyList<BatchResultItem>> LookupBatchAsync(
IEnumerable<long> numbers,
CancellationToken cancellationToken = default)
{
var allResults = new List<BatchResultItem>();
// The API accepts at most 2,000 BINs per request
foreach (var chunk in numbers.Chunk(2000))
{
HttpResponseMessage response;
try
{
var requestBody = JsonSerializer.Serialize(new { numbers = chunk });
var content = new StringContent(requestBody, Encoding.UTF8, "application/json");
response = await _httpClient.PostAsync(BatchUrl, content, cancellationToken);
}
catch (TaskCanceledException ex) when (ex.InnerException is TimeoutException)
{
throw new ServiceException("Request timed out. Please try again.", ex);
}
catch (HttpRequestException ex)
{
throw new ServiceException("Could not connect to API. Check your network.", ex);
}
var statusCode = (int)response.StatusCode;
switch (response.StatusCode)
{
case HttpStatusCode.BadRequest: // 400 — request-level problem
var errorJson = await response.Content.ReadAsStringAsync(cancellationToken);
var errorResponse = JsonSerializer.Deserialize<ApiErrorResponse>(errorJson, _jsonOptions);
throw new InvalidBinException(errorResponse?.Message ?? "Invalid batch request");
case HttpStatusCode.Unauthorized: // 401
throw new AuthenticationException("Invalid API key. Check your credentials.");
case HttpStatusCode.Forbidden: // 403
throw new AuthenticationException("API key lacks required permissions.");
case (HttpStatusCode)429: // Batch exceeds remaining quota — nothing consumed
throw new QuotaExceededException(
"Batch exceeds remaining daily quota. No lookups were consumed."
);
}
if (statusCode >= 500)
{
throw new ServiceException(
$"API service error (HTTP {statusCode}). Please try again later."
);
}
if (!response.IsSuccessStatusCode)
{
throw new BinLookupException($"Unexpected error: HTTP {statusCode}");
}
var json = await response.Content.ReadAsStringAsync(cancellationToken);
var batchResponse = JsonSerializer.Deserialize<BatchApiResponse>(json, _jsonOptions);
allResults.AddRange(
batchResponse?.Results ?? throw new BinLookupException("Invalid API response format")
);
}
return allResults;
}
Using it is straightforward — iterate the results and branch on whether each item has data or an error:
using BinLookup;
using var client = new BinLookupClient();
var results = await client.LookupBatchAsync(new long[] { 400062, 400597, 99999999 });
foreach (var result in results)
{
if (result.Data is not null)
{
Console.WriteLine(
$"{result.Number}: {result.Data.Scheme} {result.Data.Funding} — " +
$"{result.Data.Issuer.Name} ({result.Data.Country.Code})"
);
}
else
{
Console.WriteLine($"{result.Number}: {result.Error} — {result.Message}");
}
}
Output:
400062: visa debit — EMIRATES NBD BANK (P.J.S.C.) (AE)
400597: visa credit — FIRST ELECTRONIC BANK (US)
99999999: NOT_FOUND — BIN not found
Batch lookups are available on the BLAPI-500KPM plan ($100/mo). Test-mode organisations always have access — with mock data and a 500-lookups/day limit — so you can build against the endpoint for free. Every submitted number counts as one lookup against your daily quota, including invalid or unknown BINs. If a batch is larger than your remaining quota, the API returns 429, consumes nothing, and the X-Quota-Remaining header reports your actual remaining quota.
One safety note: if a submitted value is longer than 11 digits — a possible full card number — the API returns it as "[REDACTED]" with a per-item BAD_REQUEST error, and the value is never stored in request logs. Still, validate lengths client-side before sending.
See the batch lookups documentation for full details.
Step 8: Real-World Example — Payment Form Validation
Here’s a practical example of using BIN lookup in a payment flow:
using BinLookup;
namespace PaymentProcessing;
/// <summary>
/// Result of card BIN validation.
/// </summary>
public sealed record CardValidationResult
{
public required bool Valid { get; init; }
public string? CardType { get; init; }
public string? Issuer { get; init; }
public string? Country { get; init; }
public bool IsPrepaid { get; init; }
public List<string>? Warnings { get; init; }
public string? Error { get; init; }
}
/// <summary>
/// Service for validating payment card BINs.
/// </summary>
public sealed class CardValidationService
{
private readonly BinLookupClient _binLookupClient;
public CardValidationService(BinLookupClient binLookupClient)
{
_binLookupClient = binLookupClient;
}
/// <summary>
/// Validate a card BIN for payment processing.
/// </summary>
/// <param name="cardNumber">The card number (only first 6-8 digits are used).</param>
/// <param name="blockPrepaid">If true, reject prepaid cards.</param>
/// <param name="allowedCountries">List of allowed country codes (e.g., ["US", "GB"]).</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>CardValidationResult with validation details.</returns>
public async Task<CardValidationResult> ValidateCardBinAsync(
string cardNumber,
bool blockPrepaid = false,
IReadOnlySet<string>? allowedCountries = null,
CancellationToken cancellationToken = default)
{
var warnings = new List<string>();
// Extract BIN (first 8 digits)
var digitsOnly = new string(cardNumber.Where(char.IsDigit).ToArray());
if (digitsOnly.Length < 6)
{
return new CardValidationResult
{
Valid = false,
Error = "Card number must be at least 6 digits"
};
}
var binNumber = int.Parse(digitsOnly[..Math.Min(8, digitsOnly.Length)]);
BinInfo info;
try
{
info = await _binLookupClient.LookupAsync(binNumber, cancellationToken);
}
catch (BinNotFoundException)
{
return new CardValidationResult
{
Valid = false,
Error = "Unable to identify card. Please check the number."
};
}
catch (QuotaExceededException)
{
// Fail open - allow the transaction but log the issue
return new CardValidationResult
{
Valid = true,
Warnings = ["BIN validation skipped due to quota limits"]
};
}
catch (BinLookupException ex)
{
// Fail open for service errors
return new CardValidationResult
{
Valid = true,
Warnings = [$"BIN validation unavailable: {ex.Message}"]
};
}
// Check prepaid status
if (blockPrepaid && info.Prepaid)
{
return new CardValidationResult
{
Valid = false,
CardType = info.Scheme,
Issuer = info.Issuer.Name,
Country = info.Country.Code,
IsPrepaid = true,
Error = "Prepaid cards are not accepted"
};
}
// Check country restrictions
if (allowedCountries is not null && !allowedCountries.Contains(info.Country.Code))
{
return new CardValidationResult
{
Valid = false,
CardType = info.Scheme,
Issuer = info.Issuer.Name,
Country = info.Country.Code,
Error = $"Cards from {info.Country.Name} are not accepted"
};
}
// Add warnings for high-risk indicators
if (info.Prepaid)
{
warnings.Add("This is a prepaid card");
}
if (info.Commercial)
{
warnings.Add("This is a corporate/business card");
}
return new CardValidationResult
{
Valid = true,
CardType = info.Scheme,
Issuer = info.Issuer.Name,
Country = info.Country.Code,
IsPrepaid = info.Prepaid,
Warnings = warnings.Count > 0 ? warnings : null
};
}
}
// Usage example
public static class Program
{
public static async Task Main()
{
using var client = new BinLookupClient();
var validationService = new CardValidationService(client);
var allowedCountries = new HashSet<string> { "US", "GB", "CA", "AU" };
var result = await validationService.ValidateCardBinAsync(
cardNumber: "4246710012345678",
blockPrepaid: true,
allowedCountries: allowedCountries
);
if (result.Valid)
{
Console.WriteLine($"Card accepted: {result.CardType} from {result.Issuer}");
if (result.Warnings is not null)
{
foreach (var warning in result.Warnings)
{
Console.WriteLine($"Warning: {warning}");
}
}
}
else
{
Console.WriteLine($"Card rejected: {result.Error}");
}
}
}
For payment validation, consider “failing open” when the API is unavailable. It’s usually better to allow a transaction and verify later than to block all payments during an outage.
Best Practices Summary
- ✓ Store API key in environment variable or IConfiguration
- ✓ Use IHttpClientFactory in ASP.NET Core applications
- ✓ Handle all error types: network, auth, quota, not-found
- ✓ Set request timeouts (10 seconds recommended)
- ✓ Implement retry logic with exponential backoff for transient errors
- ✓ Use the batch endpoint (/v1/bins) for bulk work — up to 2,000 BINs per request
- ✓ Consider fail-open strategy for non-critical validation
- ✓ Monitor your quota usage via response headers
- ✓ Use CancellationToken for proper async cancellation support
Next Steps
- View the full API Reference for all available fields and error codes
- Explore pricing plans to find the right quota for your needs
- Contact support if you need help with your integration
Ready to get started? Create your free account and start building today.