StampMitraDevelopers
आधिकारिक SDK

PHP SDK

StampMitra Developer API का आधिकारिक PHP क्लाइंट: typed immutable models, PSR-18 transport और Laravel व सादे PHP के लिए signed-webhook helpers के साथ identity verification और e-Stamp।

Pre-release 0.1.0 - package registry पर प्रकाशन जारी है

Package
stampmitra/stampmitra-php
संस्करण
0.1.0
आवश्यकता
PHP 8.1 या उससे नया। SDK PSR-18 और PSR-17 से बात करता है, इसलिए कोई भी संगत HTTP क्लाइंट चलता है: Guzzle अपने आप मिल जाता है, या अपना httpClient दें।
लाइसेंस
MIT
Changelog
CHANGELOG.md
इंस्टॉल

Package इंस्टॉल करें

Composer
composer require stampmitra/stampmitra-php guzzlehttp/guzzle

प्रकाशित होने के बाद उपलब्ध। अभी Packagist पर प्रकाशित नहीं हुआ है। यह कमांड package के रिलीज़ होने के बाद काम करेगा; तब तक रिलीज़ के लिए GitHub repository देखते रहें।

Composer (from GitHub)
composer config repositories.stampmitra vcs https://github.com/Bani-Global-Industries-LLP/stampmitra-developer-php
composer require stampmitra/stampmitra-php:dev-main guzzlehttp/guzzle

तब तक GitHub से इंस्टॉल करें: composer.json repository के root में है और package का नाम stampmitra/stampmitra-php है, इसलिए Composer इसे VCS repository के रूप में पढ़ सकता है।

Quickstart

पाँच पंक्तियों में PAN verify करें

बनाते समय sandbox key (sk_test_...) इस्तेमाल करें। यह मुफ़्त है, आपके वॉलेट से कुछ नहीं कटता और sandbox डेटा पर चलती है।

PHP
use StampMitra\StampMitra;

$client = new StampMitra(apiKey: getenv('STAMPMITRA_API_KEY') ?: null); // or just new StampMitra()
$pan = $client->verify->pan('ABCDE1234F', 'Rahul Kumar');
echo $pan->valid ? 'valid' : 'invalid', ' ', $pan->nameMatchResult, ' ', $pan->referenceId, PHP_EOL;
Authentication

API keys और environments

Sandbox

Sandbox keys sk_test_ से शुरू होती हैं। ये मुफ़्त हैं और sandbox डेटा लौटाती हैं।

Live

Live keys sk_live_ से शुरू होती हैं। इनके लिए स्वीकृत production access request चाहिए और हर सफल कॉल पर शुल्क लगता है।

Key STAMPMITRA_API_KEY environment variable से पढ़ी जाती है, जब तक आप apiKey: न दें। $client->environment का मान 'test' या 'live' होता है। जो key ^sk_(test|live)_[A-Za-z0-9_-]{8,}$ से मेल नहीं खाती वह अस्वीकार होती है, जब तक आप allowCustomKey: true न दें।

सिर्फ़ server-side। sk_ keys को कभी browser या mobile ऐप में न डालें और न ही किसी repository में commit करें। इन्हें environment variables या secrets manager में रखें। Authentication
Client options
$client = new StampMitra(
    apiKey: 'sk_test_...',
    baseUrl: 'https://api-b2b.stampmitra.in',
    timeout: 30,
    maxRetries: 2,
    httpClient: null,        // any PSR-18 client; Guzzle is auto-discovered
    defaultHeaders: [],
    appInfo: ['name' => 'my-app', 'version' => '1.0.0', 'url' => 'https://example.com'],
    logger: null,            // any PSR-3 logger
    validateInput: true,
    allowCustomKey: false,
);

// Every method also takes per-request options (a RequestOptions or an array):
$client->orders->create($body, ['idempotencyKey' => 'order-123']);
Resources

हर resource एक जगह

Responses typed, immutable models हैं ($pan->registeredName)। जो fields SDK नहीं जानता वे कभी नहीं छूटते: $pan->raw() पूरी decoded body देता है और $pan->get('field') कोई भी field पढ़ता है। HTTP metadata (status, headers, request id, attempts) $pan->response() पर है। जिन endpoints का schema अभी तय नहीं, वे GenericResponse लौटाते हैं।

