Dla integratorów
Dokumentacja API podpiszmy.pl
Umowa powstaje w Twoim systemie, my wysyłamy ją do podpisu, a podpisany plik wraca do Ciebie. Bez klikania w panelu.
Uwierzytelnianie
Każde zapytanie niesie token osobisty w nagłówku Authorization.
Token tworzysz i unieważniasz w panelu, w sekcji API i integracje. Pokazujemy go jeden raz, przy utworzeniu,
i nie mamy sposobu, żeby pokazać go ponownie. Token działa wyłącznie na koncie, na którym powstał,
i widzi dokładnie te dokumenty, które widzi to konto w przeglądarce.
Odpowiedzi są zawsze w formacie JSON, także przy błędzie. Warto wysyłać nagłówek
Accept: application/json, ale nie jest on wymagany.
curl -s https://podpiszmy.pl/api/v1/me \
-H "Authorization: Bearer TWOJ_TOKEN" \
-H "Accept: application/json"
Adres bazowy to https://podpiszmy.pl/api/v1.
Wersja siedzi w adresie, więc kolejne wydanie API nie zepsuje działającej integracji.
Typowy obieg
Najczęstszy scenariusz wygląda tak. W Twoim systemie powstaje umowa (oferta zaakceptowana, zlecenie przyjęte, nowy współpracownik). Wysyłasz ją jednym zapytaniem, my zajmujemy się resztą, a po komplecie podpisów przychodzi do Ciebie zdarzenie i pobierasz podpisany plik.
- Raz, przy wdrożeniu: rejestrujesz adres webhooka i zapisujesz jego sekret.
- POST /documents z plikiem PDF i listą sygnatariuszy. Dokument idzie do podpisu od razu.
- Dostajesz zdarzenia o kolejnych krokach: wysłany, otwarty, podpisany.
- Po komplecie podpisów przychodzi document.completed.
- GET /documents/{uuid}/pdf zwraca podpisany plik, a /audyt ślad audytowy do Twojej bazy.
Wysłanie dokumentu do podpisu
Jedno zapytanie tworzy dokument, zaprasza sygnatariuszy i wysyła im wiadomość z linkiem.
Plik przesyłasz jako multipart/form-data.
Maksymalny rozmiar PDF to 6 MB.
curl -s https://podpiszmy.pl/api/v1/documents \
-H "Authorization: Bearer TWOJ_TOKEN" \
-F "[email protected]" \
-F "title=Umowa o dzieło nr 14/2026" \
-F "message=W razie pytań proszę o kontakt." \
-F "signing_mode=sequential" \
-F "signers[0][name]=Anna Nowak" \
-F "signers[0][email][email protected]" \
-F "signers[1][name]=Jan Kowalski" \
-F "signers[1][email][email protected]"
Pola: file (PDF, wymagane), title (wymagane, do 180 znaków),
message (opcjonalna wiadomość do sygnatariuszy),
signing_mode (sequential po kolei albo
parallel równolegle, domyślnie po kolei),
signers (od jednego do piętnastu, każdy z name
i email, opcjonalnie
require_id_check dla weryfikacji tożsamości),
send (domyślnie true; ustaw
false, żeby przygotować dokument i wysłać go osobnym zapytaniem).
HTTP/1.1 201 Created
{
"data": {
"uuid": "9f1c2d3e-4a5b-6c7d-8e9f-0a1b2c3d4e5f",
"title": "Umowa o dzieło nr 14/2026",
"status": "sent",
"effective_status": "sent",
"status_label": "Wysłany",
"signing_mode": "sequential",
"sent_at": "2026-09-19T12:40:11+02:00",
"expires_at": "2026-10-03T12:40:11+02:00",
"signed_count": 0,
"pdf_url": "https://podpiszmy.pl/api/v1/documents/9f1c2d3e.../pdf",
"audit_url": "https://podpiszmy.pl/api/v1/documents/9f1c2d3e.../audyt",
"signers": [
{ "name": "Anna Nowak", "email": "[email protected]", "status": "pending", "signed_at": null }
]
}
}
Punkty końcowe
| Metoda i adres | Co robi |
|---|---|
| GET /me | Dane konta, plan i obowiązujące limity zapytań. |
| GET /documents | Lista dokumentów. Filtr ?status=draft|sent|in_progress|completed|rejected|cancelled|expired|w_toku, wyszukiwanie ?q=, stronicowanie ?per_page= (do 100). |
| POST /documents | Tworzy dokument i domyślnie od razu wysyła go do podpisu. |
| GET /documents/{uuid} | Status jednego dokumentu razem ze stanem każdego sygnatariusza. |
| POST /documents/{uuid}/send | Wysyła dokument przygotowany wcześniej z send=false. |
| POST /documents/{uuid}/cancel | Anuluje dokument. Wysłane linki do podpisu przestają działać. Opcjonalne pole reason. |
| POST /documents/{uuid}/reminders | Przypomina o podpisie. Bez pola email przypomina wszystkim, na których czekamy. |
| GET /documents/{uuid}/pdf | Podpisany PDF. Parametr ?wariant=oryginal zwraca plik bez podpisów. |
| GET /documents/{uuid}/audyt | Ślad audytowy jako dane, razem z wynikiem sprawdzenia łańcucha skrótów. |
| GET /webhooks | Lista zarejestrowanych adresów i katalog dostępnych zdarzeń. |
| POST /webhooks | Rejestruje adres. Odpowiedź zawiera sekret, pokazywany tylko ten jeden raz. |
| PATCH /webhooks/{id} | Zmienia listę zdarzeń albo wyłącza adres. |
| DELETE /webhooks/{id} | Usuwa adres. |
| POST /webhooks/{id}/test | Wysyła zdarzenie próbne, żeby sprawdzić podpis bez czekania na umowę. |
| GET /webhooks/{id}/dostarczenia | Ostatnie próby dostarczenia razem z kodami odpowiedzi i błędami. |
# status jednego dokumentu
curl -s https://podpiszmy.pl/api/v1/documents/UUID \
-H "Authorization: Bearer TWOJ_TOKEN"
# tylko te, na które jeszcze czekamy
curl -s "https://podpiszmy.pl/api/v1/documents?status=w_toku" \
-H "Authorization: Bearer TWOJ_TOKEN"
# podpisany plik prosto na dysk
curl -s https://podpiszmy.pl/api/v1/documents/UUID/pdf \
-H "Authorization: Bearer TWOJ_TOKEN" -o umowa-podpisana.pdf
# ślad audytowy do zapisania u siebie
curl -s https://podpiszmy.pl/api/v1/documents/UUID/audyt \
-H "Authorization: Bearer TWOJ_TOKEN"
# przypomnienie do jednej osoby
curl -s -X POST https://podpiszmy.pl/api/v1/documents/UUID/reminders \
-H "Authorization: Bearer TWOJ_TOKEN" \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]"}'
# anulowanie
curl -s -X POST https://podpiszmy.pl/api/v1/documents/UUID/cancel \
-H "Authorization: Bearer TWOJ_TOKEN" \
-H "Content-Type: application/json" \
-d '{"reason":"Zlecenie wycofane przez klienta"}'
Podpisany plik powstaje w chwili złożenia ostatniego podpisu. Wcześniej
/pdf odpowiada kodem 409 i mówi, ilu podpisów brakuje,
zamiast oddawać plik bez podpisów.
Webhooki
Zamiast odpytywać nas w pętli, podaj adres, na który mamy wysyłać zdarzenia. Wysyłamy je metodą POST, w formacie JSON, wyłącznie na publiczne adresy https.
curl -s -X POST https://podpiszmy.pl/api/v1/webhooks \
-H "Authorization: Bearer TWOJ_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "https://twoj-system.pl/hooki/podpiszmy",
"events": ["document.sent", "document.signed", "document.completed", "document.rejected"]
}'
| Zdarzenie | Kiedy przychodzi |
|---|---|
| document.sent | Dokument wysłany do podpisu |
| document.viewed | Sygnatariusz otworzył dokument |
| document.signed | Jeden z sygnatariuszy podpisał |
| document.rejected | Dokument odrzucony |
| document.expired | Minął termin podpisania |
| document.cancelled | Dokument anulowany przez nadawcę |
| document.completed | Dokument podpisany przez wszystkich |
Treść zdarzenia
POST /hooki/podpiszmy
Content-Type: application/json
X-Podpiszmy-Event: document.completed
X-Podpiszmy-Signature: sha256=7b1c...
X-Podpiszmy-Delivery: 2f9a1c40-1d8e-4d21-9f4e-6a0b0c7d2e11
X-Podpiszmy-Attempt: 1
{
"event": "document.completed",
"created_at": "2026-09-19T13:02:44+02:00",
"data": {
"uuid": "9f1c2d3e-4a5b-6c7d-8e9f-0a1b2c3d4e5f",
"title": "Umowa o dzieło nr 14/2026",
"status": "completed",
"completed_at": "2026-09-19T13:02:41+02:00",
"signers": [
{ "name": "Anna Nowak", "email": "[email protected]", "status": "signed", "signed_at": "2026-09-19T13:02:41+02:00" }
]
}
}
Sprawdzenie podpisu
Nagłówek X-Podpiszmy-Signature to HMAC-SHA256 policzony
z surowego ciała zapytania i Twojego sekretu, w postaci
sha256=HEX. Licz go przed sparsowaniem JSON-a.
Przepuszczenie treści przez dekoder i koder zmienia bajty, a wtedy podpis przestaje pasować,
mimo że wszystko jest w porządku. Porównuj podpisy funkcją odporną na pomiar czasu.
// PHP
$body = file_get_contents('php://input');
$oczekiwany = 'sha256=' . hash_hmac('sha256', $body, $sekret);
if (! hash_equals($oczekiwany, $_SERVER['HTTP_X_PODPISZMY_SIGNATURE'] ?? '')) {
http_response_code(400);
exit;
}
$zdarzenie = json_decode($body, true);
# Python
import hmac, hashlib
oczekiwany = "sha256=" + hmac.new(sekret.encode(), body, hashlib.sha256).hexdigest()
if not hmac.compare_digest(oczekiwany, naglowki.get("X-Podpiszmy-Signature", "")):
return 400
Ponowienia
Odpowiedz kodem 2xx, gdy przyjmiesz zdarzenie. Każda inna odpowiedź i każdy brak połączenia
uruchamiają ponowienie: łącznie pięć podejść z odstępami 10 sekund, minuta, 5 minut i 30 minut.
Nagłówek X-Podpiszmy-Delivery jest ten sam we wszystkich
podejściach tego samego zdarzenia, więc użyj go do odsiania duplikatów.
Wszystkie próby razem z kodami odpowiedzi widzisz w panelu oraz pod
GET /webhooks/{id}/dostarczenia.
Limity zapytań
Limity liczymy na konto, nie na adres IP, więc integracja na współdzielonym hostingu nie konkuruje
z cudzym ruchem. Odczyt: 120 zapytań na minutę. Zapis, czyli tworzenie dokumentów,
wysyłka, anulowanie, przypomnienia i zmiany webhooków: 20 na minutę.
Po przekroczeniu dostajesz kod 429 razem z nagłówkiem
Retry-After. Bieżące zużycie widzisz w panelu.
Kody odpowiedzi
| Kod | Znaczenie |
|---|---|
| 200, 201 | Zapytanie wykonane. |
| 401 | Brak tokena, token odwołany albo nieprawidłowy. |
| 402 | Konto nie ma planu z dostępem do API. Odpowiedź podaje nazwę planu i adres cennika. |
| 404 | Nie ma takiego dokumentu na tym koncie. Tego samego kodu używamy dla cudzych dokumentów, żeby nie potwierdzać, że istnieją. |
| 409 | Dokument jest w stanie, w którym ta operacja nie ma sensu. Na przykład podpisany plik przed kompletem podpisów. |
| 422 | Dane zapytania są nieprawidłowe albo wyczerpała się pula dokumentów. |
| 429 | Przekroczony limit zapytań tego konta albo przypomnienie wysłane zbyt szybko po poprzednim. |
Podłącz swój system do podpisu
API i webhooki działają w planie Business. Umowy wychodzą z Twojego systemu, a podpisany plik wraca do niego automatycznie.