PHP Integration
This guide shows how to integrate TxnCheck API into your PHP application.Installation
Using Guzzle (Recommended)
Copy
composer require guzzlehttp/guzzle
Using cURL
cURL is built into PHP, no installation needed.Basic Client Setup (Guzzle)
Copy
<?php
namespace App\Services;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
class TxnCheckClient
{
private Client $client;
private string $apiKey;
private ?string $secretKey;
public function __construct(
string $apiKey,
?string $secretKey = null,
string $baseUrl = 'https://api.txncheck.in/api/v1'
) {
$this->apiKey = $apiKey;
$this->secretKey = $secretKey;
$this->client = new Client([
'base_uri' => $baseUrl,
'timeout' => 30,
'headers' => [
'X-API-Key' => $apiKey,
'Content-Type' => 'application/json',
],
]);
}
/**
* Sign request with HMAC-SHA256
*/
private function signRequest(string $method, string $path, string $body): array
{
if (!$this->secretKey) {
return [];
}
$timestamp = (string) round(microtime(true) * 1000);
$message = "{$timestamp}.{$method}.{$path}.{$body}";
$signature = hash_hmac('sha256', $message, $this->secretKey);
return [
'X-Timestamp' => $timestamp,
'X-Signature' => $signature,
];
}
/**
* Make API request
*/
private function request(string $method, string $endpoint, ?array $data = null, bool $sync = false): array
{
if ($data !== null && $sync) {
$data['async'] = false;
}
$body = $data ? json_encode($data) : '';
$headers = $this->signRequest(strtoupper($method), $endpoint, $body);
try {
$response = $this->client->request($method, $endpoint, [
'headers' => $headers,
'json' => $data,
]);
return json_decode($response->getBody()->getContents(), true);
} catch (RequestException $e) {
if ($e->hasResponse()) {
$error = json_decode($e->getResponse()->getBody()->getContents(), true);
throw new TxnCheckException(
$error['message'] ?? 'Unknown error',
$e->getResponse()->getStatusCode(),
$error['error'] ?? 'Error'
);
}
throw $e;
}
}
/**
* Get UPI VPAs linked to a mobile number
*/
public function upiByMobile(string $mobile, bool $sync = false): array
{
return $this->request('POST', '/upi-by-mobile', ['mobile' => $mobile], $sync);
}
/**
* Get KYC data by mobile number
*/
public function kycByMobile(string $mobile, bool $sync = false): array
{
return $this->request('POST', '/kyc-by-mobile', ['mobile' => $mobile], $sync);
}
/**
* Check VPAs against blocklist
*/
public function vpaChargebackCheck(array $vpas, bool $sync = false): array
{
return $this->request('POST', '/vpa-chargeback-check', ['vpas' => $vpas], $sync);
}
/**
* Full verification: UPI + KYC + Chargeback check
*/
public function fullCheck(string $mobile, bool $sync = false): array
{
return $this->request('POST', '/full-check', ['mobile' => $mobile], $sync);
}
/**
* Bulk check VPAs against blocklist
*/
public function bulkVpaCheck(array $vpas, bool $sync = false): array
{
return $this->request('POST', '/bulk/vpa-chargeback-check', ['vpas' => $vpas], $sync);
}
/**
* Get request status and results
*/
public function getRequestStatus(string $requestId): array
{
return $this->request('GET', "/requests/{$requestId}");
}
/**
* Poll for request completion
*/
public function waitForResult(string $requestId, int $pollInterval = 2, int $maxWait = 60): array
{
$terminalStatuses = ['COMPLETED', 'FAILED', 'PARTIAL'];
$startTime = time();
while (time() - $startTime < $maxWait) {
$result = $this->getRequestStatus($requestId);
if (in_array($result['status'], $terminalStatuses)) {
return $result;
}
sleep($pollInterval);
}
throw new \RuntimeException("Request {$requestId} did not complete within {$maxWait}s");
}
}
class TxnCheckException extends \Exception
{
public string $errorType;
public function __construct(string $message, int $code, string $errorType)
{
parent::__construct($message, $code);
$this->errorType = $errorType;
}
}
Basic Client Setup (cURL)
Copy
<?php
class TxnCheckCurlClient
{
private string $apiKey;
private string $baseUrl;
private ?string $secretKey;
public function __construct(
string $apiKey,
?string $secretKey = null,
string $baseUrl = 'https://api.txncheck.in/api/v1'
) {
$this->apiKey = $apiKey;
$this->secretKey = $secretKey;
$this->baseUrl = rtrim($baseUrl, '/');
}
private function request(string $method, string $endpoint, ?array $data = null, bool $sync = false): array
{
if ($data !== null && $sync) {
$data['async'] = false;
}
$url = $this->baseUrl . $endpoint;
$body = $data ? json_encode($data) : '';
$headers = [
"X-API-Key: {$this->apiKey}",
'Content-Type: application/json',
];
// Sign request if secret key is configured
if ($this->secretKey) {
$timestamp = (string) round(microtime(true) * 1000);
$message = "{$timestamp}." . strtoupper($method) . ".{$endpoint}.{$body}";
$signature = hash_hmac('sha256', $message, $this->secretKey);
$headers[] = "X-Timestamp: {$timestamp}";
$headers[] = "X-Signature: {$signature}";
}
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_TIMEOUT => 30,
]);
if ($method === 'POST') {
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
}
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
curl_close($ch);
if ($error) {
throw new \RuntimeException("cURL error: {$error}");
}
$result = json_decode($response, true);
if ($httpCode >= 400) {
throw new TxnCheckException(
$result['message'] ?? 'Unknown error',
$httpCode,
$result['error'] ?? 'Error'
);
}
return $result;
}
public function upiByMobile(string $mobile, bool $sync = false): array
{
return $this->request('POST', '/upi-by-mobile', ['mobile' => $mobile], $sync);
}
public function kycByMobile(string $mobile, bool $sync = false): array
{
return $this->request('POST', '/kyc-by-mobile', ['mobile' => $mobile], $sync);
}
public function vpaChargebackCheck(array $vpas, bool $sync = false): array
{
return $this->request('POST', '/vpa-chargeback-check', ['vpas' => $vpas], $sync);
}
public function fullCheck(string $mobile, bool $sync = false): array
{
return $this->request('POST', '/full-check', ['mobile' => $mobile], $sync);
}
public function getRequestStatus(string $requestId): array
{
return $this->request('GET', "/requests/{$requestId}");
}
}
Usage Examples
Async Mode (Default)
Copy
<?php
$client = new TxnCheckClient('fb_your_api_key_here');
// Submit request
$response = $client->upiByMobile('+919876543210');
echo "Request ID: {$response['requestId']}\n";
// Poll for result
$result = $client->waitForResult($response['requestId']);
echo "Status: {$result['status']}\n";
echo "UPI addresses: " . implode(', ', $result['result']['upi']) . "\n";
Sync Mode
Copy
<?php
// Get result immediately (waits up to 30 seconds)
$result = $client->upiByMobile('+919876543210', sync: true);
if ($result['status'] === 'COMPLETED') {
echo "Name: {$result['result']['name']}\n";
echo "UPI addresses: " . implode(', ', $result['result']['upi']) . "\n";
}
Full Check
Copy
<?php
$result = $client->fullCheck('+919876543210', sync: true);
if ($result['status'] === 'COMPLETED') {
// UPI data
$upiData = $result['result']['upiByMobile'];
echo "Name: {$upiData['name']}\n";
echo "VPAs: " . implode(', ', $upiData['upi']) . "\n";
// KYC data
$kycData = $result['result']['kycByMobile'];
echo "PAN: {$kycData['pan']}\n";
echo "DOB: {$kycData['dob']}\n";
// Blocklist status
$blocklist = $result['result']['vpaChargebackCheck'];
echo "Blocklisted: {$blocklist['summary']['blocklisted']}\n";
}
VPA Blocklist Check
Copy
<?php
$vpas = ['user1@upi', 'user2@paytm', 'suspicious@ybl'];
$result = $client->vpaChargebackCheck($vpas, sync: true);
if ($result['status'] === 'COMPLETED') {
// Blocklisted VPAs
foreach ($result['result']['blocklisted'] as $vpa) {
echo "⚠️ BLOCKED: {$vpa['vpa']}\n";
}
// Clean VPAs
foreach ($result['result']['clean'] as $vpa) {
echo "✓ Clean: {$vpa['vpa']}\n";
}
}
Error Handling
Copy
<?php
class TxnCheckException extends \Exception
{
public string $errorType;
public function __construct(string $message, int $code, string $errorType)
{
parent::__construct($message, $code);
$this->errorType = $errorType;
}
}
// Usage with retry logic
function verifyWithRetry(TxnCheckClient $client, string $mobile, int $maxRetries = 3): array
{
$lastError = null;
for ($attempt = 1; $attempt <= $maxRetries; $attempt++) {
try {
return $client->upiByMobile($mobile, sync: true);
} catch (TxnCheckException $e) {
$lastError = $e;
// Don't retry client errors (except rate limit)
if ($e->getCode() >= 400 && $e->getCode() < 500 && $e->getCode() !== 429) {
throw $e;
}
// Exponential backoff
$delay = min(pow(2, $attempt - 1), 10);
echo "Retry {$attempt}/{$maxRetries} in {$delay}s...\n";
sleep($delay);
}
}
throw $lastError;
}
// Usage
try {
$result = verifyWithRetry($client, '+919876543210');
echo "Verified: {$result['result']['name']}\n";
} catch (TxnCheckException $e) {
echo "Error ({$e->getCode()}): {$e->getMessage()}\n";
}
Webhook Signature Verification
Copy
<?php
function verifyWebhookSignature(
string $payload,
string $signature,
string $timestamp,
string $secretKey,
int $maxAgeSeconds = 300
): bool {
// Check timestamp freshness
$webhookTime = (int) $timestamp;
$currentTime = (int) (microtime(true) * 1000);
$ageMs = $currentTime - $webhookTime;
if ($ageMs > $maxAgeSeconds * 1000) {
return false; // Webhook too old
}
// Compute expected signature
$message = "{$timestamp}.{$payload}";
$expected = hash_hmac('sha256', $message, $secretKey);
// Constant-time comparison
return hash_equals($expected, $signature);
}
// Laravel example
Route::post('/webhook/fraud-buster', function (Request $request) {
$signature = $request->header('X-Webhook-Signature');
$timestamp = $request->header('X-Webhook-Timestamp');
$secretKey = config('services.txncheck.webhook_secret');
if (!verifyWebhookSignature(
$request->getContent(),
$signature,
$timestamp,
$secretKey
)) {
return response()->json(['error' => 'Invalid signature'], 401);
}
$data = $request->json();
$event = $data['event'];
switch ($event) {
case 'request.completed':
// Handle completed request
$requestId = $data['data']['requestId'];
Log::info("Request completed: {$requestId}");
break;
case 'request.failed':
// Handle failed request
Log::error("Request failed: {$data['data']['requestId']}");
break;
}
return response()->json(['status' => 'ok']);
});
Laravel Service Provider
Copy
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Services\TxnCheckClient;
class TxnCheckServiceProvider extends ServiceProvider
{
public function register(): void
{
$this->app->singleton(TxnCheckClient::class, function ($app) {
return new TxnCheckClient(
apiKey: config('services.txncheck.api_key'),
secretKey: config('services.txncheck.secret_key'),
baseUrl: config('services.txncheck.base_url', 'https://api.txncheck.in/api/v1')
);
});
}
}
// config/services.php
return [
'txncheck' => [
'api_key' => env('FRAUD_BUSTER_API_KEY'),
'secret_key' => env('FRAUD_BUSTER_SECRET_KEY'),
'webhook_secret' => env('FRAUD_BUSTER_WEBHOOK_SECRET'),
'base_url' => env('FRAUD_BUSTER_BASE_URL', 'https://api.txncheck.in/api/v1'),
],
];
Complete Integration Example
Copy
<?php
/**
* Complete example: E-commerce checkout verification
*/
class CheckoutVerificationService
{
private TxnCheckClient $client;
public function __construct(TxnCheckClient $client)
{
$this->client = $client;
}
public function verifyCustomerForCheckout(string $mobile, string $paymentVpa): array
{
$outcome = [
'verified' => false,
'riskScore' => 0,
'details' => [
'name' => null,
'panVerified' => false,
'vpaLinked' => false,
'vpaCount' => 0,
'blocklisted' => false,
],
'error' => null,
];
try {
// Step 1: Full verification
error_log("Starting verification for {$mobile}");
$verification = $this->client->fullCheck($mobile, sync: true);
if ($verification['status'] !== 'COMPLETED') {
error_log("Verification incomplete: {$verification['status']}");
$outcome['riskScore'] = 100;
return $outcome;
}
// Step 2: Extract data
$upiData = $verification['result']['upiByMobile'] ?? [];
$kycData = $verification['result']['kycByMobile'] ?? [];
$blocklist = $verification['result']['vpaChargebackCheck'] ?? [];
// Step 3: Check if payment VPA belongs to user
$userVpas = array_map('strtolower', $upiData['upi'] ?? []);
$vpaLinked = in_array(strtolower($paymentVpa), $userVpas);
if (!$vpaLinked) {
error_log("Payment VPA {$paymentVpa} not linked to {$mobile}");
$outcome['riskScore'] += 50;
}
// Step 4: Check blocklist
$blocklistedVpas = array_map(
fn($v) => strtolower($v['vpa']),
$blocklist['blocklisted'] ?? []
);
if (in_array(strtolower($paymentVpa), $blocklistedVpas)) {
error_log("Payment VPA {$paymentVpa} is BLOCKLISTED!");
$outcome['riskScore'] = 100;
$outcome['details']['blocklisted'] = true;
return $outcome;
}
// Step 5: Build result
$outcome['verified'] = $outcome['riskScore'] < 50;
$outcome['details'] = [
'name' => $kycData['fullName'] ?? $upiData['name'] ?? null,
'panVerified' => !empty($kycData['pan']),
'vpaLinked' => $vpaLinked,
'vpaCount' => count($userVpas),
'blocklisted' => false,
];
error_log("Verification complete. Risk score: {$outcome['riskScore']}");
return $outcome;
} catch (\Exception $e) {
error_log("Verification failed: {$e->getMessage()}");
$outcome['riskScore'] = 100;
$outcome['error'] = $e->getMessage();
return $outcome;
}
}
}
// Usage
$client = new TxnCheckClient('fb_your_api_key_here');
$service = new CheckoutVerificationService($client);
$result = $service->verifyCustomerForCheckout(
'+919876543210',
'user@upi'
);
if ($result['verified']) {
echo "✓ Customer verified, proceed with payment\n";
echo " Name: {$result['details']['name']}\n";
} else {
echo "⚠️ Verification failed. Risk score: {$result['riskScore']}\n";
if ($result['details']['blocklisted']) {
echo " Reason: VPA is blocklisted\n";
}
}
