Siirry pääsisältöön
Certyneo
Julkinen API v1

Integroi sähköinen allekirjoitus pinoonsa

Lähetä kirjekuoria, seuraa allekirjoituksia, vastaanota webhookeja. Yksinkertainen REST API, OpenAPI 3.0, curl/Node/Python-esimerkit — kaikki mitä tarvitset Certyneoin liittämiseksi HRIS-, CRM- tai muuhun liiketoiminnalliseen ohjelmistoosi muutamassa tunnissa.

Nopea aloitus

Kolme vaihetta: luodaan API-näkymä asetuksista, base64-koodataan PDF-asiakirja ja lähetetään. Vastauksesta löytyy `signUrl`, jota voidaan jakaa suoraan asiakkaalle.

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

Kokeile API:a omilla työkaluillasi

Postman-kokoelma ja RapidAPI-kortti luodaan OpenAPI-spesifikaatiosta, joka dokumentoi myös tämän sivun. Kaikki kolme pysyvät siis linjassa todellisen API:n kanssa, endpoint kerrallaan, sen sijaan että hajoaisivat ensimmäisessä lisäyksessä.

Postman-kokoelma

25 pyynnöt järjestettyinä aihealueittain — kirjekuoret, asiakirjat, mallit, leimaukset, webhookit — joista jokaisesta on esimerkki rungosta ja vastauksesta. Liitä avaimesi kokoelman apiKey-muuttujaan ja käynnistä sitten GET /health: se ei vaadi todennusta ja vahvistaa, että konfiguraatiosi on oikein ennen ensimmäistä todennettua kutsua.

RapidAPI-kortti

Sama luettelo päätepisteistä, joita voi kokeilla suoraan selaimesta. Testialusta odottaa kahta erillistä otsikkoa: RapidAPI-avainta, jonka alusta sinulle antaa, ja Certyneo-avaintasi Authorization-kenttään — toinen näistä antaa todelliset oikeudet kutsuun.

Kirjekuoret

Luominen, lähettäminen, tilanseuraanta, peruutus. Kirjekuori voi sisältää useita asiakirjoja ja useita allekirjoittajia (rinnakkainen tai peräkkäinen).

Webhookit

Kaikki kirjekuoren ja vastaanottajan tapahtumat (`envelope.sent`, `recipient.signed`, `envelope.completed`…) toimitetaan valitsemaasi URL-osoitteeseen — täydellinen luettelo kohdassa /developers/webhooks. HMAC SHA-256 jokaisella payload-tiedolla lähteen tarkistamista varten.

Yksinkertainen tunnistaminen

Bearer-tunnus. Yksi avain ympäristöä kohden (testi / prod). Peruutettavissa välittömästi. Raja 100 pyyyntöä/min/avain, 200:n purskeilla, siisti 429 Retry-After-otsikolla.

Saatavilla olevat päätepisteet

Kaikki julkiset reitit: tili, dokumentit, kirjekuoret, mallit, webhookit, sähköiset leimapainat, API-avaimet ja laskutus. Kaikki hyväksyvät Bearer-tunnuksen ja palauttavat JSON:n.

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

Käyttöjärjestelmien mallit

Malli tallentaa kerran kaikille PDF:lle, rooleille ja allekirjoituskenttien sijainnille, ja sitä käytetään uudelleen jokaisessa lähetyksessä: välitä sen tunnus templateId:ssä documentIds:n sijaan, ja sijoitetut kentät kopioidaan luodun kirjekuoren päälle.

  • Mallit luodaan koontinäytöstä (Mallit → Uusi malli), jossa lataat asiakirjan ja sijoitat kentät hiirellä — se on yksinkertaisin tapa. API sallii myös niiden luomisen POST /api/v1/templates:lla toimittamalla asiakirjat, roolit ja kentät; huomio, kentät sijoitetaan siellä absoluuttisiin koordinaatteihin (sivu, x, y, leveys, korkeus), joten sinun on tiedettävä PDF:n asettelu.
  • Tilillä, joka ei ole vielä tallentanut yhtään mallia, GET /api/v1/templates palauttaa tyhjän luettelon. Se on normaali käyttäytyminen, ei todentamisvirhe.
  • Luettelo sisältää vain mallit, jotka kuuluvat API-avaimen omistajalle. Kollegasi luoma malli ei näy siinä, vaikka jaetun työtilan sisällä: luo avain tililtä, joka omistaa mallin.
  • templateId ja documentIds sulkevat toisensa pois: lähetä toinen tai toinen, ei koskaan molemmat eikä kumpikaan.
  • Toimita vähintään yhtä monta SIGNER-vastaanottajaa kuin malli sisältää allekirjoitusvuoroja, muuten luominen hylätään 400:lla. Luettelon palauttama signerCount-kenttä ilmoittaa odotetun määrän.
  • Mallin allekirjoitustaso peritään kirjekuorella, ellei pyyntö välitä nimenomaisesti signatureLevel-arvoa.
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.

