Gå til hovedindhold
Certyneo
Offentlig API v1

Integrer elektronisk signering i din stack

Send kuverter, spor signaturer, modtag webhooks. Simpel REST API, OpenAPI 3.0, curl/Node/Python-eksempler — alt hvad du skal bruge for at forbinde Certyneo med din HRIS, CRM eller forretningssoftware på få timer.

Hurtig start

Tre trin: opret en API-nøgle fra indstillingerne, kodér din PDF i base64, send. Svaret indeholder `signUrl`, som du direkte kan dele med modtageren.

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

Prøv API'en fra dine værktøjer

Postman-samlingen og RapidAPI-arket genereres fra OpenAPI-specifikationen, som også dokumenterer denne side. De tre forbliver således justeret på det rigtige API, endpoint for endpoint, snarere end at divergere ved første tilføjelse.

Postman-samling

De 25 anmodninger organiseret efter domæne — konvolutter, dokumenter, skabeloner, segl, webhooks — med et eksempel på brødtekst og svar for hver enkelt. Indsæt din nøgle i samlingens apiKey-variabel, og kør derefter GET /health: den kræver ingen godkendelse og bekræfter, at din konfiguration er god før det første godkendte opkald.

RapidAPI-ark

Det samme katalog over endpoints, som kan testes direkte fra browseren. Testbænken forventer to forskellige headers: RapidAPI-nøglen, som platformen tildeler dig, og din Certyneo-nøgle i Authorization — det er sidstnævnte, der faktisk autoriserer opkaldet.

Kuverter

Oprettelse, afsendelse, statussporings-, aflysning. En kuvert kan indeholde flere dokumenter og flere underskrivere (parallelt eller sekventielt).

Webhooks

Alle konvolut- og modtagerhændelser (`envelope.sent`, `recipient.signed`, `envelope.completed`…) leveret til din valgte URL — komplet liste på /developers/webhooks. HMAC SHA-256 på hver payload for at verificere oprindelsen.

Simpel autentificering

Bearer token. En nøgle pr. miljø (test/prod). Øjeblikkeligt tilbagekaldelig. Grænse 100 anmodninger/minut/nøgle, burst på 200, korrekt 429 med Retry-After-header.

Tilgængelige endpoints

Alle offentlige ruter: konto, dokumenter, konvolutter, skabeloner, webhooks, elektroniske segl, API-nøgler og fakturering. Alle accepterer et Bearer-token og returnerer 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

Modeller af udstyr

En skabelon registrerer én gang for alle PDF'en, rollerne og placeringen af underskriftfelter, som derefter genbruges ved hver afsendelse: overfør dens identifikator i templateId i stedet for documentIds, og de positionerede felter kopieres til den oprettede kuvert.

  • Skabeloner oprettes fra dashboardet (Skabeloner → Ny skabelon), hvor du uploader dokumentet og positionerer felterne med musen — dette er den enkleste vej. API'en giver også mulighed for at oprette dem via POST /api/v1/templates ved at angive dokumenterne, rollerne og felterne; vær opmærksom på, at felterne her er positioneret i absolutte koordinater (side, x, y, bredde, højde), så du skal kende PDF'ens layout.
  • På en konto, der endnu ikke har registreret nogen skabelon, returnerer GET /api/v1/templates en tom liste. Dette er den normale adfærd, ikke en autentificeringsfejl.
  • Listen indeholder kun skabeloner, der ejes af brugeren, der ejer API-nøglen. En skabelon, der er oprettet af en kollega, vises ikke, selv inden for et delt arbejdsområde: generer nøglen fra kontoen, der ejer skabelonen.
  • templateId og documentIds udelukker hinanden: send den ene eller den anden, aldrig begge eller ingen af dem.
  • Angiv mindst lige så mange SIGNER-modtagere, som skabelonen har underskriftsroller, ellers afvises oprettelsen med 400. Feltet signerCount returneret af listen angiver det forventede antal.
  • Signaturens niveau på skabelonen arves af kuverten, medmindre anmodningen eksplicit sender 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.

Fra Power Automate eller Zapier

Handlingen « Opret en kuvert » i vores no-code-forbindelser dækker kun stien pr. skabelon: feltet Skabelon er obligatorisk der. For et ad hoc-dokument, der ændrer sig ved hver udførelse, skal du bruge handlingen « Upload et dokument » og derefter en råt HTTP-handling til POST /api/v1/envelopes, hvor du sender det returnerede documentIds.

Dokumentafsendelse: to formularer accepteret

POST /api/v1/documents accepterer filen på to måder efter eget valg. De samme kontroller gælder i begge tilfælde: autoriserede typer, grænse på 50 MB, verifikation af binær signatur og antivirusanalyse.

  • I multipart/form-data med en del kaldet file. Det er den klassiske form, den som curl -F og de fleste biblioteker bruger.
  • I råt krop: filens bytes udgør anmodningskroppen, og headeren Content-Type angiver dens type (for eksempel application/pdf). Nyttigt fra et værktøj, der videresender indholdet direkte, uden at pakke anmodningen ind — det er hvad Power Automate-forbindelsen gør.
  • I råt krop har filnavnet ingen plads i kroppen: angiv det via headeren X-File-Name eller parameteren ?fileName=. Uden den navngives dokumentet efter dets type.
  • En ikke-understøttet type svarer 415 ved at navngive de to accepterede formularer, og en krop annonceret som multipart, men ulæselig, svarer 400. Ingen af dem er en serverfejl.
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.

