رفتن به محتوای اصلی
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
// Plain fetch, no SDK to install.
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.

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

52 مسیرهای عمومی: حساب، اسناد، پاکت‌ها، الگوها، webhook‌ها، مهرهای الکترونیکی، کلیدهای API و صورت‌حساب. همه آن‌ها یک Bearer token را می‌پذیرند و JSON برمی‌گردانند.

روشمسیرتوضیح
GET/api/v1/account/meهویت تماس‌گیرنده احراز‌شده (شناسه، ایمیل، بسته): آزمایش شناسه‌ها بدون نیاز به scope
GET/api/v1/sandboxشمارش داده‌های ایجادشده با کلیدهای آزمایشی (پس از ۳۰ روز به‌طور خودکار حذف می‌شوند)
DELETE/api/v1/sandboxحذف همه داده‌های ایجادشده با کلیدهای آزمایشی، بدون دست زدن به داده‌های واقعی
POST/api/v1/documentsآپلود کردن PDF (چندبخشی): شناسه سند را برمی‌گرداند
GET/api/v1/documentsفهرست اسناد
GET/api/v1/documents/{id}خواندن فراداده یک سند
DELETE/api/v1/documents/{id}حذف یک سند
GET/api/v1/envelopesفهرست پاکت‌ها (فیلتر کردن با ?status= و ?limit=)
POST/api/v1/envelopesایجاد پاکت (وضعیت DRAFT): از templateId یا documentIds با آرایه fields اختیاری
GET/api/v1/envelopes/{id}خواندن وضعیت یک پاکت
PATCH/api/v1/envelopes/{id}ویرایش یک پاکت DRAFT
DELETE/api/v1/envelopes/{id}حذف یک پاکت DRAFT (409 پس از ارسال: به جای آن لغو کنید)
POST/api/v1/envelopes/{id}/sendارسال یک پاکت DRAFT: دعوت‌نامه‌ها را فرستادید
POST/api/v1/envelopes/{id}/voidلغو کردن یک پاکت ارسال‌شده که هنوز به‌طور کامل امضاء نشده است: امضاکنندگان منتظر مطلع می‌شوند
GET/api/v1/envelopes/{id}/audit-trailدانلود PDF سند اثبات eIDAS
POST/api/v1/envelopes/{id}/embed-urlURL امضای یک گیرنده را به همراه اجازه کادری برای منشأ درخواست‌شده ارائه می‌دهد. در زمان کلیک فراخوانی کنید: اجازه دو ساعت معتبر است.
GET/api/v1/audit-anchors/{root}عمومی: فراداده یک دسته حسابرسی لنگر‌شده یا فایل اثبات .ots با ?format=ots (بدون احراز‌هویت)
POST/api/v1/audit-anchors/verifyعمومی: تایید یک ورودی حسابرسی و اثبات آن در مقابل ریشه مرکل لنگر‌شده (بدون احراز‌هویت، چیزی را آشکار نمی‌کند)
GET/api/v1/envelopes/{id}/signed-documentدانلود PDF امضاء‌شده (پس از COMPLETED)
GET/api/v1/envelopes/bulkفهرست ارسال‌های دسته‌ای شما
POST/api/v1/envelopes/bulkارسال انبوهی: ایجاد N پاکت از یک الگو و CSV (فقط Standard/Business)
GET/api/v1/envelopes/bulk/{id}پیشرفت ارسال انبوهی: شمارنده‌ها، شکست‌های هر ردیف، پاکت‌های ایجاد شده
GET/api/v1/templatesفهرست الگوهای پاکت قابل استفاده مجدد
POST/api/v1/templatesایجاد یک الگو (اسناد، نقش‌ها، فیلدهای موضع‌یافته)
GET/api/v1/workspacesفهرست کردن فضاهای کاری که می‌توانید در آنها یک پاکت ایجاد کنید
POST/api/v1/sepa-mandatesتولید PDF یک تفویض SEPA و پاکت DRAFT آن، فیلدها قبلاً قرارگرفته
POST/api/v1/payroll-adapters/normalizeنرمال‌سازی CSV دستمزد (Silae, Sage Paie, PayFit, Lucca) به فرمت ارسال انبوهی
POST/api/v1/ag-coproprieteایجاد یک پاکت مجمع عمومی مالکیت مشترک (قطع‌نامه‌ها و سهم)
POST/api/v1/ag-copropriete/{envelopeId}/votesثبت آرا مالک مشترک در قطع‌نامه‌های مجمع
POST/api/v1/ag-copropriete/{envelopeId}/tallyشمارش مجمع: نتیجه بر اساس قطع‌نامه، وزن‌دار بر اساس سهم
GET/api/v1/videos/{videoId}دانلود ویدیوی هویت حفظ‌شده: حق دسترسی RGPD (ماده 15)
GET/api/v1/webhooksفهرست webhook‌ها
POST/api/v1/webhooksثبت یک webhook: بازگشت راز امضا تنها یک بار
GET/api/v1/webhooks/{id}خواندن یک اشتراک webhook
PATCH/api/v1/webhooks/{id}تغییر URL، رویدادها یا وضعیت فعال
DELETE/api/v1/webhooks/{id}لغو ثبت webhook
POST/api/v1/sealsاعمال یک مهر الکترونیکی واجد‌شرایط بر روی یک سند
GET/api/v1/seals/{id}خواندن وضعیت یک مهر
GET/api/v1/seals/{id}/certificateدانلود گواهی مهر
GET/api/v1/payslips/workspacesحکم‌های حقوقی: فضاهایی که این کلید توزیع می‌کند، داشته‌شده یا تفویض‌شده توسط یک مشتری (دفاتر حسابداری، مدیران دستمزد)
GET/api/v1/payslips/employeesحکم‌های حقوقی: ثبت کارکنان، با آن‌هایی که تحویل الکترونیکی را رد کرده‌اند (حکم کاغذی مقروض)
PUT/api/v1/payslips/employeesفیش حقوقی: افزودن یا به‌روزرسانی کارمندان ثبت (هرگز حذف نمی‌شود)
POST/api/v1/payslipsتحویل فیش حقوقی (PDF) در صندوق یک کارمند: مهرشده، نگهداری 50 سال، تلاش مجدد بدون تکرار
GET/api/v1/payslipsفهرست فیش‌های تحویل‌شده، همراه با اثبات مشاهده آنها
GET/api/v1/keysفهرست کلیدهای API
POST/api/v1/keysایجاد کلید API: راز تنها یک بار نمایش داده می‌شود
PATCH/api/v1/keys/{id}تغییر نام یا لغو کلید
DELETE/api/v1/keys/{id}حذف کلید
GET/api/v1/billing/usageمصرف دوره جاری و هزینه پیش‌بینی‌شده
GET/api/v1/statusوضعیت سرویس
GET/api/v1/healthبررسی سلامت: پایگاه داده، صف و ذخیره‌سازی اشیاء
GET/api/v1/openapiمشخصات OpenAPI قابل‌خواندن توسط ماشین