Avaimet voivat ottaa käyttöön Power Automatesta tai Zapieristä

Meidän no-code-liittimien "Luo kirjekuori" -toiminto kattaa vain mallipolun: Malli-kenttä on pakollinen. Ad hoc -dokumentille, joka muuttuu jokaisella suorituksella, käytä "Lataa dokumentti" -toimintoa ja sitten HTTP-raakatapahtuma osoitteeseen POST /api/v1/envelopes välittämällä palautetun documentIds-arvon.

Dokumentin lähettäminen: kaksi hyväksyttyä muotoa

POST /api/v1/documents hyväksyy tiedoston kahdella tavalla, valintasi mukaan. Samoja valvontoja sovelletaan molemmissa tapauksissa: sallitut tyypit, 50 Mt:n enimmäisraja, binäärisen allekirjoituksen varmennus ja virusanalyysi.

  • Multipart/form-data-muodossa, jossa on file-niminen osa. Se on klassinen muoto, curl -F:n ja useimpien kirjastojen muoto.
  • Raakamuodossa: tiedoston tavut muodostavat pyynnön rungon ja Content-Type-otsikko antaa sen tyypin (esimerkiksi application/pdf). Hyödyllinen työkalusta, joka välittää sisällön sellaisenaan ilman pyynnön käärimistä – näin tekee Power Automate -liitin.
  • Raakamuodossa tiedoston nimellä ei ole paikkaa rungossa: ilmoita se X-File-Name-otsikon tai ?fileName=-parametrin kautta. Ilman sitä dokumentti nimetään sen tyypin mukaan.
  • Ei-tuettu tyyppi vastaa 415:llä mainiten kaksi hyväksyttyä muotoa, ja multipart-ilmoitettu mutta lukematon runko vastaa 400:lla. Kumpikaan ei ole palvelinvirhe.
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.

Allekirjoitusten sijainti

Ilman mallia documentIds-arvoista luodulla kirjekuorella ei ole mitään esiasetettuja kenttiä: allekirjoittaja saa dokumentin ilman allekirjoitusaluetta. Luontikutsun kanssa välitetty fields-taulukko sijoittaa kunkin kentän tarkkaan pisteeseen – se vastaa API-puolella sitä, mitä malli tallentaa kerran ja lopullisesti.

  • Koordinaatit ovat PDF-pisteitä, origo vasemmassa yläkulmassa sivua ja Y-akseli alaspäin (A4-sivu on 595 × 842 pistettä). x ja y ilmoittavat kentän vasemman yläkulman, width ja height sen koon.
  • pageNumber alkaa arvosta 1, documentIndex arvosta 0. Sivunumero, joka ylittää dokumentin, ei hylätä luonnin yhteydessä: kenttä jätetään huomiotta allekirjoituksen yhteydessä eikä näy missään – tämä on ensimmäinen asia tarkistaa, kun kenttä puuttuu puhelusta.
  • recipientEmail:n on vastattava yhtä saman kutsun vastaanottajista, isolla/pienellä kirjoituksella erottamatta. Muussa tapauksessa luonti epäonnistuu ja luetteloi kaikki virheelliset rivit, mikä välttää niiden korjaamisen yksi kerrallaan.
  • fields ja templateId sulkevat toisensa pois: mallilla on jo oma asettelu. Siten fields-taulukkoa käytetään vain documentIds-arvon kanssa.
  • Hyväksytyt tyypit: SIGNATURE, INITIALS, DATE_SIGNED, TEXT, CHECKBOX ja RADIO_GROUP. required on oletusarvoisesti true; placeholder ja dateFormat ovat valinnaisia, ja options huomioidaan vain RADIO_GROUP:ille.
  • Kirjekuori hyväksyy enintään 100 kenttää, 20 dokumenttia ja 50 vastaanottajaa – suunnitelmasi rajat voivat olla pienemmät.
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.

