# StampMitra Developer Platform: full API reference

> Indian identity verification (PAN, GSTIN, vehicle RC, Voter ID, Driving Licence, Passport, CIN, Udyam, bank account) and e-Stamp Paper issuance APIs. Free sandbox, pay per successful call in production.

Docs: https://developer.stampmitra.in/docs/auth · Quickstart: https://developer.stampmitra.in/quickstart · Pricing: https://developer.stampmitra.in/pricing · AI prompts: https://developer.stampmitra.in/build-with-ai · Index: https://developer.stampmitra.in/llms.txt

Base URL: https://api-b2b.stampmitra.in
Authentication: `Authorization: Bearer sk_test_...` or `x-api-key: sk_test_...`. Use a sandbox key while building.

---

# PAN

Verify a PAN in real time.

Base URL: https://api-b2b.stampmitra.in

Price: ₹5 per successful call

## Verify PAN

`POST /v1/verify/pan`

Required scope: `verification.pan.read`

Validates and verifies a PAN. Requires the `verification.pan.read` scope on the API key. Metered as `pan.verify` after a successful response - usage is only recorded (and the fulfilment wallet debited, for priced services) once verification completes successfully. The response below is the exact real shape returned by `/v1/verify/pan`, including its `referenceId` field.

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Authorization` | header | Yes | Bearer <api-key> (e.g. sk_test_... in sandbox, sk_live_... in production). The x-api-key header is also accepted. |
| `pan` | string | Yes | PAN, format ABCDE1234F. |
| `name` | string | No | Name to match against records (max 256 chars). |

### Request example

```bash
curl -X POST "https://api-b2b.stampmitra.in/v1/verify/pan" \
  -H "Authorization: Bearer sk_test_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"pan":"ABCDE1234F","name":"Rahul Kumar"}'
```

### Response example

```json
{
  "referenceId": "SMV-20260927-8F42K7",
  "pan": "ABCDE1234F",
  "type": "Individual",
  "valid": true,
  "registeredName": "RAHUL KUMAR",
  "fatherName": "SURESH KUMAR",
  "panStatus": "VALID",
  "panStatusCode": "E",
  "panStatusDescription": "Existing and valid PAN",
  "nameMatchResult": "MATCH",
  "nameMatchScore": "100",
  "aadhaarSeedingStatus": "y",
  "aadhaarSeedingStatusDescription": "Aadhaar linked",
  "lastUpdatedAt": "2023-04-01",
  "message": "PAN is Valid"
}
```

### Errors

- 401: Missing or invalid API key
- 403: Valid key, missing required scope
- 400: Validation error
- 402: Insufficient wallet balance
- 429: Rate limited
- 502: Upstream verification service unreachable

Note: Input format is validated up front - a malformed pan/gstin/etc. fails fast with a 400 rather than being submitted for verification. referenceId (format SMV-YYYYMMDD-XXXXXXX) is StampMitra's own transaction id for this call and is always present, including on a negative (valid: false / found: false) result - both positive and negative determinations are completed, billable verifications. This is not an idempotency key.


---

# GSTIN

Verify a GSTIN in real time.

Base URL: https://api-b2b.stampmitra.in

Price: ₹5 per successful call

## Verify GSTIN

`POST /v1/verify/gstin`

Required scope: `verification.gstin.read`

Validates and verifies a GSTIN. Requires the `verification.gstin.read` scope on the API key. Metered as `gstin.verify` after a successful response - usage is only recorded (and the fulfilment wallet debited, for priced services) once verification completes successfully. The response below is the exact real shape returned by `/v1/verify/gstin`, including its `referenceId` field.

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Authorization` | header | Yes | Bearer <api-key> (e.g. sk_test_... in sandbox, sk_live_... in production). The x-api-key header is also accepted. |
| `gstin` | string | Yes | 15-character GSTIN. |
| `businessName` | string | No | Business name to match. |

### Request example

```bash
curl -X POST "https://api-b2b.stampmitra.in/v1/verify/gstin" \
  -H "Authorization: Bearer sk_test_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"gstin":"07AAAAA1111A1Z1","businessName":"Jane Doe Enterprises"}'
```

### Response example

```json
{
  "referenceId": "SMV-20260927-9K21P4",
  "GSTIN": "07AAAAA1111A1Z1",
  "valid": true,
  "legalName": "Jane Doe Enterprises Private Limited",
  "tradeName": "Jane Doe Enterprises",
  "registrationStatus": "Active",
  "principalPlaceOfBusiness": "123, MG Road, Bengaluru, Karnataka, 560001",
  "message": "GSTIN Exists"
}
```

### Errors

- 401: Missing or invalid API key
- 403: Valid key, missing required scope
- 400: Validation error
- 402: Insufficient wallet balance
- 429: Rate limited
- 502: Upstream verification service unreachable

Note: Input format is validated up front - a malformed pan/gstin/etc. fails fast with a 400 rather than being submitted for verification. referenceId (format SMV-YYYYMMDD-XXXXXXX) is StampMitra's own transaction id for this call and is always present, including on a negative (valid: false / found: false) result - both positive and negative determinations are completed, billable verifications. This is not an idempotency key.


---

# Vehicle RC

Verify a Vehicle RC in real time.

Base URL: https://api-b2b.stampmitra.in

Price: ₹9 per successful call

## Verify Vehicle RC

`POST /v1/verify/rc`

Required scope: `verification.rc.read`

Validates and verifies a Vehicle RC. Requires the `verification.rc.read` scope on the API key. Metered as `rc.verify` after a successful response - usage is only recorded (and the fulfilment wallet debited, for priced services) once verification completes successfully. The response below is the exact real shape returned by `/v1/verify/rc`, including its `referenceId` field.

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Authorization` | header | Yes | Bearer <api-key> (e.g. sk_test_... in sandbox, sk_live_... in production). The x-api-key header is also accepted. |
| `vehicleNumber` | string | Yes | Vehicle registration number. |

### Request example

```bash
curl -X POST "https://api-b2b.stampmitra.in/v1/verify/rc" \
  -H "Authorization: Bearer sk_test_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"vehicleNumber":"MH12AB1234"}'
