Integrera elektronisk signatur i din stack
Skicka kuvert, följ signaturer, ta emot webhooks. Enkelt REST API, OpenAPI 3.0, curl/Node/Python-exempel — allt för att koppla Certyneo till din HRIS, CRM eller affärsmjukvara på några timmar.
Snabbstart
Tre steg: skapa en API-nyckel från inställningarna, koda din PDF i base64, skicka. Svaret innehåller `signUrl` som du kan dela direkt med mottagaren.
# 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"// 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);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"])Prova API:et från dina verktyg
Postman-samlingen och RapidAPI-arket genereras från OpenAPI-specifikationen som också dokumenterar denna sida. De tre förblir därför justerade med det verkliga API:et, endpoint för endpoint, snarare än att divergera vid första tillägg.
Postman-samling
De 25 förfrågningarna organiserade efter domän — kuvert, dokument, mallar, sigill, webhooks — med ett exempel på brödtext och svar för var och en. Klistra in din nyckel i samlingens apiKey-variabel och kör sedan GET /health: den kräver ingen autentisering och bekräftar att din konfiguration är bra före det första autentiserade anropet.
Kuvert
Skapande, sändning, statusövervakning, annullering. Ett kuvert kan innehålla flera dokument och flera undertecknare (parallell eller sekventiell).
Webbooks
Alla kuvert- och mottagarhändelser (`envelope.sent`, `recipient.signed`, `envelope.completed`…) levererade till din valda URL — komplett lista på /developers/webhooks. HMAC SHA-256 på varje payload för att verifiera ursprunget.
Enkel autentisering
Bearer-token. En nyckel per miljö (test / prod). Återkallningsbar omedelbar. Gräns 100 req/min/nyckel, burst på 200, ren 429 med Retry-After-rubrik.
Tillgängliga endpoints
Alla offentliga vägar: konto, dokument, kuvert, mallar, webhooks, elektroniska sigill, API-nycklar och fakturering. Alla accepterar en Bearer-token och returnerar 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/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/verify | Public: verify an audit entry + proof against its anchored Merkle root (no auth, reveals nothing) |
| 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 |
Modell för innehållskapsul
En mall registrerar en gång för alla PDF-filen, rollerna och placeringen av signeringsfält, och återanvänds sedan vid varje sändning: skicka dess identifierare i templateId istället för documentIds, och de positionerade fälten kopieras om på det skapade kuvertet.
- • Mallar skapas från instrumentpanelen (Mallar → Ny mall), där du överför dokumentet och placerar sedan fälten med musen — det är det enklaste sättet. API:et tillåter också att skapa dem via POST /api/v1/templates, genom att tillhandahålla dokument, roller och fält; notera att fält där positioneras i absoluta koordinater (sida, x, y, bredd, höjd), så du måste känna till PDF:ens layout.
- • På ett konto som ännu inte har registrerat någon mall returnerar GET /api/v1/templates en tom lista. Det är normalt beteende, inte en autentiseringsfel.
- • Listan innehåller endast mallar som tillhör användaren som äger API-nyckeln. En mall som skapats av en kollega finns inte i listan, även inom en delad arbetsyta: generera nyckeln från kontot som äger mallen.
- • templateId och documentIds är ömsesidigt uteslutande: skicka antingen det ena eller det andra, aldrig båda eller inget av dem.
- • Ange minst lika många SIGNER-mottagare som mallen har undertecknarroller, annars nekas skapandet med 400. Fältet signerCount som returneras av listan anger det förväntade antalet.
- • Mallens signeringsnivå ärvs av kuvertet, såvida inte begäran uttryckligen skickar signatureLevel.
# 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.Från Power Automate eller Zapier
Åtgärden "Skapa ett kuvert" för våra no-code-anslutningar täcker endast mallvägen: fältet Mall är obligatoriskt där. För ett ad hoc-dokument som ändras vid varje körning, använd åtgärden "Ladda upp ett dokument" och sedan en rå HTTP-åtgärd till POST /api/v1/envelopes genom att skicka det returnerade documentIds.
Sändning av dokument: två godkända former
POST /api/v1/documents accepterar filen på två sätt, efter eget val. Samma kontroller gäller i båda fallen: tillåtna typer, gräns på 50 MB, verifiering av binär signatur och antivirusanalys.
- • I multipart/form-data, med en del som heter file. Det är den klassiska formen, den för curl -F och de flesta biblioteken.
- • I rå brödtext: filens oktetter utgör begärandets brödtext, och Content-Type-huvudet anger dess typ (application/pdf till exempel). Användbar från ett verktyg som överför innehållet som det är, utan att linda in begäran — det är vad Power Automate-kopplingen gör.
- • I raw body är filnamnet inte på plats i body: ange det via X-File-Name-huvudet eller parametern ?fileName=. Utan det namnges dokumentet efter sin typ.
- • En icke-stödd typ svarar 415 och namnger de två accepterade formaten, och en body som annonseras som multipart men inte är läsbar svarar 400. Ingen av dessa är ett serverfel.
# 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.Placering av signaturfält
Utan mall skapar ett kuvert från documentIds inga förpositionerade fält: mottagaren får dokumentet utan någon signeringsplats. Matrisen fields, överfördl i samma skapelseanrop, placerar varje fält på punkten — det är motsvarigheten på API-sidan till vad en mall sparar en gång för alla.
- • Koordinaterna är i PDF-poäng, ursprung i övre vänstra hörnet av sidan och Y-axel nedåt (en A4-sida mäter 595 × 842 poäng). x och y anger övre vänstra hörnet av fältet, width och height dess storlek.
- • pageNumber börjar på 1, documentIndex börjar på 0. Ett sidnummer bortom dokumentet avvisas inte vid skapelse: fältet ignoreras vid underteckningstillfället och visas inte någonstans — det är det första att kontrollera när ett fält saknas i anropet.
- • recipientEmail måste matcha en av mottagarna från samma anrop, utan skiftlägeskänslighet. Annars misslyckas skapelsen genom att lista alla felaktiga rader, vilket undviker att korrigera dem en efter en.
- • fields och templateId utesluter varandra: en mall bär redan sin egen layout. Matrisen fields används därför bara med documentIds.
- • Accepterade typer: SIGNATURE, INITIALS, DATE_SIGNED, TEXT, CHECKBOX och RADIO_GROUP. required är sant som standard; placeholder och dateFormat är valfria, och options beaktas bara för RADIO_GROUP.
- • Ett kuvert accepterar högst 100 fält, 20 dokument och 50 mottagare — din plans gränser kan vara lägre.
# 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.Textankar: placera ett fält utan att känna till koordinaterna
I stället för koordinater kan ett fält citera en text som är tryckt i dokumentet: anchorText letar upp det i PDF:en och servern beräknar positionen vid skapelse. Det är läget att föredra när dokumentet återskapas vid varje sändning — kopplingsbrev, kontraktsgenerator — eftersom layouten ändras medan anmärkningen "Kundens signatur" förblir. anchorPlacement anger på vilken sida av texten fältet placeras (right som standard, annars below, above eller left) och anchorIndex väljer förekomsten när texten visas flera gånger.
x och y förblir obligatoriska även med ett ankar: de fungerar som fallback. Ett ankar som inte hittas orsakar inte att skapelsen misslyckas — fältet behåller den bokstavliga positionen du angav, utan fel eller varning i svaret. Ange därför ett rimligt fallback i stället för 0,0 och verifiera renderingen vid en första sändning.
Autentisering
Varje anrop bär en API-nyckel i Authorization-huvudet. Nycklar genereras från Inställningar → API-nycklar och visas bara en gång.
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_… i produktion, sk_test_… för sandbox. Rubrik: Authorization: Bearer <clé>.
- • Omfång: envelopes, documents, webhooks, seals — i läsning (:read) eller skrivning (:write). Skrivning medför läsning; omfånget * ger alla rättigheter.
- • Nycklarna sk_test_ skapar resurser i sandlådan, exkluderade från kvoten och faktureringen. Inget riktigt e-postmeddelande skickas till mottagaren, om inte dennes adress matchar det sändande kontots e-post — användbart för att testa hela flödet på dig själv.
- • Fel: 401 ogiltig nyckel, 403 otillräckligt omfång, 429 gräns för datahastighet överskriden, 402 månatlig kvot nådd.
Formulär för svar
En sak att känna till innan du skriver din klient: samlingar är inkapslade i ett data-objekt, medan enskilda resurser returneras platt. Att läsa response.data.data på en enskild resurs returnerar därför 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": [ /* … */ ]
}Hastighetsgränser
Gränserna garanterar stabil servicekvalitet för alla kunder. Om du behöver mer, kontakta oss.
- • 100 förfrågningar per minut per API-nyckel
- • Burst tolererat upp till 200 förfrågningar på mindre än 10 sekunder
- • 429-svar med Retry-After-rubrik som anger fördröjningen i sekunder