iSign.mn
Developers

iSign интеграцийн гарын авлага — гуравдагч системд зориулав

iSign-тэй интеграц хийх гуравдагч системд зориулсан бүрэн заавар — браузерын SDK, сервер API, webhook.

Download

Хэрэглэгч таны сайтаас гаралгүйгээр гэрээгээ үүсгэж, тоон гарын үсгээ зурна. Дууссаны дараа та эцсийн PDF-ээ сервер талаасаа татаж авна.


Хамгийн эхэнд — хоёр өөр зүйлийг андуурч болохгүй

Интеграц нь хоёр тусдаа сувгаас бүрдэнэ. Аль нь юунд зориулагдсаныг эхэнд нь ойлгоод авбал цаашид төөрөхгүй.

Браузер талСервер тал
Юу хийдэгнэвтрэх, гэрээ үүсгэх, гарын үсэг зурахгэрээ үүсгэх, төлөв харах, эцсийн PDF татах
Хэрхэнwindow.isign.* (JS SDK)HTTP + Authorization: Bearer
Яагаад тэгсэн бэСмарт карт / USB токен зөвхөн хэрэглэгчийн компьютерт байдагФайл, аудит нь таны серверт хэрэгтэй
Postman-аар дуудагдах ууҮгүй — HTTP биш, postMessageТийм

Гарын үсгийг сервер талаас зурах боломжгүй. ПИН код нь хэрэглэгчийн компьютерээс гардаггүй — iSign сервер ч, таны сервер ч түүнийг хардаггүй.


Бэлтгэл — 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 авна.


1. Браузер тал

1.1 SDK ачаалах

<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-гээ солиход л ажиллана.

1.2 Өргөтгөл суулгасан эсэхийг шалгах

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-ыг шалгаж байгаад л дуудаарай — хувилбар бүрд өснө.

1.2.1 ⚠ Хэрэглэгч таны сайтыг нэг удаа идэвхжүүлнэ

Өргөтгөл нь суулгасан төдийд бүх сайт дээр ажилладаггүй. Хэрэглэгч таны домэйныг нэг удаа зөвшөөрөх ёстой (хөтчийн зөвшөөрлийн загвар ийм).

Тиймээс info() нь null буцаах нь хоёр утгатай:

  1. Өргөтгөл огт суулгаагүй
  2. Суулгасан ч таны сайтыг идэвхжүүлээгүй

Хоёуланд нь тохирох мессеж харуулна уу:

if (!await isign.info()) {
  show(
    'iSign өргөтгөлийг суулгаад, энэ сайтыг идэвхжүүлнэ үү.',
    isign.getInstallUrl(),           // → https://isign.mn/ext
  )
}

Хэрэглэгчид зориулсан алхам: өргөтгөлийн дүрс дээр дараад таны сайтын хажууд «Идэвхжүүлэх». Нэг удаа хийвэл хөтөч дахин асаасан ч хадгалагдана.

Таны домэйн iSign дээр бүртгэгдсэн байх ёстой — эс бөгөөс өргөтгөлийн жагсаалтад огт харагдахгүй. Бүртгүүлэхийн тулд iSign-тай холбогдоно уу.

1.3 Нэвтрэх

const { subject } = await isign.login()
// subject: { kind: 'citizen'|'org', display_name: 'ОВОГ НЭР', masked_id: 'АА******99' }

Хэрэглэгч ПИН кодоо өргөтгөлийн өөрийн цонхонд оруулна — таны хуудас түүнийг харахгүй.

⚠ login()-ийн үр дүнг таних баталгаа болгож ХЭРЭГЛЭЖ БОЛОХГҮЙ. Одоогоор зөвхөн маскласан харагдах нэр буцдаг (masked_id нь бүтэн регистр биш). Сертификатын гинжин шалгалт (CA bundle) хийгдэх хүртэл iSign нь «энэ хүн үнэхээр тэр хүн мөн» гэсэн баталгаа гаргахгүй. Хэрэглэгчийг танихдаа өөрийн одоогийн нэвтрэлтээ ашиглаарай.

1.4 Гэрээ үүсгэх

Хэрэглэгч 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.dataFile, Blob, ArrayBuffer эсвэл base64 мөр. Дээд хэмжээ 6 MB
source: 'template'PDF-ийн оронд iSign-ий загвараас үүсгэнэ
templateIdЗагварыг урьдчилан сонгох (эс бөгөөс хэрэглэгч сонгоно)
externalNumberЗаавал өгөөрэй — үүнгүйгээр webhook хүлээн авахгүй
signNowfalse бол ноорог үлдэнэ, дараа нь sign()-ээр зурна

Таны байгууллага автоматаар нэг талд бөглөгдөнө — хэрэглэгч түншийг гараар хайх шаардлагагүй. Аль талд бөглөгдөхийг загварын тохиргоо шийднэ.

Тусгай загвар (тал бүр бөглөдөг гэрээ)

Танд бүртгэгдсэн загваруудын дунд тусгай загвар байж болно — энэ нь бэлэн PDF биш, талууд агуулгыг нь бөглөж, баталсны дараа PDF нь шинээр үүсдэг гэрээ. Дуудлага нь ижил (isign.create({ source: 'template' })) — өргөтгөл загварын төрлийг өөрөө таньж зохих засварлагчийг нээнэ.