Placering af signaturfelter

Uden en skabelon har en kuvert, der er oprettet fra documentIds, ingen forudpositionerede felter: underskriveren modtager dokumentet uden et sted at underskrive. Arrayet fields, der sendes i det samme opkald til oprettelse, placerer hvert felt med præcision — det svarer på API-siden til, hvad en skabelon engang for alle registrerer.

  • Koordinaterne er i PDF-punkter, oprindelsen i øverste venstre hjørne af siden, og Y-aksen peger nedad (en A4-side måler 595 × 842 punkter). x og y angiver feltets øverste venstre hjørne, width og height dets størrelse.
  • pageNumber starter ved 1, documentIndex starter ved 0. Et sidetal udover dokumentet afvises ikke ved oprettelse: feltet ignoreres ved underskrivelse og vises ingen steder — det er det første, man skal kontrollere, når et felt mangler i opkaldet.
  • recipientEmail skal svare til en af modtagerne i det samme opkald uden forskel på store og små bogstaver. Ellers mislykkes oprettelsen ved at angive alle de fejlagtige linjer, hvilket undgår at korrigere dem en ad gangen.
  • fields og templateId udelukker hinanden: en skabelon har allerede sit eget layout. Arrayet fields bruges derfor kun med documentIds.
  • Accepterede typer: SIGNATURE, INITIALS, DATE_SIGNED, TEXT, CHECKBOX og RADIO_GROUP. required er true som standard; placeholder og dateFormat er valgfri, og options ignoreres kun for RADIO_GROUP.
  • En kuvert accepterer maksimalt 100 felter, 20 dokumenter og 50 modtagere — grænserne for din plan kan være lavere.
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.

Tekstanker: placering af et felt uden at kende koordinaterne

I stedet for koordinater kan et felt citere en tekst, der er udskrevet i dokumentet: anchorText finder det i PDF'en, og serveren beregner positionen ved oprettelsen. Det er tilstanden at foretrække, når dokumentet regenereres ved hvert udsendelse — serialisering, kontraktgenerator — fordi layoutet bevæger sig, mens omtalen « Kundens underskrift » forbliver. anchorPlacement angiver, på hvilken side af teksten feltet er placeret (right som standard, ellers below, above eller left), og anchorIndex vælger forekomsten, når teksten vises flere gange.

x og y er stadig obligatoriske selv med et anker: de tjener som fallback. En ikke-fundet anker medfører ikke oprettelsestransport — feltet bevarer den ordret position, du har leveret, uden fejl eller advarsel i svaret. Angiv derfor et plausibelt fallback i stedet for 0,0, og bekræft gengivelsen på en første udsendelse.

Autentisering

Hvert kald har en API-nøgle i hovedet Authorization. Nøglerne genereres fra Indstillinger → API-nøgler og vises kun én gang.

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_… i produktion, sk_test_… for sandbox. Hovedet: Authorization: Bearer <nøgle>.
  • Omfang: envelopes, documents, webhooks, seals — læsning (:read) eller skrivning (:write). Skrivning implikerer læsning; omfang * giver alle rettigheder.
  • Nøglerne sk_test_ opretter ressourcer i sandbox, udelukket fra kvote og fakturering. Der sendes ingen rigtig e-mail til modtageren, medmindre adressen matcher den afsendende kontos e-mail — nyttigt til at teste hele flowet på dig selv.
  • Fejl: 401 ugyldig nøgle, 403 manglende rettigheder, 429 forhøjet belastning, 402 månedlig kvote nået.

Formen af svar

En ting at vide før du skriver din kunde: samlingerne er indkapslet i et data-objekt, mens enkelte ressourcer returneres flat. Læs response.data.data på en enkeltresurs returnerer derfor undefined.

Samling — indkapsletjson
// GET /api/v1/envelopes
// Collections are WRAPPED in a "data" array.
{
  "data": [
    { "id": "env_abc123", "subject": "Contrat", "status": "SENT" }
  ]
}
Enkeltresurs — flatjson
// GET /api/v1/envelopes/{id}
// Single resources are returned FLAT — no "data" envelope.
{
  "id": "env_abc123",
  "subject": "Contrat",
  "status": "COMPLETED",
  "recipients": [ /* … */ ]
}

Hastighedsbegrænsninger

Begrænsningerne garanterer stabil servicekvalitet for alle kunder. Hvis du har brug for mere, kontakt os.

  • 100 anmodninger pr. minut pr. API-nøgle
  • Burst tolereret op til 200 anmodninger på mindre end 10s
  • 429-svar med Retry-After-header, der angiver forsinkelsen i sekunder