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

Wszystkie publiczne trasy: konto, dokumenty, koperty, szablony, webhooks, pieczęcie elektroniczne, klucze API i rozliczenia. Wszystkie akceptują token Bearer i zwracają JSON.

MethodPathDescription
GET/api/v1/account/meIdentity of the authenticated caller (id, email, plan) — scope-less credential probe
POST/api/v1/documentsUpload a PDF (multipart) — returns document id
GET/api/v1/documentsList documents
GET/api/v1/documents/{id}Fetch document metadata
DELETE/api/v1/documents/{id}Delete document
GET/api/v1/envelopesList envelopes (filter with ?status= and ?limit=)
POST/api/v1/envelopesCreate envelope (status: DRAFT) — from a templateId, or from documentIds with an optional fields array
GET/api/v1/envelopes/{id}Fetch envelope state
PATCH/api/v1/envelopes/{id}Update DRAFT envelope
DELETE/api/v1/envelopes/{id}Void / delete DRAFT envelope
POST/api/v1/envelopes/{id}/sendDispatch DRAFT — sends invitations
GET/api/v1/envelopes/{id}/audit-trailDownload eIDAS audit-trail PDF
GET/api/v1/audit-anchors/{root}Public: metadata of an anchored audit batch, or the .ots proof file with ?format=ots (no auth)
POST/api/v1/audit-anchors/verifyPublic: verify an audit entry + proof against its anchored Merkle root (no auth, reveals nothing)
GET/api/v1/envelopes/{id}/signed-documentDownload signed PDF (once COMPLETED)
GET/api/v1/envelopes/bulkList your bulk-send jobs
POST/api/v1/envelopes/bulkBulk send: create N envelopes from one template + a CSV (Standard/Business only)
GET/api/v1/envelopes/bulk/{id}Bulk-send job progress: counts, per-row failures, created envelopes
GET/api/v1/templatesList reusable envelope templates
POST/api/v1/templatesCreate a template (documents, roles, positioned fields)
POST/api/v1/sepa-mandatesGenerate a SEPA mandate PDF and its DRAFT envelope, fields already placed
POST/api/v1/payroll-adapters/normalizeNormalise a payroll CSV (Silae, Sage Paie, PayFit, Lucca) into the bulk-send shape
POST/api/v1/ag-coproprieteCreate a condominium general-meeting envelope (resolutions + ownership shares)
POST/api/v1/ag-copropriete/{envelopeId}/votesRecord a co-owner's votes on the meeting resolutions
POST/api/v1/ag-copropriete/{envelopeId}/tallyTally the meeting - per-resolution result weighted by ownership shares
GET/api/v1/videos/{videoId}Download a stored identity video - GDPR art. 15 access path
GET/api/v1/webhooksList webhooks
POST/api/v1/webhooksRegister webhook — returns the signing secret once
GET/api/v1/webhooks/{id}Fetch webhook subscription
PATCH/api/v1/webhooks/{id}Update url / events / active state
DELETE/api/v1/webhooks/{id}Unregister
POST/api/v1/sealsApply a qualified electronic seal to a document
GET/api/v1/seals/{id}Fetch seal status
GET/api/v1/seals/{id}/certificateDownload the seal certificate
GET/api/v1/keysList API keys
POST/api/v1/keysCreate API key — the secret is shown once
PATCH/api/v1/keys/{id}Rename / revoke key
DELETE/api/v1/keys/{id}Delete key
GET/api/v1/billing/usageCurrent period usage and projected cost
GET/api/v1/statusService status
GET/api/v1/openapiMachine-readable OpenAPI specification

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.

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