```

### Response example

```json
{
  "referenceId": "SMV-20260927-3D71Q9",
  "regNo": "MH12AB1234",
  "registrationStatus": "VALID",
  "ownerName": "RAHUL KUMAR",
  "ownerFatherName": "SURESH KUMAR",
  "vehicleClass": "LMV",
  "vehicleManufacturerName": "MARUTI SUZUKI",
  "model": "SWIFT",
  "vehicleColor": "WHITE",
  "chassis": "MA3ERLF1S00123456",
  "engine": "K12MN1234567",
  "registrationDate": "2019-05-14",
  "rcStatus": "ACTIVE",
  "rcExpiryDate": "2034-05-13",
  "insuranceUpto": "2025-05-13",
  "isCommercial": false
}
```

### Errors

- 401: Missing or invalid API key
- 403: Valid key, missing required scope
- 400: Validation error
- 402: Insufficient wallet balance
- 429: Rate limited
- 502: Upstream verification service unreachable

Note: Input format is validated up front - a malformed pan/gstin/etc. fails fast with a 400 rather than being submitted for verification. referenceId (format SMV-YYYYMMDD-XXXXXXX) is StampMitra's own transaction id for this call and is always present, including on a negative (valid: false / found: false) result - both positive and negative determinations are completed, billable verifications. This is not an idempotency key.


---

# Voter ID

Verify a Voter ID in real time.

Base URL: https://api-b2b.stampmitra.in

Price: ₹5 per successful call

## Verify Voter ID

`POST /v1/verify/voter-id`

Required scope: `verification.voter.read`

Validates and verifies a Voter ID. Requires the `verification.voter.read` scope on the API key. Metered as `voter.verify` after a successful response - usage is only recorded (and the fulfilment wallet debited, for priced services) once verification completes successfully. The response below is the exact real shape returned by `/v1/verify/voter-id`, including its `referenceId` field.

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Authorization` | header | Yes | Bearer <api-key> (e.g. sk_test_... in sandbox, sk_live_... in production). The x-api-key header is also accepted. |
| `voterId` | string | Yes | EPIC / Voter ID number. |
| `name` | string | No | Name to match against records. |

### Request example

```bash
curl -X POST "https://api-b2b.stampmitra.in/v1/verify/voter-id" \
  -H "Authorization: Bearer sk_test_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"voterId":"ABC1234567","name":"Rahul Kumar"}'
```

### Response example

```json
{
  "referenceId": "SMV-20260927-7H83M1",
  "valid": true,
  "name": "RAHUL KUMAR",
  "dob": "1990-01-01",
  "gender": "M",
  "age": 35,
  "address": "123, MG Road, Bengaluru",
  "state": "Karnataka"
}
```

### Errors

- 401: Missing or invalid API key
- 403: Valid key, missing required scope
- 400: Validation error
- 402: Insufficient wallet balance
- 429: Rate limited
- 502: Upstream verification service unreachable

Note: Input format is validated up front - a malformed pan/gstin/etc. fails fast with a 400 rather than being submitted for verification. referenceId (format SMV-YYYYMMDD-XXXXXXX) is StampMitra's own transaction id for this call and is always present, including on a negative (valid: false / found: false) result - both positive and negative determinations are completed, billable verifications. This is not an idempotency key.


---

# Driving Licence

Verify a Driving Licence in real time.

Base URL: https://api-b2b.stampmitra.in

Price: ₹5 per successful call

## Verify Driving Licence

`POST /v1/verify/driving-license`

Required scope: `verification.dl.read`

Validates and verifies a Driving Licence. Requires the `verification.dl.read` scope on the API key. Metered as `dl.verify` after a successful response - usage is only recorded (and the fulfilment wallet debited, for priced services) once verification completes successfully. The response below is the exact real shape returned by `/v1/verify/driving-license`, including its `referenceId` field.

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Authorization` | header | Yes | Bearer <api-key> (e.g. sk_test_... in sandbox, sk_live_... in production). The x-api-key header is also accepted. |
| `dlNumber` | string | Yes | Driving licence number. |
| `dob` | string | Yes | Date of birth (YYYY-MM-DD). |

### Request example

```bash
curl -X POST "https://api-b2b.stampmitra.in/v1/verify/driving-license" \
  -H "Authorization: Bearer sk_test_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"dlNumber":"MH1420110012345","dob":"1990-01-01"}'
```

### Response example

```json
{
  "referenceId": "SMV-20260927-2Q56T8",
  "valid": true,
  "name": "RAHUL KUMAR",
  "fatherOrHusbandName": "SURESH KUMAR",
  "dob": "1990-01-01",
  "address": "123, MG Road, Bengaluru",
  "validUpto": "2030-12-31",
  "dlStatus": "ACTIVE"
}
```

### Errors

- 401: Missing or invalid API key
- 403: Valid key, missing required scope
- 400: Validation error
- 402: Insufficient wallet balance
- 429: Rate limited
- 502: Upstream verification service unreachable

Note: Input format is validated up front - a malformed pan/gstin/etc. fails fast with a 400 rather than being submitted for verification. referenceId (format SMV-YYYYMMDD-XXXXXXX) is StampMitra's own transaction id for this call and is always present, including on a negative (valid: false / found: false) result - both positive and negative determinations are completed, billable verifications. This is not an idempotency key.


---

# Passport

Verify a Passport in real time.

Base URL: https://api-b2b.stampmitra.in

Price: ₹9 per successful call

## Verify Passport

`POST /v1/verify/passport`

Required scope: `verification.passport.read`

Validates and verifies a Passport. Requires the `verification.passport.read` scope on the API key. Metered as `passport.verify` after a successful response - usage is only recorded (and the fulfilment wallet debited, for priced services) once verification completes successfully. The response below is the exact real shape returned by `/v1/verify/passport`, including its `referenceId` field.

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Authorization` | header | Yes | Bearer <api-key> (e.g. sk_test_... in sandbox, sk_live_... in production). The x-api-key header is also accepted. |
| `fileNumber` | string | Yes | Passport application file number. |
| `dob` | string | Yes | Date of birth (YYYY-MM-DD). |
| `name` | string | No | Name to match against records. |

### Request example

```bash
curl -X POST "https://api-b2b.stampmitra.in/v1/verify/passport" \
  -H "Authorization: Bearer sk_test_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"fileNumber":"PA1079341954215","dob":"1990-01-01","name":"Rahul Kumar"}'
```

### Response example

```json
{
  "referenceId": "SMV-20260927-4W19X6",
  "valid": true,
  "name": "RAHUL KUMAR",
  "dob": "1990-01-01",
  "applicationType": "Fresh"
}
```

### Errors

- 401: Missing or invalid API key
- 403: Valid key, missing required scope
- 400: Validation error
- 402: Insufficient wallet balance
- 429: Rate limited
- 502: Upstream verification service unreachable

