Zintegruj podpis elektroniczny w swoim stosie technologicznym
Wysyłaj koperty, śledź podpisy, odbieraj webhoki. Proste API REST, OpenAPI 3.0, przykłady curl/Node/Python — wszystko, aby podłączyć Certyneo do swojego HRIS, CRM lub oprogramowania biznesowego w kilka godzin.
Szybki start
Trzy kroki: utwórz klucz API z ustawień, zakoduj swój PDF w base64, wyślij. Odpowiedź zawiera `signUrl`, którą możesz bezpośrednio udostępnić odbiorcy.
# 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"])Spróbuj API za pomocą swoich narzędzi
Kolekcja Postman i karta RapidAPI są generowane ze specyfikacji OpenAPI, która dokumentuje również tę stronę. Wszystkie trzy pozostają wyrównane do rzeczywistego API, endpoint po endpoincie, zamiast rozbiegać się przy pierwszym dodaniu.
Kolekcja Postman
25 żądania podzielone według domenów — koperty, dokumenty, szablony, pieczęcie, webhooki — z przykładem treści i odpowiedzi dla każdego. Wklej swój klucz do zmiennej apiKey w kolekcji, a następnie uruchom GET /health: nie wymaga żadnego uwierzytelnienia i potwierdza, że Twoja konfiguracja jest prawidłowa przed pierwszym uwierzytelnionym wywołaniem.
Koperty
Tworzenie, wysyłanie, śledzenie stanu, anulowanie. Koperta może zawierać wiele dokumentów i wielu signatariuszy (równolegle lub sekwencyjnie).
Webhoki
Wszystkie zdarzenia koperty i odbiorcy (`envelope.sent`, `recipient.signed`, `envelope.completed`…) dostarczane na wybrany przez Ciebie URL — pełna lista na /developers/webhooks. HMAC SHA-256 na każdym payload'u w celu weryfikacji pochodzenia.
Proste uwierzytelnianie
Bearer token. Jeden klucz na środowisko (test / prod). Natychmiast odwoływalny. Limit 100 req/min/klucz, burst do 200, czysty kod 429 z nagłówkiem Retry-After.
Dostępne endpointy
Wszystkie publiczne trasy: konto, dokumenty, koperty, szablony, webhooks, pieczęcie elektroniczne, klucze API i rozliczenia. Wszystkie akceptują token Bearer i zwracają 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 |
Modely obudowa
Szablon zapisuje raz na zawsze plik PDF, role i lokalizację pól podpisu, a następnie jest ponownie używany przy każdym wysłaniu: przekaż jego identyfikator w templateId zamiast documentIds, a umieszczone pola zostaną skopiowane do utworzonej koperty.
- • Szablony są tworzone z pulpitu nawigacyjnego (Szablony → Nowy szablon), gdzie wgrywasz dokument i umieszczasz pola za pomocą myszy — to najprostszy sposób. API umożliwia również ich tworzenie za pośrednictwem POST /api/v1/templates, dostarczając dokumenty, role i pola; uwaga, pola są tam umieszczane we współrzędnych bezwzględnych (strona, x, y, szerokość, wysokość), musisz zatem znać układ PDF.
- • Na koncie, które jeszcze nie zarejestrowało żadnego szablonu, GET /api/v1/templates zwraca pustą listę. To normalne zachowanie, a nie błąd uwierzytelnienia.
- • Lista zawiera tylko szablony należące do użytkownika będącego właścicielem klucza API. Szablon utworzony przez kolegę nie pojawia się na liście, nawet w ramach udostępnionej przestrzeni roboczej: wygeneruj klucz z konta, które posiada szablon.
- • templateId i documentIds wzajemnie się wykluczają: wyślij jeden lub drugi, nigdy oba ani żaden z nich.
- • Podaj co najmniej tyle odbiorców SIGNER, ile ról podpisujących zawiera szablon, w przeciwnym razie utworzenie jest odrzucane z kodem 400. Pole signerCount zwrócone przez listę wskazuje oczekiwaną liczbę.
- • Poziom podpisu szablonu jest dziedziczony przez kopertę, chyba że żądanie wyraźnie przekazuje 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.Z powodu Power Automate lub Zapier
Akcja « Utwórz kopertę » naszych łączników no-code obejmuje tylko ścieżkę według szablonu: pole Szablon jest tam obowiązkowe. W przypadku dokumentu ad hoc, który zmienia się przy każdym wykonaniu, użyj akcji « Prześlij dokument », a następnie akcji HTTP do POST /api/v1/envelopes, przekazując zwrócone documentIds.
Wysyłanie dokumentu: dwie akceptowane formy
POST /api/v1/documents akceptuje plik na dwa sposoby, do wyboru. Te same kontrole mają zastosowanie w obu przypadkach: dozwolone typy, limit 50 MB, weryfikacja sygnatury binarnej i analiza antywirusowa.
- • W multipart/form-data, z częścią o nazwie file. Jest to forma klasyczna, ta z curl -F i większości bibliotek.
- • W surowym korpusie: bajty pliku stanowią treść żądania, a nagłówek Content-Type podaje jego typ (na przykład application/pdf). Przydatne z narzędzia, które przekazuje zawartość jako taką, bez owijania żądania — to właśnie robi łącznik Power Automate.
- • W surowym korpusie nazwa pliku nie ma miejsca w treści: podaj ją poprzez nagłówek X-File-Name lub parametr ?fileName=. Bez niej dokument jest nazwany selon jego typ.
- • Nieobsługiwany typ odpowiada 415 i wymienia dwie akceptowane formy, a korpus ogłoszony jako multipart ale niemożliwy do odczytania odpowiada 400. Żaden z nich nie jest błędem serwera.
# 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.Umieszczenie pól podpisu
Bez szablonu koperta utworzona z documentIds nie ma żadnych wstępnie umieszczonych pól: podpisujący otrzymuje dokument bez miejsca do podpisu. Tablica fields, przesłana w tym samym wywołaniu tworzenia, umieszcza każde pole z dokładnością do punktu — jest to odpowiednik API tego, co szablon zapisuje raz na zawsze.
- • Współrzędne są w punktach PDF, początek w lewym górnym rogu strony i oś Y w dół (strona A4 ma wymiary 595 × 842 punktów). x i y oznaczają lewy górny róg pola, width i height jego rozmiar.
- • pageNumber zaczyna się od 1, documentIndex zaczyna się od 0. Numer strony poza dokumentem nie jest odrzucany podczas tworzenia: pole jest ignorowane w momencie podpisywania i nigdzie się nie pojawia — to pierwsza rzecz do sprawdzenia, gdy pole brakuje w wywołaniu.
- • recipientEmail musi odpowiadać jednemu z odbiorców z tego samego wywołania, bez rozróżniania wielkości liter. W przeciwnym razie tworzenie nie powiedzie się, wymieniając wszystkie błędne wiersze, co pozwala uniknąć korygowania ich pojedynczo.
- • fields i templateId się wzajemnie wykluczają: szablon nosi już własny układ. Tablica fields jest zatem używana tylko z documentIds.
- • Akceptowane typy: SIGNATURE, INITIALS, DATE_SIGNED, TEXT, CHECKBOX i RADIO_GROUP. required jest domyślnie true; placeholder i dateFormat są opcjonalne, a options jest brane pod uwagę tylko dla RADIO_GROUP.
- • Koperta akceptuje maksymalnie 100 pól, 20 dokumentów i 50 odbiorców — limity planu mogą być niższe.
# 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.Zakotwiczenia tekstowe: umieszczenie pola bez znajomości współrzędnych
Zamiast współrzędnych pole może cytować tekst wydrukowany w dokumencie: anchorText wyszukuje go w PDF, a serwer oblicza pozycję podczas tworzenia. Jest to tryb do preferowania, gdy dokument jest regenerowany przy każdym wysłaniu — korespondencja seryjna, generator umów — ponieważ układ się zmienia, podczas gdy tekst „Podpis klienta" pozostaje. anchorPlacement wskazuje, po której stronie tekstu umieszczone jest pole (domyślnie right, w przeciwnym razie below, above lub left) a anchorIndex wybiera wystąpienie, gdy tekst pojawia się wiele razy.
x i y pozostają obowiązkowe nawet z zakotwiczeniem: służą jako rezerwowe. Nieznalezione zakotwiczenie nie powoduje niepowodzenia tworzenia — pole zachowuje dosłowną pozycję, którą podałeś, bez błędu ani ostrzeżenia w odpowiedzi. Podaj zatem wiarygodne rezerwowe zamiast 0,0 i sprawdź renderowanie przy pierwszym wysłaniu.
Autoryzacja
Każde wywołanie zawiera klucz API w nagłówku Authorization. Klucze generuje się z poziomu Ustawienia → Klucze API i są wyświetlane tylko raz.
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_… w produkcji, sk_test_… dla piaskownicy. Nagłówek: Authorization: Bearer <clé>.
- • Zakresy: envelopes, documents, webhooks, seals — do odczytu (:read) lub zapisu (:write). Zapis implikuje odczyt; zakres * udziela wszystkich uprawnień.
- • Klucze sk_test_ tworzą zasoby w piaskownicy, wyłączone z limitu i rozliczeń. Żaden prawdziwy e-mail nie jest wysyłany do odbiorcy, chyba że jego adres pokrywa się z adresem e-mail konta wysyłającego — przydatne do przetestowania całego przepływu na sobie.
- • Błędy: 401 nieprawidłowy klucz, 403 niewystarczający zakres, 429 przekroczony limit szybkości, 402 osiągnięty miesięczny limit.
Forma odpowiedzi
Ważny punkt do zapamiętania przed napisaniem klienta: kolekcje są hermetyzowane w obiekcie data, podczas gdy zasoby jednostkowe są zwracane płasko. Odczyt response.data.data na zasobie jednostkowym zwraca zatem 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": [ /* … */ ]
}Limity szybkości
Limity gwarantują stabilną jakość usług dla wszystkich klientów. Jeśli potrzebujesz więcej, skontaktuj się z nami.
- • 100 żądań na minutę na klucz API
- • Burst tolerowany do 200 żądań w mniej niż 10s
- • Odpowiedź 429 z nagłówkiem Retry-After wskazującym opóźnienie w sekundach