All resources
// Verification (every call is billed, including valid=false results)
$client->verify->pan('ABCDE1234F', 'Rahul Kumar');
$client->verify->gstin('27ABCDE1234F1Z5');
$client->verify->rc('MH12AB1234');
$client->verify->voterId('ABC1234567');
$client->verify->drivingLicense('MH1420110012345', '1990-01-31');   // IP-allowlisted key required
$client->verify->passport('PA1079341954215', '1990-01-31');         // IP-allowlisted key required
$client->verify->cin('U74999DL2015PTC284009');
$client->verify->udyam('UDYAM-MH-12-1234567');
$client->verify->panToGstin('ABCDE1234F');
$client->verify->panToUdyam('ABCDE1234F');
$client->verify->bankAccount('000123456789', 'ICIC0001234', name: 'Rahul Kumar');

// Services and e-Stamp reference data
$client->services->list();
$client->services->get('estamp.instrument.rent_agreement');
$client->estamp->getSchema('estamp.instrument.rent_agreement');
$client->estamp->listStates();
$client->estamp->listInstruments('MH');
$client->estamp->listArticles('rent_agreement');
$client->estamp->calculateDuty(['stateCode' => 'MH', 'articleCode' => '5']);
$client->estamp->addParties('ord_123', ['customerName' => '...', 'partyName' => '...']);

// Orders and payments
$order = $client->orders->create(['externalOrderId' => 'o1', 'externalCustomerId' => 'c1', 'serviceCode' => 'estamp....']);
$client->orders->get('o1');
$client->orders->getStatus('o1');
$client->orders->getPayment('o1');
$client->orders->listDocuments('o1');
$client->orders->getDocumentDownload('o1', 'doc_1');
$client->payments->intents->create(['externalOrderId' => 'o1', 'amountMinor' => 50000, 'currency' => 'INR', 'paymentConnectionId' => '...']);
$client->payments->intents->get('pi_1');

// Usage, logs, webhook events
$client->usage->summary();
$client->logs->list(['service' => 'pan.verify', 'status' => 'success', 'limit' => 50]);
$client->webhooks->events->list(limit: 20);
$client->webhooks->events->replay('evt_1');
Pagination

Pagination

iterate() एक lazy Generator लौटाता है जो nextCursor को आगे बढ़ाता है; list() एक पेज लौटाता है।

Pagination
foreach ($client->logs->iterate(['service' => 'pan.verify', 'limit' => 100]) as $entry) {
    echo $entry->id, ' ', $entry->createdAt, PHP_EOL;   // follows nextCursor lazily (a Generator)
}

$page = $client->logs->list(['limit' => 50]);          // $page->items, $page->nextCursor
Errors

Error classes

सभी errors StampMitra\Exception में हैं और StampMitraError से बने हैं (getStatus(), getErrorCode(), getMessage(), getRequestId(), getField(), getBody())। Header मौजूद हो तो RateLimitError में getRetryAfter() जुड़ता है। दूसरे statuses पर base StampMitraError उठता है, और non-JSON error body भी status से map होती है।

HTTP statusClassटिप्पणी
400 (and local validation)ValidationErrorगलत इनपुट। Validation helpers इसे request भेजने से पहले local रूप से भी उठाते हैं।
401AuthenticationErrorAPI key न मिली, गलत है या रद्द हो चुकी है।
402PaymentRequiredErrorवॉलेट में बैलेंस या क्रेडिट कम है।
403PermissionErrorसर्वर का संदेश जस का तस दिया जाता है, जैसे Passport और Driving Licence के लिए IP-allowlisted key चाहिए।
404NotFoundErrorऑर्डर, सेवा या इवेंट की id मौजूद नहीं है।
409ConflictErrorIdempotency-Key किसी दूसरी body के साथ दोबारा इस्तेमाल हुई, या state में टकराव है।
429RateLimitErrorरुककर दोबारा कोशिश करें; सर्वर Retry-After भेजे तो वह मान उपलब्ध रहता है।
5xxUpstreamErrorसर्वर या upstream की ओर की विफलता। 502, 503 और 504 पर अपने आप retry होता है।
network / timeoutConnectionError / TimeoutErrorकोई उपयोगी response नहीं मिला: कनेक्शन विफल, timeout या cancel।
PHP
try {
    $client->verify->gstin('27ABCDE1234F1Z5');
} catch (\StampMitra\Exception\RateLimitError $e) {
    // back off: $e->getRetryAfter()
} catch (\StampMitra\Exception\StampMitraError $e) {
    error_log($e->getRequestId() . ': ' . $e->getMessage());
}
Retries और idempotency