Note: Input format is validated up front - a malformed pan/gstin/etc. fails fast with a 400 rather than being submitted for verification. referenceId (format SMV-YYYYMMDD-XXXXXXX) is StampMitra's own transaction id for this call and is always present, including on a negative (valid: false / found: false) result - both positive and negative determinations are completed, billable verifications. This is not an idempotency key.


---

# Company CIN

Verify a Company CIN in real time.

Base URL: https://api-b2b.stampmitra.in

Price: ₹5 per successful call

## Verify Company CIN

`POST /v1/verify/cin`

Required scope: `verification.cin.read`

Validates and verifies a Company CIN. Requires the `verification.cin.read` scope on the API key. Metered as `cin.verify` after a successful response - usage is only recorded (and the fulfilment wallet debited, for priced services) once verification completes successfully. The response below is the exact real shape returned by `/v1/verify/cin`, including its `referenceId` field.

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Authorization` | header | Yes | Bearer <api-key> (e.g. sk_test_... in sandbox, sk_live_... in production). The x-api-key header is also accepted. |
| `cin` | string | Yes | Corporate Identification Number. |

### Request example

```bash
curl -X POST "https://api-b2b.stampmitra.in/v1/verify/cin" \
  -H "Authorization: Bearer sk_test_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"cin":"U74999DL2015PTC284009"}'
```

### Response example

```json
{
  "referenceId": "SMV-20260927-6R38Y3",
  "valid": true,
  "companyName": "JANE DOE ENTERPRISES PRIVATE LIMITED",
  "incorporationDate": "2015-03-12",
  "cinStatus": "ACTIVE",
  "companyStatus": "Active",
  "directors": [
    {
      "din": "01234567",
      "name": "RAHUL KUMAR",
      "designation": "Director"
    }
  ],
  "email": "contact@example.com",
  "registrationNumber": "U74999DL2015PTC284009",
  "incorporationCountry": "India"
}
```

### Errors

- 401: Missing or invalid API key
- 403: Valid key, missing required scope
- 400: Validation error
- 402: Insufficient wallet balance
- 429: Rate limited
- 502: Upstream verification service unreachable

Note: Input format is validated up front - a malformed pan/gstin/etc. fails fast with a 400 rather than being submitted for verification. referenceId (format SMV-YYYYMMDD-XXXXXXX) is StampMitra's own transaction id for this call and is always present, including on a negative (valid: false / found: false) result - both positive and negative determinations are completed, billable verifications. This is not an idempotency key.


---

# Udyam Registration

Verify a Udyam Registration in real time.

Base URL: https://api-b2b.stampmitra.in

Price: ₹5 per successful call

## Verify Udyam Registration

`POST /v1/verify/udyam`

Required scope: `verification.udyam.read`

Validates and verifies a Udyam Registration. Requires the `verification.udyam.read` scope on the API key. Metered as `udyam.verify` after a successful response - usage is only recorded (and the fulfilment wallet debited, for priced services) once verification completes successfully. The response below is the exact real shape returned by `/v1/verify/udyam`, including its `referenceId` field.

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Authorization` | header | Yes | Bearer <api-key> (e.g. sk_test_... in sandbox, sk_live_... in production). The x-api-key header is also accepted. |
| `udyamNumber` | string | Yes | Udyam Registration Number (URN). |

### Request example

```bash
curl -X POST "https://api-b2b.stampmitra.in/v1/verify/udyam" \
  -H "Authorization: Bearer sk_test_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"udyamNumber":"UDYAM-MH-12-1234567"}'
```

### Response example

```json
{
  "referenceId": "SMV-20260927-5U29V7",
  "found": true,
  "udyamStatus": "Active",
  "enterpriseName": "Jane Doe Enterprises",
  "enterpriseType": "Proprietorship",
  "organizationType": "Micro",
  "certificateUrl": "https://udyamregistration.gov.in/Udyam_Download/UDYAM-MH-12-1234567.pdf"
}
```

### Errors

- 401: Missing or invalid API key
- 403: Valid key, missing required scope
- 400: Validation error
- 402: Insufficient wallet balance
- 429: Rate limited
- 502: Upstream verification service unreachable

Note: Input format is validated up front - a malformed pan/gstin/etc. fails fast with a 400 rather than being submitted for verification. referenceId (format SMV-YYYYMMDD-XXXXXXX) is StampMitra's own transaction id for this call and is always present, including on a negative (valid: false / found: false) result - both positive and negative determinations are completed, billable verifications. This is not an idempotency key.


---

# PAN to GSTIN

Verify a PAN to GSTIN in real time.

Base URL: https://api-b2b.stampmitra.in

Price: ₹5 per successful call

## Verify PAN to GSTIN

`POST /v1/verify/pan-to-gstin`

Required scope: `verification.pan_to_gstin.read`

Validates and verifies a PAN to GSTIN. Requires the `verification.pan_to_gstin.read` scope on the API key. Metered as `pan.to_gstin` after a successful response - usage is only recorded (and the fulfilment wallet debited, for priced services) once verification completes successfully. The response below is the exact real shape returned by `/v1/verify/pan-to-gstin`, including its `referenceId` field.

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Authorization` | header | Yes | Bearer <api-key> (e.g. sk_test_... in sandbox, sk_live_... in production). The x-api-key header is also accepted. |
| `pan` | string | Yes | PAN to resolve to associated GSTIN(s). |

### Request example

```bash
curl -X POST "https://api-b2b.stampmitra.in/v1/verify/pan-to-gstin" \
  -H "Authorization: Bearer sk_test_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"pan":"ABCDE1234F"}'
```

### Response example

```json
{
  "referenceId": "SMV-20260927-1L67Z5",
  "found": true,
  "gstins": [
    {
      "gstin": "07AAAAA1111A1Z1",
      "state": "Delhi",
      "status": "Active"
    }
  ]
}
```

### Errors

- 401: Missing or invalid API key
- 403: Valid key, missing required scope
- 400: Validation error
- 402: Insufficient wallet balance
- 429: Rate limited
- 502: Upstream verification service unreachable

Note: Input format is validated up front - a malformed pan/gstin/etc. fails fast with a 400 rather than being submitted for verification. referenceId (format SMV-YYYYMMDD-XXXXXXX) is StampMitra's own transaction id for this call and is always present, including on a negative (valid: false / found: false) result - both positive and negative determinations are completed, billable verifications. This is not an idempotency key.


---

# PAN to Udyam

Verify a PAN to Udyam in real time.

Base URL: https://api-b2b.stampmitra.in

Price: ₹5 per successful call

## Verify PAN to Udyam

`POST /v1/verify/pan-to-udyam`

Required scope: `verification.pan_to_udyam.read`

Validates and verifies a PAN to Udyam. Requires the `verification.pan_to_udyam.read` scope on the API key. Metered as `pan.to_udyam` after a successful response - usage is only recorded (and the fulfilment wallet debited, for priced services) once verification completes successfully. The response below is the exact real shape returned by `/v1/verify/pan-to-udyam`, including its `referenceId` field.

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Authorization` | header | Yes | Bearer <api-key> (e.g. sk_test_... in sandbox, sk_live_... in production). The x-api-key header is also accepted. |
| `pan` | string | Yes | PAN to resolve to associated Udyam registration(s). |

