رفتن به محتوای اصلی
Certyneo
API عمومی v1

امضای الکترونیکی را در پشته خود ادغام کنید

پاکت‌ها را ارسال کنید، امضاها را دنبال کنید، webhooks دریافت کنید. API REST ساده، OpenAPI 3.0، نمونه‌های curl/Node/Python — همه چیز برای اتصال Certyneo به HRIS، CRM یا نرم‌افزار تجاری خود در چند ساعت.

شروع سریع

سه مرحله: یک کلید API از تنظیمات ایجاد کنید، PDF خود را به base64 رمزگذاری کنید، ارسال کنید. پاسخ شامل `signUrl` است که می‌توانید مستقیماً با گیرنده به اشتراک بگذارید.

cURLbash
# 1. Upload the PDF (multipart) and capture the returned document id.
DOC_ID=$(curl -s -X POST https://certyneo.com/api/v1/documents \
  -H "Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -F "file=@contrat.pdf" | jq -r .id)

# 2. Create a DRAFT envelope referencing the uploaded document.
ENV_ID=$(curl -s -X POST https://certyneo.com/api/v1/envelopes \
  -H "Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d "{
    \"subject\": \"Contrat de prestation\",
    \"documentIds\": [\"$DOC_ID\"],
    \"recipients\": [
      { \"email\": \"client@example.com\", \"name\": \"Marie Dubois\", \"role\": \"SIGNER\" }
    ]
  }" | jq -r .id)

# 3. Dispatch the envelope — this sends the invitation email/SMS.
curl -X POST https://certyneo.com/api/v1/envelopes/$ENV_ID/send \
  -H "Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxxxxxx"
JavaScript / Nodets
// npm install @certyneo/sdk  (or call fetch directly)
const auth = { Authorization: `Bearer ${process.env.CERTYNEO_API_KEY}` };

// 1. Upload the PDF (multipart).
const fd = new FormData();
fd.append("file", new Blob([pdfBuffer], { type: "application/pdf" }), "contrat.pdf");
const doc = await fetch("https://certyneo.com/api/v1/documents", {
  method: "POST", headers: auth, body: fd,
}).then((r) => r.json());

// 2. Create the DRAFT envelope.
const envelope = await fetch("https://certyneo.com/api/v1/envelopes", {
  method: "POST",
  headers: { ...auth, "Content-Type": "application/json" },
  body: JSON.stringify({
    subject: "Contrat de prestation",
    documentIds: [doc.id],
    recipients: [
      { email: "client@example.com", name: "Marie Dubois", role: "SIGNER" },
    ],
  }),
}).then((r) => r.json());

// 3. Dispatch — this triggers the invitation channel for every recipient.
await fetch(`https://certyneo.com/api/v1/envelopes/${envelope.id}/send`, {
  method: "POST", headers: auth,
});
console.log(envelope.id);
Pythonpython
import os, requests

auth = {"Authorization": f"Bearer {os.environ['CERTYNEO_API_KEY']}"}

# 1. Upload the PDF (multipart).
with open("contrat.pdf", "rb") as f:
    doc = requests.post(
        "https://certyneo.com/api/v1/documents",
        headers=auth,
        files={"file": ("contrat.pdf", f, "application/pdf")},
    ).json()

# 2. Create the DRAFT envelope.
envelope = requests.post(
    "https://certyneo.com/api/v1/envelopes",
    headers={**auth, "Content-Type": "application/json"},
    json={
        "subject": "Contrat de prestation",
        "documentIds": [doc["id"]],
        "recipients": [
            {"email": "client@example.com", "name": "Marie Dubois", "role": "SIGNER"},
        ],
    },
).json()

# 3. Dispatch — this triggers the invitation channel for every recipient.
requests.post(
    f"https://certyneo.com/api/v1/envelopes/{envelope['id']}/send",
    headers=auth,
)
print(envelope["id"])

تست API از ابزارهای شما

مجموعه Postman و فیش RapidAPI از مشخصات OpenAPI تولید می‌شوند که این صفحه را نیز مستند می‌کنند. هر سه بنابراین در هر endpoint با API واقعی هم‌راستا می‌مانند، نه اینکه در اولین اضافه‌کردن جدا شوند.

مجموعه Postman

۲۲ درخواست دسته‌بندی‌شده بر اساس دامنه — پوش‌های اطلاعات، اسناد، الگوها، مهرها، webhooks — با نمونه متن و پاسخ برای هر کدام. کلید خود را در متغیر apiKey مجموعه قرار دهید، سپس GET /health را اجرا کنید: هیچ احراز هویتی نمی‌طلبد و تأیید می‌کند که پیکربندی شما قبل از اولین فراخوانی احراز‌شده خوب است.

فیش RapidAPI

همان فهرست endpoints، قابل تست مستقیم از مرورگر. پایگاه تست دو سرصحت متمایز را انتظار می‌کشد: کلید RapidAPI که پلتفرم برای شما اختصاص می‌دهد، و کلید Certyneo شما در Authorization — دومی است که فراخوانی را واقعاً مجاز می‌کند.

پاکت‌ها

ایجاد، ارسال، پیگیری وضعیت، لغو. یک پاکت می‌تواند شامل چندین سند و چندین امضاکننده (موازی یا متوالی) باشد.

Webhooks

تمام رویدادهای پاکت و گیرنده (`envelope.sent`، `recipient.signed`، `envelope.completed`…) ارسال شده به URL انتخاب شده شما — فهرست کامل در /developers/webhooks. امضای HMAC SHA-256 روی هر بار برای تأیید منشأ.

احراز هویت ساده

Bearer token. یک کلید در هر محیط (test / prod). فوری قابل لغو. حد 100 درخواست/دقیقه/کلید، burst تا 200، 429 تمیز با سرصحافه Retry-After.

نقاط انتهایی موجود

12 مسیر پوشش دهنده چرخه کامل: پاکت‌ها، اسناد، webhooks، کلیدهای API. تمام مسیرها یک Bearer token را می‌پذیرند و JSON را برمی‌گردانند.

MethodPathDescription
GET/api/v1/account/meIdentity of the authenticated caller (id, email, plan) — scope-less credential probe
POST/api/v1/documentsUpload a PDF (multipart) — returns document id
GET/api/v1/documentsList documents
GET/api/v1/documents/{id}Fetch document metadata
DELETE/api/v1/documents/{id}Delete document
GET/api/v1/envelopesList envelopes (filter with ?status= and ?limit=)
POST/api/v1/envelopesCreate envelope (status: DRAFT) — from a templateId, or from documentIds with an optional fields array
GET/api/v1/envelopes/{id}Fetch envelope state
PATCH/api/v1/envelopes/{id}Update DRAFT envelope
DELETE/api/v1/envelopes/{id}Void / delete DRAFT envelope
POST/api/v1/envelopes/{id}/sendDispatch DRAFT — sends invitations
GET/api/v1/envelopes/{id}/audit-trailDownload eIDAS audit-trail PDF
GET/api/v1/envelopes/{id}/signed-documentDownload signed PDF (once COMPLETED)
GET/api/v1/envelopes/bulkList your bulk-send jobs
POST/api/v1/envelopes/bulkBulk send: create N envelopes from one template + a CSV (Standard/Business only)
GET/api/v1/envelopes/bulk/{id}Bulk-send job progress: counts, per-row failures, created envelopes
GET/api/v1/templatesList reusable envelope templates
POST/api/v1/templatesCreate a template (documents, roles, positioned fields)
POST/api/v1/sepa-mandatesGenerate a SEPA mandate PDF and its DRAFT envelope, fields already placed
POST/api/v1/payroll-adapters/normalizeNormalise a payroll CSV (Silae, Sage Paie, PayFit, Lucca) into the bulk-send shape
POST/api/v1/ag-coproprieteCreate a condominium general-meeting envelope (resolutions + ownership shares)
POST/api/v1/ag-copropriete/{envelopeId}/votesRecord a co-owner's votes on the meeting resolutions
POST/api/v1/ag-copropriete/{envelopeId}/tallyTally the meeting - per-resolution result weighted by ownership shares
GET/api/v1/videos/{videoId}Download a stored identity video - GDPR art. 15 access path
GET/api/v1/webhooksList webhooks
POST/api/v1/webhooksRegister webhook — returns the signing secret once
GET/api/v1/webhooks/{id}Fetch webhook subscription
PATCH/api/v1/webhooks/{id}Update url / events / active state
DELETE/api/v1/webhooks/{id}Unregister
POST/api/v1/sealsApply a qualified electronic seal to a document
GET/api/v1/seals/{id}Fetch seal status
GET/api/v1/seals/{id}/certificateDownload the seal certificate
GET/api/v1/keysList API keys
POST/api/v1/keysCreate API key — the secret is shown once
PATCH/api/v1/keys/{id}Rename / revoke key
DELETE/api/v1/keys/{id}Delete key
GET/api/v1/billing/usageCurrent period usage and projected cost
GET/api/v1/statusService status
GET/api/v1/openapiMachine-readable OpenAPI specification

الگوهای پاکت

یک الگو PDF، نقش‌ها و موقعیت فیلدهای امضا را یک بار برای همیشه ثبت می‌کند، سپس در هر ارسال دوباره استفاده می‌شود: شناسهٔ آن را در templateId به جای documentIds قرار دهید، و فیلدهای موقعیت‌یافته بر روی پاکت ایجادشده کپی می‌شوند.

  • الگوها از داشبورد ایجاد می‌شوند (الگوها → الگوی جدید)، جایی که سند را رها می‌کنید و سپس فیلدها را با ماوس موقعیت می‌دهید — این ساده‌ترین راه است. API همچنین اجازه می‌دهد آنها را از طریق POST /api/v1/templates ایجاد کنید، با ارائهٔ اسناد، نقش‌ها و فیلدها؛ توجه داشته باشید که فیلدها در آنجا با مختصات مطلق موقعیت‌یافته‌اند (صفحه، x، y، عرض، ارتفاع)، بنابراین باید طرح‌بندی PDF را بدانید.
  • در حسابی که هنوز هیچ الگو ثبت نکرده است، GET /api/v1/templates فهرستی خالی برمی‌گرداند. این رفتار عادی است، نه یک خرابی احراز هویت.
  • فهرست فقط الگوهایی را شامل می‌شود که متعلق به کاربری هستند که مالک کلید API هستند. الگویی که توسط یک همکار ایجاد شده است در آن ظاهر نمی‌شود، حتی در یک فضای کاری مشترک: کلید را از حسابی تولید کنید که الگو را دارا است.
  • templateId و documentIds متقابلاً منحصر به فرد هستند: یکی یا دیگری را ارسال کنید، هرگز هر دو یا هیچ یک را نه.
  • حداقل به اندازهٔ تعداد نقش‌های امضاکننده الگو، گیرندگان SIGNER فراهم کنید، در غیر این صورت ایجاد در ۴۰۰ رد می‌شود. فیلد signerCount برگردانده شده توسط فهرست، تعداد انتظار رفته را نشان می‌دهد.
  • سطح امضای الگو توسط پاکت به ارث می‌رسد، مگر اینکه درخواست به صراحت signatureLevel را پاس کند.
cURLbash
# 1. Discover the templates saved on this account.
curl -s https://certyneo.com/api/v1/templates \
  -H "Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxxxxxx"

# {
#   "data": [
#     { "id": "cmdq7f4k80001s6y2h1xa9pl3", "name": "Contrat de prestation",
#       "signerCount": 2, "documentCount": 1, "signatureLevel": "SIMPLE" }
#   ],
#   "pagination": { "page": 1, "pageSize": 20, "total": 1, "pages": 1 }
# }
#
# An empty "data" array means no template exists on this account yet —
# create one from the dashboard, it is not an authentication problem.

# 2. Create the envelope FROM the template: no documentIds and no field
#    coordinates, both are carried by the template. Pass one SIGNER
#    recipient per signer role, in the template's role order.
curl -X POST https://certyneo.com/api/v1/envelopes \
  -H "Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "subject": "Contrat de prestation",
    "templateId": "cmdq7f4k80001s6y2h1xa9pl3",
    "recipients": [
      { "email": "client@example.com", "name": "Marie Dubois", "role": "SIGNER" },
      { "email": "legal@example.com", "name": "Paul Martin", "role": "SIGNER" }
    ]
  }'

# 3. The envelope is DRAFT at this point — POST /envelopes/{id}/send
#    dispatches it, exactly as in the quick-start above.

از Power Automate یا Zapier

عملیات «ایجاد پاکت» از متصل‌کننده‌های بدون کد ما فقط مسیر الگو را پوشش می‌دهد: فیلد الگو در آنجا اجباری است. برای سند موردی که در هر اجرا تغییر می‌کند، از عملیات «بارگذاری سند» و سپس از عملیات HTTP خام به سمت POST /api/v1/envelopes استفاده کنید و documentIds برگردانده شده را پاس کنید.

ارسال سند: دو فرم پذیرفته شده

POST /api/v1/documents فایل را به دو روش می‌پذیرد، به انتخاب شما. کنترل‌های یکسانی در هر دو مورد اعمال می‌شود: انواع مجاز، سقف ۵۰ مگابایت، تأیید امضای دودویی و تحلیل آنتی‌ویروس.

  • در multipart/form-data، با بخشی به نام file. این فرم کلاسیک است، همان‌طور که curl -F و اکثر کتابخانه‌ها.
  • در متن خام: بایت‌های فایل بدنه درخواست را تشکیل می‌دهند و سرصحافه Content-Type نوع آن را مشخص می‌کند (برای مثال application/pdf). از یک ابزار که محتوا را همان‌طور که هست منتقل می‌کند، بدون بسته‌بندی درخواست مفید است — این کاری است که Certyneo انجام می‌دهد.
  • در متن خام، نام فایل جایی در بدنه ندارد: آن را از طریق سرصحافه X-File-Name یا پارامتر ?fileName= مشخص کنید. بدون آن، سند از نوع آن نام‌گذاری می‌شود.
  • یک نوع پشتیبانی‌نشده با ۴۱۵ پاسخ می‌دهد و دو فرم پذیرفته‌شده را نام می‌برد، و بدنه‌ای که به عنوان multipart اعلام شده است اما خوانایی ندارد ۴۰۰ پاسخ می‌دهد. هیچ یک از اینها خطای سرور نیست.
cURLbash
# a. multipart/form-data — the classic shape.
curl -X POST https://certyneo.com/api/v1/documents \
  -H "Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -F "file=@contrat.pdf;type=application/pdf"

# b. raw body — the file bytes ARE the body, typed by Content-Type.
#    The filename has nowhere to live in the body, so pass it as a header
#    (or ?fileName=). Without it the document is named after its type.
curl -X POST https://certyneo.com/api/v1/documents \
  -H "Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/pdf" \
  -H "X-File-Name: contrat.pdf" \
  --data-binary "@contrat.pdf"

# Both return the same 201 with the document id to pass as documentIds.

جایابی فیلدهای امضا

بدون الگو، پاکتی که از documentIds ایجاد می‌شود، هیچ فیلد پیش‌موقعیت‌یافته ای ندارد: امضاکننده سند را بدون مکانی برای امضا دریافت می‌کند. آرایهٔ fields، در همان فراخوانی ایجاد منتقل شده، هر فیلد را در نقطهٔ دقیق قرار می‌دهد — این معادل API است که الگو یک بار برای همیشه ثبت می‌کند.

  • مختصات بر حسب نقاط PDF هستند، منشأ در گوشهٔ بالا سمت چپ صفحه و محور Y به سمت پایین (صفحهٔ A4 برابر است با ۵۹۵ × ۸۴۲ نقطه). x و y گوشهٔ بالا سمت چپ فیلد را مشخص می‌کنند، width و height اندازهٔ آن را.
  • pageNumber از ۱ شروع می‌شود، documentIndex از ۰ شروع می‌شود. شمارهٔ صفحه‌ای فراتر از سند در ایجاد رد نمی‌شود: فیلد در زمان امضا نادیده گرفته می‌شود و جای هیچ‌کس ظاهر نمی‌شود — این اولین چیزی است که باید وقتی فیلدی در فراخوانی کم شود، بررسی کنید.
  • recipientEmail باید با یکی از گیرندگان همان فراخوانی مطابقت داشته باشد، بدون تمایز بزرگ و کوچک. در غیر این صورت ایجاد با فهرست تمام ردیف‌های خاطی ناموفق است، که از تصحیح آنها یکی یکی جلوگیری می‌کند.
  • fields و templateId متقابلاً منحصر به فرد هستند: الگو قبلاً طرح‌بندی خود را دارد. بنابراین آرایهٔ fields فقط با documentIds استفاده می‌شود.
  • انواع پذیرفته‌شده: SIGNATURE، INITIALS، DATE_SIGNED، TEXT، CHECKBOX و RADIO_GROUP. required به طور پیش‌فرض true است؛ placeholder و dateFormat اختیاری هستند، و options فقط برای RADIO_GROUP نگهداری می‌شود.
  • یک پاکت حداکثر ۱۰۰ فیلد، ۲۰ سند و ۵۰ گیرنده را می‌پذیرد — حدود برنامه‌ای شما ممکن است کمتر باشد.
cURLbash
# Ad-hoc envelope WITH pre-placed fields — no template involved.
# Coordinates are PDF points, origin TOP-LEFT of the page, +Y downwards
# (A4 = 595 x 842 pt). x / y are the field box's top-left corner.
#
# The last field is positioned by ANCHOR instead of by eye: the server
# locates "Signature du client" in the PDF and computes the spot. x / y
# stay required there — they are the fallback if the text is not found.
curl -X POST https://certyneo.com/api/v1/envelopes \
  -H "Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "subject": "Contrat de prestation",
    "documentIds": ["cmdq7f4k80001s6y2h1xa9pl3"],
    "recipients": [
      { "email": "client@example.com", "name": "Marie Dubois", "role": "SIGNER" }
    ],
    "fields": [
      { "recipientEmail": "client@example.com", "documentIndex": 0,
        "pageNumber": 2, "fieldType": "SIGNATURE",
        "x": 90, "y": 640, "width": 180, "height": 44 },
      { "recipientEmail": "client@example.com", "documentIndex": 0,
        "pageNumber": 2, "fieldType": "DATE_SIGNED",
        "x": 320, "y": 640, "width": 140, "height": 30,
        "dateFormat": "DD/MM/YYYY" },
      { "recipientEmail": "client@example.com", "documentIndex": 0,
        "pageNumber": 2, "fieldType": "TEXT",
        "x": 90, "y": 700, "width": 200, "height": 30,
        "placeholder": "Fonction", "required": false },
      { "recipientEmail": "client@example.com", "documentIndex": 0,
        "pageNumber": 2, "fieldType": "SIGNATURE",
        "anchorText": "Signature du client", "anchorPlacement": "below",
        "anchorIndex": 0,
        "x": 90, "y": 640, "width": 180, "height": 44 }
    ]
  }'

