Przejdź do zawartości głównej
Certyneo
Publiczne API v1

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.

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

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.

Karta RapidAPI

Ten sam katalog endpointów, którzy można testować bezpośrednio z przeglądarki. Stanowisko testowe oczekuje dwóch odrębnych nagłówków: klucza RapidAPI przydzielonego przez platformę i twojego klucza Certyneo w Authorization — to drugi klucz faktycznie autoryzuje wywołanie.

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żkaOpis
GET/api/v1/account/meTożsamość uwierzytelnionego wywołującego (id, e-mail, plan) : test identyfikatorów bez wymaganego zakresu
GET/api/v1/sandboxZliczanie danych utworzonych kluczami testowymi (usuwanych automatycznie po 30 dniach)
DELETE/api/v1/sandboxUsuwanie wszystkich danych utworzonych kluczami testowymi, bez naruszania prawdziwych danych
POST/api/v1/documentsPrzesłać plik PDF (multipart) : zwraca identyfikator dokumentu
GET/api/v1/documentsWyświetl listę dokumentów
GET/api/v1/documents/{id}Odczytaj metadane dokumentu
DELETE/api/v1/documents/{id}Usuń dokument
GET/api/v1/envelopesWyświetl listę kopert (filtruj za pomocą ?status= i ?limit=)
POST/api/v1/envelopesUtwó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}/sendWyślij kopertę DRAFT : wysyła zaproszenia
POST/api/v1/envelopes/{id}/voidAnuluj wysłaną kopertę, która nie jest jeszcze w pełni podpisana : oczekujący sygnatariusze są powiadamiani
GET/api/v1/envelopes/{id}/audit-trailPobierz plik PDF dziennika audytu eIDAS
POST/api/v1/envelopes/{id}/embed-urlZwraca 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/verifyPubliczne : 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-documentPobierz podpisany plik PDF (po ukończeniu COMPLETED)
GET/api/v1/envelopes/bulkWyświetl listę swoich wysyłek masowych
POST/api/v1/envelopes/bulkWysył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/templatesWyświetlanie listy szablonów koperty wielokrotnego użytku
POST/api/v1/templatesTworzenie szablonu (dokumenty, role, umieszczone pola)
GET/api/v1/workspacesWyświetl listę obszarów roboczych, w których możesz utworzyć kopertę
POST/api/v1/sepa-mandatesGenerowanie PDF mandatu SEPA i jego koperty DRAFT z już umieszczonymi polami
POST/api/v1/payroll-adapters/normalizeNormalizowanie CSV wynagrodzeń (Silae, Sage Paie, PayFit, Lucca) do formatu wysyłki masowej
POST/api/v1/ag-coproprieteTworzenie koperty zebrania wspólników nieruchomości (uchwały i udziały)
POST/api/v1/ag-copropriete/{envelopeId}/votesRejestrowanie głosów wspólnika nieruchomości w uchwałach zebrania
POST/api/v1/ag-copropriete/{envelopeId}/tallyObliczenie 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/webhooksWyświetlanie listy webhooków
POST/api/v1/webhooksRejestrowanie 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/sealsStosowanie kwalifikowanego pieczęcia elektronicznego do dokumentu
GET/api/v1/seals/{id}Odczytywanie statusu pieczęcia
GET/api/v1/seals/{id}/certificatePobieranie certyfikatu pieczęcia
GET/api/v1/payslips/workspacesOdcinki wynagrodzeń: przestrzenie, dla których ten klucz dystrybuuje, posiadane lub delegowane przez klienta (biura rachunkowe, menedżerowie wynagrodzeń)
GET/api/v1/payslips/employeesOdcinki wynagrodzeń: rejestr pracowników, w tym ci, którzy odmówili dostarczenia elektronicznego (należne wynagrodzenie papierowe)
PUT/api/v1/payslips/employeesOdcinki wypłaty: dodawanie lub aktualizowanie pracowników w rejestrze (nigdy ich nie usuwa)
POST/api/v1/payslipsDostarczanie odcinka wypłaty (PDF) do sejfu pracownika: zapieczętowany, przechowywany 50 lat, ponowna próba bez duplikatu
GET/api/v1/payslipsLista dostarczonych odcinków wypłaty z dowodem ich przeglądnięcia
GET/api/v1/keysWyświetlanie kluczy API
POST/api/v1/keysTworzenie 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/usageZużycie w bieżącym okresie i prognozowany koszt
GET/api/v1/statusStan usługi
GET/api/v1/healthSprawdzenie zdrowotne: baza danych, kolejka i magazyn obiektów
GET/api/v1/openapiSpecyfikacja 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.
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.

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.
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.

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.
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.

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.
JavaScriptjavascript
// 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.
JavaScriptjavascript
// 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.
JSONjson
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.
JSONjson
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.

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_… 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.

Zbiorcza — zagnieżdżonajson
// GET /api/v1/envelopes
// Collections are WRAPPED in a "data" array.
{
  "data": [
    { "id": "env_abc123", "subject": "Contrat", "status": "SENT" }
  ]
}
Jednostkowa zasob — płaskojson
// 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

Dowiedz się więcej