الگوهای پاکت

یک الگو 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 حتی با یک لنگر اجباری هستند: آنها به عنوان بازگشت عمل می‌کنند. یک لنگری که قابل یافتن نیست باعث شکست ایجاد نمی‌شود — فیلد موقعیت لغو‌الحال را که شما فراهم کردید حفظ می‌کند، بدون خطا یا هشدار در پاسخ. بنابراین یک بازگشت معقول به جای ۰٫۰ نشان دهید و نمایش را در یک ارسال اول بررسی کنید.

امضای یکپارچه: امضا کردن بدون ترک برنامه شما

مشتری شما سند خود را از رابط کاربری خود مشاهده و امضا می‌کند. مراسم در پنجره‌ای بالای صفحه شما باز می‌شود و پس از اتمام، او به صورت خودکار به شما بازمی‌گردد. از سوی سرور، چیز جدیدی نیست: پاکت را طبق معمول با پر کردن redirectUrl ایجاد می‌کنید، سپس URL امضای دریافت‌کننده را به SDK محول می‌کنید.

  • • Certyneo.sign() را مستقیماً در کنترل‌کننده کلیک خود فراخوانی کنید و تماس سرور خود را از طریق getUrl ارسال کنید. یک await قبل از sign() از ژست کاربری خارج می‌شود: Safari و Firefox سپس پنجره را مسدود می‌کنند. SDK آن را فوری‌تر باز می‌کند و وقتی وعده شما حل می‌شود بارگذاری می‌کند.
  • • redirectUrl کانال بازگشت است. ما امضاکننده را با اضافه کردن certyneo_status (completed یا declined) و certyneo_envelope به آن ارجاع می‌دهیم. همان اسکریپت را در این صفحه بازگشت بارگذاری کنید: این اسکریپت است که پنجره پورتال باز مانده را از پس‌زمینه مطلع می‌کند.
  • • در حالت یکپارچه، دکمه‌های عمل خود ما غیرفعال می‌شوند. مشتری شما هرگز دعوتی برای ایجاد حساب Certyneo نمی‌بیند.
  • • اگر مرورگر پنجره را رد کند، SDK به‌طور خودکار به تغییر مسیر تمام‌صفحه می‌رود. مسیر برای امضاکننده یکسان است و صفحه بازگشت شما دقیقاً همان پارامترها را دریافت می‌کند.
  • • عمداً هیچ فراخوان «کاربر کنار گذاشت» وجود ندارد: وضعیت پنجره از صفحه شما قابل‌خواندن نیست، و چنین فراخوانی به‌اشتباه فعال می‌شود. امضایی که انجام نشود در انتظار تا webhook باقی می‌ماند.