Tekstiankkurit: kentän sijoittaminen ilman koordinaatteja tuntematta

Koordinaattien sijaan kenttä voi viitata dokumentissa tulostettuun tekstiin: anchorText etsii sen PDF:stä ja palvelin laskee sijainnin luonnissa. Tämä on suositeltava tapa, kun dokumentti luodaan uudelleen jokaisella lähettämisellä – pyöräytys, sopimuksien luonti – koska asettelu muuttuu kun taas "Asiakkaan allekirjoitus" pysyy. anchorPlacement kertoo, millä tekstin puolella kenttä sijaitsee (oletuksena right, muuten below, above tai left) ja anchorIndex valitsee esiintymisen kun teksti esiintyy useita kertoja.

x ja y ovat pakollisia jopa ankkurin kanssa: ne toimivat varasuunnitelmana. Löytämätön ankkuri ei epäonnistu luontia – kenttä säilyttää antamasi kirjaimellisen sijainnin ilman virhettä eikä varoitusta vastauksessa. Ilmoita siis todennäköinen varasuunnitelma 0,0:n sijaan ja tarkista piirtäminen ensimmäisellä lähetyksellä.

Tunnistautuminen

Jokainen kutsu sisältää API:n avaimen oikeussa. Avaimet luodaan asetuksia -> API:na ja ne näkyvät vain yhden kerran.

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" } }
  • Muoto: sk_live_… tuotannossa, sk_test_… hiekkalaatikolla. Otsake: Authorization: Bearer <clé>.
  • Vallat: envottimet, dokumentit, webhooks, merkit — lukemiselle (:read) tai kirjoittamiselle (:write). Kirjoittaminen sisältää luettelon myös; vallan * antaa kaikki oikeudet.
  • Avaimet sk_test_ luovat sandbox-resursseja, jotka on jätetty kiintiön ja laskutuksen ulkopuolelle. Vastaanottajalle ei lähetetä oikeaa sähköpostia, ellei hänen osoitteensa vastaa lähettävän tilin sähköpostia — hyödyllinen koko kulun testaamiseen itsellesi.
  • Virheet: 401 väärä avain, 403 riittämätön valloitus, 429 liian suuri lähdöskapasiteetti, 402 kuukausimäärärajan ylittynyt.

Vastauksen muoto

Tieto, miten kirjoittaa asiakkaalle: kokoelmat ovat sisällytetty objektiin dataa, kun taas yksittäiset resurssit palautetaan tasaisesti. Yksittäisen ressin lukemisesta response.data.data palauttaa siis undefined.

Kokoelma — sisällytettyjson
// GET /api/v1/envelopes
// Collections are WRAPPED in a "data" array.
{
  "data": [
    { "id": "env_abc123", "subject": "Contrat", "status": "SENT" }
  ]
}
Yksittäinen resurssi — tasaisestijson
// GET /api/v1/envelopes/{id}
// Single resources are returned FLAT — no "data" envelope.
{
  "id": "env_abc123",
  "subject": "Contrat",
  "status": "COMPLETED",
  "recipients": [ /* … */ ]
}

Nopeudenrajoitukset

Rajoitukset takaavat vakaan palvelun laadun kaikille asiakkaille. Jos tarvitset lisää, ota meihin yhteyttä.

  • 100 pyyntöä minuutissa API-avainta kohden
  • Purskeena sallittu jopa 200 pyyntöä alle 10 sekunnissa
  • 429-vastaus Retry-After-otsikolla, joka ilmoittaa viiveen sekunteissa