SHCIL eStamp
6 endpoints · Core API
SHCIL eStamp enables secure and legally valid electronic stamp certificate generation through the Stock Holding Corporation of India Limited (SHCIL). Your applications can initiate e-Stamp requests, generate stamp certificates using system templates or custom PDF documents, and retrieve the generated e-Stamp digitally. No physical stamp paper procurement is required. SignCare provides seamless integration with SHCIL's e-Stamping services, so you can generate and manage e-Stamps directly from your application without dealing with the underlying SHCIL platform.
New to SHCIL eStamp? Read this integration guide first.
SHCIL eStamp lets you generate legally valid electronic stamp certificates through the Stock Holding Corporation of India Limited (SHCIL) — fully digitally, with no physical stamp paper. You call the REST APIs below, SignCare handles the SHCIL platform integration end to end, and you get back the stamped document (or stamp certificate) as a base64 PDF.
The walkthrough covers which API to call, when, why, and where every field comes from — including the two flows (Pdf vs Template), the full field-origin map, validation rules, and error codes.
Table of Contents
- Before You Start — Authentication
- The Two Flows — Pdf Flow vs Template Flow
- End-to-End Flow at a Glance
- API 1 — Get Master Details
- API 2 — Get Template Fields
- API 3 — Generate E-Stamp
- Slow Generation and the 202 Response
- API 4 — Get Procured E-Stamps
- API 5 — Attach E-Stamp
- API 6 — Report Execution
- Webhook Delivery
- Field Origin Map — Where Every Field Comes From
- Validation Rules & Limits
- Error Codes
- FAQ
Before You Start — Authentication
Every API call must include these two headers (issued to you during onboarding):
| Header | Description |
|---|---|
X-API-KEY | Your API key |
X-API-APP-ID | Your application id |
Base path: {BASE_URL}/api/v1/StockHoldingEStamp
All requests and responses are JSON. All responses use a common envelope:
{
"success": true,
"statusCode": 200,
"message": "Success",
"data": { }
}Fields with no value are omitted from responses — always code defensively for absent optional fields.
Configure a webhook before you start. The Generate API needs a webhook URL — either sent as
webhookUrl on each request, or configured for your app during onboarding. A request with neither is
rejected. See Webhook Delivery for why.
The Two Flows — Pdf Flow vs Template Flow
The Master Details API returns articles in two lists — one per flow — and every article carries an
articleType confirming which flow it belongs to:
| List | articleType | Flow | What you send | What you get back |
|---|---|---|---|---|
pdfArticles | CUSTOM | Pdf flow — you already have the document | Your own PDF/DOCX in documentInfo | Your document with the e-Stamp certificate applied — ready in one call |
templateArticles | SYSTEM | Template flow — the document is generated from a SHCIL template | Field values in fields (field ids from the Template Fields API) | The e-Stamp certificate. Attach it to your own PDF later with the Attach API |
articleType is only ever SYSTEM or CUSTOM, and it always matches the list the article came from
— so you never have to decide what a value means. An article that works with either flow simply
appears in both lists under the same articleCode: take it from templateArticles to send
fields, or from pdfArticles to send documentInfo.
Rule: documentInfo and fields are mutually exclusive — send exactly one of them.
Which flow should I use?
- You already have the final agreement PDF → Pdf flow. One call and you're done:
Generatereturns the stamped document. - You want to procure stamps first and attach them to documents later → Template flow.
Generategives you a stamp certificate (statusCOMPLETED— procured); when your document is ready, callAttachto merge them (status becomesCONSUMED).
End-to-End Flow at a Glance
Pdf flow (CUSTOM article) — single call
| Step | What you send | What you get |
|---|---|---|
| 1. Master Details | — | stateCode + articleCode (articleType = CUSTOM) |
| 2. Generate E-Stamp | documentInfo + parties + stampDetails | stamped PDF + documentId |
| 3. eSign API (optional) | the documentId | signatures |
Template flow (SYSTEM article) — procure now, attach later
| Step | What you send | What you get |
|---|---|---|
| 1. Master Details | — | stateCode + articleCode (articleType = SYSTEM) |
| 2. Template Fields | the articleCode | field ids to fill |
| 3. Generate E-Stamp | fields + parties + stamp details | e-Stamp certificate + eStampId |
| 4. Attach E-Stamp | your PDF + eStampId | stamped PDF + documentId |
| 5. eSign API (optional) | the documentId | signatures |
| Get Procured E-Stamps (any time after step 3) | — | stamps generated but not yet attached |
Execution reporting. SHCIL requires the execution of every stamped document to be reported back once it has been signed. If you sign through the SignCare eSign API this happens automatically — see API 6 — Report Execution for when you would call it yourself.
API 1 — Get Master Details
GET /api/v1/StockHoldingEStamp/master-details
What it is: The starting point of every integration. Returns the reference data you need before generating any stamp.
Why you need it: The Generate API only accepts state codes and article codes from this list, and checks your stamp duty, consideration price and parties against the limits returned here. Calling Generate with values not present here is rejected.
When to call it: Once at integration time to build your state/article dropdowns, then refresh periodically (the data rarely changes — daily refresh is more than enough).
states[] — the states supported for SHCIL stamping:
| Field | Type | Description |
|---|---|---|
stateName | string | Display name (e.g. "Assam") |
stateCode | string | Two-letter code (e.g. "AS") → pass in stampDetails.stateCode of the Generate API |
templateArticles[] and pdfArticles[] — the articles available in those states, one list per
flow. Both use the same shape:
| Field | Type | Description |
|---|---|---|
stateCode | string | The state this article belongs to |
articleNumber | string | Stamp article number under the state's Stamp Act (e.g. "4" for Affidavit). Omitted when unmapped |
articleCode | number | Unique code of the article → pass in stampDetails.articleCode of the Generate API |
articleDescription | string | Description of the article. In pdfArticles: the generic legal description (e.g. "Affidavit"). In templateArticles: it also carries the specific template name (e.g. "Affidavit - Bharat Gas"), so you can tell templates of one article apart. Omitted when unavailable |
articleName | string | Display name of the article. Omitted when unavailable |
minDuty | string | Minimum stamp duty (INR) — stampDutyAmount must not be below this |
maxDuty | string | Maximum stamp duty (INR) — stampDutyAmount must not exceed this. Omitted when the article has no upper limit |
articleType | string | SYSTEM in templateArticles, CUSTOM in pdfArticles — always matches the list it came from |
stampDutyType | string | How stamp duty is calculated: STAMP_DUTY_RANGE (a fixed range between minDuty and maxDuty) or CONSIDERATION_PRICE (a percentage of the transaction value) |
considerationPercentage | string | For CONSIDERATION_PRICE articles: the percentage of the consideration price that becomes the stamp duty |
minConsiderationPrice | string | For CONSIDERATION_PRICE articles: the lowest considerationPrice accepted for this article. Omitted for other articles |
maxConsiderationPrice | string | For CONSIDERATION_PRICE articles: the highest considerationPrice accepted for this article. Omitted when the article has no upper limit, and for other articles |
bothPartyRequired | boolean | true → this article needs both firstParty and secondParty (name and mobile) in the Generate request |
Important:
articleCodevalues are unique per state, not globally. Always pick the article for the samestateCodeyou intend to stamp in.
Tip: several articles can share one
articleNumberandarticleName— e.g. a state's Affidavit article covers many templates. Each still has its ownarticleCode; send thearticleCodeof the exact entry you want. IntemplateArticles,articleDescriptioncarries the template name to help you choose.
What the stamp-duty fields mean for your Generate request:
stampDutyType | considerationPrice | stampDutyAmount |
|---|---|---|
STAMP_DUTY_RANGE | Optional | Must be between minDuty and maxDuty |
CONSIDERATION_PRICE | Required, between minConsiderationPrice and maxConsiderationPrice | Must be between minDuty and maxDuty |
Example response (trimmed):
{
"success": true,
"statusCode": 200,
"message": "Success",
"data": {
"states": [
{ "stateName": "Assam", "stateCode": "AS" },
{ "stateName": "Karnataka", "stateCode": "KA" }
],
"templateArticles": [
{
"stateCode": "AS",
"articleNumber": "4",
"articleCode": 19,
"articleDescription": "Affidavit - Bharat Gas",
"articleName": "Affidavit",
"minDuty": "10",
"maxDuty": "100",
"articleType": "SYSTEM",
"stampDutyType": "STAMP_DUTY_RANGE",
"considerationPercentage": "0",
"bothPartyRequired": false
},
{
"stateCode": "AS",
"articleNumber": "4",
"articleCode": 20,
"articleDescription": "Affidavit - Domicile",
"articleName": "Affidavit",
"minDuty": "10",
"maxDuty": "100",
"articleType": "SYSTEM",
"stampDutyType": "STAMP_DUTY_RANGE",
"considerationPercentage": "0",
"bothPartyRequired": false
}
],
"pdfArticles": [
{
"stateCode": "KA",
"articleNumber": "6(2)(i)",
"articleCode": 286,
"articleDescription": "Pawn or pledge - loan between Rs.1 lakh and Rs.10 lakh",
"articleName": "Pawn or pledge - loan between Rs.1 lakh and Rs.10 lakh",
"minDuty": "500",
"maxDuty": "5000",
"articleType": "CUSTOM",
"stampDutyType": "CONSIDERATION_PRICE",
"considerationPercentage": "0.5",
"minConsiderationPrice": "100001",
"maxConsiderationPrice": "1000000",
"bothPartyRequired": true
}
]
}
}Note how the two template-flow rows share articleNumber "4" and articleName "Affidavit" — only
articleCode (and the template name in articleDescription) differs. That is the normal case, not an edge case.
API 2 — Get Template Fields
GET /api/v1/StockHoldingEStamp/template/fields/{articleCode}
What it is: Returns the dynamic fields of a document template.
Why you need it: In the template flow the document is generated from a SHCIL template — you must supply values for the template's fields. This API tells you which fields exist, their ids, types, and validation rules.
When to call it: Template flow only, after the user picks a SYSTEM article from the Master Details response. Skip it entirely in the pdf flow.
Path parameter: articleCode (required, positive integer) — from templateArticles[].articleCode of the Master Details API.
| Field | Type | Description |
|---|---|---|
id | number | Template id |
articleTemplateName | string | Name of the template |
html | string | HTML content of the template — render it to preview the document |
fields[] | array | The fields to populate |
fields[].id | number | Field id → pass as fields[].id in the Generate API (as a string, e.g. "1024") |
fields[].fieldName | string | Human-readable label for your form |
fields[].fieldType | string | TEXT | TEXTAREA | NUMBER | DROPDOWN | DATE_PICKER | STRING_DATE | MULTISELECT |
fields[].sectionGroupName | string | Logical group for your form layout |
fields[].props | object | Validation rules — see below |
props (each key omitted when not applicable):
| Key | Meaning |
|---|---|
mandatory | "true" → the field must be supplied to the Generate API |
maxLength / minLength | Character-length limits |
options | Allowed values for DROPDOWN/MULTISELECT |
minDate / maxDate | Date range for date fields (dd/MM/yyyy) |
prefilled | Suggested/pre-filled value |
multiple | "true" → the value appears at multiple places in the document |
hidden | "true" → system-managed field, don't show it in your UI |
dependent | This field's value is auto-copied into another field |
Send dates in
dd/MM/yyyyformat, and no earlier than the field'sminDate.
API 3 — Generate E-Stamp
POST /api/v1/StockHoldingEStamp/generate
What it is: The core API — generates the e-Stamp certificate. In the pdf flow it also applies the certificate to your document in the same call.
When to call it: After you've chosen the state + article from Master Details (and collected field values via Template Fields, if template flow).
| Field | Type | Required | Where it comes from / rules |
|---|---|---|---|
referenceId | string | required | Your own unique id for this request. 1–64 chars: letters, digits, -, _. Never reused — a duplicate is rejected. Echoed back in the response and webhook so you can correlate |
selfReportExecution | boolean | optional | Who reports the document's execution to SHCIL when it is not signed through SignCare eSign. false (default) — SignCare reports it for you. true — you report it yourself with API 6 — Report Execution. Ignored when the document is signed through SignCare eSign — that reports automatically |
documentInfo | object | conditional | Pdf flow only (CUSTOM articles). Must be null in the template flow |
documentInfo.name | string | required | File name with extension, e.g. "Loan Agreement.pdf" |
documentInfo.content | string | required | Base64-encoded PDF or DOCX, max 5 MB |
fields | array | conditional | Template flow only (SYSTEM articles). Must be null in the pdf flow. Each field id may appear only once; an id that is not part of the article's template is rejected |
fields[].id | string | required | Field id ← Template Fields API fields[].id, sent as a string (e.g. "1024") |
fields[].value | string | required | The value to print into the document. Checked against that field's props: mandatory fields must be filled, NUMBER must be numeric, DATE_PICKER must be dd/MM/yyyy and not before minDate, DROPDOWN must be one of options, TEXT/TEXTAREA must fit maxLength |
firstParty | object | conditional | At least one of firstParty / secondParty is required. Required when the first party pays the duty, or when the article has bothPartyRequired: true |
firstParty.name | string | conditional | Required whenever firstParty is sent |
firstParty.mobile | string | conditional | Exactly 10 digits. Required when the first party pays the duty, or bothPartyRequired: true |
firstParty.pan | string | conditional | 10-char PAN (AAAAA9999A). Required when the first party pays and stampDutyAmount is greater than ₹2,00,000 |
secondParty | object | conditional | Required when the second party pays the duty, or when the article has bothPartyRequired: true |
secondParty.name | string | conditional | Required whenever secondParty is sent |
secondParty.mobile | string | conditional | Exactly 10 digits. Required when the second party pays the duty, or bothPartyRequired: true |
secondParty.pan | string | conditional | 10-char PAN. Required when the second party pays and stampDutyAmount is greater than ₹2,00,000 |
stampDetails | object | required | Stamp specifics |
stampDetails.stateCode | string | required | ← Master Details API states[].stateCode |
stampDetails.articleCode | number | required | ← Master Details API — templateArticles[].articleCode (template flow) or pdfArticles[].articleCode (pdf flow), same state! |
stampDetails.stampDutyAmount | integer | required | INR, whole number greater than zero (no decimals). Must be within the article's minDuty–maxDuty range |
stampDetails.stampDutyPaidBy | string | required | The duty payer's name — must exactly match firstParty.name or secondParty.name |
stampDetails.considerationPrice | number | conditional | Value of the transaction. Required for CONSIDERATION_PRICE articles and must be between the article's minConsiderationPrice and maxConsiderationPrice. Optional for other articles. Never negative |
stampDetails.documentDescription | string | optional | Property / document description printed on the certificate. Max 100 characters; letters, numbers and spaces only |
webhookUrl | string | conditional | Use an HTTPS URL — the result is POSTed here. Required unless a webhook is configured for your app. The request value takes priority over the configured one |
isAsync | boolean | optional | Default false. false — the API waits up to ~40 seconds and answers with the stamp (200); only when SHCIL is slow does it answer 202. true — the API does not wait: once the request is validated and accepted it answers 202 immediately and the result is delivered to your webhook. See Asking for the 202 on purpose |
Example request — Pdf flow (a CONSIDERATION_PRICE article):
{
"referenceId": "LOAN-2026-000123",
"selfReportExecution": false,
"documentInfo": {
"name": "Loan Agreement.pdf",
"content": "<base64>"
},
"firstParty": { "name": "Rahul Sharma", "pan": "ABCDE1234F", "mobile": "9876543210" },
"secondParty": { "name": "Acme Finance Ltd", "pan": "AABCA9876B", "mobile": "9123456780" },
"stampDetails": {
"stateCode": "KA",
"articleCode": 286,
"stampDutyAmount": 2500,
"stampDutyPaidBy": "Rahul Sharma",
"considerationPrice": 500000,
"documentDescription": "Loan agreement between Rahul Sharma and Acme Finance Ltd"
},
"webhookUrl": "https://yourapp.com/webhooks/estamp"
}Example request — Template flow (a STAMP_DUTY_RANGE article):
{
"referenceId": "AFF-2026-000124",
"fields": [
{ "id": "1024", "value": "Rahul Sharma" },
{ "id": "1025", "value": "Guwahati" }
],
"firstParty": { "name": "Rahul Sharma", "mobile": "9876543210" },
"stampDetails": {
"stateCode": "AS",
"articleCode": 19,
"stampDutyAmount": 100,
"stampDutyPaidBy": "Rahul Sharma"
},
"webhookUrl": "https://yourapp.com/webhooks/estamp"
}Response (HTTP 200)
| Field | Type | Description / where you use it next |
|---|---|---|
referenceId | string | The reference id you sent — correlate with your records |
eStampId | string (uuid) | Unique id of the e-Stamp. Template flow: pass this to the Attach API. Keep it for support queries |
documentId | string (uuid) | Id of the stamped document — pdf flow only (omitted in template flow). Pass this to the eSign API to send the document for signature |
userDocumentId | number | SHCIL document id — pass to the Report Execution API if you report execution yourself; quote in support queries |
reconMappingId | string | Auto-generated correlation key — quote in reconciliation/support queries |
status | string | COMPLETED = stamp generated. Pdf flow stamps are applied immediately; template flow stamps are procured and ready to attach |
certId | string | Certificate id issued by SHCIL |
urn | string | Unique reference number of the e-Stamp |
certificateNo | string | Certificate number printed on the stamp |
certificateIssuedDate | string | Certificate issue date/time |
base64FileData | string | The PDF. Pdf flow: your document with the e-Stamp applied. Template flow: the e-Stamp certificate itself |
This API can also return HTTP 202 — when generation is taking longer than usual, or always when you send
isAsync: true— see Slow Generation and the 202 Response below. When that happens,eStampId,documentId,userDocumentId, and every certificate field above are absent (not yet created) — onlyreferenceId,reconMappingIdandstatus: "ACCEPTED"are present.
Charges: stamp duty and applicable charges are deducted from your SHCIL eStamp wallet when the stamp is generated. A request is refused up front if your wallet balance cannot cover it.
Slow Generation and the 202 Response
Generate normally answers synchronously — SHCIL almost always responds within seconds. Occasionally SHCIL's own platform is slower than usual. Rather than holding your connection open indefinitely, if the certificate isn't ready within the sync wait window (server-configured, currently ~40 seconds), the API responds immediately with:
{
"success": true,
"statusCode": 202,
"message": "Accepted. Generation is taking longer than usual — the result will be delivered to your webhookUrl. Do not retry this referenceId.",
"data": {
"referenceId": "LOAN-2026-000123",
"reconMappingId": "SC0000000000000ABCDE",
"status": "ACCEPTED"
}
}202 is a normal response, not an error. During a slow spell it can be the outcome for most or all of your requests, not a rare edge case — don't treat it as a failure path you can skip building.
What happens next: the certificate is still being generated in the background. Once it finishes
(success or failure), the outcome is delivered to your webhook — the same payload shape as the 200
response on success (see Webhook Delivery below for the failure shape). There is
currently no separate "check status" endpoint — the webhook is the only delivery channel for a 202,
which is why a webhook is required.
The one rule that matters — do not retry the same operation:
| Situation | HTTP you get | What it means | What to do |
|---|---|---|---|
| SHCIL answers within the wait window | 200 | Done | Nothing — use the response as normal |
| Still processing when the wait window elapses | 202 | Generation is in progress | Wait for the webhook. Do not retry |
You call again with the same referenceId while it's still processing | 202 (again) | Safe — echoes the same request, no second certificate is generated | Stop retrying; one outcome is coming, for this referenceId only |
You call again with the same referenceId after it already finished | 400 | That referenceId is already used | Use a new referenceId if you need to generate again |
| The webhook eventually reports failure | (delivered via webhook, not HTTP) | Nothing was charged | Fix whatever the webhook's message says, then retry with a new referenceId |
Calling again with a new referenceId while the original is still processing does not cancel or
replace it — it starts a second, independent generation and, if both succeed, you pay for both. The
only safe move while a referenceId is in flight is to wait.
Asking for the 202 on purpose — isAsync
If you would rather not hold the connection at all — because you handle every result on your webhook, or to
test your own 202 handling — send isAsync: true on the Generate request. The default is false,
and then everything above stays exactly as it is.
isAsync: false (default) | isAsync: true | |
|---|---|---|
| How long the call takes | Up to ~40 seconds, usually a few | Immediate (after validation) |
| Normal answer | 200 with the stamp | 202 with status: "ACCEPTED" — no stamp yet |
When you get a 202 | Only if SHCIL is slow | Always, once the request is accepted |
| Where the stamp arrives | In the response (or on the webhook after a 202) | On the webhook |
How it behaves with isAsync: true:
-
The request is validated first. Missing fields, a wrong article, an insufficient wallet, an unsupported state and similar problems are still returned immediately as the usual
4xx— nothing is accepted. -
If it is valid, you get
202at once:{ "success": true, "statusCode": 202, "message": "Accepted. As requested (isAsync), the stamp is generated in the background and the result will be delivered to your webhookUrl. Do not retry this referenceId.", "data": { "referenceId": "LOAN-2026-000123", "reconMappingId": "SC0000000000000ABCDE", "status": "ACCEPTED" } } -
The stamp is generated in the background, and the outcome is POSTed to your webhook — the same success payload as the
200response, or the failure payload described in Webhook Delivery. -
A webhook is needed — send
webhookUrlor have one configured for your app, as for every Generate request. -
Do not send the same
referenceIdagain. While it is still being processed it just returns the same202; once it has finished it is rejected as already used.
The 202 itself is identical to the "slow SHCIL" one described above, so one piece of code handles both: on a 202,
store the referenceId and wait for the webhook.
When SHCIL has not finished the stamp — status: "PENDING"
Occasionally SHCIL creates the document but does not finish the eStamp (SHCIL statuses
ESTAMP_PENDING or ERROR_IN_PDF_GENERATION). SignCare then completes it for you automatically by
regenerating it with SHCIL — SHCIL does not charge again for this. You get:
{
"success": true,
"statusCode": 202,
"message": "eStamp is being completed by SHCIL. The result will be delivered to your webhookUrl. Do not retry this referenceId — you have not been charged yet.",
"data": {
"referenceId": "LOAN-2026-000123",
"reconMappingId": "SCAB12CD34EF56GH78IJ",
"eStampId": "3f2a9c1e-5b7d-4e2a-9f10-2c3d4e5f6a7b",
"userDocumentId": 45237,
"status": "PENDING"
}
}- You are not charged until the stamp is ready.
- When it is ready, the normal success webhook is sent (same payload as for a
202above), and the stamp appears in Get Procured E-Stamps. - If SHCIL cannot complete it after several automatic attempts, the failure webhook is sent and you are never charged for it.
- Do not retry — the same
referenceIdis rejected, and a newreferenceIdwould make SHCIL issue (and charge) a second stamp.
API 4 — Get Procured E-Stamps
POST /api/v1/StockHoldingEStamp/procured
What it is: Your stamp inventory — every e-Stamp procured via the template flow with the Generate API that has not yet been attached to a document, newest first.
Why you need it: In the procure-now-attach-later model this is your source of truth. Use it to build
a "pick a stamp" screen, reconcile what you've paid for, or recover an eStampId you didn't store.
When to call it: Any time between Generate and Attach.
Request body — optional filters. Send {} (or no body) to get everything:
| Field | Type | Description |
|---|---|---|
estampIds | array of string (uuid) | Optional. Only stamps whose id is in this list are returned |
stateCode | string | Optional. Only stamps from this state are returned |
Response fields
| Field | Type | Description |
|---|---|---|
count | number | Number of procured stamps returned |
stamps[] | array | Procured stamps, newest first |
stamps[].eStampId | string (uuid) | → pass to the Attach API |
stamps[].userDocumentId | number | SHCIL document id → pass in userDocumentIds of the Report Execution API |
stamps[].reconMappingId | string | Correlation key from generation time |
stamps[].status | string | Always COMPLETED (procured, ready to attach) |
stamps[].certId | string | Certificate id issued by SHCIL |
stamps[].urn | string | Unique reference number |
stamps[].certificateIssuedDate | string | Certificate issue date and time |
stamps[].articleName | string | Article the stamp was generated with |
stamps[].stampDetails | object | stateCode, articleCode, stampDutyAmount, stampDutyPaidBy, considerationPrice, documentDescription from generation |
stamps[].firstParty / secondParty | object | Party details (name, pan, mobile) from generation. secondParty omitted when not provided |
stamps[].createdOn | string (UTC) | When the stamp was generated |
stamps[].base64FileData | string | The stamp's certificate PDF. Omitted if the file could not be retrieved |
Example request:
{ "stateCode": "DL" }Example response:
{
"success": true,
"statusCode": 200,
"message": "Success",
"data": {
"count": 1,
"stamps": [
{
"eStampId": "42bf8e05-7823-47f0-92b8-c997cac919e2",
"userDocumentId": 80832,
"reconMappingId": "SC641A5I2MR42I9NJ57L",
"status": "COMPLETED",
"certId": "IN-DL68613570100523Y",
"urn": "DL1007DIGID2026217795031DLJN",
"certificateIssuedDate": "05-Aug-2026 04:27 PM",
"articleName": "Loan Agreement Title Deed",
"stampDetails": { "stateCode": "DL", "articleCode": 1007, "stampDutyAmount": 100, "stampDutyPaidBy": "Acme Pvt Ltd" },
"firstParty": { "name": "Acme Pvt Ltd", "mobile": "9876543210" },
"createdOn": "2026-08-05T10:57:04Z",
"base64FileData": "<the stamp's certificate PDF>"
}
]
}
}A stamp disappears once attached. After a successful Attach the stamp becomes
CONSUMEDand drops out of this list — so what you see here is always safe to attach.
Response size: every entry carries its certificate PDF. If you hold many un-attached stamps, use the
stateCodeorestampIdsfilter to fetch only what you need.
API 5 — Attach E-Stamp
POST /api/v1/StockHoldingEStamp/attach
What it is: Attaches a procured e-Stamp (template flow) onto your own PDF — the certificate pages are merged with your document, producing the final stamped document.
Why you need it: Completes the template flow. Duty was already paid at generation — no additional stamp duty is charged here.
When to call it: After template-flow Generate, whenever your final document is ready.
| Field | Type | Required | Where it comes from / rules |
|---|---|---|---|
referenceId | string | required | A new unique reference id (same format rules as Generate; must not reuse any earlier referenceId) |
eStampId | string (uuid) | required | ← Generate API response (template flow), or a Get Procured E-Stamps entry. Must belong to your account and must not already be attached. A stamp from a bulk batch is rejected |
documentInfo | object | required | The PDF to stamp |
documentInfo.name | string | required | File name ending in .pdf |
documentInfo.content | string | required | Base64 PDF only, max 5 MB (DOCX is not supported for attach) |
Response (HTTP 200)
| Field | Type | Description / where you use it next |
|---|---|---|
referenceId | string | The reference id you sent |
documentId | string (uuid) | Id of the stamped document → pass to the eSign API for signatures |
base64FileData | string | The stamped PDF (e-Stamp certificate pages + your document) |
Each e-Stamp can be attached exactly once. After a successful attach its status becomes
CONSUMEDand it disappears from the Procured list. A second attempt is rejected with "This eStamp has already been attached to a document."
API 6 — Report Execution
POST /api/v1/StockHoldingEStamp/consume/report
What it is: Tells SHCIL that a stamped document has been executed (signed by its parties) — the document reference and how many people signed it. SHCIL requires this for every stamp.
Do you need to call it? Usually not:
| Your situation | Who reports execution |
|---|---|
| The document is signed through the SignCare eSign API | SignCare, automatically — when the last signatory signs. Don't call this API |
Signed outside SignCare, and you sent selfReportExecution: false (the default) on Generate | SignCare, automatically — after a grace period (currently 48 hours from generation) |
Signed outside SignCare, and you sent selfReportExecution: true on Generate | You — call this API once the document has actually been executed |
Call it yourself when the exact signing date or signatory count matters to you, or when only you know when signing finished.
Request
| Field | Type | Required | Description |
|---|---|---|---|
userDocumentIds | array of number | required | One or more SHCIL document ids ← the userDocumentId from the Generate API or Get Procured E-Stamps. Each must be a positive number belonging to your account |
executionDateTime | string | optional | When the document was executed — dd/MM/yyyy HH:mm:ss (e.g. "27/07/2026 14:30:00") or dd/MM/yyyy (current IST time is added). Omit to use the current IST date and time |
noOfSignatories | number | optional | Total number of signatories on the document. Defaults to 0 |
noOfDigitalSignatures | number | optional | How many signed with a DSC (Class 2 / Class 3 digital signature certificate). Defaults to 0 |
noOfElectronicSignatures | number | optional | How many signed with Aadhaar or OTP-based electronic signature. Defaults to 0 |
The signatory counts apply to every id in userDocumentIds.
Example request:
{
"userDocumentIds": [80832],
"executionDateTime": "27/07/2026 14:30:00",
"noOfSignatories": 2,
"noOfDigitalSignatures": 0,
"noOfElectronicSignatures": 2
}Response
- One id sent →
data.message: SHCIL's confirmation. An id that is not found (or not yours) returns HTTP 404. - Several distinct ids sent →
data.results[]: one entry per id, so one bad id never hides the others. HTTP 200 when all succeed, 207 when any failed.
| Field | Type | Description |
|---|---|---|
message | string | Confirmation from SHCIL (one id sent) |
results[] | array | One entry per id (several ids sent) |
results[].userDocumentId | number | The id this result is for |
results[].success | boolean | true if SHCIL accepted the report for this stamp |
results[].message | string | SHCIL's confirmation or the reason it failed |
Safe to repeat. A stamp whose execution was already reported — by you, by SignCare eSign, or by the automatic report — is returned as successful with "Execution was already reported for this stamp." It is never filed with SHCIL twice.
Webhook Delivery
SignCare POSTs the outcome of every Generate request to your webhook as JSON — the webhookUrl on the
request, or the webhook configured for your app if the request has none. This is not just a courtesy
notification — for any request that returned HTTP 202 (see
Slow Generation and the 202 Response), the webhook is the
only place the outcome is delivered, which is why a webhook is required.
Success payload — the same fields as the Generate response:
{
"success": true,
"statusCode": 200,
"message": "Success",
"data": {
"referenceId": "LOAN-2026-000123",
"eStampId": "0d1f7f5e-…",
"documentId": "8c2a41d9-…",
"userDocumentId": 123456,
"reconMappingId": "SC0000000000000ABCDE",
"status": "COMPLETED",
"certId": "IN-AS12345678901234X",
"urn": "…",
"certificateNo": "…",
"certificateIssuedDate": "10-Jul-2026 11:42:05",
"base64FileData": "<base64 PDF>"
}
}Failure payload — sent when a 202 request ultimately fails (nothing was created and nothing was
charged in this case):
{
"success": false,
"statusCode": 422,
"message": "eStamp generation failed. Please try again.",
"data": {
"referenceId": "LOAN-2026-000123",
"status": "FAILED",
"errorMessage": "eStamp generation failed. Please try again."
}
}On failure, eStampId/documentId/userDocumentId/certificate fields are all absent — nothing was
generated. Read errorMessage, fix whatever it describes, and retry with a new referenceId.
Notes:
- The PDF arrives as base64, unless your account is set up to receive webhooks without file content.
- Use an HTTPS URL for
webhookUrl. - Respond with HTTP 2xx to acknowledge. Failed deliveries are retried, so treat deliveries as at-least-once and de-duplicate on
referenceId/eStampId.
Field Origin Map — Where Every Field Comes From
| You send… | In API | It comes from |
|---|---|---|
stampDetails.stateCode | Generate | Master Details → states[].stateCode |
stampDetails.articleCode | Generate | Master Details → templateArticles[] or pdfArticles[] → articleCode (same state) |
stampDetails.stampDutyAmount | Generate | Your business logic — must fit the chosen article's minDuty–maxDuty |
stampDetails.considerationPrice | Generate | Your transaction value — required for CONSIDERATION_PRICE articles, within minConsiderationPrice–maxConsiderationPrice |
stampDetails.stampDutyPaidBy | Generate | Must equal firstParty.name or secondParty.name in the same request |
firstParty / secondParty | Generate | Your parties — both required when the article has bothPartyRequired: true |
fields[].id | Generate (template flow) | Template Fields → fields[].id |
fields[].value | Generate (template flow) | Your user's input, validated against fields[].props |
documentInfo | Generate (pdf flow) / Attach | Your own document (base64) |
eStampId | Attach | Generate response (template flow) → eStampId, or Get Procured E-Stamps → stamps[].eStampId |
userDocumentIds | Report Execution | Generate response → userDocumentId, or Get Procured E-Stamps → stamps[].userDocumentId |
referenceId | Generate / Attach | You generate it — unique per request, never reused |
webhookUrl | Generate | Your endpoint (or the one configured for your app) |
And where response fields go next:
| You receive… | From API | You use it for |
|---|---|---|
eStampId | Generate / Procured | Attach API (template flow); support queries |
documentId | Generate (pdf flow) / Attach | eSign API — send the stamped document for signature |
userDocumentId | Generate / Procured | Report Execution API; support queries |
base64FileData | Generate / Attach / Procured | The actual PDF — store or present it |
reconMappingId, certId, urn | Generate / Procured | Reconciliation and support queries |
referenceId | All | Correlating responses/webhooks with your records |
Validation Rules & Limits
| Rule | Detail |
|---|---|
referenceId | 1–64 chars, A-Z a-z 0-9 - _ only, unique across every Generate and Attach request |
| Webhook | Required — webhookUrl on the request, or a webhook configured for your app. Use an HTTPS URL |
| File size | documentInfo.content max 5 MB (base64 decoded) |
| File types | Generate: PDF or DOCX. Attach: PDF only |
| Flow exclusivity | Send documentInfo or fields — never both, never neither |
stateCode | Two letters, and must be in the Master Details states list |
articleCode | Must exist for that same stateCode in the flow's article list |
| Stamp duty | Whole number greater than zero, within the article's minDuty–maxDuty |
| Consideration price | Never negative. For CONSIDERATION_PRICE articles: required, within minConsiderationPrice–maxConsiderationPrice |
| Parties | At least one of firstParty / secondParty. Every party sent needs a name. Both are required (name + mobile) when the article has bothPartyRequired: true |
| Duty payer | stampDutyPaidBy must exactly match a party name in the request |
| Payer's mobile | Required for the party who pays — exactly 10 digits |
| Payer's PAN | Required for the party who pays when stampDutyAmount > ₹2,00,000. Format AAAAA9999A |
documentDescription | Max 100 characters; letters, numbers and spaces only |
| Template field dates | dd/MM/yyyy, not before the field's minDate |
| Attach | One attach per e-Stamp; already-attached stamps are rejected |
| Report Execution | userDocumentIds required, positive numbers, your own stamps only. executionDateTime as dd/MM/yyyy HH:mm:ss or dd/MM/yyyy |
Error Codes
Every error uses the standard envelope, with a plain-English message naming the problem:
{
"data": null,
"messages": [],
"request_id": null,
"success": false,
"statusCode": 400,
"message": "Consideration price must be between 100001 and 1000000 for article 'Pawn or pledge - loan between Rs.1 lakh and Rs.10 lakh'."
}| HTTP | Meaning | What to do |
|---|---|---|
| 202 | Generate only. Taking longer than usual, or status: "PENDING" (SHCIL is still completing the stamp; not charged yet) — not an error. See Slow Generation and the 202 Response | Wait for the webhook. Do not retry this referenceId |
| 400 | Validation failed — message says exactly what is wrong | Fix the request and retry with a new referenceId |
| 401 | Missing/invalid X-API-KEY or X-API-APP-ID | Check the headers |
| 402 | Insufficient wallet balance / API access not enabled for your app | Recharge, or contact your SignCare account manager |
| 207 | Report Execution only, when several ids were sent and at least one failed — check data.results[] | Retry only the ids that failed |
| 404 | Attach: eStampId not found or does not belong to you. Report Execution: the single userDocumentId sent is not found or not yours | Verify the id via Get Procured E-Stamps |
| 429 | Rate limit exceeded | Back off and retry |
| 500 | Unexpected error | See the retry rule below — do not always assume it's safe to retry blind |
Common validation messages:
| Message | Cause |
|---|---|
| Consideration price is required for article 'X'. | CONSIDERATION_PRICE article sent without considerationPrice |
| Consideration price must be between A and B for article 'X'. | considerationPrice outside the article's range |
| Stamp duty amount must be between A and B for article 'X'. | stampDutyAmount outside minDuty–maxDuty |
| Stamp duty amount must be a whole number (no decimals), e.g. 100, 500, 1000. | Decimal duty amount |
| Stamp duty paid by must match the first party or second party name. | stampDutyPaidBy matches neither party |
| Both party details are required for article 'X'. Please provide secondParty.name. | bothPartyRequired article missing a party |
| firstParty.pan is required when stampDutyAmount is greater than ₹2,00,000. | Payer's PAN missing above ₹2,00,000 |
| Article code 'N' belongs to state 'XX', not 'YY'. | articleCode taken from a different state |
| Validation Error: webhookUrl is required. … | No webhookUrl and none configured for your app |
| Validation Error: The 'ReferenceId' passed in the request already exists. | referenceId reused |
Safe retry rule — read this before wiring up automatic retries. Not every non-200 means nothing happened:
- 400 / 401 / 402 / 429 — nothing was created, safe to fix-and-retry with a new
referenceId.- 500, or no response at all (a client-side timeout) — the request may have already succeeded on our side before your connection dropped or timed out. Blindly retrying with a new
referenceIdcan create — and charge for — a second stamp for a request that actually went through. Before retrying, check whether the originalreferenceIdalready produced a result (a webhook that arrived late, or Get Procured E-Stamps for the template flow) rather than assuming it failed.- 202 is not in either bucket — it is not a failure at all. See the row above.
This is exactly why
referenceIdexists: reconcile on it before you resend the same operation.
FAQ
Q. Does the Generate API also get the document signed?
No. Generation and signing are separate. Generate only produces the stamped document; to collect signatures, pass the returned documentId to the eSign API.
Q. Is eSign mandatory to procure a stamp? No. A stamp is procured — valid and charged — as soon as Generate returns success. eSign is how the document gets signed; when it is signed through SignCare eSign, execution is also reported to SHCIL automatically.
Q. Do you send document links in responses or webhooks?
No — the document is always delivered inline as base64FileData. Nothing is exposed via public links.
Q. Can I attach one e-Stamp to multiple documents?
No. One e-Stamp = one document. After attach, the stamp is CONSUMED.
Q. Can I reuse a referenceId?
Never. It's your idempotency/correlation key — one per request, across Generate and Attach alike.
Q. How do I know whether considerationPrice is required?
Check the article's stampDutyType in Master Details. For CONSIDERATION_PRICE it is required and must sit between minConsiderationPrice and maxConsiderationPrice. For any other type it is optional.
Q. When do I need to send both parties?
When the article has bothPartyRequired: true — both firstParty and secondParty, each with name and mobile. Otherwise one party is enough, as long as stampDutyPaidBy names a party you sent.
Q. Do I have to call the Report Execution API?
Only if you sign outside SignCare and set selfReportExecution: true on Generate. Signing through SignCare eSign reports automatically, and with the default selfReportExecution: false SignCare reports for you after a grace period.
Q. Do I have to store eStampId myself?
It's recommended, but not required — anything procured and not yet attached is always retrievable from Get Procured E-Stamps.
Q. The articleCode I used worked for one state but is rejected for another. Why?
Article codes are unique per state. The same numeric code can mean a different article in another state — always select the article entry matching your stateCode.
Q. Several articles have the same name. Which one do I pick?
Many entries share one legal article (articleNumber and articleName). Each has its own articleCode — that is what identifies the exact entry. Send the articleCode of the one you want.
Q. What is reconMappingId for?
It's an auto-generated correlation key tied to the stamp. Quote it (along with referenceId) in any support or reconciliation conversation.
Q. Which states/articles are supported? Whatever the Master Details API returns — it is the live source of truth. Don't hardcode the lists.
Q. I got a 202. Did my request fail?
No — 202 means it's still processing, not that it failed. It happens when generation is taking
longer than usual, or always when you sent isAsync: true. Wait for the webhook; don't retry the
same referenceId. See Slow Generation and the 202 Response.
Q. What does isAsync do, and should I use it?
It is optional and defaults to false (the API waits up to ~40 seconds and answers with the stamp). Set it to
true if you want an immediate 202 and prefer to receive every result on your webhook — or to test your 202
handling. It needs a webhook. Request errors are still returned immediately as 4xx. See
Asking for the 202 on purpose.
Q. My request timed out on my end (or I never got a response) — is it safe to retry?
Not automatically. Unlike a clean 400/401/402/429, a timeout or a 500 doesn't tell you whether the
stamp was actually generated on our side before your connection dropped. Check the webhook or
Get Procured E-Stamps for that referenceId first — if it already succeeded, retrying with a new
referenceId creates and charges for a second stamp.
Q. Is a webhook actually required?
Yes — either webhookUrl on the request or a webhook configured for your app. It is the only
delivery channel when a request returns 202; there is no separate status-check API.
Returns SHCIL master reference data, split into template and PDF generation flows.
The response contains three lists:
→ templateArticles: use these for template generation. Every article here has
articleType: "SYSTEM". Send the selected articleCode with populated
fields to the Generate E-Stamp API.
→ pdfArticles: use these for PDF generation. Every article here has
articleType: "CUSTOM". Send the selected articleCode with
documentInfo (base64 PDF) to the Generate E-Stamp API.
→ An article that supports both ways of stamping simply appears in both lists under
the same articleCode — pick whichever list matches how you want to stamp. You never
have to interpret a combined value.
→ states: the states supported for SHCIL stamping. Only these state codes are accepted by the Generate E-Stamp API.
→ templateArticles and pdfArticles: articles available in the supported states.
Choose an article from the appropriate list and pass its articleCode to the
Generate E-Stamp API. Fields with no value are omitted from the response.
states — entity fields:
| Field | Type | Description |
|---|---|---|
| stateName | string | Display name of the state (e.g. "Assam"). |
| stateCode | string | Two-letter state code (e.g. "AS"). Pass this in stampDetails.stateCode of the Generate E-Stamp API. |
templateArticles and pdfArticles — article fields:
| Field | Type | Description |
|---|---|---|
| stateCode | string | Two-letter state code the article belongs to. Matches an entry in the states list. |
| articleNumber | string | Stamp article number under the state's Stamp Act (e.g. "4" for Affidavit). Omitted when no mapping is available for the state. |
| articleCode | number | Unique code of the article. Pass this in stampDetails.articleCode of the Generate E-Stamp API. |
| articleName | string | Name/category of the article (e.g. "Affidavit", "Agreement"). |
| articleDescription | string | Description of the article. In pdfArticles it is the generic legal description of the article (e.g. "Affidavit"). In templateArticles it also carries the specific template name (e.g. "Affidavit - Bharat Gas" vs "Affidavit - Domicile"), so display it to tell templates of one article apart. Omitted when unavailable. |
| minDuty | string | Minimum stamp duty (INR) allowed for this article. stampDetails.stampDutyAmount must not be below this. |
| maxDuty | string | Maximum stamp duty (INR) allowed for this article. stampDetails.stampDutyAmount must not exceed this. |
| articleType | string | Only two values are returned: SYSTEM = template flow (send fields), CUSTOM = PDF flow (send documentInfo). Always matches the list the article appears in, so it confirms which payload to send. |
| stampDutyType | string | How stamp duty is calculated for this article — STAMP_DUTY_RANGE (fixed range between minDuty/maxDuty) or CONSIDERATION_PRICE (percentage of the transaction value; see considerationPercentage). |
| considerationPercentage | string | Percentage of the consideration price used to compute stamp duty when stampDutyType is CONSIDERATION_PRICE; not meaningful otherwise. |
| minConsiderationPrice | string | Calculated by us, not returned by SHCIL. Only present for CONSIDERATION_PRICE articles: the transaction value at which minDuty is the resulting stamp duty (minDuty × 100 / considerationPercentage). A guide, not a guarantee — SHCIL's own validation at generate time is authoritative. |
| maxConsiderationPrice | string | Calculated by us, not returned by SHCIL. Only present for CONSIDERATION_PRICE articles when maxDuty is present (maxDuty × 100 / considerationPercentage); omitted when maxDuty is blank, meaning SHCIL places no upper bound. A guide, not a guarantee — SHCIL's own validation at generate time is authoritative. |
| bothPartyRequired | boolean | true means the Generate E-Stamp API needs both firstParty and secondParty (name and mobile) for this article. false means one party is enough, or the article has not been verified yet. |
stampDutyType values, and when considerationPercentage applies:STAMP_DUTY_RANGE — a fixed stamp duty is charged for this article,
independent of the transaction value (typical for affidavits, general agreements,
etc.). Pick any stampDutyAmount between minDuty and maxDuty when
calling the Generate E-Stamp API. considerationPercentage does not apply here —
SHCIL always returns "0" for these articles; ignore it.CONSIDERATION_PRICE — stamp duty is a percentage of the transaction value
(typical for loan agreements, sale deeds, and other value-based documents).
considerationPercentage is that rate — e.g. "0.5" means 0.5% of the
transaction value. Pass the transaction value in
stampDetails.considerationPrice, and compute:
stampDutyAmount = considerationPrice × (considerationPercentage / 100)
The result must still fall within `minDuty`/`maxDuty` when either is
present.</item></list><b>Worked example</b> — article returns `stampDutyType = "CONSIDERATION_PRICE"`,
minDuty = "5000", maxDuty = "" (no upper bound),
considerationPercentage = "0.5". We calculate and return
minConsiderationPrice = "1000000" (₹10,00,000 is the smallest transaction value
that still charges the ₹5,000 minimum duty); maxConsiderationPrice is omitted since
maxDuty is blank. For a ₹10,00,000 loan: send
considerationPrice = 1000000 and stampDutyAmount = 5000
(0.5% of ₹10,00,000).
This data is used to:
- Populate the State and Article dropdowns
- Identify the articleCode to send in stampDetails to the Generate E-Stamp API
- Determine article numbers and stamp duty limits
Headers
- X-API-KEYstringrequiredYour secret API key for the environment you are calling (Stage and Live use different keys).
- X-API-APP-IDstringrequiredThe App ID issued together with the key.
Responses
200OK
- successbooleanoptionalNo description.
- statusCodeinteger (int32)optionalNo description.default 200
- messagestringoptionalNo description.nullabledefault XXXXX
- dataobjectoptionalTrimmed master reference data: supported states + articles split by flow.
3 fields
- statesarray<object>optionalStates supported for SHCIL stamping — the only states accepted by the Generate API.nullable
Each item: 2 fields
- stateNamestringoptionalNo description.nullable
- stateCodestringoptionalTwo-letter state code (e.g. "AS", "DL") — use this in the Generate API.nullable
- templateArticlesarray<object>optionalArticles for the template flow — every row has articleType "SYSTEM". Pass the article's articleCode and filled template fields to the Generate API.nullable
Each item: 13 fields
- stateCodestringoptionalTwo-letter state code the article belongs to.nullable
- articleNumberstringoptionalStamp article number (omitted when unmapped).nullable
- articleCodeinteger (int32)optionalArticle code — pass this as `stampDetails.articleCode` to the Generate API. Unique per state, not globally.
- articleDescriptionstringoptionalFull original name of the article as per StockHolding; omitted when unavailable.nullable
- articleNamestringoptionalArticle name (category).nullable
- minDutystringoptionalMinimum stamp duty for this template.nullable
- maxDutystringoptionalMaximum stamp duty for this template.nullable
- articleTypestringoptionalOnly two values are returned: "SYSTEM" (template flow — send fields) and "CUSTOM" (pdf flow — send documentInfo). Always matches the list the article appears in, so it confirms which payload the Generate API expects.nullable
- stampDutyTypestringoptionalHow stamp duty is calculated for this article — e.g. "STAMP_DUTY_RANGE" (fixed range between MinDuty/MaxDuty) or "CONSIDERATION_PRICE" (percentage of the transaction value; see ConsiderationPercentage).nullable
- considerationPercentagestringoptionalPercentage of the consideration price used to compute stamp duty when StampDutyType is "CONSIDERATION_PRICE"; not meaningful otherwise.nullable
- minConsiderationPricestringoptionalCALCULATED BY US — not returned by SHCIL. Only present when StampDutyType is "CONSIDERATION_PRICE" and ConsiderationPercentage is a valid non-zero number: the smallest transaction value (considerationPrice) for which MinDuty is the resulting stamp duty, i.e. MinDuty × 100 / ConsiderationPercentage. A guide, not a guarantee — SHCIL's own validation at generate time is authoritative.nullable
- maxConsiderationPricestringoptionalCALCULATED BY US — not returned by SHCIL. Only present when StampDutyType is "CONSIDERATION_PRICE", ConsiderationPercentage is a valid non-zero number, and MaxDuty is present (SHCIL sometimes leaves MaxDuty blank, meaning "no upper bound" — in that case this is omitted too): MaxDuty × 100 / ConsiderationPercentage. A guide, not a guarantee — SHCIL's own validation at generate time is authoritative.nullable
- bothPartyRequiredbooleanoptionalTrue when this article requires BOTH firstParty and secondParty at generate time; false when only one party is required OR the article hasn't been verified yet (defaults to false when unclassified — NOT a confirmed "no"). NOT returned by SHCIL.
- pdfArticlesarray<object>optionalArticles for the PDF/upload flow — every row has articleType "CUSTOM". Pass the article's articleCode and documentInfo (base64-encoded PDF) to the Generate API.nullable
Each item: 13 fields
- stateCodestringoptionalTwo-letter state code the article belongs to.nullable
- articleNumberstringoptionalStamp article number (omitted when unmapped).nullable
- articleCodeinteger (int32)optionalArticle code — pass this as `stampDetails.articleCode` to the Generate API. Unique per state, not globally.
- articleDescriptionstringoptionalFull original name of the article as per StockHolding; omitted when unavailable.nullable
- articleNamestringoptionalArticle name (category).nullable
- minDutystringoptionalMinimum stamp duty for this template.nullable
- maxDutystringoptionalMaximum stamp duty for this template.nullable
- articleTypestringoptionalOnly two values are returned: "SYSTEM" (template flow — send fields) and "CUSTOM" (pdf flow — send documentInfo). Always matches the list the article appears in, so it confirms which payload the Generate API expects.nullable
- stampDutyTypestringoptionalHow stamp duty is calculated for this article — e.g. "STAMP_DUTY_RANGE" (fixed range between MinDuty/MaxDuty) or "CONSIDERATION_PRICE" (percentage of the transaction value; see ConsiderationPercentage).nullable
- considerationPercentagestringoptionalPercentage of the consideration price used to compute stamp duty when StampDutyType is "CONSIDERATION_PRICE"; not meaningful otherwise.nullable
- minConsiderationPricestringoptionalCALCULATED BY US — not returned by SHCIL. Only present when StampDutyType is "CONSIDERATION_PRICE" and ConsiderationPercentage is a valid non-zero number: the smallest transaction value (considerationPrice) for which MinDuty is the resulting stamp duty, i.e. MinDuty × 100 / ConsiderationPercentage. A guide, not a guarantee — SHCIL's own validation at generate time is authoritative.nullable
- maxConsiderationPricestringoptionalCALCULATED BY US — not returned by SHCIL. Only present when StampDutyType is "CONSIDERATION_PRICE", ConsiderationPercentage is a valid non-zero number, and MaxDuty is present (SHCIL sometimes leaves MaxDuty blank, meaning "no upper bound" — in that case this is omitted too): MaxDuty × 100 / ConsiderationPercentage. A guide, not a guarantee — SHCIL's own validation at generate time is authoritative.nullable
- bothPartyRequiredbooleanoptionalTrue when this article requires BOTH firstParty and secondParty at generate time; false when only one party is required OR the article hasn't been verified yet (defaults to false when unclassified — NOT a confirmed "no"). NOT returned by SHCIL.
- messagesarray<string>optionalNo description.nullable
- request_idstringoptionalNo description.nullable
- isBillablebooleanoptionalWhether this request was charged: true if it was, false if not. Errors always show false. Flows that finish later (ITR Fetch, SHCIL eStamp, DigiLocker, eSign) show false here, because the charge is made when the result is ready. eSign charges each signer when they complete signing. DigiLocker deducts the credit when the link is created and refunds it automatically if the link expires before the user completes it.
400Bad Request
- dataobjectoptionalNo description.
- messagesarray<string>optionalNo description.nullable
- request_idstringoptionalNo description.nullable
- successbooleanoptionalNo description.default false
- messagestringoptionalNo description.nullabledefault XXXXX
- isBillablebooleanoptionalNo description.
- statusCodeinteger (int32)optionalNo description.default 400
401Unauthorized
- dataobjectoptionalNo description.
- messagesarray<string>optionalNo description.nullable
- request_idstringoptionalNo description.nullable
- successbooleanoptionalNo description.default false
- messagestringoptionalNo description.nullabledefault XXXXX
- isBillablebooleanoptionalNo description.
- statusCodeinteger (int32)optionalNo description.default 401
429Too Many Requests
- successbooleanoptionalNo description.
- statusCodeinteger (int32)optionalNo description.default 200
- messagestringoptionalNo description.nullabledefault XXXXX
- dataanyoptionalNo description.nullable
- messagesarray<string>optionalNo description.nullable
- request_idstringoptionalNo description.nullable
- isBillablebooleanoptionalWhether this request was charged: true if it was, false if not. Errors always show false. Flows that finish later (ITR Fetch, SHCIL eStamp, DigiLocker, eSign) show false here, because the charge is made when the result is ready. eSign charges each signer when they complete signing. DigiLocker deducts the credit when the link is created and refunds it automatically if the link expires before the user completes it.
500Internal Server Error
- dataobjectoptionalNo description.
- messagesarray<string>optionalNo description.nullable
- request_idstringoptionalNo description.nullable
- successbooleanoptionalNo description.default false
- messagestringoptionalNo description.nullabledefault XXXXX
- isBillablebooleanoptionalNo description.
- statusCodeinteger (int32)optionalNo description.default 500
Code samplescurl · Node.js · Python
Retrieve the complete structure of a document template using the articleCode.
This API returns the complete structure of a document template, including:
→ Template metadata.
→ HTML content used for document preview/rendering.
→ All dynamic fields that must be populated before generating an E-Stamp document.
The articleCode is obtained from the Get Master Details API.
Each returned field corresponds to a placeholder inside the HTML (e.g. span{id}), and the populated values must be sent to the Generate E-Stamp Document API.
Path Parameter:
→ articleCode (required, integer): The articleCode of the template for which fields are needed,
a positive integer taken from templateArticles[].articleCode of the Master Details API.
The articleCode must be provided as a path parameter in the request URL
(e.g., /api/v1/StockHoldingEStamp/template/fields/22, where 22 is the articleCode).
Headers
- X-API-KEYstringrequiredYour secret API key for the environment you are calling (Stage and Live use different keys).
- X-API-APP-IDstringrequiredThe App ID issued together with the key.
Path parameters
- articleCodeinteger (int32)requiredRequired. Article code (positive integer) from the Master Details API (templateArticles).
Responses
200OK
- successbooleanoptionalNo description.
- statusCodeinteger (int32)optionalNo description.default 200
- messagestringoptionalNo description.nullabledefault XXXXX
- dataobjectoptionalTemplate fields response from GetTemplateFields API.
4 fields
- idinteger (int32)optionalNo description.
- articleTemplateNamestringoptionalNo description.nullable
- htmlstringoptionalNo description.nullable
- fieldsarray<object>optionalNo description.nullable
Each item: 5 fields
- sectionGroupNamestringoptionalNo description.nullable
- idinteger (int32)optionalNo description.
- fieldNamestringoptionalNo description.nullable
- fieldTypestringoptionalTEXT | TEXTAREA | NUMBER | DROPDOWN | STRING_DATE | MULTISELECTnullable
- propsobjectoptionalNo description.
10 fields
- prefilledstringoptionalNo description.nullable
- mandatorystringoptionalNo description.nullable
- maxLengthstringoptionalMaximum character length. JSON key: maxlength (lowercase).nullable
- minLengthstringoptionalMinimum character length. JSON key: minlength (lowercase).nullable
- optionsstringoptionalNo description.nullable
- minDatestringoptionalMinimum selectable date (dd/MM/yyyy). JSON key: minDate.nullable
- maxDatestringoptionalMaximum selectable date (dd/MM/yyyy). JSON key: maxDate.nullable
- multiplestringoptionalWhen "true", the field appears at multiple locations in the document (span duplicates).nullable
- hiddenstringoptionalWhen "true", the field is hidden in the UI (system-managed).nullable
- dependentstringoptionalJSON string specifying a dependent field. Format: {"id": fieldId, "value": "duplicate"}. When present, this field's value is copied into the dependent field automatically.nullable
- messagesarray<string>optionalNo description.nullable
- request_idstringoptionalNo description.nullable
- isBillablebooleanoptionalWhether this request was charged: true if it was, false if not. Errors always show false. Flows that finish later (ITR Fetch, SHCIL eStamp, DigiLocker, eSign) show false here, because the charge is made when the result is ready. eSign charges each signer when they complete signing. DigiLocker deducts the credit when the link is created and refunds it automatically if the link expires before the user completes it.
400Bad Request
- dataobjectoptionalNo description.
- messagesarray<string>optionalNo description.nullable
- request_idstringoptionalNo description.nullable
- successbooleanoptionalNo description.default false
- messagestringoptionalNo description.nullabledefault XXXXX
- isBillablebooleanoptionalNo description.
- statusCodeinteger (int32)optionalNo description.default 400
401Unauthorized
- dataobjectoptionalNo description.
- messagesarray<string>optionalNo description.nullable
- request_idstringoptionalNo description.nullable
- successbooleanoptionalNo description.default false
- messagestringoptionalNo description.nullabledefault XXXXX
- isBillablebooleanoptionalNo description.
- statusCodeinteger (int32)optionalNo description.default 401
429Too Many Requests
- successbooleanoptionalNo description.
- statusCodeinteger (int32)optionalNo description.default 200
- messagestringoptionalNo description.nullabledefault XXXXX
- dataanyoptionalNo description.nullable
- messagesarray<string>optionalNo description.nullable
- request_idstringoptionalNo description.nullable
- isBillablebooleanoptionalWhether this request was charged: true if it was, false if not. Errors always show false. Flows that finish later (ITR Fetch, SHCIL eStamp, DigiLocker, eSign) show false here, because the charge is made when the result is ready. eSign charges each signer when they complete signing. DigiLocker deducts the credit when the link is created and refunds it automatically if the link expires before the user completes it.
500Internal Server Error
- dataobjectoptionalNo description.
- messagesarray<string>optionalNo description.nullable
- request_idstringoptionalNo description.nullable
- successbooleanoptionalNo description.default false
- messagestringoptionalNo description.nullabledefault XXXXX
- isBillablebooleanoptionalNo description.
- statusCodeinteger (int32)optionalNo description.default 500
Code samplescurl · Node.js · Python
Create and generate an E-Stamp certificate using a selected article template or your own uploaded document.
This API generates an E-Stamp certificate.
→ A URN and a reconMappingId are generated automatically and returned in the response.
→ On success, the certificate details are returned in the response and also delivered to your webhook.
Two ways to generate:
The Master Details API returns articles in two lists, and each article's
articleType tells you which flow to use:
→ Pdf flow (articleType = CUSTOM, from pdfArticles): send your own document in
documentInfo and the e-Stamp is applied to it. fields must be null.
→ Template flow (articleType = SYSTEM, from templateArticles): send the
article's field values in fields (field ids from the Fields-By-Template API) and the
document is generated from the template. documentInfo must be null.
→ An article that works with either flow appears in both lists under the same
articleCode — just take it from the list matching the flow you want.
How to consume:
-
Call the Master Details API to get the supported states and articles — pick the article from
templateArticlesorpdfArticlesdepending on the flow you want. -
Call this API with the party details, the selected
stateCode+articleCodeinstampDetails, and eitherdocumentInfo(pdf flow) orfields(template flow). -
Read the certificate details from the response — the same stamp details are also delivered to your webhook.
-
Pdf flow: to get the stamped document signed, call the eSign API with the
documentIdreturned in the response. -
Template flow: attach the generated e-Stamp onto your own PDF using the Attach E-Stamp API with the
eStampIdreturned in the response.
Request Body — entity fields:
| Field | Type | Required | Description |
|---|---|---|---|
| referenceId | string | required | Your unique reference id for this request (1-64 chars: letters, numbers, hyphen, underscore). Must not have been used before by any Generate or Attach request. |
| selfReportExecution | boolean | optional | Who reports the document's execution to SHCIL when it is not signed through SignCare eSign. false (default): SignCare reports it. true: you report it with the Report Execution API. See "Execution Reporting" below. |
| documentInfo | object | conditional | The document to be stamped. Required for the pdf flow (CUSTOM articles); must be null in the template flow. |
| documentInfo.name | string | required | File name with extension (e.g. "Loan Agreement.pdf"). |
| documentInfo.content | string | required | Base64-encoded PDF or DOCX, max 5 MB. |
| fields | array | conditional | Field values for the article — required for the template flow (SYSTEM articles); must be null in the pdf flow. Each field id may appear only once; ids not in the article's template are rejected. |
| fields[].id | string | required | Field id from the Fields-By-Template API (send it as a string, e.g. "1024"). |
| fields[].value | string | required | Value to populate in the document. Checked against the field's rules: mandatory fields must be filled, NUMBER must be numeric, DATE_PICKER must be dd/MM/yyyy and not before minDate, DROPDOWN must be one of the options, TEXT/TEXTAREA must fit maxLength. |
| firstParty | object | conditional | First party details. Required when the first party pays the stamp duty, or when the article has bothPartyRequired: true. At least one of firstParty or secondParty must be provided. |
| firstParty.name | string | conditional | First party full name. Required when firstParty is provided. |
| firstParty.mobile | string | conditional | Exactly 10 digits. Required when the first party pays the stamp duty, or when the article has bothPartyRequired: true. |
| firstParty.pan | string | conditional | PAN (10 chars, format AAAAA9999A, e.g. ABCDE1234F). Required when the first party pays and stampDutyAmount exceeds ₹2,00,000. |
| secondParty | object | conditional | Second party details. Required when the second party pays the stamp duty, or when the article has bothPartyRequired: true. At least one of firstParty or secondParty must be provided. |
| secondParty.name | string | conditional | Second party full name. Required when secondParty is provided. |
| secondParty.mobile | string | conditional | Exactly 10 digits. Required when the second party pays the stamp duty, or when the article has bothPartyRequired: true. |
| secondParty.pan | string | conditional | PAN (10 chars, format AAAAA9999A, e.g. ABCDE1234F). Required when the second party pays and stampDutyAmount exceeds ₹2,00,000. |
| stampDetails | object | required | Stamp-specific details. |
| stampDetails.stateCode | string | required | Two-letter state code (e.g. "AS"). Must be one of the supported states from the Master Details API. |
| stampDetails.articleCode | integer | required | The articleCode value from the Master Details API, for the same state. Article codes are unique per state, not globally. |
| stampDetails.stampDutyAmount | integer | required | Stamp duty amount in INR, a whole number greater than zero. Decimals and fractional notation are rejected. Must be within the article's minDuty/maxDuty range. |
| stampDetails.stampDutyPaidBy | string | required | Name of the duty payer. Must exactly match firstParty.name or secondParty.name (case-insensitive). |
| stampDetails.considerationPrice | number | conditional | Transaction value in INR. Required for articles whose stampDutyType is CONSIDERATION_PRICE (and then it must be between minConsiderationPrice and maxConsiderationPrice); optional for other articles. Never negative. |
| stampDetails.documentDescription | string | optional | Property or document description printed on the certificate. Max 100 characters; letters, numbers and spaces only. |
| webhookUrl | string | conditionally required | Use an HTTPS URL for the final result. The request value has priority. If omitted or blank, the webhook configured for your app is used. At least one must be available; otherwise validation fails before acceptance, charging, or the SHCIL call. |
| isAsync | boolean | optional | Default false. false: the API waits up to about 40 seconds and answers with the stamp (200); only when SHCIL is slow does it answer 202. true: the API does not wait — after validating and accepting the request it answers 202 immediately and the result is delivered to your webhook. See "Getting the result later (isAsync)" below. |
Response — entity fields:
| Field | Type | Description |
|---|---|---|
| referenceId | string | The unique reference id you passed in the request. |
| eStampId | string (uuid) | Unique id of the generated e-Stamp. Keep this for reference and support queries. |
| documentId | string (uuid) | Unique id of the stamped document (pdf flow; omitted in the template flow). Pass this id to the eSign API to send the document for signature. |
| userDocumentId | number | SHCIL document id. Pass it in userDocumentIds of the Report Execution API if you report execution yourself; quote it in support queries. |
| reconMappingId | string | Auto-generated correlation key. Quote this in support and reconciliation queries. |
| status | string | Status of the e-Stamp (e.g. COMPLETED, CONSUMED). |
| certId | string | Certificate id issued by SHCIL. |
| urn | string | Unique reference number of the e-Stamp. |
| certificateNo | string | Certificate number printed on the stamp. |
| certificateIssuedDate | string | Certificate issue date and time. |
| base64FileData | string | Base64-encoded generated PDF — the stamped document (pdf flow) or the e-Stamp certificate (template flow). |
Fields with no value are omitted from the response.
Next step — signing the stamped document (pdf flow):
This API only generates the e-Stamp — it does not initiate any signature. To get the stamped document signed, call the eSign API with the documentId returned in this response. The eSign API sends the signing request to your signers, and each signer receives a link to complete the signature on the stamped document.
Execution Reporting — what it is and why it is required:
StockHolding (SHCIL) issues the e-Stamp certificate at the moment it is generated, but the certificate on its own does not record that the document was ever actually executed. SHCIL requires execution to be confirmed back against the certificate once the parties have signed it — the document reference and how many signatories signed. This is what keeps the issued certificate and the executed document consistent in SHCIL's records, and it is expected for every stamp that gets used.
The selfReportExecution field on this request decides who sends that confirmation:
Left as false (default) — SignCare submits the confirmation for you, so there is nothing further to integrate.
Set to true — you submit the confirmation yourself by calling Report Execution
(POST /api/v1/StockHoldingEStamp/consume/report) after the document has actually been
executed. Choose this when the exact signatory count or execution date matters to you, or
when signing happens on your side and only you know when it completed.
If the document is signed through SignCare eSign, the confirmation is sent automatically when the last signer completes — whatever this field is set to. It only decides what happens when signing takes place outside SignCare.
Getting the result later (isAsync):
By default (isAsync: false) this API waits up to about 40 seconds for SHCIL and answers with the stamp (200).
Set isAsync: true if you would rather not wait:
→ The request is validated first. Any problem (missing fields, wrong article, insufficient wallet…) is still returned immediately as a normal 4xx.
→ If it is valid, the API accepts it and answers 202 at once with referenceId, reconMappingId and
status: "ACCEPTED". There is no stamp in that response.
→ The stamp is generated in the background. When it is ready (or if it fails) the result is POSTed to your webhook — the
same payload as described below. A webhook URL is therefore needed: send webhookUrl or configure one for your app.
→ Do not send the request again for the same referenceId: sending it again while it is still being processed
just returns the same 202, and after it finished it is rejected as a duplicate.
The same 202 can also reach you without the flag, on a slow SHCIL day. Handle it the same way: wait for the webhook.
Webhook Delivery:
Once processing is complete, the generated stamp details are POSTed to the selected URL
as JSON — the same fields as this API's response
(referenceId, eStampId, documentId, userDocumentId, reconMappingId, status, certId, urn,
certificateNo, certificateIssuedDate, base64FileData). When you send
isAsync: true, or when StockHolding takes longer than the sync wait window, the webhook
becomes the delivery channel — see the 202 response below.
This is not just a courtesy notification — for any request that returned 202, the webhook is the only place the outcome is delivered. There is no separate status-check endpoint. Make sure webhookUrl is set (directly, or configured for your app) before relying on this path.
Webhook payload — success (same shape as this API's 200 response):
{
"success": true,
"statusCode": 200,
"message": "Success",
"data": {
"referenceId": "LOAN-2026-000123",
"eStampId": "0d1f7f5e-...",
"documentId": "8c2a41d9-...",
"userDocumentId": 123456,
"reconMappingId": "SC0000000000000ABCDE",
"status": "COMPLETED",
"certId": "IN-AS12345678901234X",
"urn": "...",
"certificateNo": "...",
"certificateIssuedDate": "10-Jul-2026 11:42:05",
"base64FileData": ""
}
}
Webhook payload — failure (sent when a 202 request ultimately fails; nothing was
generated and nothing was charged — eStampId/documentId/certificate fields are all absent):
{
"success": false,
"statusCode": 422,
"message": "eStamp generation failed. Please try again.",
"data": {
"referenceId": "LOAN-2026-000123",
"status": "FAILED",
"errorMessage": "eStamp generation failed. Please try again."
}
}
Respond with HTTP 2xx to acknowledge. Treat deliveries as at-least-once and de-duplicate on referenceId/eStampId. A webhook is sent after persistence, so a 202 response does not mean the stamp already exists; wait for the final webhook payload.
Headers
- X-API-KEYstringrequiredYour secret API key for the environment you are calling (Stage and Live use different keys).
- X-API-APP-IDstringrequiredThe App ID issued together with the key.
- Content-Typestringrequiredapplication/json
Body parameters
application/json- selfReportExecutionbooleanoptionalOptional. Who reports execution of this stamp back to SHCIL. Defaults to false. SHCIL requires the execution of a stamped document to be confirmed against the certificate once the parties have signed it — the document reference and the number of signatories. This field tells us who will send that confirmation. <b>false (default)</b> — SignCare sends the confirmation for you. Choose this if you do not want to make an extra API call. <b>true</b> — you will send the confirmation yourself by calling `POST /api/v1/StockHoldingEStamp/consume/report` after the document has actually been executed. Recommended when the exact signatory count or execution date matters to you, or when signing is completed outside SignCare and only you know when it happened. If the document is signed through SignCare eSign, the confirmation is sent automatically when the last signer completes, whatever this field is set to. It only decides what happens when signing takes place outside SignCare.
- referenceIdstringrequiredRequired. Your unique reference id for this request (1-64 chars: A-Z a-z 0-9 - _). Must be unique across every Generate and Attach request — a request with an already-used referenceId is rejected.minLength 1maxLength 64pattern ^[a-zA-Z0-9-_]{1,64}$
- documentInfoobjectoptionalThe customer's document to be stamped — file name + base64 content.
2 fields
- namestringrequiredRequired. File name including extension (e.g. "Loan Agreement.pdf"). Attach APIs require a name ending in .pdf.minLength 1default Loan Agreement.pdf
- contentstringrequiredRequired. Base64-encoded file content (PDF or DOCX, max 5 MB). Attach APIs accept PDF only.minLength 1
- firstPartyobjectoptionalA party to the stamped document (first or second party).
3 fields
- namestringconditionalConditional: required whenever the party object is sent. Full name of the party.nullabledefault Rahul Sharma
- panstringconditionalConditional: required when this party pays the stamp duty and the stamp duty amount is greater than 2,00,000. 10-character PAN in the format AAAAA9999A. Validated whenever it is sent.nullablelength 10pattern ^[A-Z]{5}[0-9]{4}[A-Z]{1}$
- mobilestringconditionalConditional: required when this party pays the stamp duty (and for both parties when the article needs both). Exactly 10 digits.nullablelength 10pattern ^\d{10}$
- secondPartyobjectoptionalA party to the stamped document (first or second party).
3 fields
- namestringconditionalConditional: required whenever the party object is sent. Full name of the party.nullabledefault Rahul Sharma
- panstringconditionalConditional: required when this party pays the stamp duty and the stamp duty amount is greater than 2,00,000. 10-character PAN in the format AAAAA9999A. Validated whenever it is sent.nullablelength 10pattern ^[A-Z]{5}[0-9]{4}[A-Z]{1}$
- mobilestringconditionalConditional: required when this party pays the stamp duty (and for both parties when the article needs both). Exactly 10 digits.nullablelength 10pattern ^\d{10}$
- stampDetailsobjectrequiredStamp-specific details: state, article, duty and description.
6 fields
- stateCodestringrequiredRequired. Two-letter state code (e.g. "AS", "DL"). Must be a supported state from the Master Details API.length 2default AS
- articleCodeinteger (int32)requiredRequired. Article code from the Master Details API. Article codes are unique per state, so use the code listed for the same stateCode.default 7
- stampDutyAmountnumber (double)requiredRequired. Stamp duty amount in INR. Must be a whole number greater than zero — decimals are rejected. Must be within the article's minDuty and maxDuty. Validated in the handler (not via DataAnnotation) so every stampDutyAmount error uses the same clean response shape.default 1000
- stampDutyPaidBystringrequiredRequired. Name of the duty payer. Must match firstParty.name or secondParty.name (case-insensitive).minLength 1default Rahul Sharma
- considerationPricenumber (double)conditionalConditional: required for articles whose stampDutyType is CONSIDERATION_PRICE, and then it must be between the article's minConsiderationPrice and maxConsiderationPrice. Optional for other articles. Transaction value in INR. Never negative.nullable
- documentDescriptionstringoptionalOptional. Property or document description printed on the certificate. Max 100 characters; letters, numbers and spaces only.nullablemaxLength 100
- fieldsarray<object>conditionalConditional: required for the template flow (SYSTEM articles); must be null in the pdf flow (when documentInfo is provided). Article field values, one entry per template field (ids from the Template Fields API). Each field id may appear only once.nullable
Each item: 2 fields
- idstringrequiredRequired. Field id, sent as a string, from the Template Fields API (`fields[].id`). Must be a field of the article's template and used only once.minLength 1
- valuestringrequiredRequired. Value to populate in the document. Checked against the field's rules from the Template Fields API: mandatory, NUMBER must be numeric, DATE_PICKER must be dd/MM/yyyy and not before minDate, DROPDOWN must be one of the options, TEXT/TEXTAREA must fit maxLength.minLength 1
- webhookUrlstringconditionalConditional: required unless a webhook is configured for your app. The generated stamp details are POSTed to this URL. Use an HTTPS URL. The request value takes priority over the configured one.nullable
- isAsyncbooleanoptionalOptional. Defaults to false. <b>false (default)</b> — the API waits up to about 40 seconds for the stamp and answers with it (HTTP 200). Only when SHCIL is slow does it answer 202 instead, and the result then arrives on your webhook. <b>true</b> — the API does not wait. Once your request has been validated and accepted it answers <b>202 straight away</b> (no stamp in that response), and the stamp or the failure is delivered to your webhook. Use it when you prefer to handle every result on the webhook, or to test your 202 handling. Needs a webhook URL (this field or the one configured for your app). Request errors (missing fields, wrong article, insufficient wallet…) are still returned immediately as 4xx, because they are checked before the request is accepted.
Sample request body
Responses
200Stamp generated — full result, including base64FileData.
- successbooleanoptionalNo description.
- statusCodeinteger (int32)optionalNo description.default 200
- messagestringoptionalNo description.nullabledefault XXXXX
- dataobjectoptionalFlat response of the Generate E-Stamp API (external SHCIL flow). Certificate essentials in one level — the same stamp details are additionally delivered to the request's webhookUrl.
12 fields
- referenceIdstringoptionalThe unique reference id you passed in the request.nullable
- eStampIdstring (uuid)optionalSignCare eStamp record id — use this to reference the stamp itself (e.g. Phase 2). Omitted on a 202 (ACCEPTED) response — the stamp does not exist yet at that point.nullable
- documentIdstring (uuid)optionalSignCare Document id of the stored document (documentInfo flow); omitted for template flow.nullable
- userDocumentIdinteger (int64)optionalSHCIL document id — quote it in support queries and pass it to the Report Execution API. Omitted on a 202 (ACCEPTED) response — the stamp has not been created yet at that point.nullable
- reconMappingIdstringoptionalCorrelation key (client-supplied or auto-generated).nullable
- statusstringoptionalDocument status (e.g. COMPLETED, IN_PROCESS).nullable
- certIdstringoptionalNo description.nullable
- urnstringoptionalNo description.nullable
- certificateNostringoptionalNo description.nullable
- certificateIssuedDatestringoptionalNo description.nullable
- requestIdstringoptionalReserved. Not currently returned — the field is always omitted from the response.nullable
- base64FileDatastringoptionalBase64-encoded generated PDF — the stamped document (pdf flow) or the eStamp certificate (template flow). Omitted if the file could not be retrieved.nullable
- messagesarray<string>optionalNo description.nullable
- request_idstringoptionalNo description.nullable
- isBillablebooleanoptionalWhether this request was charged: true if it was, false if not. Errors always show false. Flows that finish later (ITR Fetch, SHCIL eStamp, DigiLocker, eSign) show false here, because the charge is made when the result is ready. eSign charges each signer when they complete signing. DigiLocker deducts the credit when the link is created and refunds it automatically if the link expires before the user completes it.
202Returned in two cases: (1) you sent isAsync: true — the request was accepted and is processed in the background, so you get this at once; (2) you did not, bu…same body as 200
Returned in two cases: (1) you sent isAsync: true — the request was accepted and is processed in the
background, so you get this at once; (2) you did not, but StockHolding takes longer than the sync wait window
(server-configured, currently ~40 seconds) to respond. Everything else about this API
(fields, validation, flows) stays exactly the same — this is just what you get back instead of the 200 shown above. Example body:
{
"data": {
"referenceId": "LOAN-2026-000123",
"reconMappingId": "SC0000000000000ABCDE",
"status": "ACCEPTED"
},
"messages": [],
"request_id": null,
"success": true,
"statusCode": 202,
"message": "Accepted. Generation is taking longer than usual — the result will be delivered to your webhookUrl. Do not retry this referenceId."
}
With isAsync: true the body is identical except for the message: "Accepted. As requested (isAsync), the stamp
is generated in the background and the result will be delivered to your webhookUrl. Do not retry this referenceId."
Why you got this instead of a 200: either you asked for it (isAsync: true), or the certificate is still
being generated — StockHolding hasn't answered yet. This is not an error and not something wrong with your
request.
What is NOT in this response: notice data only has referenceId,
reconMappingId and status. There is no eStampId, no certId, no
base64FileData — because the stamp does not exist yet at the moment this reply is
sent. (A 202 with status: "PENDING" means SHCIL is still completing a stamp that was
already created: eStampId and userDocumentId are present, and you are not
charged until it is ready.)
Where the real result shows up: it is POSTed later to your webhookUrl — see
the "Webhook payload — success / failure" examples above for the exact shape you'll
receive. There is no separate status-check API, so if webhookUrl is not set (on the
request or configured for your app), you will have no way to learn the outcome.
What to do: store this referenceId, stop calling this endpoint for it, and
wait for the webhook. Calling again with the same referenceId just returns another
202 (harmless). Calling again with a new referenceId starts a second, independent
generation — if both eventually succeed, you are charged twice.
400Invalid flow, unsupported state/article, invalid amount, unavailable webhook URL, or a referenceId that has already been used.
- dataobjectoptionalNo description.
- messagesarray<string>optionalNo description.nullable
- request_idstringoptionalNo description.nullable
- successbooleanoptionalNo description.default false
- messagestringoptionalNo description.nullabledefault XXXXX
- isBillablebooleanoptionalNo description.
- statusCodeinteger (int32)optionalNo description.default 400
401Unauthorized
- dataobjectoptionalNo description.
- messagesarray<string>optionalNo description.nullable
- request_idstringoptionalNo description.nullable
- successbooleanoptionalNo description.default false
- messagestringoptionalNo description.nullabledefault XXXXX
- isBillablebooleanoptionalNo description.
- statusCodeinteger (int32)optionalNo description.default 401
402Insufficient wallet balance, or API access not enabled for your app.
- successbooleanoptionalNo description.
- statusCodeinteger (int32)optionalNo description.default 200
- messagestringoptionalNo description.nullabledefault XXXXX
- dataanyoptionalNo description.nullable
- messagesarray<string>optionalNo description.nullable
- request_idstringoptionalNo description.nullable
- isBillablebooleanoptionalWhether this request was charged: true if it was, false if not. Errors always show false. Flows that finish later (ITR Fetch, SHCIL eStamp, DigiLocker, eSign) show false here, because the charge is made when the result is ready. eSign charges each signer when they complete signing. DigiLocker deducts the credit when the link is created and refunds it automatically if the link expires before the user completes it.
409Rare: two requests with the same referenceId arrived at the same moment. Treat it like a duplicate referenceId — do not retry with a new one until you have checked the first request's outcome.
429Rate limit exceeded.same body as 402
500Unexpected processing failure.
- dataobjectoptionalNo description.
- messagesarray<string>optionalNo description.nullable
- request_idstringoptionalNo description.nullable
- successbooleanoptionalNo description.default false
- messagestringoptionalNo description.nullabledefault XXXXX
- isBillablebooleanoptionalNo description.
- statusCodeinteger (int32)optionalNo description.default 500
Code samplescurl · Node.js · Python
Attach a generated E-Stamp onto your own PDF.
This API attaches an e-Stamp generated via the template flow onto your own PDF — the e-Stamp certificate pages are added to your document and the stamped document is created.
→ No additional stamp duty is charged — the duty was already paid when the e-Stamp was generated.
→ Each e-Stamp can be attached only once.
How to consume:
-
Generate an e-Stamp via the template flow of the Generate E-Stamp API and keep the
eStampIdfrom its response. -
Call this API with that
eStampId, your PDF indocumentInfo, and a new uniquereferenceId. -
Read the
documentIdfrom the response — to get the stamped document signed, call the eSign API with thisdocumentId.
Request Body — entity fields:
| Field | Type | Required | Description |
|---|---|---|---|
| referenceId | string | required | Your unique reference id for this request (1-64 chars: letters, numbers, hyphen, underscore). Must not have been used before by any Generate or Attach request. |
| eStampId | string (uuid) | required | The eStampId returned by the Generate E-Stamp API (template flow), or listed by the Get Procured E-Stamps API. It must belong to your account (otherwise 404) and must not already be attached. A stamp that belongs to a bulk batch is rejected — attach that whole batch with the Bulk Attach API using its batchId. |
| documentInfo | object | required | The PDF the e-Stamp will be attached to. |
| documentInfo.name | string | required | File name with extension; it must end in .pdf (e.g. "Loan Agreement.pdf"). |
| documentInfo.content | string | required | Base64-encoded PDF, max 5 MB. DOCX and other Office formats are not supported for attach. |
Response — entity fields:
| Field | Type | Description |
|---|---|---|
| referenceId | string | The unique reference id you passed in the request. |
| documentId | string (uuid) | Unique id of the stamped document. Pass this id to the eSign API to send the document for signature. |
| base64FileData | string | Base64-encoded stamped PDF (e-Stamp certificate pages + your document). |
Headers
- X-API-KEYstringrequiredYour secret API key for the environment you are calling (Stage and Live use different keys).
- X-API-APP-IDstringrequiredThe App ID issued together with the key.
- Content-Typestringrequiredapplication/json
Body parameters
application/json- referenceIdstringrequiredRequired. Your unique reference id for this request (1-64 chars: A-Z a-z 0-9 - _). Must be new — a referenceId already used by any earlier Generate or Attach request is rejected.minLength 1maxLength 64pattern ^[a-zA-Z0-9-_]{1,64}$
- eStampIdstring (uuid)requiredRequired. The eStampId (uuid) returned by the Generate E-Stamp API (template flow) or listed by the Get Procured E-Stamps API. The e-Stamp must belong to your account and must not already be attached.
- documentInfoobjectrequiredThe customer's document to be stamped — file name + base64 content.
2 fields
- namestringrequiredRequired. File name including extension (e.g. "Loan Agreement.pdf"). Attach APIs require a name ending in .pdf.minLength 1default Loan Agreement.pdf
- contentstringrequiredRequired. Base64-encoded file content (PDF or DOCX, max 5 MB). Attach APIs accept PDF only.minLength 1
Sample request body
Responses
200OK
- successbooleanoptionalNo description.
- statusCodeinteger (int32)optionalNo description.default 200
- messagestringoptionalNo description.nullabledefault XXXXX
- dataobjectoptionalResponse of the Attach eStamp API.
3 fields
- referenceIdstringoptionalThe unique reference id you passed in the request.nullable
- documentIdstring (uuid)optionalSignCare Document id of the stamped document. Pass this id to the eSign API to send it for signature.
- base64FileDatastringoptionalBase64-encoded stamped PDF (eStamp certificate pages + your document).nullable
- messagesarray<string>optionalNo description.nullable
- request_idstringoptionalNo description.nullable
- isBillablebooleanoptionalWhether this request was charged: true if it was, false if not. Errors always show false. Flows that finish later (ITR Fetch, SHCIL eStamp, DigiLocker, eSign) show false here, because the charge is made when the result is ready. eSign charges each signer when they complete signing. DigiLocker deducts the credit when the link is created and refunds it automatically if the link expires before the user completes it.
400Bad Request
- dataobjectoptionalNo description.
- messagesarray<string>optionalNo description.nullable
- request_idstringoptionalNo description.nullable
- successbooleanoptionalNo description.default false
- messagestringoptionalNo description.nullabledefault XXXXX
- isBillablebooleanoptionalNo description.
- statusCodeinteger (int32)optionalNo description.default 400
401Unauthorized
- dataobjectoptionalNo description.
- messagesarray<string>optionalNo description.nullable
- request_idstringoptionalNo description.nullable
- successbooleanoptionalNo description.default false
- messagestringoptionalNo description.nullabledefault XXXXX
- isBillablebooleanoptionalNo description.
- statusCodeinteger (int32)optionalNo description.default 401
404Not Found
- successbooleanoptionalNo description.
- statusCodeinteger (int32)optionalNo description.default 200
- messagestringoptionalNo description.nullabledefault XXXXX
- dataanyoptionalNo description.nullable
- messagesarray<string>optionalNo description.nullable
- request_idstringoptionalNo description.nullable
- isBillablebooleanoptionalWhether this request was charged: true if it was, false if not. Errors always show false. Flows that finish later (ITR Fetch, SHCIL eStamp, DigiLocker, eSign) show false here, because the charge is made when the result is ready. eSign charges each signer when they complete signing. DigiLocker deducts the credit when the link is created and refunds it automatically if the link expires before the user completes it.
429Too Many Requestssame body as 404
500Internal Server Error
- dataobjectoptionalNo description.
- messagesarray<string>optionalNo description.nullable
- request_idstringoptionalNo description.nullable
- successbooleanoptionalNo description.default false
- messagestringoptionalNo description.nullabledefault XXXXX
- isBillablebooleanoptionalNo description.
- statusCodeinteger (int32)optionalNo description.default 500
Code samplescurl · Node.js · Python
Get all procured single E-Stamps ready to be attached — use `eStampId` with the Attach API. Bulk-generated stamps are listed separately by the Get Bulk Procured E-Stamps API.
This API is your single-stamp inventory: every stamp procured with the Generate API and not yet attached to a document, newest first. Anything listed here is safe to attach; once attached it disappears from this list.
Next step:POST /api/v1/StockHoldingEStamp/attach — pass eStampId.
For stamps from the Bulk Generate API use POST /api/v1/StockHoldingEStamp/bulk-procured
and bulk-attach instead.
Response — entity fields:
| Field | Type | Description |
|---|---|---|
| count | number | Number of procured single stamps returned. |
| stamps | array | Procured single stamps, newest first. |
| stamps[].eStampId | string (uuid) | Unique id of the e-Stamp — pass to the Attach E-Stamp API. |
| stamps[].userDocumentId | number | SHCIL document id — pass in userDocumentIds of the Report Execution API. |
| stamps[].reconMappingId | string | Correlation key from generation time. |
| stamps[].status | string | Always COMPLETED — procured, ready to attach. |
| stamps[].certId | string | Certificate id issued by SHCIL. |
| stamps[].urn | string | Unique reference number. |
| stamps[].certificateIssuedDate | string | Certificate issue date and time. |
| stamps[].articleName | string | Name of the article the e-Stamp was generated with. |
| stamps[].stampDetails | object | Stamp details from generation time — stateCode, articleCode, stampDutyAmount, stampDutyPaidBy, considerationPrice, documentDescription. |
| stamps[].firstParty | object | First party details — name, pan, mobile. |
| stamps[].secondParty | object | Second party details — name, pan, mobile. Omitted when not provided at generation. |
| stamps[].createdOn | string (date-time) | When the stamp was generated (UTC). |
| stamps[].base64FileData | string | Base64 PDF of the stamp certificate. Omitted if the file could not be retrieved. |
Fields with no value are omitted from the response.
Request body (optional filters):
| Field | Type | Description |
|---|---|---|
| estampIds | array of string (uuid) | Optional. Only stamps whose eStampId is in this list are returned. |
| stateCode | string | Optional. Only stamps from this two-letter state code (e.g. "DL") are returned. |
Omit both fields (or send an empty body) to get everything.
Headers
- X-API-KEYstringrequiredYour secret API key for the environment you are calling (Stage and Live use different keys).
- X-API-APP-IDstringrequiredThe App ID issued together with the key.
- Content-Typestringrequiredapplication/json
Body parameters
application/json- estampIdsarray<string>optionalOptional. When provided, only stamps whose eStampId (uuid) is in this list are returned.nullable
- stateCodestringoptionalOptional. When provided, only stamps from this two-letter state code (e.g. "DL") are returned.nullable
Sample request body
Responses
200OK
- successbooleanoptionalNo description.
- statusCodeinteger (int32)optionalNo description.default 200
- messagestringoptionalNo description.nullabledefault XXXXX
- dataobjectoptionalResponse of the Get Procured E-Stamps API.
2 fields
- countinteger (int32)optionalNumber of procured eStamps.
- stampsarray<object>optionalProcured eStamps, newest first.nullable
Each item: 15 fields
- eStampIdstring (uuid)optionalUnique id of the eStamp — pass this to the Attach E-Stamp API. Present for single stamps only; omitted for batches (use API.Models.SignCare.StockHolding.ShcilProcuredStamp.BatchId).nullable
- batchIdstring (uuid)optionalUnique id of the bulk batch — pass this to the Bulk Attach API. Present for batches only; omitted for single stamps (use API.Models.SignCare.StockHolding.ShcilProcuredStamp.EStampId).nullable
- userDocumentIdinteger (int64)optionalSHCIL document id of this stamp — pass it in `userDocumentIds` of the Report Execution API when the document is signed outside SignCare. Present for single stamps only; a batch has one per member, so for batches see `stamps[].userDocumentId`.nullable
- reconMappingIdstringoptionalCorrelation key generated at generation time.nullable
- statusstringoptionalStatus of the eStamp (always COMPLETED — procured, ready to attach).nullable
- certIdstringoptionalNo description.nullable
- urnstringoptionalNo description.nullable
- certificateIssuedDatestringoptionalNo description.nullable
- articleNamestringoptionalName of the article the eStamp was generated with.nullable
- stampDetailsobjectoptionalStamp-specific details: state, article, duty and description.
6 fields
- stateCodestringrequiredRequired. Two-letter state code (e.g. "AS", "DL"). Must be a supported state from the Master Details API.length 2default AS
- articleCodeinteger (int32)requiredRequired. Article code from the Master Details API. Article codes are unique per state, so use the code listed for the same stateCode.default 7
- stampDutyAmountnumber (double)requiredRequired. Stamp duty amount in INR. Must be a whole number greater than zero — decimals are rejected. Must be within the article's minDuty and maxDuty. Validated in the handler (not via DataAnnotation) so every stampDutyAmount error uses the same clean response shape.default 1000
- stampDutyPaidBystringrequiredRequired. Name of the duty payer. Must match firstParty.name or secondParty.name (case-insensitive).minLength 1default Rahul Sharma
- considerationPricenumber (double)conditionalConditional: required for articles whose stampDutyType is CONSIDERATION_PRICE, and then it must be between the article's minConsiderationPrice and maxConsiderationPrice. Optional for other articles. Transaction value in INR. Never negative.nullable
- documentDescriptionstringoptionalOptional. Property or document description printed on the certificate. Max 100 characters; letters, numbers and spaces only.nullablemaxLength 100
- firstPartyobjectoptionalA party to the stamped document (first or second party).
3 fields
- namestringconditionalConditional: required whenever the party object is sent. Full name of the party.nullabledefault Rahul Sharma
- panstringconditionalConditional: required when this party pays the stamp duty and the stamp duty amount is greater than 2,00,000. 10-character PAN in the format AAAAA9999A. Validated whenever it is sent.nullablelength 10pattern ^[A-Z]{5}[0-9]{4}[A-Z]{1}$
- mobilestringconditionalConditional: required when this party pays the stamp duty (and for both parties when the article needs both). Exactly 10 digits.nullablelength 10pattern ^\d{10}$
- secondPartyobjectoptionalA party to the stamped document (first or second party).
3 fields
- namestringconditionalConditional: required whenever the party object is sent. Full name of the party.nullabledefault Rahul Sharma
- panstringconditionalConditional: required when this party pays the stamp duty and the stamp duty amount is greater than 2,00,000. 10-character PAN in the format AAAAA9999A. Validated whenever it is sent.nullablelength 10pattern ^[A-Z]{5}[0-9]{4}[A-Z]{1}$
- mobilestringconditionalConditional: required when this party pays the stamp duty (and for both parties when the article needs both). Exactly 10 digits.nullablelength 10pattern ^\d{10}$
- createdOnstring (date-time)optionalDate and time (UTC) the eStamp was generated.nullable
- stampsarray<object>optionalThe individual certificates inside a bulk batch. Present for batches only — omitted entirely for single stamps, whose certificate details sit at the top level.nullable
Each item: 6 fields
- userDocumentIdinteger (int64)optionalSHCIL document id of this individual stamp — pass it in `userDocumentIds` of the Report Execution API when the document is signed outside SignCare.
- reconMappingIdstringoptionalNo description.nullable
- certIdstringoptionalNo description.nullable
- urnstringoptionalNo description.nullable
- certificateIssuedDatestringoptionalNo description.nullable
- stampDutyAmountnumber (double)optionalStamp duty paid for this individual stamp.
- base64FileDatastringoptionalBase64-encoded certificate PDF — the stamp's own certificate for a single stamp, or the batch's combined certificate PDF (all stamps merged) for a batch. Omitted if the file could not be retrieved. Always the last field in the object.nullable
- messagesarray<string>optionalNo description.nullable
- request_idstringoptionalNo description.nullable
- isBillablebooleanoptionalWhether this request was charged: true if it was, false if not. Errors always show false. Flows that finish later (ITR Fetch, SHCIL eStamp, DigiLocker, eSign) show false here, because the charge is made when the result is ready. eSign charges each signer when they complete signing. DigiLocker deducts the credit when the link is created and refunds it automatically if the link expires before the user completes it.
400Bad Request
- dataobjectoptionalNo description.
- messagesarray<string>optionalNo description.nullable
- request_idstringoptionalNo description.nullable
- successbooleanoptionalNo description.default false
- messagestringoptionalNo description.nullabledefault XXXXX
- isBillablebooleanoptionalNo description.
- statusCodeinteger (int32)optionalNo description.default 400
401Unauthorized
- dataobjectoptionalNo description.
- messagesarray<string>optionalNo description.nullable
- request_idstringoptionalNo description.nullable
- successbooleanoptionalNo description.default false
- messagestringoptionalNo description.nullabledefault XXXXX
- isBillablebooleanoptionalNo description.
- statusCodeinteger (int32)optionalNo description.default 401
429Too Many Requests
- successbooleanoptionalNo description.
- statusCodeinteger (int32)optionalNo description.default 200
- messagestringoptionalNo description.nullabledefault XXXXX
- dataanyoptionalNo description.nullable
- messagesarray<string>optionalNo description.nullable
- request_idstringoptionalNo description.nullable
- isBillablebooleanoptionalWhether this request was charged: true if it was, false if not. Errors always show false. Flows that finish later (ITR Fetch, SHCIL eStamp, DigiLocker, eSign) show false here, because the charge is made when the result is ready. eSign charges each signer when they complete signing. DigiLocker deducts the credit when the link is created and refunds it automatically if the link expires before the user completes it.
500Internal Server Error
- dataobjectoptionalNo description.
- messagesarray<string>optionalNo description.nullable
- request_idstringoptionalNo description.nullable
- successbooleanoptionalNo description.default false
- messagestringoptionalNo description.nullabledefault XXXXX
- isBillablebooleanoptionalNo description.
- statusCodeinteger (int32)optionalNo description.default 500
Code samplescurl · Node.js · Python
Report document execution to SHCIL.
Use this API when you manage your own eSign flow outside SignCare and need to notify SHCIL that all signatories have completed signing on a stamped document.
Pass userDocumentIds as an array — one element for a single stamp, or one element
per stamp for a bulk batch. Signer counts apply equally to all entries.
SHCIL will update each certificate record to reflect the signed state.
When to call this: SHCIL requires the execution of a stamped document to be confirmed against the certificate once the parties have signed. Call this endpoint after the document has actually been executed.
You do not need to call it when the document was signed through SignCare eSign — the confirmation
is sent automatically on the final signature. You also do not need to call it if you left
selfReportExecution as false on the Generate request, in which case SignCare submits
the confirmation for you. Set
selfReportExecution to true at generate time and call this endpoint when you want
the exact signatory count and execution date to come from you.
Request Body — entity fields:
| Field | Type | Required | Description |
|---|---|---|---|
| userDocumentIds | array of number | required | SHCIL userDocumentIds to report; at least one, each a positive number belonging to your account. Single stamp: one element. Several stamps: one element per stamp. Each value is the userDocumentId returned by the Generate API or the Get Procured E-Stamps API. |
| executionDateTime | string | optional | Execution date and time in dd/MM/yyyy HH:mm:ss or dd/MM/yyyy format (the current IST time is added to a date-only value). Defaults to the current IST date and time when omitted. |
| noOfSignatories | number | optional | Total number of signatories on the document. Defaults to 0. Send the actual count — it is recorded against the certificate at SHCIL. |
| noOfDigitalSignatures | number | optional | Signatories who signed with a DSC (Class 2 / Class 3 digital signature certificate). Defaults to 0. |
| noOfElectronicSignatures | number | optional | Signatories who signed with an Aadhaar-based eSign or OTP-based electronic signature. Defaults to 0. |
Response — entity fields (single stamp, HTTP 200):
| Field | Type | Description |
|---|---|---|
| message | string | Confirmation message from SHCIL. |
A single stamp that is not found (or is not yours) returns HTTP 404. A stamp whose execution was already reported is returned as successful and is never filed twice.
Response — entity fields (several stamps, HTTP 200 all ok / HTTP 207 partial failure):
| Field | Type | Description |
|---|---|---|
| results | array | One entry per userDocumentId submitted. |
| results[].userDocumentId | number | The stamp this result corresponds to. |
| results[].success | boolean | True if SHCIL acknowledged this stamp successfully. |
| results[].message | string | SHCIL confirmation message or error description. |
Headers
- X-API-KEYstringrequiredYour secret API key for the environment you are calling (Stage and Live use different keys).
- X-API-APP-IDstringrequiredThe App ID issued together with the key.
- Content-Typestringrequiredapplication/json
Body parameters
application/json- userDocumentIdsarray<integer>requiredRequired. One or more SHCIL userDocumentIds (positive numbers) to report; at least one. Single stamp: pass one element. Several stamps (for example a bulk batch): pass one element per stamp. Each value is the userDocumentId returned by the Generate API or the Get Procured E-Stamps API, and must belong to your account.
- executionDateTimestringoptionalOptional. Date (and optionally time) when the document was executed. Accepted formats: `dd/MM/yyyy HH:mm:ss` (e.g. "27/07/2026 14:30:00") or date-only `dd/MM/yyyy` (e.g. "27/07/2026") — current IST time is appended automatically. Omit entirely to use the current IST date and time.nullable
- noOfSignatoriesinteger (int32)optionalOptional. Total number of signatories on the document. Defaults to 0 when omitted. Applies to every id in userDocumentIds.nullable
- noOfDigitalSignaturesinteger (int32)optionalOptional. Number of signatories who signed using a DSC (Digital Signature Certificate) — hardware USB token, PKI-based (Class 2 / Class 3). Defaults to 0 when omitted.nullable
- noOfElectronicSignaturesinteger (int32)optionalOptional. Number of signatories who signed using Aadhaar-based eSign or OTP-based electronic signature — not DSC. Defaults to 0 when omitted.nullable
Sample request body
Responses
200OK
- successbooleanoptionalNo description.
- statusCodeinteger (int32)optionalNo description.default 200
- messagestringoptionalNo description.nullabledefault XXXXX
- dataobjectoptionalResponse of the Report Execution API.
2 fields
- messagestringoptionalConfirmation message from SHCIL (single-stamp path).nullable
- resultsarray<object>optionalPer-stamp results (multi-stamp path). One entry per userDocumentId submitted. Absent when a single userDocumentId was used.nullable
Each item: 3 fields
- userDocumentIdinteger (int64)optionalThe SHCIL userDocumentId this result corresponds to.
- successbooleanoptionalTrue if SHCIL acknowledged this stamp successfully.
- messagestringoptionalSHCIL confirmation message or reason for failure.nullable
- messagesarray<string>optionalNo description.nullable
- request_idstringoptionalNo description.nullable
- isBillablebooleanoptionalWhether this request was charged: true if it was, false if not. Errors always show false. Flows that finish later (ITR Fetch, SHCIL eStamp, DigiLocker, eSign) show false here, because the charge is made when the result is ready. eSign charges each signer when they complete signing. DigiLocker deducts the credit when the link is created and refunds it automatically if the link expires before the user completes it.
207Successsame body as 200
400Bad Request
- dataobjectoptionalNo description.
- messagesarray<string>optionalNo description.nullable
- request_idstringoptionalNo description.nullable
- successbooleanoptionalNo description.default false
- messagestringoptionalNo description.nullabledefault XXXXX
- isBillablebooleanoptionalNo description.
- statusCodeinteger (int32)optionalNo description.default 400
401Unauthorized
- dataobjectoptionalNo description.
- messagesarray<string>optionalNo description.nullable
- request_idstringoptionalNo description.nullable
- successbooleanoptionalNo description.default false
- messagestringoptionalNo description.nullabledefault XXXXX
- isBillablebooleanoptionalNo description.
- statusCodeinteger (int32)optionalNo description.default 401
404Not Found
- successbooleanoptionalNo description.
- statusCodeinteger (int32)optionalNo description.default 200
- messagestringoptionalNo description.nullabledefault XXXXX
- dataanyoptionalNo description.nullable
- messagesarray<string>optionalNo description.nullable
- request_idstringoptionalNo description.nullable
- isBillablebooleanoptionalWhether this request was charged: true if it was, false if not. Errors always show false. Flows that finish later (ITR Fetch, SHCIL eStamp, DigiLocker, eSign) show false here, because the charge is made when the result is ready. eSign charges each signer when they complete signing. DigiLocker deducts the credit when the link is created and refunds it automatically if the link expires before the user completes it.
429Too Many Requestssame body as 404
500Internal Server Error
- dataobjectoptionalNo description.
- messagesarray<string>optionalNo description.nullable
- request_idstringoptionalNo description.nullable
- successbooleanoptionalNo description.default false
- messagestringoptionalNo description.nullabledefault XXXXX
- isBillablebooleanoptionalNo description.
- statusCodeinteger (int32)optionalNo description.default 500