JavaScriptjavascript
// 1. Your server creates and sends the envelope, then hands the browser the
//    recipient's signing URL. Nothing new on the API side:
//      POST /api/v1/envelopes        { …, "redirectUrl": "https://your-app.com/quote/42/signed" }
//      POST /api/v1/envelopes/{id}/send   → recipients[].accessToken
//      signingUrl = "https://certyneo.com/sign/" + accessToken

// 2. On your quote page — load the SDK once:
//      <script src="https://certyneo.com/embed.js"></script>

document.querySelector("#sign").addEventListener("click", () => {
  Certyneo.sign({
    // Called AFTER the window is already open, so no popup blocker ever
    // sees a delay between the click and window.open.
    getUrl: () =>
      fetch("/api/quote/42/signature", { method: "POST" })
        .then((r) => r.json())
        .then((d) => d.signingUrl),

    onCompleted: (e) => showConfirmation(e.envelopeId),
    onDeclined: () => showDeclined(),
    onError: (e) => showError(e),
  });
});

// 3. On https://your-app.com/quote/42/signed — your return page — load the
//    same script and render a short confirmation. It relays the outcome to
//    the portal window behind it, then closes itself.

رویداد مرورگر اثبات امضا نیست

onCompleted سیگنال نمایشی است که توسط مرورگر منتشر می‌شود، بنابراین هر کسی می‌تواند آن را از کنسول خود جعل کند. هرگز پرونده را بر این اساس به «امضاشده» تغییر ندهید: از آن برای تازه‌کردن صفحه استفاده کنید، و برای وضعیت واقعی به webhook امضاشده envelope.completed که سرور شما دریافت می‌کند تکیه کنید. این تله کلاسیکی ادغام‌های پرداخت است، و اینجا دقیقاً تکرار می‌شود.

توسعه بر روی رایانه شما

با کلید آزمایش، redirectUrl از http://localhost (و 127.0.0.1) پذیرفته می‌شود: تمام مسیر را بر روی ماشین خود پیش از استقرار راه‌اندازی کنید. کلید واقعی آن را رد می‌کند، تا هیچ پاکت تولیدی امضاکننده واقعی را به ماشینی که متعلق به او نیست برنگرداند.

نمایش مراسم در صفحه خود

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

  • • سایت خود را در تنظیمات → امضای یکپارچه اعلام کنید، سپس رکورد DNS نشان‌داده‌شده را منتشر کنید. یک آدرس دقیق: یک زیردامنه یا پورت متفاوت به‌عنوان سایت دیگری محسوب می‌شود.
  • • در هر امضا، یک URL تازه را برای POST /api/v1/envelopes/{id}/embed-url درخواست کنید. این URL دارای اجازه نمایش است و به مدت دو ساعت معتبر است، که با زمان کلیک مطابقت دارد، نه با زمان ایجاد پاکت.
  • • دو مسیر نمی‌توانند در یک فریم اجرا شوند: امضای واجد شرایط، که تایید هویت آن از فریم شدن امتناع می‌کند، و پرداخت در امضا. در هر دو مورد، امضاکننده به سمت یک پنجره کامل هدایت می‌شود.
  • • عبارت «توسط Certyneo قدرت‌گرفته» از فریم از طرح Business حذف می‌شود. خود حالت فریم از طرح Standard شامل است.
JavaScriptjavascript
// Mode cadre : la cérémonie s'affiche DANS votre page.
//
// 1. Déclarez votre site une fois pour toutes dans Réglages → Signature
//    intégrée, et publiez l'enregistrement DNS qu'on vous y donne.
//
// 2. À chaque signature, votre serveur demande une URL fraîche. Elle porte
//    l'autorisation qui permet au navigateur d'afficher la cérémonie chez
//    vous, et vaut deux heures :
//
//      POST /api/v1/envelopes/{id}/embed-url
//      { "origin": "https://portail.exemple.fr" }
//      -> { "signingUrl": "…", "expiresAt": "…" }