# The envelope is DRAFT at this point — POST /envelopes/{id}/send
# dispatches it, exactly as in the quick-start above.

لنگرهای متنی: قرار دادن یک فیلد بدون دانستن مختصات

به جای مختصات، یک فیلد می‌تواند متنی را که در سند چاپ شده است نام ببرد: anchorText آن را در PDF پیدا می‌کند و سرور موقعیت را در هنگام ایجاد محاسبه می‌کند. این روش زمانی ترجیح داده می‌شود که سند در هر ارسال دوباره تولید شود — افزودن متن، تولیدکننده قرارداد — زیرا صفحه‌بندی تغییر می‌کند اما عبارت «امضای مشتری» ثابت می‌ماند. anchorPlacement نشان می‌دهد که فیلد از کدام سمت متن قرار می‌گیرد (به‌طور پیش‌فرض راست، در غیر این صورت زیر، بالا یا چپ) و anchorIndex هنگامی که متن چندین بار ظاهر شود، یک رخداد را انتخاب می‌کند.

x و y حتی با یک لنگر اجباری هستند: آنها به عنوان بازگشت عمل می‌کنند. یک لنگری که قابل یافتن نیست باعث شکست ایجاد نمی‌شود — فیلد موقعیت لغو‌الحال را که شما فراهم کردید حفظ می‌کند، بدون خطا یا هشدار در پاسخ. بنابراین یک بازگشت معقول به جای ۰٫۰ نشان دهید و نمایش را در یک ارسال اول بررسی کنید.

