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
52 publicznych tras: konto, dokumenty, koperty, szablony, webhooki, pieczęcie elektroniczne, klucze API i rozliczenia. Wszystkie akceptują token Bearer i zwracają JSON.
| Metoda | Ścieżka | Opis |
|---|---|---|
| GET | /api/v1/account/me | Tożsamość uwierzytelnionego wywołującego (id, e-mail, plan) : test identyfikatorów bez wymaganego zakresu |
| GET | /api/v1/sandbox | Zliczanie danych utworzonych kluczami testowymi (usuwanych automatycznie po 30 dniach) |
| DELETE | /api/v1/sandbox | Usuwanie wszystkich danych utworzonych kluczami testowymi, bez naruszania prawdziwych danych |
| POST | /api/v1/documents | Przesłać plik PDF (multipart) : zwraca identyfikator dokumentu |
| GET | /api/v1/documents | Wyświetl listę dokumentów |
| GET | /api/v1/documents/{id} | Odczytaj metadane dokumentu |
| DELETE | /api/v1/documents/{id} | Usuń dokument |
| GET | /api/v1/envelopes | Wyświetl listę kopert (filtruj za pomocą ?status= i ?limit=) |
| POST | /api/v1/envelopes | Utwórz kopertę (status DRAFT) : na podstawie templateId lub documentIds z opcjonalną tablicą fields |
| GET | /api/v1/envelopes/{id} | Odczytaj stan koperty |
| PATCH | /api/v1/envelopes/{id} | Zmodyfikuj kopertę DRAFT |
| DELETE | /api/v1/envelopes/{id} | Usuń kopertę DRAFT (409 po wysłaniu : anuluj ją zamiast tego) |
| POST | /api/v1/envelopes/{id}/send | Wyślij kopertę DRAFT : wysyła zaproszenia |
| POST | /api/v1/envelopes/{id}/void | Anuluj wysłaną kopertę, która nie jest jeszcze w pełni podpisana : oczekujący sygnatariusze są powiadamiani |
| GET | /api/v1/envelopes/{id}/audit-trail | Pobierz plik PDF dziennika audytu eIDAS |
| POST | /api/v1/envelopes/{id}/embed-url | Zwraca adres URL podpisu odbiorcy wraz z autoryzacją ramki dla żądanego pochodzenia. Należy wywołać w momencie kliknięcia: autoryzacja ważna przez dwie godziny. |
| GET | /api/v1/audit-anchors/{root} | Publiczne : metadane zakotwiczonej partii audytu lub plik dowodu .ots z ?format=ots (bez uwierzytelnienia) |
| POST | /api/v1/audit-anchors/verify | Publiczne : weryfikuj wpis audytu i jego dowód względem zakotwiczonego głównego węzła Merkle'a (bez uwierzytelnienia, nie ujawnia nic) |
| GET | /api/v1/envelopes/{id}/signed-document | Pobierz podpisany plik PDF (po ukończeniu COMPLETED) |
| GET | /api/v1/envelopes/bulk | Wyświetl listę swoich wysyłek masowych |
| POST | /api/v1/envelopes/bulk | Wysyłka masowa: tworzenie N kopert na podstawie szablonu i pliku CSV (tylko Standard/Business) |
| GET | /api/v1/envelopes/bulk/{id} | Postęp wysyłki masowej: liczniki, błędy na wiersz, utworzone koperty |
| GET | /api/v1/templates | Wyświetlanie listy szablonów koperty wielokrotnego użytku |
| POST | /api/v1/templates | Tworzenie szablonu (dokumenty, role, umieszczone pola) |
| GET | /api/v1/workspaces | Wyświetl listę obszarów roboczych, w których możesz utworzyć kopertę |
| POST | /api/v1/sepa-mandates | Generowanie PDF mandatu SEPA i jego koperty DRAFT z już umieszczonymi polami |
| POST | /api/v1/payroll-adapters/normalize | Normalizowanie CSV wynagrodzeń (Silae, Sage Paie, PayFit, Lucca) do formatu wysyłki masowej |
| POST | /api/v1/ag-copropriete | Tworzenie koperty zebrania wspólników nieruchomości (uchwały i udziały) |
| POST | /api/v1/ag-copropriete/{envelopeId}/votes | Rejestrowanie głosów wspólnika nieruchomości w uchwałach zebrania |
| POST | /api/v1/ag-copropriete/{envelopeId}/tally | Obliczenie wyników zebrania: wynik dla każdej uchwały, ważony udziałami |
| GET | /api/v1/videos/{videoId} | Pobieranie wideo tożsamości zachowanego: prawo dostępu RODO (art. 15) |
| GET | /api/v1/webhooks | Wyświetlanie listy webhooków |
| POST | /api/v1/webhooks | Rejestrowanie webhooka: zwraca tajny klucz podpisu tylko raz |
| GET | /api/v1/webhooks/{id} | Odczytywanie subskrypcji webhooka |
| PATCH | /api/v1/webhooks/{id} | Modyfikowanie adresu URL, zdarzeń lub stanu aktywnego |
| DELETE | /api/v1/webhooks/{id} | Wypisanie webhooka |
| POST | /api/v1/seals | Stosowanie kwalifikowanego pieczęcia elektronicznego do dokumentu |
| GET | /api/v1/seals/{id} | Odczytywanie statusu pieczęcia |
| GET | /api/v1/seals/{id}/certificate | Pobieranie certyfikatu pieczęcia |
| GET | /api/v1/payslips/workspaces | Odcinki wynagrodzeń: przestrzenie, dla których ten klucz dystrybuuje, posiadane lub delegowane przez klienta (biura rachunkowe, menedżerowie wynagrodzeń) |
| GET | /api/v1/payslips/employees | Odcinki wynagrodzeń: rejestr pracowników, w tym ci, którzy odmówili dostarczenia elektronicznego (należne wynagrodzenie papierowe) |
| PUT | /api/v1/payslips/employees | Odcinki wypłaty: dodawanie lub aktualizowanie pracowników w rejestrze (nigdy ich nie usuwa) |
| POST | /api/v1/payslips | Dostarczanie odcinka wypłaty (PDF) do sejfu pracownika: zapieczętowany, przechowywany 50 lat, ponowna próba bez duplikatu |
| GET | /api/v1/payslips | Lista dostarczonych odcinków wypłaty z dowodem ich przeglądnięcia |
| GET | /api/v1/keys | Wyświetlanie kluczy API |
| POST | /api/v1/keys | Tworzenie klucza API: sekret jest wyświetlany tylko raz |
| PATCH | /api/v1/keys/{id} | Zmiana nazwy lub odwołanie klucza |
| DELETE | /api/v1/keys/{id} | Usuwanie klucza |
| GET | /api/v1/billing/usage | Zużycie w bieżącym okresie i prognozowany koszt |
| GET | /api/v1/status | Stan usługi |
| GET | /api/v1/health | Sprawdzenie zdrowotne: baza danych, kolejka i magazyn obiektów |
| GET | /api/v1/openapi | Specyfikacja OpenAPI czytelna dla maszyn |
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.
Podpis zintegrowany: podpisuj bez opuszczania aplikacji
Twój klient przegląda i podpisuje dokument w Twojej własnej aplikacji. Ceremonia otwiera się w oknie nad Twoją stroną i automatycznie powraca do Ciebie po zakończeniu. Po stronie serwera nic się nie zmienia: tworzysz kopertę jak zwykle, podając redirectUrl, a następnie powierzasz SDK adres URL podpisu adresata.
- • Wywołaj Certyneo.sign() bezpośrednio w programie obsługi kliknięcia i przekaż swoje wywołanie serwera przez getUrl. Await przed sign() wychodzi z gestu użytkownika: Safari i Firefox wówczas blokują okno. SDK otwiera je od razu i ładuje, gdy obietnica się rozwiąże.
- • redirectUrl to kanał powrotny. Odsyłamy do niego sygnatariusza, dodając certyneo_status (completed lub declined) i certyneo_envelope. Załaduj ten sam skrypt na tej stronie powrotnej: to on powiadamia okno portalu pozostawione otwarte w tle.
- • W trybie zintegrowanym nasze własne wezwania do działania są usuwane. Twój klient nigdy nie widzi zaproszenia do utworzenia konta Certyneo.
- • Jeśli przeglądarka odrzuci okno, SDK automatycznie przechodzi do pełnostronicowego przekierowania. Przebieg jest identyczny dla sygnatariusza, a Twoja strona powrotna otrzymuje dokładnie te same parametry.
- • Celowo nie istnieje callback "użytkownik porzucił": stan okna nie jest czytelny z Twojej strony, a taki callback wyzwoliłby się błędnie. Podpis, który się nie pojawi, pozostaje oczekujący aż do webhooka.
// 1. Your server creates and sends the envelope, then hands the browser the
// recipient's signing URL. Nothing new on the API side:
// POST /api/v1/envelopes { …, "redirectUrl": "https://your-app.com/quote/42/signed" }
// POST /api/v1/envelopes/{id}/send → recipients[].accessToken
// signingUrl = "https://certyneo.com/sign/" + accessToken
// 2. On your quote page — load the SDK once:
// <script src="https://certyneo.com/embed.js"></script>
document.querySelector("#sign").addEventListener("click", () => {
Certyneo.sign({
// Called AFTER the window is already open, so no popup blocker ever
// sees a delay between the click and window.open.
getUrl: () =>
fetch("/api/quote/42/signature", { method: "POST" })
.then((r) => r.json())
.then((d) => d.signingUrl),
onCompleted: (e) => showConfirmation(e.envelopeId),
onDeclined: () => showDeclined(),
onError: (e) => showError(e),
});
});
// 3. On https://your-app.com/quote/42/signed — your return page — load the
// same script and render a short confirmation. It relays the outcome to
// the portal window behind it, then closes itself.Zdarzenie przeglądarki nie jest dowodem podpisu
onCompleted to sygnał wyświetlenia, emitowany przez przeglądarkę, więc możliwy do sfałszowania przez kogokolwiek z jego konsoli. Nigdy nie przełączaj sprawy na "podpisaną" na tej podstawie: użyj tego do odświeżenia ekranu i polegaj na webhooku podpisanego envelope.completed otrzymanym przez Twój serwer dla rzeczywistego stanu. To klasyczna pułapka integracji płatności i powtarza się tutaj identycznie.
Rozwijaj na swoim komputerze
Z kluczem testowym redirectUrl akceptuje http://localhost (i 127.0.0.1): możesz zbudować cały przebieg na swojej maszynie przed wdrożeniem. Klucz rzeczywisty to odrzuca, aby żadna koperta produkcyjna nie odsyłała prawdziwego sygnatariusza na maszynę, która nie jest jego.
Wyświetl ceremonię na swojej stronie
Tryb ramki wyświetla podpis w obrębie interfejsu, bez okna. Wymaga jeden dodatkowy krok niż tryb okna: udowodnienie, że witryna, która ją wyświetli, należy do Ciebie. To uniemożliwia stronie trzeciej ramkowanie naszych ceremonii w celu oszukania Twoich klientów.
- • Zadeklaruj swoją witrynę w Ustawienia → Podpis zintegrowany, a następnie opublikuj wskazany rekord DNS. Dokładny adres: inna subdomena lub port liczy się jako inna witryna.
- • Przy każdym podpisie poproś o świeży adres URL do POST /api/v1/envelopes/{id}/embed-url. Nosi on uprawnienie do wyświetlenia i ważny jest przez dwie godziny, co odpowiada momentowi kliknięcia, a nie utworzeniu koperty.
- • Dwie ścieżki nie mogą przebiegać w ramce: podpis kwalifikowany, którego weryfikacja tożsamości odmawia ramkowania, oraz płatność przy podpisie. W obu przypadkach podpisujący jest kierowany do pełnego okna.
- • Napis „Powered by Certyneo" znika z ramki od planu Business. Tryb ramki jest zawarty już w planie Standard.
// Mode cadre : la cérémonie s'affiche DANS votre page.
//
// 1. Déclarez votre site une fois pour toutes dans Réglages → Signature
// intégrée, et publiez l'enregistrement DNS qu'on vous y donne.
//
// 2. À chaque signature, votre serveur demande une URL fraîche. Elle porte
// l'autorisation qui permet au navigateur d'afficher la cérémonie chez
// vous, et vaut deux heures :
//
// POST /api/v1/envelopes/{id}/embed-url
// { "origin": "https://portail.exemple.fr" }
// -> { "signingUrl": "…", "expiresAt": "…" }
Certyneo.sign({
mode: "iframe",
el: "#zone-signature", // sélecteur ou nœud de votre page
getUrl: () =>
fetch("/api/devis/42/signature", { method: "POST" })
.then((r) => r.json())
.then((d) => d.signingUrl),
onCompleted: (e) => afficherConfirmation(e.envelopeId),
onDeclined: () => afficherRefus(),
});
// Le cadre parle à votre page par postMessage — pas besoin de page de retour,
// contrairement au mode fenêtre.Poproś o podpis bez wysyłania żadnego e-maila
Portal wyświetlający ceremonię na jego stronie często nie potrzebuje naszego zaproszenia: przychodzi obok jego własnej ścieżki i proponuje konto klientowi, który go nie chce. Ustaw wartość NONE dla kanału powiadomień odbiorcy i nic mu już nie będzie wysyłane — to ty doprowadzisz go do jego podpisu.
- • Ustawienie jest per odbiorca, nie per koperta: możesz wyciszyć klienta, którego hostisz, i zachować e-mail dla zewnętrznego kontrasygnatariusza, który nie ma portalu.
- • Jest zarezerwowany dla podpisujących i zatwierdzających, jedynych, którym masz link do przekazania. Odczytujesz go z odpowiedzi na utworzenie i wysłanie, lub poprawisz świeży adres URL w momencie kliknięcia na POST /api/v1/envelopes/{id}/embed-url.
- • Automatyczne przypomnienia zatrzymują się same dla tego odbiorcy: nigdy mu nie pisaliśmy, nie zaczynamy od przypomnienia. Inni odbiorcy będą nadal otrzymywać przypomnienia normalnie.
- • Certyfikat podpisu wspomina o tym, odbiorca po odbiorcy. Dossier dowodowe, które byłoby tam milczące, mogłoby sugerować, że ten podpisujący otrzymał od nas zaproszenie, które nigdy nie istniało.
POST /api/v1/envelopes
{
"subject": "Mandat de gestion",
"documentIds": ["doc_8f2c1a4b9e7d"],
"recipients": [
{
"email": "client@exemple.fr",
"name": "Camille Client",
"role": "SIGNER",
"notificationChannel": "NONE"
},
{
"email": "notaire@exemple.fr",
"name": "Maître Notaire",
"role": "SIGNER"
}
]
}
// La réponse rend le lien de chaque signataire :
//
// "recipients": [
// { "email": "client@exemple.fr", "accessToken": "…",
// "notificationChannel": "NONE" },
// { "email": "notaire@exemple.fr", "accessToken": "…",
// "notificationChannel": "EMAIL" }
// ]
//
// Le client ne reçoit rien : vous l'emmenez sur sa signature depuis votre
// portail. Le notaire, lui, reçoit son invitation comme d'habitude.Wyświetl nazwę swojego klienta jako nadawcę
Domyślnie podpisujący widzi nazwę właściciela klucza API. Jeśli podpisujesz dokumenty kilku firm za pomocą jednego klucza, przekaż pole sender podczas tworzenia koperty: strona podpisu oraz e-maile z zaproszeniem i przypomnieniem wyświetlają wtedy nazwę odpowiedniej firmy.
- • Zarezerwowane dla planu Business i wyższych. W planie niższym tworzenie jest odrzucane, aby nie pozwolić podpisującemu na przeczytanie innej nazwy niż oczekiwana.
- • Nazwa jest wyświetlana: certyfikat i ścieżka audytu zachowują rzeczywistego nadawcę, a e-maile zawsze pochodzą od Certyneo.
- • Adres jest opcjonalny. Bez niego podpisujący widzi tylko nazwę, nigdy adres właściciela klucza.
POST /api/v1/envelopes
{
"subject": "Devis 2026-118",
"documentIds": ["doc_8f2c1a4b9e7d"],
"recipients": [
{ "email": "client@exemple.fr", "name": "Camille Client", "role": "SIGNER" }
],
"sender": {
"name": "1.2.3. Panneaux Solaires",
"email": "devis@123-panneaux-solaires.fr"
}
}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