Documentation Index
Fetch the complete documentation index at: https://docs.txncheck.com/llms.txt
Use this file to discover all available pages before exploring further.
Go Integration
This guide shows how to integrate TxnCheck API into your Go application.Installation
No external dependencies required. Uses standard librarynet/http.
For structured JSON handling:
go get github.com/json-iterator/go # Optional, for faster JSON
Basic Client Setup
package txncheck
import (
"bytes"
"context"
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"net/http"
"strconv"
"time"
)
// Config holds client configuration
type Config struct {
APIKey string
SecretKey string // Optional, for request signing
BaseURL string
Timeout time.Duration
}
// DefaultConfig returns config with default values
func DefaultConfig(apiKey string) Config {
return Config{
APIKey: apiKey,
BaseURL: "https://api.txncheck.in/api/v1",
Timeout: 30 * time.Second,
}
}
// Client is the TxnCheck API client
type Client struct {
config Config
httpClient *http.Client
}
// NewClient creates a new TxnCheck client
func NewClient(config Config) *Client {
if config.BaseURL == "" {
config.BaseURL = "https://api.txncheck.in/api/v1"
}
if config.Timeout == 0 {
config.Timeout = 30 * time.Second
}
return &Client{
config: config,
httpClient: &http.Client{
Timeout: config.Timeout,
},
}
}
// RequestStatus represents the status of a verification request
type RequestStatus string
const (
StatusQueued RequestStatus = "QUEUED"
StatusProcessing RequestStatus = "PROCESSING"
StatusCompleted RequestStatus = "COMPLETED"
StatusFailed RequestStatus = "FAILED"
StatusPartial RequestStatus = "PARTIAL"
)
// AcceptedResponse is returned for async requests
type AcceptedResponse struct {
StatusCode int `json:"statusCode"`
Message string `json:"message"`
RequestID string `json:"requestId"`
Status RequestStatus `json:"status"`
}
// VerificationResult is returned for sync requests or status polling
type VerificationResult struct {
StatusCode int `json:"statusCode,omitempty"`
RequestID string `json:"requestId"`
Method string `json:"method,omitempty"`
Status RequestStatus `json:"status"`
Result map[string]interface{} `json:"result,omitempty"`
Error map[string]interface{} `json:"error,omitempty"`
StepStatuses map[string]string `json:"stepStatuses,omitempty"`
CreatedAt string `json:"createdAt,omitempty"`
CompletedAt string `json:"completedAt,omitempty"`
}
// APIError represents an API error response
type APIError struct {
StatusCode int `json:"statusCode"`
Message string `json:"message"`
Error string `json:"error"`
}
func (e *APIError) Error() string {
return fmt.Sprintf("%d %s: %s", e.StatusCode, e.Error, e.Message)
}
// signRequest generates HMAC-SHA256 signature
func (c *Client) signRequest(method, path string, body []byte) (timestamp, signature string) {
if c.config.SecretKey == "" {
return "", ""
}
timestamp = strconv.FormatInt(time.Now().UnixMilli(), 10)
message := fmt.Sprintf("%s.%s.%s.%s", timestamp, method, path, string(body))
h := hmac.New(sha256.New, []byte(c.config.SecretKey))
h.Write([]byte(message))
signature = hex.EncodeToString(h.Sum(nil))
return timestamp, signature
}
// request makes an HTTP request to the API
func (c *Client) request(ctx context.Context, method, endpoint string, body interface{}) ([]byte, error) {
var bodyBytes []byte
var err error
if body != nil {
bodyBytes, err = json.Marshal(body)
if err != nil {
return nil, fmt.Errorf("failed to marshal body: %w", err)
}
}
url := c.config.BaseURL + endpoint
req, err := http.NewRequestWithContext(ctx, method, url, bytes.NewReader(bodyBytes))
if err != nil {
return nil, fmt.Errorf("failed to create request: %w", err)
}
req.Header.Set("X-API-Key", c.config.APIKey)
req.Header.Set("Content-Type", "application/json")
// Sign request if secret key is configured
if timestamp, signature := c.signRequest(method, endpoint, bodyBytes); signature != "" {
req.Header.Set("X-Timestamp", timestamp)
req.Header.Set("X-Signature", signature)
}
resp, err := c.httpClient.Do(req)
if err != nil {
return nil, fmt.Errorf("request failed: %w", err)
}
defer resp.Body.Close()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read response: %w", err)
}
if resp.StatusCode >= 400 {
var apiErr APIError
if json.Unmarshal(respBody, &apiErr) == nil {
apiErr.StatusCode = resp.StatusCode
return nil, &apiErr
}
return nil, &APIError{
StatusCode: resp.StatusCode,
Message: string(respBody),
Error: "Unknown Error",
}
}
return respBody, nil
}
// UPIByMobileRequest is the request body for UPI by mobile
type UPIByMobileRequest struct {
Mobile string `json:"mobile"`
Async *bool `json:"async,omitempty"`
}
// UPIByMobile gets UPI VPAs linked to a mobile number
func (c *Client) UPIByMobile(ctx context.Context, mobile string, sync bool) (*VerificationResult, error) {
asyncVal := !sync
body := UPIByMobileRequest{
Mobile: mobile,
Async: &asyncVal,
}
respBody, err := c.request(ctx, "POST", "/upi-by-mobile", body)
if err != nil {
return nil, err
}
var result VerificationResult
if err := json.Unmarshal(respBody, &result); err != nil {
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
}
return &result, nil
}
// KYCByMobile gets KYC data by mobile number
func (c *Client) KYCByMobile(ctx context.Context, mobile string, sync bool) (*VerificationResult, error) {
asyncVal := !sync
body := map[string]interface{}{
"mobile": mobile,
"async": asyncVal,
}
respBody, err := c.request(ctx, "POST", "/kyc-by-mobile", body)
if err != nil {
return nil, err
}
var result VerificationResult
if err := json.Unmarshal(respBody, &result); err != nil {
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
}
return &result, nil
}
// VPAChargebackCheck checks VPAs against blocklist
func (c *Client) VPAChargebackCheck(ctx context.Context, vpas []string, sync bool) (*VerificationResult, error) {
asyncVal := !sync
body := map[string]interface{}{
"vpas": vpas,
"async": asyncVal,
}
respBody, err := c.request(ctx, "POST", "/vpa-chargeback-check", body)
if err != nil {
return nil, err
}
var result VerificationResult
if err := json.Unmarshal(respBody, &result); err != nil {
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
}
return &result, nil
}
// FullCheck performs full verification: UPI + KYC + Chargeback check
func (c *Client) FullCheck(ctx context.Context, mobile string, sync bool) (*VerificationResult, error) {
asyncVal := !sync
body := map[string]interface{}{
"mobile": mobile,
"async": asyncVal,
}
respBody, err := c.request(ctx, "POST", "/full-check", body)
if err != nil {
return nil, err
}
var result VerificationResult
if err := json.Unmarshal(respBody, &result); err != nil {
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
}
return &result, nil
}
// BulkVPACheck checks multiple VPAs against blocklist
func (c *Client) BulkVPACheck(ctx context.Context, vpas []string, sync bool) (*VerificationResult, error) {
asyncVal := !sync
body := map[string]interface{}{
"vpas": vpas,
"async": asyncVal,
}
respBody, err := c.request(ctx, "POST", "/bulk/vpa-chargeback-check", body)
if err != nil {
return nil, err
}
var result VerificationResult
if err := json.Unmarshal(respBody, &result); err != nil {
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
}
return &result, nil
}
// GetRequestStatus gets the status of a request
func (c *Client) GetRequestStatus(ctx context.Context, requestID string) (*VerificationResult, error) {
respBody, err := c.request(ctx, "GET", "/requests/"+requestID, nil)
if err != nil {
return nil, err
}
var result VerificationResult
if err := json.Unmarshal(respBody, &result); err != nil {
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
}
return &result, nil
}
// WaitForResult polls for request completion
func (c *Client) WaitForResult(ctx context.Context, requestID string, pollInterval, maxWait time.Duration) (*VerificationResult, error) {
if pollInterval == 0 {
pollInterval = 2 * time.Second
}
if maxWait == 0 {
maxWait = 60 * time.Second
}
terminalStatuses := map[RequestStatus]bool{
StatusCompleted: true,
StatusFailed: true,
StatusPartial: true,
}
deadline := time.Now().Add(maxWait)
ticker := time.NewTicker(pollInterval)
defer ticker.Stop()
for {
result, err := c.GetRequestStatus(ctx, requestID)
if err != nil {
return nil, err
}
if terminalStatuses[result.Status] {
return result, nil
}
select {
case <-ctx.Done():
return nil, ctx.Err()
case <-ticker.C:
if time.Now().After(deadline) {
return nil, fmt.Errorf("request %s did not complete within %v", requestID, maxWait)
}
}
}
}
Usage Examples
Async Mode (Default)
package main
import (
"context"
"fmt"
"log"
"yourproject/txncheck"
)
func main() {
client := txncheck.NewClient(txncheck.DefaultConfig("fb_your_api_key_here"))
ctx := context.Background()
// Submit request (async mode)
result, err := client.UPIByMobile(ctx, "+919876543210", false)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Request ID: %s\n", result.RequestID)
// Poll for result
finalResult, err := client.WaitForResult(ctx, result.RequestID, 0, 0)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Status: %s\n", finalResult.Status)
if upi, ok := finalResult.Result["upi"].([]interface{}); ok {
fmt.Printf("UPI addresses: %v\n", upi)
}
}
Sync Mode
package main
import (
"context"
"fmt"
"log"
"yourproject/txncheck"
)
func main() {
client := txncheck.NewClient(txncheck.DefaultConfig("fb_your_api_key_here"))
ctx := context.Background()
// Get result immediately (sync mode)
result, err := client.UPIByMobile(ctx, "+919876543210", true)
if err != nil {
log.Fatal(err)
}
if result.Status == txncheck.StatusCompleted {
fmt.Printf("Name: %v\n", result.Result["name"])
if upi, ok := result.Result["upi"].([]interface{}); ok {
fmt.Printf("UPI addresses: %v\n", upi)
}
}
}
Full Check
result, err := client.FullCheck(ctx, "+919876543210", true)
if err != nil {
log.Fatal(err)
}
if result.Status == txncheck.StatusCompleted {
// UPI data
if upiData, ok := result.Result["upiByMobile"].(map[string]interface{}); ok {
fmt.Printf("Name: %v\n", upiData["name"])
fmt.Printf("VPAs: %v\n", upiData["upi"])
}
// KYC data
if kycData, ok := result.Result["kycByMobile"].(map[string]interface{}); ok {
fmt.Printf("PAN: %v\n", kycData["pan"])
fmt.Printf("DOB: %v\n", kycData["dob"])
}
// Blocklist
if blocklist, ok := result.Result["vpaChargebackCheck"].(map[string]interface{}); ok {
if summary, ok := blocklist["summary"].(map[string]interface{}); ok {
fmt.Printf("Blocklisted: %v\n", summary["blocklisted"])
}
}
}
VPA Blocklist Check
vpas := []string{"user1@upi", "user2@paytm", "suspicious@ybl"}
result, err := client.VPAChargebackCheck(ctx, vpas, true)
if err != nil {
log.Fatal(err)
}
if result.Status == txncheck.StatusCompleted {
// Blocklisted VPAs
if blocklisted, ok := result.Result["blocklisted"].([]interface{}); ok {
for _, v := range blocklisted {
if vpa, ok := v.(map[string]interface{}); ok {
fmt.Printf("⚠️ BLOCKED: %v\n", vpa["vpa"])
}
}
}
// Clean VPAs
if clean, ok := result.Result["clean"].([]interface{}); ok {
for _, v := range clean {
if vpa, ok := v.(map[string]interface{}); ok {
fmt.Printf("✓ Clean: %v\n", vpa["vpa"])
}
}
}
}
Error Handling
package main
import (
"context"
"errors"
"fmt"
"log"
"time"
"yourproject/txncheck"
)
func verifyWithRetry(client *txncheck.Client, mobile string, maxRetries int) (*txncheck.VerificationResult, error) {
ctx := context.Background()
var lastErr error
for attempt := 1; attempt <= maxRetries; attempt++ {
result, err := client.UPIByMobile(ctx, mobile, true)
if err == nil {
return result, nil
}
lastErr = err
// Check if error is retryable
var apiErr *txncheck.APIError
if errors.As(err, &apiErr) {
// Don't retry client errors (except rate limit)
if apiErr.StatusCode >= 400 && apiErr.StatusCode < 500 && apiErr.StatusCode != 429 {
return nil, err
}
}
// Exponential backoff
delay := time.Duration(1<<(attempt-1)) * time.Second
if delay > 10*time.Second {
delay = 10 * time.Second
}
log.Printf("Retry %d/%d in %v...", attempt, maxRetries, delay)
time.Sleep(delay)
}
return nil, lastErr
}
func main() {
client := txncheck.NewClient(txncheck.DefaultConfig("fb_your_api_key_here"))
result, err := verifyWithRetry(client, "+919876543210", 3)
if err != nil {
var apiErr *txncheck.APIError
if errors.As(err, &apiErr) {
fmt.Printf("API Error (%d): %s\n", apiErr.StatusCode, apiErr.Message)
} else {
fmt.Printf("Error: %v\n", err)
}
return
}
fmt.Printf("Verified: %v\n", result.Result["name"])
}
Webhook Signature Verification
package webhooks
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"io"
"net/http"
"strconv"
"time"
)
// VerifyWebhookSignature verifies the webhook signature
func VerifyWebhookSignature(payload []byte, signature, timestamp, secretKey string, maxAgeSeconds int64) bool {
// Check timestamp freshness
webhookTime, err := strconv.ParseInt(timestamp, 10, 64)
if err != nil {
return false
}
currentTime := time.Now().UnixMilli()
ageMs := currentTime - webhookTime
if ageMs > maxAgeSeconds*1000 {
return false // Webhook too old
}
// Compute expected signature
message := timestamp + "." + string(payload)
h := hmac.New(sha256.New, []byte(secretKey))
h.Write([]byte(message))
expected := hex.EncodeToString(h.Sum(nil))
// Constant-time comparison
return hmac.Equal([]byte(signature), []byte(expected))
}
// WebhookPayload represents the webhook payload
type WebhookPayload struct {
Event string `json:"event"`
Timestamp string `json:"timestamp"`
Data map[string]interface{} `json:"data"`
}
// WebhookHandler handles incoming webhooks
func WebhookHandler(secretKey string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
signature := r.Header.Get("X-Webhook-Signature")
timestamp := r.Header.Get("X-Webhook-Timestamp")
if signature == "" || timestamp == "" {
http.Error(w, "Missing signature headers", http.StatusUnauthorized)
return
}
body, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, "Failed to read body", http.StatusBadRequest)
return
}
if !VerifyWebhookSignature(body, signature, timestamp, secretKey, 300) {
http.Error(w, "Invalid signature", http.StatusUnauthorized)
return
}
var payload WebhookPayload
if err := json.Unmarshal(body, &payload); err != nil {
http.Error(w, "Invalid JSON", http.StatusBadRequest)
return
}
switch payload.Event {
case "request.completed":
// Handle completed request
requestID := payload.Data["requestId"].(string)
log.Printf("Request completed: %s", requestID)
case "request.failed":
// Handle failed request
requestID := payload.Data["requestId"].(string)
log.Printf("Request failed: %s", requestID)
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{"status": "ok"})
}
}
// Usage
func main() {
webhookSecret := "your_webhook_secret"
http.HandleFunc("/webhook/fraud-buster", WebhookHandler(webhookSecret))
log.Fatal(http.ListenAndServe(":8080", nil))
}
Complete Integration Example
package main
import (
"context"
"fmt"
"log"
"strings"
"yourproject/txncheck"
)
// VerificationOutcome represents the verification result
type VerificationOutcome struct {
Verified bool
RiskScore int
Details struct {
Name string
PANVerified bool
VPALinked bool
VPACount int
Blocklisted bool
}
Error string
}
// VerifyCustomerForCheckout verifies a customer before payment
func VerifyCustomerForCheckout(client *txncheck.Client, mobile, paymentVPA string) VerificationOutcome {
ctx := context.Background()
outcome := VerificationOutcome{}
// Step 1: Full verification
log.Printf("Starting verification for %s", mobile)
verification, err := client.FullCheck(ctx, mobile, true)
if err != nil {
log.Printf("Verification failed: %v", err)
outcome.RiskScore = 100
outcome.Error = err.Error()
return outcome
}
if verification.Status != txncheck.StatusCompleted {
log.Printf("Verification incomplete: %s", verification.Status)
outcome.RiskScore = 100
return outcome
}
// Step 2: Extract data
upiData, _ := verification.Result["upiByMobile"].(map[string]interface{})
kycData, _ := verification.Result["kycByMobile"].(map[string]interface{})
blocklist, _ := verification.Result["vpaChargebackCheck"].(map[string]interface{})
// Step 3: Check if payment VPA belongs to user
var userVPAs []string
if upi, ok := upiData["upi"].([]interface{}); ok {
for _, v := range upi {
if vpa, ok := v.(string); ok {
userVPAs = append(userVPAs, strings.ToLower(vpa))
}
}
}
vpaLinked := false
paymentVPALower := strings.ToLower(paymentVPA)
for _, vpa := range userVPAs {
if vpa == paymentVPALower {
vpaLinked = true
break
}
}
if !vpaLinked {
log.Printf("Payment VPA %s not linked to %s", paymentVPA, mobile)
outcome.RiskScore += 50
}
// Step 4: Check blocklist
if blocklistedList, ok := blocklist["blocklisted"].([]interface{}); ok {
for _, v := range blocklistedList {
if item, ok := v.(map[string]interface{}); ok {
if vpa, ok := item["vpa"].(string); ok {
if strings.ToLower(vpa) == paymentVPALower {
log.Printf("Payment VPA %s is BLOCKLISTED!", paymentVPA)
outcome.RiskScore = 100
outcome.Details.Blocklisted = true
return outcome
}
}
}
}
}
// Step 5: Build result
outcome.Verified = outcome.RiskScore < 50
if name, ok := kycData["fullName"].(string); ok {
outcome.Details.Name = name
} else if name, ok := upiData["name"].(string); ok {
outcome.Details.Name = name
}
if pan, ok := kycData["pan"].(string); ok {
outcome.Details.PANVerified = pan != ""
}
outcome.Details.VPALinked = vpaLinked
outcome.Details.VPACount = len(userVPAs)
log.Printf("Verification complete. Risk score: %d", outcome.RiskScore)
return outcome
}
func main() {
client := txncheck.NewClient(txncheck.DefaultConfig("fb_your_api_key_here"))
result := VerifyCustomerForCheckout(
client,
"+919876543210",
"user@upi",
)
if result.Verified {
fmt.Println("✓ Customer verified, proceed with payment")
fmt.Printf(" Name: %s\n", result.Details.Name)
} else {
fmt.Printf("⚠️ Verification failed. Risk score: %d\n", result.RiskScore)
if result.Details.Blocklisted {
fmt.Println(" Reason: VPA is blocklisted")
}
}
}
Next Steps
Webhooks Guide
Set up webhooks for async notifications
Error Handling
Handle API errors properly
Security Best Practices
Secure your integration
Use Cases
See real-world examples