احراز هویت

هر درخواست کلید API را در سرصفحه Authorization حمل می‌کند. کلیدها از تنظیمات → کلیدهای API تولید می‌شوند و تنها یک بار نمایش داده می‌شوند.

HTTPhttp
GET /api/v1/account/me HTTP/1.1Host: certyneo.com
Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxxxxxx

# 200 OK
{ "data": { "id": "usr_…", "email": "you@example.com", "plan": "BUSINESS", "environment": "live" } }
  • قالب: sk_live_… در تولید، sk_test_… برای صندوق شن و ماسه. سرصفحه: Authorization: Bearer <کلید>.
  • دامنه‌ها: envelopes، documents، webhooks، seals — در خواندن (:read) یا نوشتن (:write). نوشتن خواندن را شامل می‌شود؛ دامنه * تمام حقوق را می‌دهد.
  • کلیدهای sk_test_ منابع را در صندوق شن و ماسه ایجاد می‌کنند، بدون سهمیه و صورت‌حساب.
  • خطاها: ۴۰۱ کلید نامعتبر، ۴۰۳ دامنه ناکافی، ۴۲۹ محدودیت سرعت تجاوز شده، ۴۰۲ سهمیه ماهانه رسیده است.

شکل پاسخ‌ها

نکته‌ای که باید قبل از نوشتن کلاینت خود بدانید: مجموعه‌ها در یک شیء data کپسوله شده‌اند، در حالی که منابع واحد به صورت مسطح برگردانده می‌شوند. خواندن response.data.data بر روی یک منبع واحد بنابراین undefined برمی‌گرداند.

مجموعه — کپسوله شدهjson
// GET /api/v1/envelopes
// Collections are WRAPPED in a "data" array.
{
  "data": [
    { "id": "env_abc123", "subject": "Contrat", "status": "SENT" }
  ]
}
منبع واحد — مسطحjson
// GET /api/v1/envelopes/{id}
// Single resources are returned FLAT — no "data" envelope.
{
  "id": "env_abc123",
  "subject": "Contrat",
  "status": "COMPLETED",
  "recipients": [ /* … */ ]
}

محدودیت‌های نرخ

محدودیت‌ها کیفیت خدمات پایدار را برای تمام مشتریان تضمین می‌کنند. اگر بیشتر نیاز دارید، با ما تماس بگیرید.

  • 100 درخواست در دقیقه در هر کلید API
  • Burst تا 200 درخواست در کمتر از 10 ثانیه مجاز است
  • پاسخ 429 با سرصحافه Retry-After که تأخیر را در ثانیه نشان می‌دهد