Integreer elektronische handtekeningen in uw stack
Verzend enveloppen, volg handtekeningen, ontvang webhooks. Eenvoudige REST API, OpenAPI 3.0, curl/Node/Python-voorbeelden — alles wat u nodig hebt om Certyneo in uw HRIS, CRM of bedrijfsapplicatie in enkele uren in te schakelen.
Snelstartgids
Drie stappen: maak een API-sleutel aan in instellingen, codeer uw PDF in base64, verzend. Het antwoord bevat de `signUrl` die u rechtstreeks met de ontvanger kunt delen.
# 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"// 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);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"])De API vanuit uw tools uitproberen
De Postman-collectie en RapidAPI-kaart worden gegenereerd op basis van de OpenAPI-specificatie die ook deze pagina documenteert. De drie blijven dus aligned met de echte API, endpoint voor endpoint, in plaats van uit elkaar te groeien bij de eerste toevoeging.
Postman-collectie
De 22 verzoeken ingedeeld per domein — enveloppen, documenten, sjablonen, zegels, webhooks — met een voorbeeld van de body en het antwoord voor elk. Plak uw sleutel in de variabele apiKey van de collectie, en voer vervolgens GET /health uit: deze vereist geen authenticatie en bevestigt dat uw configuratie correct is voordat de eerste geverifieerde oproep wordt gedaan.
Enveloppen
Aanmaak, verzending, statusbijhoudingen, annulering. Een enveloppe kan meerdere documenten en meerdere ondertekenaars bevatten (parallel of sequentieel).
Ontvang `envelope.created`, `envelope.completed`, `envelope.declined` op de URL van uw keuze. HMAC SHA-256 op elke payload om de origine te verifiëren.
Alle envelop- en geadresseerde-gebeurtenissen (`envelope.sent`, `recipient.signed`, `envelope.completed`…) afgeleverd op de URL van uw keuze — volledige lijst op /developers/webhooks. HMAC SHA-256 op elke payload om de oorsprong te verifiëren.
Eenvoudige authenticatie
Bearer token. Eén sleutel per omgeving (test / prod). Onmiddellijk in te trekken. Limiet 100 req/min/sleutel, burst van 200, 429 proper met Retry-After header.
Beschikbare eindpunten
12 routes die de volledige cyclus dekken: enveloppen, documenten, webhooks, API-sleutels. Alle routes accepteren een Bearer token en retourneren JSON.
| Method | Path | Description |
|---|---|---|
| GET | /api/v1/account/me | Identity of the authenticated caller (id, email, plan) — scope-less credential probe |
| POST | /api/v1/documents | Upload a PDF (multipart) — returns document id |
| GET | /api/v1/documents | List documents |
| GET | /api/v1/documents/{id} | Fetch document metadata |
| DELETE | /api/v1/documents/{id} | Delete document |
| GET | /api/v1/envelopes | List envelopes (filter with ?status= and ?limit=) |
| POST | /api/v1/envelopes | Create 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}/send | Dispatch DRAFT — sends invitations |
| GET | /api/v1/envelopes/{id}/audit-trail | Download eIDAS audit-trail PDF |
| GET | /api/v1/envelopes/{id}/signed-document | Download signed PDF (once COMPLETED) |
| GET | /api/v1/envelopes/bulk | List your bulk-send jobs |
| POST | /api/v1/envelopes/bulk | Bulk 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/templates | List reusable envelope templates |
| POST | /api/v1/templates | Create a template (documents, roles, positioned fields) |
| POST | /api/v1/sepa-mandates | Generate a SEPA mandate PDF and its DRAFT envelope, fields already placed |
| POST | /api/v1/payroll-adapters/normalize | Normalise a payroll CSV (Silae, Sage Paie, PayFit, Lucca) into the bulk-send shape |
| POST | /api/v1/ag-copropriete | Create a condominium general-meeting envelope (resolutions + ownership shares) |
| POST | /api/v1/ag-copropriete/{envelopeId}/votes | Record a co-owner's votes on the meeting resolutions |
| POST | /api/v1/ag-copropriete/{envelopeId}/tally | Tally 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/webhooks | List webhooks |
| POST | /api/v1/webhooks | Register 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/seals | Apply a qualified electronic seal to a document |
| GET | /api/v1/seals/{id} | Fetch seal status |
| GET | /api/v1/seals/{id}/certificate | Download the seal certificate |
| GET | /api/v1/keys | List API keys |
| POST | /api/v1/keys | Create 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/usage | Current period usage and projected cost |
| GET | /api/v1/status | Service status |
| GET | /api/v1/openapi | Machine-readable OpenAPI specification |
Enveloppesjablonen
Een sjabloon registreert eenmaal voor altijd de PDF, de rollen en de locatie van ondertekenningsvelden, en wordt vervolgens bij elke verzending hergebruikt: geef de bijbehorende identificatie in templateId door in plaats van documentIds, en de gepositioneerde velden worden naar de gemaakte enveloppe gekopieerd.
- • Sjablonen worden gemaakt via het dashboard (Sjablonen → Nieuw sjabloon), waar u het document uploadt en vervolgens de velden met de muis positioneert — dit is het eenvoudigste pad. De API maakt het ook mogelijk deze via POST /api/v1/templates aan te maken door de documenten, rollen en velden op te geven; let op, velden worden hier met absolute coördinaten gepositioneerd (pagina, x, y, breedte, hoogte), dus u moet de opmaak van de PDF kennen.
- • Op een account dat nog geen sjabloon heeft opgeslagen, retourneert GET /api/v1/templates een lege lijst. Dit is het normale gedrag, geen authenticatieprobleem.
- • De lijst bevat alleen sjablonen die eigendom zijn van de gebruiker die de API-sleutel bezit. Een sjabloon gemaakt door een collega staat daar niet in, zelfs niet binnen een gedeelde werkruimte: genereer de sleutel vanuit het account dat eigenaar is van het sjabloon.
- • templateId en documentIds sluiten elkaar uit: verzend het ene of het ander, nooit beide en nooit geen van beide.
- • Geef minstens zoveel SIGNER-ontvangers op als het sjabloon ondertekeningsrollen heeft, anders wordt het aanmaken in 400 geweigerd. Het veld signerCount dat door de lijst wordt geretourneerd geeft het verwachte aantal aan.
- • Het ondertekeniningsniveau van het sjabloon wordt door de enveloppe overgenomen, tenzij het verzoek expliciet signatureLevel doorgeeft.
# 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.Vanuit Power Automate of Zapier
De actie "Enveloppe aanmaken" van onze no-code connectors dekt alleen het sjabloonpad: het veld Sjabloon is daar verplicht. Voor een ad-hoc-document dat bij elke uitvoering verandert, gebruikt u de actie "Document uploaden" en vervolgens een ruwe HTTP-actie naar POST /api/v1/envelopes met de geretourneerde documentIds.
Documentverzending: twee geaccepteerde vormen
POST /api/v1/documents accepteert het bestand op twee manieren, naar keuze. In beide gevallen gelden dezelfde controles: toegestane typen, limiet van 50 MB, binaire handtekeningverificatie en antivirusscan.
- • In multipart/form-data, met een onderdeel met de naam file. Dit is de klassieke vorm, die van curl -F en van de meeste bibliotheken.
- • In onbewerkte body: de bytes van het bestand vormen de body van de verzoek, en de header Content-Type geeft het type aan (bijvoorbeeld application/pdf). Nuttig van een tool die de inhoud ongewijzigd doorgeeft, zonder het verzoek in te pakken — dit is wat de Power Automate-connector doet.
- • In onbewerkte body heeft de bestandsnaam geen plaats in de body: geef het op via de header X-File-Name of de parameter ?fileName=. Zonder het wordt het document genoemd naar het type.
- • Een niet-ondersteund type reageert 415 met vermelding van de twee geaccepteerde vormen, en een body die als multipart wordt aangekondigd maar onleesbaar is, reageert 400. Geen van beide is een serverfout.
# 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.Plaatsing van ondertekenningsvelden
Zonder sjabloon heeft een enveloppe gemaakt van documentIds geen vooraf gepositioneerde velden: de ondertekenaar ontvangt het document zonder plaats om te ondertekenen. De tabel fields, in dezelfde aanroep doorgegeven, positioneert elk veld tot op het puntje nauwkeurig — dit is het equivalent aan API-zijde van wat een sjabloon eenmaal voor altijd opslaat.
- • De coördinaten zijn in PDF-punten, oorsprong in de linkerbovenhoek van de pagina en Y-as naar beneden (een A4-pagina is 595 × 842 punten groot). x en y geven de linkerbovenhoek van het veld aan, width en height zijn de grootte.
- • pageNumber begint op 1, documentIndex begint op 0. Een paginanummer buiten het document wordt niet bij aanmaak geweigerd: het veld wordt genegeerd op het moment van ondertekening en verschijnt nergens — dit is het eerste wat u moet controleren wanneer een veld niet wordt gevonden.
- • recipientEmail moet overeenkomen met een van de ontvangers in dezelfde aanroep, zonder onderscheid naar hoofdletters. Anders mislukt het aanmaken en worden alle foutieve rijen vermeld, wat het corrigeren ervan één voor één voorkomt.
- • fields en templateId sluiten elkaar uit: een sjabloon bevat al zijn eigen opmaak. De tabel fields wordt dus alleen gebruikt met documentIds.
- • Geaccepteerde typen: SIGNATURE, INITIALS, DATE_SIGNED, TEXT, CHECKBOX en RADIO_GROUP. required is standaard true; placeholder en dateFormat zijn optioneel, en options wordt alleen gebruikt voor RADIO_GROUP.
- • Een enveloppe accepteert maximaal 100 velden, 20 documenten en 50 ontvangers — de limieten van uw plan kunnen lager zijn.
# 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.Tekstankers: een veld plaatsen zonder coördinaten te kennen
In plaats van coördinaten kan een veld een in het document afgedrukte tekst aanhalen: anchorText vindt het in de PDF en de server berekent de positie bij aanmaak. Dit is de modus die de voorkeur verdient wanneer het document bij elke verzending opnieuw wordt gegenereerd — adresseringsdruk, contractgenerator — omdat de pagina-indeling verschuift terwijl de vermelding « Handtekening van de klant » blijft staan. anchorPlacement geeft aan aan welke kant van de tekst het veld wordt geplaatst (standaard right, anders below, above of left) en anchorIndex kiest de voorvallen wanneer de tekst meerdere keren voorkomt.
x en y blijven verplicht, zelfs met een anker: ze dienen als terugval. Een anker dat niet kan worden gevonden, leidt niet tot mislukking van de aanmaak — het veld behoudt de letterlijke positie die u hebt opgegeven, zonder fout of waarschuwing in het antwoord. Geef daarom een waarschijnlijke terugval op in plaats van 0,0 en controleer de weergave bij een eerste verzending.
Authenticatie
Elk verzoek bevat een API-sleutel in de Authorization-header. Sleutels worden gegenereerd via Instellingen → API-sleutels en worden slechts eenmaal weergegeven.
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" } }- • Formaat: sk_live_… in productie, sk_test_… voor de sandbox. Header: Authorization: Bearer <clé>.
- • Bereiken: envelopes, documents, webhooks, seals — in leesmodus (:read) of schrijfmodus (:write). Schrijven impliceert lezen; het bereik * geeft alle rechten.
- • sk_test_-sleutels maken resources in de sandbox aan, uitgesloten van quota en facturering.
- • Fouten: 401 ongeldige sleutel, 403 onvoldoende bereik, 429 snelheidslimiet overschreden, 402 maandelijks quota bereikt.
Vorm van antwoorden
Een belangrijk punt voordat u uw client schrijft: collecties zijn ingekapseld in een data-object, terwijl individuele resources volledig worden geretourneerd. Het lezen van response.data.data op een individuele resource retourneert dus undefined.
// GET /api/v1/envelopes
// Collections are WRAPPED in a "data" array.
{
"data": [
{ "id": "env_abc123", "subject": "Contrat", "status": "SENT" }
]
}// GET /api/v1/envelopes/{id}
// Single resources are returned FLAT — no "data" envelope.
{
"id": "env_abc123",
"subject": "Contrat",
"status": "COMPLETED",
"recipients": [ /* … */ ]
}Debietlimieten
De limieten garanderen stabiele servicekwaliteit voor alle klanten. Als u meer nodig hebt, neem dan contact met ons op.
- • 100 verzoeken per minuut per API-sleutel
- • Burst toegestaan tot 200 verzoeken in minder dan 10s
- • Antwoord 429 met Retry-After header die de vertraging in seconden aangeeft