Certyneo.sign({
  mode: "iframe",
  el: "#zone-signature",        // sélecteur ou nœud de votre page

  getUrl: () =>
    fetch("/api/devis/42/signature", { method: "POST" })
      .then((r) => r.json())
      .then((d) => d.signingUrl),

  onCompleted: (e) => afficherConfirmation(e.envelopeId),
  onDeclined: () => afficherRefus(),
});

// Le cadre parle à votre page par postMessage — pas besoin de page de retour,
// contrairement au mode fenêtre.

امضا کردن بدون اینکه هیچ ایمیلی ارسال شود

درگاهی که مراسم را در خود نمایش می‌دهد اغلب نیازی به دعوت ما ندارد: با مسیر خود او می‌رسد و برای مشتری‌ای که آن را نمی‌خواهد حساب پیشنهاد می‌کند. مقدار NONE را برای کانال اطلاع‌رسانی دریافت‌کننده تعیین کنید و دیگر چیزی برای او ارسال نخواهد شد — شما او را به امضای خود می‌برید.

  • • این تنظیم به ازای هر دریافت‌کننده است، نه به ازای هر پاکت: می‌توانید کارفرمایی را که میزبانی می‌کنید خاموش کنید و ایمیل را برای دست‌امضاکننده خارجی نگاه دارید، کسی که درگاه ندارد.
  • • این برای امضاکنندگان و تایید‌کنندگان محفوظ است، تنها آن‌هایی که شما برای آن‌ها پیوندی دارید. آن را از پاسخ ایجاد و ارسال می‌خوانید، یا در هنگام کلیک به POST /api/v1/envelopes/{id}/embed-url درخواست یک URL تازه می‌کنید.
  • • یادآوری‌های خودکار برای این دریافت‌کننده خود به خود متوقف می‌شوند: ما هرگز به او نوشته‌ایم، با یادآوری شروع نمی‌کنیم. سایر دریافت‌کنندگان به طور معمول یادآوری می‌شوند.
  • • گواهینامه امضا آن را ذکر می‌کند، دریافت‌کننده به دریافت‌کننده. پروندۀ شواهدی که در این باره ساکت بماند، می‌تواند اعتقاد ایجاد کند که این امضاکننده دعوتی از ما دریافت کرده که هرگز وجود نداشته.
JSONjson
POST /api/v1/envelopes

{
  "subject": "Mandat de gestion",
  "documentIds": ["doc_8f2c1a4b9e7d"],
  "recipients": [
    {
      "email": "client@exemple.fr",
      "name": "Camille Client",
      "role": "SIGNER",
      "notificationChannel": "NONE"
    },
    {
      "email": "notaire@exemple.fr",
      "name": "Maître Notaire",
      "role": "SIGNER"
    }
  ]
}

// La réponse rend le lien de chaque signataire :
//
//   "recipients": [
//     { "email": "client@exemple.fr",  "accessToken": "…",
//       "notificationChannel": "NONE"  },
//     { "email": "notaire@exemple.fr", "accessToken": "…",
//       "notificationChannel": "EMAIL" }
//   ]
//
// Le client ne reçoit rien : vous l'emmenez sur sa signature depuis votre
// portail. Le notaire, lui, reçoit son invitation comme d'habitude.

نام مشتری خود را به عنوان فرستنده نمایش دهید

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

  • • فقط برای طرح Business و بالاتر محفوظ است. در یک طرح پایین‌تر، به جای اینکه امضاکننده نامی غیر از نام مورد انتظار را بخواند، ایجاد رد می‌شود.
  • • نام یک نمایش است: گواهی و ردیابی حسابرسی فرستنده واقعی را حفظ می‌کنند، و ایمیل‌ها همیشه از Certyneo ارسال می‌شوند.
  • • آدرس اختیاری است. بدون آن، امضاکننده فقط نام را می‌بیند، هرگز آدرس صاحب کلید را نه.
JSONjson
POST /api/v1/envelopes

{
  "subject": "Devis 2026-118",
  "documentIds": ["doc_8f2c1a4b9e7d"],
  "recipients": [
    { "email": "client@exemple.fr", "name": "Camille Client", "role": "SIGNER" }
  ],
  "sender": {
    "name": "1.2.3. Panneaux Solaires",
    "email": "devis@123-panneaux-solaires.fr"
  }
}

احراز هویت

هر درخواست کلید 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 که تأخیر را در ثانیه نشان می‌دهد

پیش برفتن