Mergeți la conținutul principal
Certyneo
API publică v1

Integrați semnătura electronică în stack-ul dvs.

Trimiteți pluve, urmăriți semnăturile, primiți webhooks. API REST simplu, OpenAPI 3.0, exemple curl/Node/Python — tot ceea ce trebuie pentru a conecta Certyneo la HRIS, CRM sau software-ul dvs. în câteva ore.

Trei pași: creați o cheie API din setări, codificați PDF-ul în base64, trimiteți. Răspunsul conține `signUrl` pe care îl puteți partaja direct cu destinatarul.

Pluve

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"])

Încercați API-ul din instrumentele dumneavoastră

Colecția Postman și fișa RapidAPI sunt generate din specificația OpenAPI care documentează și această pagină. Cele trei rămân deci aliniate cu API-ul real, endpoint cu endpoint, în loc să diverge la primul adaos.

Colecția Postman

Cele 25 de cereri aranjate după domeniu — plicuri, documente, șabloane, sigilii, webhook-uri — cu un exemplu de corp și răspuns pentru fiecare. Lipiți cheia dumneavoastră în variabila apiKey a colecției, apoi lansați GET /health: nu necesită nicio autentificare și confirmă că configurația dumneavoastră este bună înainte de primul apel autentificat.

Fișa RapidAPI

Același catalog de endpoint-uri, testabil direct din browser. Banca de testare așteaptă două anteturi distincte: cheia RapidAPI pe care vă o atribuie platforma și cheia Certyneo în Authorization — a doua autorizează cu adevărat apelul.

Creație, trimitere, urmărire de stare, anulare. O pluă poate conține mai multe documente și mai mulți semnatari (paralel sau secvențial).

Webhooks

Primiți `envelope.created`, `envelope.completed`, `envelope.declined` pe URL-ul dvs. HMAC SHA-256 pe fiecare payload pentru a verifica originea.

Toate evenimentele de plic și destinatar (`envelope.sent`, `recipient.signed`, `envelope.completed`…) livrate la URL-ul dvs. de alegere — listă completă pe /developers/webhooks. HMAC SHA-256 pe fiecare sarcină pentru a verifica originea.

Autentificare simplă

Token de tip „bearer”. O cheie pentru fiecare mediu (test / producție). Revocabilă instantaneu. Limită de 100 de solicitări/minut/cheie, vârf de 200, 429 propriu cu antetul Retry-After.

12 rute acoperind ciclul complet: pluve, documente, webhooks, chei API. Toate rutele acceptă Bearer token și returnează JSON.

Toate rutele publice: cont, documente, plicuri, șabloane, webhooks, ștampile electronice, chei API și facturare. Toate acceptă un token Bearer și returnează 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/audit-anchors/{root}Public: metadata of an anchored audit batch, or the .ots proof file with ?format=ots (no auth)
POST/api/v1/audit-anchors/verifyPublic: verify an audit entry + proof against its anchored Merkle root (no auth, reveals nothing)
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

Modeluri de înveliș

Un șablon înregistrează o dată pentru totdeauna PDF-ul, rolurile și locația câmpurilor de semnare, apoi se reutilizează la fiecare trimitere: transmiteți identificatorul acestuia în templateId în loc de documentIds, iar câmpurile poziționate sunt recopiate pe plicul creat.

  • Șabloanele se creează din tabloul de bord (Șabloane → Șablon nou), unde depuneți documentul și apoi poziționați câmpurile cu mouse-ul — acesta este calea cea mai simplă. API permite și crearea lor prin POST /api/v1/templates, furnizând documentele, rolurile și câmpurile; atenție, câmpurile sunt poziționate în coordonate absolute (pagină, x, y, lățime, înălțime), deci trebuie să cunoașteți aspectul PDF-ului.
  • Pe un cont care nu a înregistrat încă nici un șablon, GET /api/v1/templates returnează o listă goală. Acesta este comportamentul normal, nu o eroare de autentificare.
  • Lista conține doar șabloanele aparținând utilizatorului proprietar al cheii API. Un șablon creat de un coleg nu apare pe ea, chiar și într-un spațiu de lucru partajat: generați cheia din contul care deține șablonul.
  • templateId și documentIds se exclud reciproc: trimiteți unul sau altul, niciodată amândoi nici nici una din ele.
  • Furnizați cel puțin atât de mulți destinatari SIGNER cât are șablonul roluri semnătare, altfel crearea este respingă cu 400. Câmpul signerCount returnat de listă indică numărul așteptat.
  • Nivelul de semnătură al modelului este moștenit de către plic, decât dacă cererea transmite în mod explicit 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.

De la Power Automate sau Zapier

Acțiunea « Creează un plic » din conectoarele noastre fără cod acoperă doar calea după model: câmpul Model este obligatoriu. Pentru un document ad hoc care se schimbă la fiecare execuție, utilizați acțiunea « Încărcă un document » apoi o acțiune HTTP brută către POST /api/v1/envelopes transmițând documentIds-ul returnat.

Trimiterea documentului: două forme acceptate