### Request example

```bash
curl -X POST "https://api-b2b.stampmitra.in/v1/verify/pan-to-udyam" \
  -H "Authorization: Bearer sk_test_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"pan":"ABCDE1234F"}'
```

### Response example

```json
{
  "referenceId": "SMV-20260927-0A44B2",
  "found": true,
  "status": "Active",
  "udyamNumber": "UDYAM-MH-12-1234567"
}
```

### Errors

- 401: Missing or invalid API key
- 403: Valid key, missing required scope
- 400: Validation error
- 402: Insufficient wallet balance
- 429: Rate limited
- 502: Upstream verification service unreachable

Note: Input format is validated up front - a malformed pan/gstin/etc. fails fast with a 400 rather than being submitted for verification. referenceId (format SMV-YYYYMMDD-XXXXXXX) is StampMitra's own transaction id for this call and is always present, including on a negative (valid: false / found: false) result - both positive and negative determinations are completed, billable verifications. This is not an idempotency key.


---

# Bank Account

Verify a Bank Account in real time.

Base URL: https://api-b2b.stampmitra.in

Price: ₹4 per successful call

## Verify Bank Account

`POST /v1/verify/bank-account`

Required scope: `verification.bank-account.read`

Validates and verifies a Bank Account. Requires the `verification.bank-account.read` scope on the API key. Metered as `bank-account.verify` after a successful response - usage is only recorded (and the fulfilment wallet debited, for priced services) once verification completes successfully. The response below is the exact real shape returned by `/v1/verify/bank-account`, including its `referenceId` field.

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Authorization` | header | Yes | Bearer <api-key> (e.g. sk_test_... in sandbox, sk_live_... in production). The x-api-key header is also accepted. |
| `accountNumber` | string | Yes | 9-18 digit numeric bank account number. |
| `ifsc` | string | Yes | 11-character IFSC code, e.g. ICIC0001234. |
| `name` | string | No | Beneficiary name to match. |
| `phone` | string | No | Account holder's 10-digit Indian mobile number, when available; improves match confidence. |

### Request example

```bash
curl -X POST "https://api-b2b.stampmitra.in/v1/verify/bank-account" \
  -H "Authorization: Bearer sk_test_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"accountNumber":"000123456789","ifsc":"ICIC0001234","name":"Ravi Kumar"}'
```

### Response example

```json
{
  "referenceId": "SMV-20260927-3B71A0",
  "valid": true,
  "nameAtBank": "RAVI KUMAR",
  "bankName": "ICICI Bank",
  "utr": "017952100012345",
  "city": "Mumbai",
  "branch": "Andheri West",
  "micr": "400229002",
  "nameMatchScore": "100",
  "nameMatchResult": "GOOD_MATCH",
  "accountStatus": "ACCOUNT_IS_VALID",
  "accountStatusCode": "1",
  "ifscDetails": {
    "bank": "ICICI Bank",
    "ifsc": "ICIC0001234",
    "micr": "400229002",
    "address": "Andheri West, Mumbai",
    "city": "Mumbai",
    "state": "Maharashtra",
    "branch": "Andheri West"
  }
}
```

### Errors

- 401: Missing or invalid API key
- 403: Valid key, missing required scope
- 400: Validation error
- 402: Insufficient wallet balance
- 429: Rate limited
- 502: Upstream verification service unreachable

Note: Input format is validated up front - a malformed pan/gstin/etc. fails fast with a 400 rather than being submitted for verification. referenceId (format SMV-YYYYMMDD-XXXXXXX) is StampMitra's own transaction id for this call and is always present, including on a negative (valid: false / found: false) result - both positive and negative determinations are completed, billable verifications. This is not an idempotency key.


---

# e-Stamp Catalog Discovery

Discover which e-Stamp instruments/services are available to your organization.

Base URL: https://api-b2b.stampmitra.in

API fee: ₹5 per successful call (state procurement fee and stamp duty are quoted per order)

## List entitled services (generic catalog, covers e-Stamp services too)

`GET /v1/services`

Required scope: `services.read`

Returns every service (verification AND e-Stamp) this organization is entitled to. There is no e-Stamp-specific catalog endpoint yet; e-Stamp instruments surface here as regular service entries once entitled.

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Authorization` | header | Yes | Bearer <api-key> (e.g. sk_test_... in sandbox, sk_live_... in production). The x-api-key header is also accepted. |

### Request example

```bash
curl -X GET "https://api-b2b.stampmitra.in/v1/services" \
  -H "Authorization: Bearer sk_test_xxxxxxxxxxxx"
```

### Response example

```json
[
  {
    "serviceCode": "estamp.instrument.rent_agreement",
    "name": "Rent Agreement e-Stamp",
    "category": "estamp",
    "basePrice": "500.00",
    "currency": "INR",
    "isActive": true,
    "gstRatePercent": "18.00",
    "defaultGovernmentFee": null,
    "processingTimeHours": 24,
    "guestCheckoutEnabled": false,
    "requiresDocuments": true,
    "uiSchema": null,
    "entitled": true,
    "entitlementUpdatedAt": "2026-09-01T10:00:00.000Z"
  }
]
```

## Get one entitled service's detail

`GET /v1/services/:serviceCode`

Required scope: `services.read`

Detail for a single serviceCode, if entitled and active.

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Authorization` | header | Yes | Bearer <api-key> (e.g. sk_test_... in sandbox, sk_live_... in production). The x-api-key header is also accepted. |
| `serviceCode` | path | Yes | The service's unique code. |

### Request example

```bash
curl -X GET "https://api-b2b.stampmitra.in/v1/services/:serviceCode" \
  -H "Authorization: Bearer sk_test_xxxxxxxxxxxx"