Ялгаа нь:

  • Цонх хаагдахад гэрээ ноорог (draft) хэвээр байна — бүх тал бөглөж батлах хүртэл гарын үсгийн талбар үүсэхгүй.
  • Тиймээс signNow: true энэ төрөлд үл хамаарна — contractId буцаж, төлөвөө status() / watch()-ээр хянана.
  • Бүх тал баталмагц гэрээ created болж, ердийн гарын үсгийн урсгал руу орно.

1.5 Байгаа гэрээнд гарын үсэг зурах

const res = await isign.sign({ contractId: '01K…' })
// { contractId, status: 'pending'|'completed', signedByMe: true, signedAt }

1.6 Төлөв хянах

// Нэг удаа
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).

1.7 Алдаа боловсруулах

Бүх алдаа 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_INSession алгаlogin() дуудна
USER_DENIED / CANCELLEDХэрэглэгч татгалзсанАлдаа гэж бүү үз
DESKTOP_CLIENT_NOT_RUNNINGГарын үсгийн программ асаагүйАсаах заавар харуул
WRONG_PIN / PIN_LOCKEDПИН буруу / түгжигдсэнХэрэглэгчид мэдэгд
INSUFFICIENT_BALANCEХэтэвчний үлдэгдэл хүрэхгүйЦэнэглэх холбоос өг
CONTRACT_CHANGEDНөгөө тал зэрэг зурсанДахин оролдоно (retryable)
PDF_TOO_LARGE6 MB-аас томФайлыг багасгах
ALREADY_SIGNEDАль хэдийн зурсанТөлөвөө шинэчил

Дахин оролдож болох кодууд: CONTRACT_CHANGED, NETWORK_ERROR, TIMEOUT, DEVICE_TIMEOUT, BUSY, RATE_LIMITED. Бусад нь эцсийн — давтаж дуудах нь утгагүй.


2. Сервер тал

Postman багц: docs/postman/ — collection болон environment хоёуланг нь импортлоно.

Бүх дуудлагад:

Authorization: Bearer <webhook_token>

2.1 Эцсийн PDF татах ⭐

Энэ бол таны хамгийн их хэрэглэх дуудлага.

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 болтол хүлээнэ. Дундуур татвал тэр агшны хувилбар ирнэ.

2.2 Гэрээ дуусахад мэдэгдэл авах (webhook)

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-ээр давхардлыг шүүнэ үү.

2.3 Сервер талаас гэрээ үүсгэх

Хэрэглэгч браузер дээр байхгүй үед (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_index0 = үүсгэгч тал, 1+ = нөгөө талууд
type"citizen" эсвэл "org"
civil_idtype=citizen үед регистр (АА99999999)
reg_numtype=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 давхардвал шинэ гэрээ үүсэхгүй — өмнөх нь буцна (давхар үүсгэхээс хамгаална).

2.4 Бусад дуудлага

EndpointЮунд
POST /thirdparty/lookupИргэн/байгууллага iSign дээр бүртгэлтэй эсэхийг урьдчилан шалгах
POST /thirdparty/contract/listТухайн этгээдтэй холбоотой, таны үүсгэсэн гэрээнүүд

contract/list-ийн хариунд contractId байхгүй. Гэрээгээ хаяглахдаа serviceRequestNumber (= таны илгээсэн number) -ийг ашиглана.


3. Ердийн урсгал бүтнээрээ

Таны сайт                          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 таны серверт

4. Түгээмэл алдаанууд

Шинж тэмдэгШалтгаан
ORIGIN_NOT_ALLOWEDDomain бүртгэгдээгүй, эсвэл http vs https зөрсөн
Юу ч болохгүй, алдаа ч гарахгүйӨргөтгөлийн цонх үндсэн цонхны АРД орсон байж болно
Webhook ирэхгүйexternalNumber өгөөгүй байна — үүнгүйгээр мэдэгдэл илгээгддэггүй
Гарын үсгийн дараа pending хэвээрХэвийн — нөгөө тал хараахан зураагүй. completed болохыг хүлээнэ
contract/file → 403Хуучин нийтлэг токен ашиглаж байна. Өөрийн webhook_token-оо хэрэглэ
contract/file → 404Гэрээг өөр систем үүсгэсэн, эсвэл ID буруу

5. Аюулгүй байдлын хил

Танд хэзээ ч харагдахгүй зүйлс: хэрэглэгчийн ПИН; iSign-ий нэвтрэлтийн токен; түүхий сертификат; гарын үсгийн байт; хэрэглэгчийн хэтэвчний үлдэгдэл; хэрэглэгчийн бусад гэрээ; өөр түншийн гэрээ.

Танд харагдах зүйлс: өөрийн үүсгүүлсэн гэрээний ID, төлөв, талуудын маскласан ID (АА******99), гарын үсэг зурсан эсэх, эцсийн PDF.

webhook_token болон ext_webhook_secret-ыг зөвхөн серверт хадгална. Браузерын код руу хэзээ ч бүү оруул.