POST /api/v1/documents acceptă fișierul în două moduri, la alegere. Aceleași controale se aplică în ambele cazuri: tipuri autorizate, plafon de 50 Mo, verificarea semnăturii binare și analiză antivirus.

  • În multipart/form-data, cu o parte numită file. Aceasta este forma clasică, cea a curl -F și a majorității bibliotecilor.
  • În corp brut: octeții fișierului constituie corpul cererii, iar antetul Content-Type indică tipul acestuia (application/pdf de exemplu). Util din parte unui instrument care transmite conținutul în forma lui brută, fără a înfășura cererea — aceasta este ceea ce face conectorul Power Automate.
  • În corp brut, numele fișierului nu are loc în corp: indicați-l prin antetul X-File-Name sau prin parametrul ?fileName=. Fără acesta, documentul este numit după tipul său.
  • Un tip nesuportat răspunde 415 numind cele două forme acceptate, iar un corp anunțat ca multipart dar ilizibil răspunde 400. Nici unul dintre acestea nu este o eroare de server.
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.

Plasarea campurilor de semnare

Fără model, un plic creat din documentIds nu are niciun câmp pre-poziționat: semnatarul primește documentul fără un loc unde să semneze. Tabloul fields, transmis în același apel de creare, plasează fiecare câmp la punct exact — este echivalentul, pe partea API, a ceea ce un model înregistrează o dată pentru totdeauna.

  • Coordonatele sunt în puncte PDF, originea în colțul din stânga sus al paginii și axa Y în jos (o pagină A4 măsoară 595 × 842 puncte). x și y desemnează colțul din stânga sus al câmpului, width și height dimensiunea acestuia.
  • pageNumber începe de la 1, documentIndex începe de la 0. Un număr de pagină dincolo de document nu este respins la creare: câmpul este ignorat la momentul semnării și nu apare nicăieri — aceasta este primul lucru de verificat atunci când un câmp lipsește apelului.
  • recipientEmail trebuie să corespundă unuia dintre destinatarii din același apel, fără distincție între majuscule și minuscule. Altfel, crearea eșuează prin enumerarea tuturor liniilor defectuoase, ceea ce evită corectarea lor una după alta.
  • fields și templateId se exclud reciproc: un model poartă deja propria sa punere în pagină. Tabloul fields se utilizează deci doar cu documentIds.
  • Tipuri acceptate: SIGNATURE, INITIALS, DATE_SIGNED, TEXT, CHECKBOX și RADIO_GROUP. required valorează true în mod implicit; placeholder și dateFormat sunt opționale, iar options este reținut doar pentru RADIO_GROUP.
  • Un plic acceptă maximum 100 de câmpuri, 20 de documente și 50 de destinatari — limitele planului dvs. putând fi mai mici.
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.

Ancore de text: plasați un câmp fără a cunoaște coordonatele

Mai degrabă decât coordonate, un câmp poate cita un text imprimat în document: anchorText îl localizează în PDF și serverul calculează poziția la creare. Acesta este modul de preferat atunci când documentul este regenerat la fiecare trimitere — litere cu corespondență, generator de contracte — deoarece punerea în pagină se mișcă în timp ce menționarea « Semnătura clientului » rămâne. anchorPlacement indică de ce parte a textului se plasează câmpul (right în mod implicit, altfel below, above sau left) și anchorIndex alege apariția atunci când textul apare de mai multe ori.

x și y rămân obligatorii chiar și cu o ancoră: servesc ca rezervă. O ancoră nelocalizată nu face ca crearea să eșueze — câmpul păstrează poziția literală pe care ați furnizat-o, fără eroare sau avertisment în răspuns. Indicați deci o rezervă plauzibilă mai degrabă decât 0,0, și verificați redarea pe o primă trimitere.

Autentificare

Fiecare apel poartă o cheie API în antetul Authorization. Cheile se generează din Setări → Chei API și sunt afișate o singură dată.

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" } }
  • Format: sk_live_… în producție, sk_test_… pentru sandbox. Antet: Authorization: Bearer <clé>.
  • Domenii: envelopes, documents, webhooks, seals — în citire (:read) sau scriere (:write). Scrierea implică citirea; domeniul * acordă toate drepturile.
  • Cheile sk_test_ creează resurse în sandbox, excluse din cotă și factură. Niciun e-mail real nu este trimis destinatarului, cu excepția cazului în care adresa acestuia se potrivește cu e-mailul contului expeditor — util pentru a testa fluxul complet pe tine însuți.
  • Erori: 401 cheie nevalidă, 403 domeniu insuficient, 429 limită de debit depășită, 402 cotă lunară atinsă.

Forma răspunsurilor

Un punct de cunoscut înainte de a scrie clientul dvs.: colecțiile sunt încapsulate într-un obiect data, în timp ce resursele unitare sunt returnate plat. Citirea response.data.data pe o resursă unitară returnează deci undefined.

Collecție — închisăjson
// GET /api/v1/envelopes
// Collections are WRAPPED in a "data" array.
{
  "data": [
    { "id": "env_abc123", "subject": "Contrat", "status": "SENT" }
  ]
}
Ressource unitaire — la platăjson
// GET /api/v1/envelopes/{id}
// Single resources are returned FLAT — no "data" envelope.
{
  "id": "env_abc123",
  "subject": "Contrat",
  "status": "COMPLETED",
  "recipients": [ /* … */ ]
}

Limitele garantează o calitate de serviciu stabilă pentru toți clienții. Dacă aveți nevoie de mai mult, contactați-ne.

100 cereri pe minut pe cheie API

  • 100 de solicitări pe minut per cheie API
  • Se tolerează un vârf de trafic de până la 200 de solicitări în mai puțin de 10 secunde
  • Răspuns 429 cu antet Retry-After indicând întârzierea în secunde