```

### Response example

```json
{
  "serviceCode": "estamp.instrument.rent_agreement",
  "name": "Rent Agreement e-Stamp",
  "category": "estamp",
  "basePrice": "500.00",
  "currency": "INR",
  "isActive": true,
  "gstRatePercent": "18.00",
  "defaultGovernmentFee": null,
  "processingTimeHours": 24,
  "guestCheckoutEnabled": false,
  "requiresDocuments": true,
  "uiSchema": null,
  "entitled": true,
  "entitlementUpdatedAt": "2026-09-01T10:00:00.000Z"
}
```


---

# e-Stamp Schema / Options

Field schema and dropdown options for a given e-Stamp instrument (state, article, value ranges, etc.).

Base URL: https://api-b2b.stampmitra.in

API fee: ₹5 per successful call (state procurement fee and stamp duty are quoted per order)

## Get the e-Stamp input field schema

`GET /v1/estamp/schema/:serviceCode`

Required scope: `estamp.read`

Generic form-rendering metadata for the e-Stamp product. `serviceCode` is accepted for forward-compatible route shape parity with other schema lookups; e-Stamp has exactly one schema regardless of its value. Requires the `estamp.read` scope.

### Request example

```bash
curl -X GET "https://api-b2b.stampmitra.in/v1/estamp/schema/:serviceCode" \
  -H "Authorization: Bearer sk_test_xxxxxxxxxxxx"
```


---

# State / Instrument / Article Lookup

Resolve valid instrument types and stamp articles for a given state.

Base URL: https://api-b2b.stampmitra.in

API fee: ₹5 per successful call (state procurement fee and stamp duty are quoted per order)

## List e-Stamp-eligible states

`GET /v1/estamp/states`

Required scope: `estamp.read`

Served from StampMitra's synced master-data catalogue. Requires the `estamp.read` scope.

### Request example

```bash
curl -X GET "https://api-b2b.stampmitra.in/v1/estamp/states" \
  -H "Authorization: Bearer sk_test_xxxxxxxxxxxx"
```

## List instruments (articles) for a state

`GET /v1/estamp/states/:stateCode/instruments`

Required scope: `estamp.read`

There is no separate instrument entity distinct from an article - this returns the same state-scoped article catalogue as the articles endpoint below. Requires the `estamp.read` scope.

### Request example

```bash
curl -X GET "https://api-b2b.stampmitra.in/v1/estamp/states/:stateCode/instruments" \
  -H "Authorization: Bearer sk_test_xxxxxxxxxxxx"
```

## List articles for an instrument

`GET /v1/estamp/instruments/:instrumentCode/articles`

Required scope: `estamp.read`

`instrumentCode` is treated as a state code here - there is no article sub-breakdown below the state-scoped list. Requires the `estamp.read` scope.

### Request example

```bash
curl -X GET "https://api-b2b.stampmitra.in/v1/estamp/instruments/:instrumentCode/articles" \
  -H "Authorization: Bearer sk_test_xxxxxxxxxxxx"
```


---

# Duty / Value Calculation

Calculate applicable stamp duty for a given article, state and transaction value.

Base URL: https://api-b2b.stampmitra.in

API fee: ₹5 per successful call (state procurement fee and stamp duty are quoted per order)

## Calculate authoritative e-Stamp duty + service charges

`POST /v1/estamp/duty/calculate`

Required scope: `estamp.duty.calculate`

Runs the one authoritative pricing calculation; the response amount is never recalculated or overridden client-side. Requires the `estamp.duty.calculate` scope. Metered against your fulfilment wallet.

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Authorization` | header | Yes | Bearer <api-key> (e.g. sk_test_... in sandbox, sk_live_... in production). The x-api-key header is also accepted. |
| `stateCode` | string | Yes | State code, e.g. MH. |
| `articleCode` | string | Yes | Stamp article code from the articles lookup. |
| `stampDutyAmount` | number | Yes | Stamp duty amount to calculate charges for; must be positive. |
| `districtCode` | string | No | District code, where the state needs one. |
| `sroValue` | string | No | Sub-registrar office value, where the state needs one. |
| `doorstepDelivery` | boolean | No | Whether doorstep delivery is requested. |
| `couponCode` | string | No | Coupon code to apply. |
| `masterDataVersion` | integer | No | Master-data version the caller last read. |

### Request example

```bash
curl -X POST "https://api-b2b.stampmitra.in/v1/estamp/duty/calculate" \
  -H "Authorization: Bearer sk_test_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"stateCode":"MH","articleCode":"5","stampDutyAmount":500}'
```


---

# Parties

Attach first/second party (and witness) details to an e-Stamp order.

Base URL: https://api-b2b.stampmitra.in

API fee: ₹5 per successful call (state procurement fee and stamp duty are quoted per order)

## Attach/correct e-Stamp order party (customer) details

`POST /v1/estamp/orders/:orderId/parties`

Required scope: `estamp.parties.write`

Attaches or corrects the customer/party details on an existing e-Stamp order. Requires the `estamp.parties.write` scope. Metered against your fulfilment wallet.

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Authorization` | header | Yes | Bearer <api-key> (e.g. sk_test_... in sandbox, sk_live_... in production). The x-api-key header is also accepted. |
| `orderId` | path | Yes | The e-Stamp order id. |
| `customerName` | string | No | Customer's full name. |
| `partyName` | string | No | Counter-party's full name. |
| `customerMobile` | string | No | Customer's mobile number. |
| `customerEmail` | string | No | Customer's email address. |
| `partyAddress` | string | No | Party's address. |
| `partyPan` | string | No | Party's PAN. |

### Request example

```bash
curl -X POST "https://api-b2b.stampmitra.in/v1/estamp/orders/:orderId/parties" \
  -H "Authorization: Bearer sk_test_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"customerName":"Rahul Kumar","customerMobile":"+919876543210","customerEmail":"rahul@example.com"}'