Retries और idempotency

Validation

क्लाइंट-साइड validation

भेजने से पहले इनपुट जाँचे जाते हैं (PAN, GSTIN, IFSC, CIN, Udyam, vehicle number, 9 से 18 अंकों का account number, passport file number, driving licence, voter ID, phone, ISO तारीखें) और upper case में बदले जाते हैं। विफलता पर local ValidationError उठता है, बिना network call और बिना शुल्क के। इसे validateInput: false से बंद करें।

Webhooks

Webhook signatures जाँचें

हर डिलीवरी में X-Webhook-Signature, X-Webhook-Timestamp (Unix सेकंड) और X-Webhook-Event-Id होते हैं। Signature, timestamp, एक बिंदु और raw body का hex HMAC-SHA256 है, जो आपके endpoint secret से बनता है। जाँच हमेशा raw body पर करें, दोबारा serialise किए गए JSON पर नहीं।

Webhook::constructEvent, body को ठीक वैसी जैसी मिली उसी पर signature जाँचता है, तुलना constant-time में करता है और उन timestamps को अस्वीकार करता है जो अभी से 300 s (बदला जा सकता है) से ज़्यादा दूर हों। विफलता पर SignatureVerificationError उठता है। Webhook::verifySignature bool लौटाता है और Webhook::constructEventFromHeaders headers खुद पढ़ लेता है।

PHP
use StampMitra\Webhook;

$payload = file_get_contents('php://input');           // raw bytes, do not re-encode
$event = Webhook::constructEvent(
    $payload,
    $_SERVER['HTTP_X_WEBHOOK_TIMESTAMP'],
    $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'],
    $secret,
);
// or: Webhook::verifySignature($payload, $timestamp, $signature, $secret, toleranceSeconds: 300): bool
// or: Webhook::constructEventFromHeaders($payload, $headers, $secret)

डिलीवरी retry होती है, इसलिए events को idempotent तरीके से संभालें और X-Webhook-Event-Id की event id से duplicates हटाएँ।

Framework के उदाहरण

Framework के उदाहरण
<?php

declare(strict_types=1);

require __DIR__ . '/../vendor/autoload.php';

use StampMitra\Exception\SignatureVerificationError;
use StampMitra\Webhook;

$secret = getenv('STAMPMITRA_WEBHOOK_SECRET') ?: '';

// The signature covers the raw bytes: read the body untouched, never re-encode it.
$payload = (string) file_get_contents('php://input');

try {
    $event = Webhook::constructEvent(
        $payload,
        $_SERVER['HTTP_X_WEBHOOK_TIMESTAMP'] ?? '',
        $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '',
        $secret,
        eventId: $_SERVER['HTTP_X_WEBHOOK_EVENT_ID'] ?? null,
    );
} catch (SignatureVerificationError $e) {
    http_response_code(400);
    echo 'invalid signature';
    exit;
}

// Handle idempotently: deliveries are retried, so de-duplicate on $event->eventId.
http_response_code(200);
echo 'ok';

Webhooks: इवेंट के प्रकार, payload और retry नीति Webhooks पेज पर हैं।

सुरक्षित logging

सुरक्षित logging

डिफ़ॉल्ट रूप से कुछ भी log नहीं होता। Requests और responses के debug logs के लिए logger: के रूप में कोई भी PSR-3 logger दें; इनमें Authorization और x-api-key redact रहते हैं और bodies में identifiers व नाम masked रहते हैं।

SDKs

इंटीग्रेट करने के दूसरे तरीके

REST API किसी भी भाषा से चलती है, और बाकी SDKs भी उसी contract पर बने हैं।

API कॉल करने के लिए तैयार हैं?

मुफ़्त sandbox key लें और ऊपर का quickstart लगभग 5 मिनट में चलाएँ।