iSign-тэй интеграц хийх гуравдагч системд зориулсан бүрэн заавар — браузерын SDK, сервер API, webhook.
Хэрэглэгч таны сайтаас гаралгүйгээр гэрээгээ үүсгэж, тоон гарын үсгээ зурна. Дууссаны дараа та эцсийн PDF-ээ сервер талаасаа татаж авна.
Интеграц нь хоёр тусдаа сувгаас бүрдэнэ. Аль нь юунд зориулагдсаныг эхэнд нь ойлгоод авбал цаашид төөрөхгүй.
| Браузер тал | Сервер тал | |
|---|---|---|
| Юу хийдэг | нэвтрэх, гэрээ үүсгэх, гарын үсэг зурах | гэрээ үүсгэх, төлөв харах, эцсийн PDF татах |
| Хэрхэн | window.isign.* (JS SDK) | HTTP + Authorization: Bearer |
| Яагаад тэгсэн бэ | Смарт карт / USB токен зөвхөн хэрэглэгчийн компьютерт байдаг | Файл, аудит нь таны серверт хэрэгтэй |
| Postman-аар дуудагдах уу | Үгүй — HTTP биш, postMessage | Тийм |
Гарын үсгийг сервер талаас зурах боломжгүй. ПИН код нь хэрэглэгчийн компьютерээс гардаггүй — iSign сервер ч, таны сервер ч түүнийг хардаггүй.
iSign-тай холбогдож дараах зүйлсийг бүртгүүлнэ:
| Юу | Тайлбар | Нууц уу |
|---|---|---|
client_id | Браузерын SDK-д өгнө | Үгүй — хуудасны эх кодод байж болно |
allowed_origins | Таны сайтын domain жагсаалт (https://partner.mn) | — |
webhook_token | Сервер талын API-д Bearer болгож ашиглана | ТИЙМ |
ext_webhook_url | Гэрээ дуусахад мэдэгдэл хүлээн авах таны хаяг | — |
ext_webhook_secret | Мэдэгдлийн гарын үсгийг шалгах түлхүүр | ТИЙМ |
Загварын serviceCode | Загвараас гэрээ үүсгэх бол | — |
client_id нь нууц биш байхад яагаад аюулгүй вэ: iSign нь хүсэлт аль domain-аас
ирснийг хөтчөөс өөрөөс нь авч шалгадаг. Хэн нэгэн таны client_id-г хуулж
өөрийн сайтдаа тавибал эхний алхам дээрээ ORIGIN_NOT_ALLOWED авна.
<script src="https://isign.mn/sdk/v1/isign-sdk.js"></script>
<script>
window.isign.configure({ clientId: 'YOUR-CLIENT-ID' })
</script>
SDK нь ~11 KB, гадаад хамааралгүй.
⚠
integrity(SRI) hash-аар бэхлэх нь хараахан хийгдээгүй. Хувилбар тогтмолжмогц iSign танд hash-ыг өгнө — тэр үедintegrity+crossoriginнэмж бэхлээрэй.
Ажиллаж болох бүтэн жишээ: docs/examples/partner-demo.html —
файлыг хуулж аваад SDK-ийн замаа болон clientId-гээ солиход л ажиллана.
const info = await isign.info()
if (!info) {
// Суулгаагүй байна — өөрийн баннераа харуул
showBanner('iSign өргөтгөлийг суулгана уу', isign.getInstallUrl())
}
getInstallUrl() нь https://isign.mn/ext (Edge дээр
?browser=edge) руу заана — тэнд суулгах заавар байна.
⚠ Өргөтгөл дэлгүүрт хараахан тавигдаагүй тул одоогоор гараар суулгана. Дэлгүүрт тавигдмагц
isign.mn/extшууд тийш чиглүүлэх бөгөөд таны код өөрчлөгдөхгүй —getInstallUrl()хэвээрээ ажиллана.
info() нь суулгасан бол дараахыг буцаана:
{
"installed": true,
"version": "0.1.0",
"protocol": 1,
"capabilities": ["login", "create", "sign", "status", "watch"],
"buildId": "2026-08-13 06:45:53"
}
capabilities-ыг шалгаж байгаад л дуудаарай — хувилбар бүрд өснө.
Өргөтгөл нь суулгасан төдийд бүх сайт дээр ажилладаггүй. Хэрэглэгч таны домэйныг нэг удаа зөвшөөрөх ёстой (хөтчийн зөвшөөрлийн загвар ийм).
Тиймээс info() нь null буцаах нь хоёр утгатай:
Хоёуланд нь тохирох мессеж харуулна уу:
if (!await isign.info()) {
show(
'iSign өргөтгөлийг суулгаад, энэ сайтыг идэвхжүүлнэ үү.',
isign.getInstallUrl(), // → https://isign.mn/ext
)
}
Хэрэглэгчид зориулсан алхам: өргөтгөлийн дүрс дээр дараад таны сайтын хажууд «Идэвхжүүлэх». Нэг удаа хийвэл хөтөч дахин асаасан ч хадгалагдана.
Таны домэйн iSign дээр бүртгэгдсэн байх ёстой — эс бөгөөс өргөтгөлийн жагсаалтад огт харагдахгүй. Бүртгүүлэхийн тулд iSign-тай холбогдоно уу.
const { subject } = await isign.login()
// subject: { kind: 'citizen'|'org', display_name: 'ОВОГ НЭР', masked_id: 'АА******99' }
Хэрэглэгч ПИН кодоо өргөтгөлийн өөрийн цонхонд оруулна — таны хуудас түүнийг харахгүй.
⚠
login()-ийн үр дүнг таних баталгаа болгож ХЭРЭГЛЭЖ БОЛОХГҮЙ. Одоогоор зөвхөн маскласан харагдах нэр буцдаг (masked_idнь бүтэн регистр биш). Сертификатын гинжин шалгалт (CA bundle) хийгдэх хүртэл iSign нь «энэ хүн үнэхээр тэр хүн мөн» гэсэн баталгаа гаргахгүй. Хэрэглэгчийг танихдаа өөрийн одоогийн нэвтрэлтээ ашиглаарай.
Хэрэглэгч PDF дээр гарын үсгийн талбар байрлуулах, талуудаа нэмэх ажлыг iSign-ий өөрийн редактор дээр хийнэ — өргөтгөл түүнийг шинэ цонхонд нээж өгнө.
const res = await isign.create({
name: 'Хөдөлмөрийн гэрээ',
externalNumber: 'HR-2026-0042', // ТАНЫ дотоод дугаар
pdf: { fileName: file.name, data: file }, // File | Blob | ArrayBuffer | base64
signNow: true, // үүсгээд шууд гарын үсэг зурах алхам руу
})
// { contractId: '01K…', status: 'pending', signedByMe: true, signedAt: '…' }
| Параметр | Тайлбар |
|---|---|
pdf.data | File, Blob, ArrayBuffer эсвэл base64 мөр. Дээд хэмжээ 6 MB |
source: 'template' | PDF-ийн оронд iSign-ий загвараас үүсгэнэ |
templateId | Загварыг урьдчилан сонгох (эс бөгөөс хэрэглэгч сонгоно) |
externalNumber | Заавал өгөөрэй — үүнгүйгээр webhook хүлээн авахгүй |
signNow | false бол ноорог үлдэнэ, дараа нь sign()-ээр зурна |
Таны байгууллага автоматаар нэг талд бөглөгдөнө — хэрэглэгч түншийг гараар хайх шаардлагагүй. Аль талд бөглөгдөхийг загварын тохиргоо шийднэ.
Танд бүртгэгдсэн загваруудын дунд тусгай загвар байж болно — энэ нь бэлэн PDF биш,
талууд агуулгыг нь бөглөж, баталсны дараа PDF нь шинээр үүсдэг гэрээ. Дуудлага нь
ижил (isign.create({ source: 'template' })) — өргөтгөл загварын төрлийг өөрөө таньж
зохих засварлагчийг нээнэ.
Ялгаа нь:
signNow: true энэ төрөлд үл хамаарна — contractId буцаж, төлөвөө
status() / watch()-ээр хянана.created болж, ердийн гарын үсгийн урсгал руу орно.const res = await isign.sign({ contractId: '01K…' })
// { contractId, status: 'pending'|'completed', signedByMe: true, signedAt }
// Нэг удаа
const s = await isign.status({ contractId })
// Өөрчлөгдөх бүрд
const stop = isign.watch(contractId, (s) => {
console.log(s.signedNum + '/' + s.signerNum)
if (s.status === 'completed') stop()
})
// Эсвэл зүгээр хүлээх
const final = await isign.awaitCompletion(contractId, { timeoutMs: 600000 })
StatusResult:
{
"contractId": "01K…",
"status": "pending",
"label": "Хүлээгдэж буй",
"color": "#F59E0B",
"signerNum": 2,
"signedNum": 1,
"parties": [
{ "partyIndex": 0, "type": "citizen", "maskedId": "АА******99", "name": "ОВОГ НЭР", "signed": true },
{ "partyIndex": 1, "type": "org", "maskedId": "00***90", "name": "ТЕСТ КОМПАНИ ХХК", "signed": false }
]
}
Гэрээний төлөвүүд: draft → created → pending → completed (эсвэл rejected).
Бүх алдаа code талбартай ирнэ. Мессежээр биш, кодоор шийдээрэй.
try {
await isign.sign({ contractId })
} catch (e) {
if (e.code === 'USER_DENIED' || e.code === 'CANCELLED') return // чимээгүй өнгөрөө
if (e.retryable) return retryLater()
showError(e.message)
}
Хамгийн түгээмэл кодууд:
| Код | Утга | Та юу хийх вэ |
|---|---|---|
EXTENSION_NOT_INSTALLED | Өргөтгөл суугаагүй | getInstallUrl()-аар баннер харуул |
ORIGIN_NOT_ALLOWED | Таны domain бүртгэгдээгүй | iSign-тай холбогдож нэмүүлнэ |
NOT_LOGGED_IN | Session алга | login() дуудна |
USER_DENIED / CANCELLED | Хэрэглэгч татгалзсан | Алдаа гэж бүү үз |
DESKTOP_CLIENT_NOT_RUNNING | Гарын үсгийн программ асаагүй | Асаах заавар харуул |
WRONG_PIN / PIN_LOCKED | ПИН буруу / түгжигдсэн | Хэрэглэгчид мэдэгд |
INSUFFICIENT_BALANCE | Хэтэвчний үлдэгдэл хүрэхгүй | Цэнэглэх холбоос өг |
CONTRACT_CHANGED | Нөгөө тал зэрэг зурсан | Дахин оролдоно (retryable) |
PDF_TOO_LARGE | 6 MB-аас том | Файлыг багасгах |
ALREADY_SIGNED | Аль хэдийн зурсан | Төлөвөө шинэчил |
Дахин оролдож болох кодууд: CONTRACT_CHANGED, NETWORK_ERROR, TIMEOUT,
DEVICE_TIMEOUT, BUSY, RATE_LIMITED. Бусад нь эцсийн — давтаж дуудах нь утгагүй.
Postman багц: docs/postman/ — collection болон environment хоёуланг нь импортлоно.
Бүх дуудлагад:
Authorization: Bearer <webhook_token>
Энэ бол таны хамгийн их хэрэглэх дуудлага.
POST /api/v1/thirdparty/contract/file
Authorization: Bearer <webhook_token>
Content-Type: application/json
{ "contract_id": "01K…" }
эсвэл өөрийн дугаараараа:
{ "thirdparty_id": "HR-2026-0042" }
Хариу нь PDF-ийн түүхий байт. Төлөвийг header-ээс уншина — биеийг задлах шаардлагагүй:
Content-Type: application/pdf
Content-Disposition: attachment; filename="Хөдөлмөрийн гэрээ.pdf"
X-ISign-Contract-Status: completed
X-ISign-Signed-Num: 2
X-ISign-Signer-Num: 2
| Код | Утга |
|---|---|
200 | Амжилттай, PDF ирлээ |
401 | Токен буруу эсвэл байхгүй |
403 | Хуучин нийтлэг токен ашигласан — өөрийн webhook_token-оо хэрэглэнэ үү |
404 | Гэрээ олдсонгүй эсвэл таны систем үүсгээгүй гэрээ |
404нь хоёр тохиолдолд ялгаагүй буцдаг: байхгүй гэрээ ба өөр түншийн гэрээ. Ингэснээр хариуны ялгаагаар бусдын гэрээ оршин байгаа эсэхийг тандах боломжгүй.
Бүх тал зурж дууссан хувилбарыг авахыг хүсвэл X-ISign-Contract-Status
нь completed болтол хүлээнэ. Дундуур татвал тэр агшны хувилбар ирнэ.
ext_webhook_url бүртгүүлсэн бол:
POST https://partner.mn/isign/webhook
Content-Type: application/json
X-ISign-Event: contract.completed
X-ISign-Signature: sha256=<hex>
X-ISign-Delivery-Attempt: 1
{
"event": "contract.completed",
"contract_id": "01K…",
"external_number": "HR-2026-0042",
"status": "completed",
"signed_num": 2,
"signer_num": 2,
"occurred_at": "2026-08-20T17:58:30+08:00"
}
event: contract.created, contract.completed, contract.updated.
contract.updated нь гэрээний оролцогч тал баримтыг засуулахаар буцаахад мөн
явна. Гэрээ энэ үед дуусаагүй — draft төлөвт буцаж, талууд засаад дахин батална.
Гарын үсгийг ЗААВАЛ шалгана уу. Үүнгүйгээр хэн ч таны webhook руу хуурамч мэдэгдэл илгээж чадна.
// Express жишээ — түүхий биеийг хэвээр нь авах ёстой
app.post('/isign/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const sig = req.headers['x-isign-signature'] || ''
const want = 'sha256=' + crypto.createHmac('sha256', SECRET).update(req.body).digest('hex')
if (sig.length !== want.length ||
!crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(want))) {
return res.sendStatus(401)
}
const ev = JSON.parse(req.body.toString())
// … ажлаа хий, дараа нь 2xx буцаа
res.sendStatus(200)
})
⚠ Гарын үсэг нь хүлээн авсан яг тэр байтууд дээр тооцоологдоно. JSON-ыг задалж дахин угсарвал таарахгүй —
express.json()биш,express.raw()ашиглана уу.
Давталт. 2xx буцаагаагүй бол 1с → 3с → 9с хүлээж дахин илгээнэ (нийт 4 оролдлого).
4xx (429-ээс бусад) буцаавал давтахгүй. Бүгд бүтэхгүй бол мэдэгдэл алдагдана —
тиймээс чухал урсгалыг зөвхөн webhook дээр бүү тулгуурлуул: contract/file-ээр
өөрөө сороод шалгаж болно.
Идемпотент байлга. Сүлжээний саатлаас болж нэг мэдэгдэл хоёр удаа ирж болно.
contract_id + event-ээр давхардлыг шүүнэ үү.
Хэрэглэгч браузер дээр байхгүй үед (batch, backend урсгал) ашиглана.
POST /api/v1/thirdparty/contract/create-pdf # multipart/form-data
name = Хөдөлмөрийн гэрээ
number = HR-2026-0042
signers = [{"party_index":0,"type":"citizen","civil_id":"АА99999999"}]
file = @contract.pdf
signers-ийн бүтэц:
| Талбар | Утга |
|---|---|
party_index | 0 = үүсгэгч тал, 1+ = нөгөө талууд |
type | "citizen" эсвэл "org" |
civil_id | type=citizen үед регистр (АА99999999) |
reg_num | type=org үед байгууллагын регистр |
Загвараас үүсгэх (/thirdparty/contract/create) нь serviceCode шаарддаг бөгөөд
participantList-ийн бүтэц загвар бүрд өөр — iSign-тай тохирсон байх ёстой.
Хариу:
{ "result": true, "data": {
"contractId": "01K…", "externalNumber": "HR-2026-0042", "status": "draft",
"contractUrl": "https://partner.mn/contracts/01K…" } }
number давхардвал шинэ гэрээ үүсэхгүй — өмнөх нь буцна (давхар үүсгэхээс хамгаална).
| Endpoint | Юунд |
|---|---|
POST /thirdparty/lookup | Иргэн/байгууллага iSign дээр бүртгэлтэй эсэхийг урьдчилан шалгах |
POST /thirdparty/contract/list | Тухайн этгээдтэй холбоотой, таны үүсгэсэн гэрээнүүд |
contract/list-ийн хариундcontractIdбайхгүй. Гэрээгээ хаяглахдааserviceRequestNumber(= таны илгээсэнnumber) -ийг ашиглана.
Таны сайт iSign өргөтгөл / сервер
────────────────────────────────────────────────────────────────
1. isign.info() → суулгасан эсэх
2. isign.login() → ПИН → өргөтгөлийн цонхонд
3. isign.create({ pdf, signNow }) → редактор нээгдэнэ
хэрэглэгч талбар байрлуулна
→ ПИН → гарын үсэг
← { contractId, status: 'pending', signedByMe: true }
4. Нөгөө тал зурна (өөр цагт, өөр газраас)
← webhook: contract.completed
5. POST /thirdparty/contract/file → эцсийн PDF таны серверт
| Шинж тэмдэг | Шалтгаан |
|---|---|
ORIGIN_NOT_ALLOWED | Domain бүртгэгдээгүй, эсвэл http vs https зөрсөн |
| Юу ч болохгүй, алдаа ч гарахгүй | Өргөтгөлийн цонх үндсэн цонхны АРД орсон байж болно |
| Webhook ирэхгүй | externalNumber өгөөгүй байна — үүнгүйгээр мэдэгдэл илгээгддэггүй |
Гарын үсгийн дараа pending хэвээр | Хэвийн — нөгөө тал хараахан зураагүй. completed болохыг хүлээнэ |
contract/file → 403 | Хуучин нийтлэг токен ашиглаж байна. Өөрийн webhook_token-оо хэрэглэ |
contract/file → 404 | Гэрээг өөр систем үүсгэсэн, эсвэл ID буруу |
Танд хэзээ ч харагдахгүй зүйлс: хэрэглэгчийн ПИН; iSign-ий нэвтрэлтийн токен; түүхий сертификат; гарын үсгийн байт; хэрэглэгчийн хэтэвчний үлдэгдэл; хэрэглэгчийн бусад гэрээ; өөр түншийн гэрээ.
Танд харагдах зүйлс: өөрийн үүсгүүлсэн гэрээний ID, төлөв, талуудын
маскласан ID (АА******99), гарын үсэг зурсан эсэх, эцсийн PDF.
webhook_token болон ext_webhook_secret-ыг зөвхөн серверт хадгална.
Браузерын код руу хэзээ ч бүү оруул.