```


---

# e-Stamp Order Creation

Create an e-Stamp order using the generic orders API with an e-Stamp serviceCode.

Base URL: https://api-b2b.stampmitra.in

API fee: ₹5 per successful call (state procurement fee and stamp duty are quoted per order)

## Create an order (generic - works for any entitled serviceCode, including e-Stamp)

`POST /v1/orders`

Required scope: `orders.create`

Generic order-creation endpoint. For e-Stamp, pass an e-Stamp `serviceCode` (from GET /v1/services) and put instrument/party/value details in the free-form `details` object. There is no e-Stamp-specific request/response contract yet (no first-class `state`, `article`, `parties[]` fields) - the shape of `details` for e-Stamp is not finalized upstream.

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Authorization` | header | Yes | Bearer <api-key> (e.g. sk_test_... in sandbox, sk_live_... in production). The x-api-key header is also accepted. |
| `Idempotency-Key` | header | No | Optional idempotency key. |
| `externalOrderId` | string | Yes | Your own reference for this order. |
| `externalCustomerId` | string | Yes | Your own reference for the customer. |
| `serviceCode` | string | Yes | The entitled service to order (e.g. an estamp.* code). |
| `details` | object | No | Free-form service-specific payload (e-Stamp field shape is not finalized). |

### Request example

```bash
curl -X POST "https://api-b2b.stampmitra.in/v1/orders" \
  -H "Authorization: Bearer sk_test_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"externalOrderId":"ord_ext_123","externalCustomerId":"cust_ext_456","serviceCode":"estamp.instrument.rent_agreement","details":{"state":"MH","stampValue":500,"note":"Shape not finalized - illustrative only"}}'
```

### Response example

```json
{
  "externalOrderId": "ord_ext_123",
  "createdAt": "2026-10-15T09:41:07.000Z",
  "serviceCode": "estamp.instrument.rent_agreement"
}
```

## Get an order

`GET /v1/orders/:id`

Required scope: `orders.read`

Fetch an order by the externalOrderId you supplied when you created it.

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Authorization` | header | Yes | Bearer <api-key> (e.g. sk_test_... in sandbox, sk_live_... in production). The x-api-key header is also accepted. |

### Request example

```bash
curl -X GET "https://api-b2b.stampmitra.in/v1/orders/:id" \
  -H "Authorization: Bearer sk_test_xxxxxxxxxxxx"
```

## Get order status

`GET /v1/orders/:id/status`

Required scope: `orders.read`

Poll the current lifecycle status of an order.

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Authorization` | header | Yes | Bearer <api-key> (e.g. sk_test_... in sandbox, sk_live_... in production). The x-api-key header is also accepted. |

### Request example

```bash
curl -X GET "https://api-b2b.stampmitra.in/v1/orders/:id/status" \
  -H "Authorization: Bearer sk_test_xxxxxxxxxxxx"
```


---

# Payment

Create a payment intent and check payment status for an order.

Base URL: https://api-b2b.stampmitra.in

API fee: ₹5 per successful call (state procurement fee and stamp duty are quoted per order)

## Create a payment intent

`POST /v1/payments/intents`

Required scope: `payments.write`

Create a payment intent (Razorpay-backed) for an order.

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Authorization` | header | Yes | Bearer <api-key> (e.g. sk_test_... in sandbox, sk_live_... in production). The x-api-key header is also accepted. |
| `Idempotency-Key` | header | No | Optional idempotency key. |
| `externalOrderId` | string | Yes | Your reference for the order being paid. |
| `amountMinor` | integer | Yes | Amount in minor units (paise); positive integer. |
| `currency` | string | Yes | Currency code, at least 3 characters, e.g. INR. |
| `paymentConnectionId` | string | Yes | Id of one of your active payment connections. |

### Request example

```bash
curl -X POST "https://api-b2b.stampmitra.in/v1/payments/intents" \
  -H "Authorization: Bearer sk_test_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"externalOrderId":"ord_ext_123","amountMinor":50000,"currency":"INR","paymentConnectionId":"pc_8d1f3a2b"}'
```

### Response example

```json
{
  "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "externalOrderId": "ord_ext_123",
  "coreOrderId": null,
  "amountMinor": 50000,
  "currency": "INR",
  "status": "CREATED",
  "providerIntentId": "order_Nf3k2m9QxPz1Ab",
  "createdAt": "2026-10-15T09:41:07.000Z"
}
```

## Get a payment intent

`GET /v1/payments/intents/:id`

Required scope: `payments.read`

Fetch the current state of a payment intent.

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Authorization` | header | Yes | Bearer <api-key> (e.g. sk_test_... in sandbox, sk_live_... in production). The x-api-key header is also accepted. |

### Request example

```bash
curl -X GET "https://api-b2b.stampmitra.in/v1/payments/intents/:id" \
  -H "Authorization: Bearer sk_test_xxxxxxxxxxxx"
```

### Response example

```json
{
  "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "externalOrderId": "ord_ext_123",
  "coreOrderId": null,
  "amountMinor": 50000,
  "currency": "INR",
  "status": "CREATED",
  "providerIntentId": "order_Nf3k2m9QxPz1Ab",
  "createdAt": "2026-10-15T09:41:07.000Z"
}
```

## Get an order's payment

`GET /v1/orders/:id/payment`

Required scope: `orders.read`

Fetch the payment associated with a given order.

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Authorization` | header | Yes | Bearer <api-key> (e.g. sk_test_... in sandbox, sk_live_... in production). The x-api-key header is also accepted. |

### Request example

```bash
curl -X GET "https://api-b2b.stampmitra.in/v1/orders/:id/payment" \
  -H "Authorization: Bearer sk_test_xxxxxxxxxxxx"
```


---

# Order Status & Document Access

Retrieve the generated e-Stamp certificate/document once an order completes.

Base URL: https://api-b2b.stampmitra.in

API fee: ₹5 per successful call (state procurement fee and stamp duty are quoted per order)

## List documents for an order

`GET /v1/orders/:id/documents`

Required scope: `documents.read`

List generated documents (e.g. the e-Stamp certificate PDF) for a completed order.

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Authorization` | header | Yes | Bearer <api-key> (e.g. sk_test_... in sandbox, sk_live_... in production). The x-api-key header is also accepted. |

### Request example

```bash
curl -X GET "https://api-b2b.stampmitra.in/v1/orders/:id/documents" \
  -H "Authorization: Bearer sk_test_xxxxxxxxxxxx"
```

## Get a document download URL

`GET /v1/orders/:id/documents/:documentId/download`

Required scope: `documents.read`

Get a (typically short-lived, signed) URL to download a specific document.

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Authorization` | header | Yes | Bearer <api-key> (e.g. sk_test_... in sandbox, sk_live_... in production). The x-api-key header is also accepted. |

### Request example

```bash
curl -X GET "https://api-b2b.stampmitra.in/v1/orders/:id/documents/:documentId/download" \
  -H "Authorization: Bearer sk_test_xxxxxxxxxxxx"
```

### Response example

```json
{
  "downloadUrl": "https://files.stampmitra.in/signed/doc_00789.pdf?token=abc123",
  "expiresAt": "2026-10-15T09:56:07.000Z"
}
```


---

# API Key Authentication

How every authenticated request to the B2B API is authorized.

Base URL: https://api-b2b.stampmitra.in

## Bearer API key + scopes

`GET (applies to every /v1/* endpoint)`

Every protected endpoint requires either `Authorization: Bearer <key>` or an `x-api-key: <key>` header. Keys are environment-scoped (SANDBOX `sk_test_...` vs PRODUCTION `sk_live_...`) and carry a list of OAuth-style scopes (e.g. `verification.pan.read`, `orders.create`, `payments.write`). Sensitive scopes can additionally be restricted to an IP allowlist. Requests are also subject to per-endpoint rate limits enforced server-side.

### Request example

```bash
curl -X GET "https://api-b2b.stampmitra.in(applies to every /v1/* endpoint)" \
  -H "Authorization: Bearer sk_test_xxxxxxxxxxxx"
```


---

# Dashboard Login (Email + Password + OTP)

Cookie-session email/password login for the developer dashboard, with a 2-step email-OTP second factor.

Base URL: https://api-b2b.stampmitra.in

## Sign up a dashboard user (email + password)

`POST /v1/auth/password/signup`

Creates an Organization (or joins none - organizationName is optional and auto-creates a personal workspace when omitted) and an owner User with a bcrypt-hashed password. Sets no session yet; a verification email is sent. Rate-limited per-IP and per-email.

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `fullName` | string | Yes | 1-150 characters. |
| `email` | string | Yes | Valid email address. |
| `password` | string | Yes | 10-72 chars; must include upper, lower, digit and symbol. |
| `organizationName` | string | No | Up to 200 characters. Omit to auto-create a personal workspace. |
| `mobileNumber` | string | Yes | E.164-ish phone number, e.g. +919876543210. |

### Request example

```bash
curl -X POST "https://api-b2b.stampmitra.in/v1/auth/password/signup" \
  -H "Authorization: Bearer sk_test_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"fullName":"Ravi Kumar","email":"ravi@acmetraders.in","password":"Str0ng!Passw0rd","organizationName":"Acme Traders","mobileNumber":"+919876543210"}'
```

### Response example

```json
{
  "organizationId": "org_5f2c1a9b3d7e4f6a",
  "userId": "usr_2b8e4d4a5fc9f3a1",
  "message": "Signup successful. Check your email to verify your account."
}
```

### Errors

- 400: Weak password
- 409: Email already registered
- 429: Rate limited

## Login step 1 of 2: verify email + password, send OTP

`POST /v1/auth/password/login`

Verifies the email/password pair and, on success, emails a one-time code and returns a challengeId. No session is created yet - call verify-otp with the code to finish logging in.

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `email` | string | Yes | Account email. |
| `password` | string | Yes | Account password. |
| `rememberMe` | boolean | No | Extends the resulting session's lifetime. |

### Request example

```bash
curl -X POST "https://api-b2b.stampmitra.in/v1/auth/password/login" \
  -H "Authorization: Bearer sk_test_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"email":"ravi@acmetraders.in","password":"Str0ng!Passw0rd","rememberMe":true}'
```

### Response example

```json
{
  "challengeId": "chal_7d3e1f2a9b4c5d6e"
}
```

### Errors

- 401: Invalid credentials
- 403: Email not verified
- 429: Rate limited

## Login step 2 of 2: verify the emailed OTP, create session

`POST /v1/auth/password/login/verify-otp`

Verifies the 6-digit code emailed in step 1 and, on success, sets an httpOnly session cookie scoped to the B2B origin.

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `challengeId` | string | Yes | From the login response. |
| `code` | string | Yes | Exactly 6 digits, emailed to the user. |

### Request example

```bash
curl -X POST "https://api-b2b.stampmitra.in/v1/auth/password/login/verify-otp" \
  -H "Authorization: Bearer sk_test_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"challengeId":"chal_7d3e1f2a9b4c5d6e","code":"482913"}'
```

### Response example

```json
{
  "user": {
    "id": "usr_2b8e4d4a5fc9f3a1",
    "email": "ravi@acmetraders.in",
    "fullName": "Ravi Kumar",
    "organizationId": "org_5f2c1a9b3d7e4f6a",
    "organizationName": "Acme Traders",
    "emailVerified": true
  }
}
```

### Errors

- 400: Wrong or expired code
- 429: Rate limited

Note: The response's Set-Cookie header (not shown above) carries the httpOnly session cookie; the frontend must send credentials: "include" on every subsequent password-auth call.

## Get the current session's user

`GET /v1/auth/password/me`

Returns the logged-in user for the current session cookie.

### Request example

```bash
curl -X GET "https://api-b2b.stampmitra.in/v1/auth/password/me" \
  -H "Authorization: Bearer sk_test_xxxxxxxxxxxx"
```

### Response example

```json
{
  "user": {
    "id": "usr_2b8e4d4a5fc9f3a1",
    "email": "ravi@acmetraders.in",
    "fullName": "Ravi Kumar",
    "organizationId": "org_5f2c1a9b3d7e4f6a",
    "organizationName": "Acme Traders",
    "emailVerified": true
  }
}
```

### Errors

- 401: No active session

## Log out (clear session)

`POST /v1/auth/password/logout`

Invalidates the current session cookie.

### Request example

```bash
curl -X POST "https://api-b2b.stampmitra.in/v1/auth/password/logout" \
  -H "Authorization: Bearer sk_test_xxxxxxxxxxxx"
```

### Response example

```json
{
  "status": "logged_out"
}
```

## Verify the account's email address

`POST /v1/auth/password/verify-email`

Verifies the token emailed at signup.

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `token` | string | Yes | At least 16 characters, from the verification email link. |

### Request example

```bash
curl -X POST "https://api-b2b.stampmitra.in/v1/auth/password/verify-email" \
  -H "Authorization: Bearer sk_test_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"token":"vt_9f2a1c8b3d7e4f5a6b1c2d3e4f5a6b7c"}'
```

### Response example

```json
{
  "status": "verified"
}
```

### Errors

- 400: Invalid or expired token

## Resend the email-verification link

`POST /v1/auth/password/resend-verification`

Rate-limited per-email; sends a fresh verification email if the account exists and is unverified.

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `email` | string | Yes | Account email. |

### Request example

```bash
curl -X POST "https://api-b2b.stampmitra.in/v1/auth/password/resend-verification" \
  -H "Authorization: Bearer sk_test_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"email":"ravi@acmetraders.in"}'
```

### Response example

```json
{
  "message": "If that account exists and is unverified, a new link has been sent."
}
```

### Errors

- 429: Rate limited

## Request a password-reset email

`POST /v1/auth/password/forgot-password`

Always returns 200 whether or not the email exists, to avoid leaking account existence.

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `email` | string | Yes | Valid email address. |

### Request example

```bash
curl -X POST "https://api-b2b.stampmitra.in/v1/auth/password/forgot-password" \
  -H "Authorization: Bearer sk_test_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"email":"ravi@acmetraders.in"}'
```

### Response example

```json
{
  "message": "If that account exists, a password reset link has been sent."
}
```

### Errors

- 429: Rate limited

## Reset the password using a reset token

`POST /v1/auth/password/reset-password`

Consumes the token emailed by forgot-password and sets a new password (same strength policy as signup).

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `token` | string | Yes | From the reset-password email link. |
| `newPassword` | string | Yes | 10-72 chars; must include upper, lower, digit and symbol. |

### Request example

```bash
curl -X POST "https://api-b2b.stampmitra.in/v1/auth/password/reset-password" \
  -H "Authorization: Bearer sk_test_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"token":"rt_3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f","newPassword":"N3wStr0ng!Pass"}'
```

### Response example

```json
{
  "status": "reset"
}
```

### Errors

- 400: Invalid token or weak password


---

# Team Management

Invite teammates, manage roles, and remove members from your organization (session-authenticated, not API-key).

Base URL: https://api-b2b.stampmitra.in

## Invite a member by email + role

`POST /v1/team/invites`

Owner/Admin only. Creates a pending invite and emails an accept link. Rate-limited per-IP and per-email.

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `email` | string | Yes | Invitee's email. |
| `role` | string | Yes | One of ADMIN, MEMBER (OWNER cannot be granted via invite). |

### Request example

```bash
curl -X POST "https://api-b2b.stampmitra.in/v1/team/invites" \
  -H "Authorization: Bearer sk_test_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"email":"priya@acmetraders.in","role":"MEMBER"}'
```

### Response example

```json
{
  "id": "inv_4f5a6b7c8d9e0f1a",
  "organizationId": "org_5f2c1a9b3d7e4f6a",
  "email": "priya@acmetraders.in",
  "role": "MEMBER",
  "status": "PENDING",
  "invitedBy": "usr_2b8e4d4a5fc9f3a1",
  "createdAt": "2026-09-25T09:00:00.000Z",
  "expiresAt": "2026-10-02T09:00:00.000Z"
}
```

### Errors

- 403: Not owner/admin
- 429: Rate limited

## List pending invites

`GET /v1/team/invites`

Owner/Admin only.

### Request example

```bash
curl -X GET "https://api-b2b.stampmitra.in/v1/team/invites" \
  -H "Authorization: Bearer sk_test_xxxxxxxxxxxx"
```

### Response example

```json
{
  "invites": [
    {
      "id": "inv_4f5a6b7c8d9e0f1a",
      "email": "priya@acmetraders.in",
      "role": "MEMBER",
      "status": "PENDING",
      "createdAt": "2026-09-25T09:00:00.000Z",
      "expiresAt": "2026-10-02T09:00:00.000Z"
    }
  ]
}
```

## Revoke a pending invite

`DELETE /v1/team/invites/:id`

Owner/Admin only.

### Request example

```bash
curl -X DELETE "https://api-b2b.stampmitra.in/v1/team/invites/:id" \
  -H "Authorization: Bearer sk_test_xxxxxxxxxxxx"
```

### Response example

```json
{
  "status": "revoked"
}
```

### Errors

- 404: Resource not found

## List organization members

`GET /v1/team/members`

Any authenticated member of the organization.

### Request example

```bash
curl -X GET "https://api-b2b.stampmitra.in/v1/team/members" \
  -H "Authorization: Bearer sk_test_xxxxxxxxxxxx"
```

### Response example

```json
{
  "members": [
    {
      "userId": "usr_2b8e4d4a5fc9f3a1",
      "email": "ravi@acmetraders.in",
      "fullName": "Ravi Kumar",
      "role": "OWNER",
      "joinedAt": "2026-06-01T10:00:00.000Z"
    },
    {
      "userId": "usr_7a1b2c3d4e5f6a7b",
      "email": "priya@acmetraders.in",
      "fullName": "Priya Sharma",
      "role": "MEMBER",
      "joinedAt": "2026-09-10T14:30:00.000Z"
    }
  ]
}
```

## Change a member's role

`PATCH /v1/team/members/:userId/role`

Owner/Admin only. Cannot demote the last owner.

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `role` | string | Yes | One of ADMIN, MEMBER (promoting to OWNER is not supported via this endpoint). |

### Request example

```bash
curl -X PATCH "https://api-b2b.stampmitra.in/v1/team/members/:userId/role" \
  -H "Authorization: Bearer sk_test_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"role":"ADMIN"}'
```

### Response example

```json
{
  "userId": "usr_7a1b2c3d4e5f6a7b",
  "organizationId": "org_5f2c1a9b3d7e4f6a",
  "role": "ADMIN",
  "updatedAt": "2026-09-25T09:15:00.000Z"
}
```

### Errors

- 400: Would demote the last owner
- 404: Resource not found

## Remove a member from the organization

`DELETE /v1/team/members/:userId`

Owner/Admin only. Cannot remove the last owner.

### Request example

```bash
curl -X DELETE "https://api-b2b.stampmitra.in/v1/team/members/:userId" \
  -H "Authorization: Bearer sk_test_xxxxxxxxxxxx"
```

### Response example

```json
{
  "status": "removed"
}
```

### Errors

- 400: Would remove the last owner
- 404: Resource not found

## Accept a team invite

`POST /v1/team/invites/:token/accept`

Public endpoint (no auth required at the route level). If the caller has an active session for the invited email, the invite attaches immediately; otherwise it returns signup_required so the frontend can route to signup with the invite token carried through.

### Request example

```bash
curl -X POST "https://api-b2b.stampmitra.in/v1/team/invites/:token/accept" \
  -H "Authorization: Bearer sk_test_xxxxxxxxxxxx"
```

### Response example

```json
{
  "status": "accepted",
  "organizationId": "org_5f2c1a9b3d7e4f6a",
  "role": "MEMBER"
}
```

### Errors

- 200: Not logged in as the invited email
- 404: Resource not found

