11 min read
SignKoala for developers
API v1A little less paperwork.A few lines of code.
Bring document signing into your workflow. Upload, share a private link, and get a signed PDF with one simple API.
Base URLhttps://signkoala.com/api/v1
01 / Start here
A signature, from your app
Upload a document. Share a signing link. Get a signed PDF.
Build document signing into your own workflow with the SignKoala API. Your server uploads a file or provides a direct download URL, and SignKoala prepares a private signing page.
Your signer reviews the document, places their signature, and confirms their consent in the browser. They do not need a SignKoala account. Your application checks the document status and downloads the completed PDF.
- One signer per document in API v1.
- Keep API keys on your server. Share only the document signing link.
- All examples are ready to adapt; this page never sends API requests.
A signature, from your app
Terminal · cURL
curl --fail-with-body --request POST \
'https://signkoala.com/api/v1/documents' \
--header "Authorization: Bearer $SIGNKOALA_API_KEY" \
--header 'Accept: application/json' \
--form 'file=@./agreement.pdf'
Example JSON response
{
"data": {
"id": "01JEXAMPLE00000000000000000",
"status": "preparing",
"signing_url": "https://signkoala.com/invitation/EXAMPLE_SIGNING_TOKEN",
"signing_url_expires_at": "2026-10-25T08:00:00Z",
"expires_at": "2026-11-23T08:00:00Z"
}
}
02 / Start here
Request API access
API access is enabled individually by our team.
Contact [email protected] to request API access. Include the email address of your SignKoala account and a short description of your integration.
Create your account and verify your email first. Once support approves your account, the API keys page lets you create credentials for your integration.
Request API access
Terminal · cURL
# Set this in your server environment.
# Replace the placeholder with your secret.
export SIGNKOALA_API_KEY='YOUR_API_KEY'
export SIGNKOALA_API_URL='https://signkoala.com/api/v1'
Example JSON response
{
"data": {
"id": "01JEXAMPLE00000000000000000",
"status": "preparing",
"signing_url": "https://signkoala.com/invitation/EXAMPLE_SIGNING_TOKEN",
"signing_url_expires_at": "2026-10-25T08:00:00Z",
"expires_at": "2026-11-23T08:00:00Z"
}
}
03 / Start here
Create an API key
A named key for each integration makes access easier to manage.
Open API keys in your account, choose a recognizable name, and create a key. Copy the secret immediately: it is displayed only once.
Store the secret in your server environment or secrets manager. The key list shows its masked prefix, creation date, and last use. Revoke keys you no longer need, and replace a key immediately if it is exposed.
- Keys for the same account can access that account’s API-created documents.
- Revocation and disabling API access take effect immediately for API requests.
- You can revoke existing keys even while API approval is disabled.
Create an API key
Terminal · cURL
# Set this in your server environment.
# Replace the placeholder with your secret.
export SIGNKOALA_API_KEY='YOUR_API_KEY'
export SIGNKOALA_API_URL='https://signkoala.com/api/v1'
Example JSON response
{
"data": {
"id": "01JEXAMPLE00000000000000000",
"status": "preparing",
"signing_url": "https://signkoala.com/invitation/EXAMPLE_SIGNING_TOKEN",
"signing_url_expires_at": "2026-10-25T08:00:00Z",
"expires_at": "2026-11-23T08:00:00Z"
}
}
04 / Start here
Authenticate requests
Use a bearer token on every API request.
Authorization: Bearer YOUR_API_KEY
Send your key in the Authorization header and request JSON responses with Accept: application/json. All API endpoints are under the base URL shown above.
Use your backend to call this API. Never embed a secret in browser JavaScript, a mobile application, a public repository, or a URL. Redact authorization headers in your application logs.
Authenticate requests
Terminal · cURL
curl --fail-with-body --request GET \
'https://signkoala.com/api/v1/documents/01JEXAMPLE00000000000000000' \
--header "Authorization: Bearer $SIGNKOALA_API_KEY" \
--header 'Accept: application/json'
Example JSON response
{
"data": {
"id": "01JEXAMPLE00000000000000000",
"status": "preparing",
"signing_url": "https://signkoala.com/invitation/EXAMPLE_SIGNING_TOKEN",
"signing_url_expires_at": "2026-10-25T08:00:00Z",
"expires_at": "2026-11-23T08:00:00Z"
}
}
05 / Send a document
Your first signing flow
Four steps from an upload to a completed document.
POST /documents
Send a document to POST /documents. A 202 response means it has been accepted for preparation; it does not mean it is ready or signed yet.
Save the document ID and securely share the returned signing_url with your intended signer. Poll GET /documents/{id} until the status is completed, then download the signed PDF.
- Upload the file and save the response.
- Send the signing link to the intended signer.
- Poll the document status at a reasonable interval.
- Download and store the completed PDF before it expires.
Your first signing flow
Terminal · cURL
curl --fail-with-body --request POST \
'https://signkoala.com/api/v1/documents' \
--header "Authorization: Bearer $SIGNKOALA_API_KEY" \
--header 'Accept: application/json' \
--form 'file=@./agreement.pdf'
Example JSON response
{
"data": {
"id": "01JEXAMPLE00000000000000000",
"status": "preparing",
"signing_url": "https://signkoala.com/invitation/EXAMPLE_SIGNING_TOKEN",
"signing_url_expires_at": "2026-10-25T08:00:00Z",
"expires_at": "2026-11-23T08:00:00Z"
}
}
06 / Send a document
Upload a file
Send a document directly from your server.
POST /documents
Use multipart/form-data with a single file field named file. Your HTTP client should generate the multipart boundary; do not set a JSON Content-Type for a file upload.
Supported formats are PDF, DOC, DOCX, JPG, JPEG, PNG, and WEBP. Files must be no larger than 25 MiB and documents must contain no more than 100 pages. Every completed document is delivered as a PDF.
Upload a file
Terminal · cURL
curl --fail-with-body --request POST \
'https://signkoala.com/api/v1/documents' \
--header "Authorization: Bearer $SIGNKOALA_API_KEY" \
--header 'Accept: application/json' \
--form 'file=@./agreement.pdf'
Example JSON response
{
"data": {
"id": "01JEXAMPLE00000000000000000",
"status": "preparing",
"signing_url": "https://signkoala.com/invitation/EXAMPLE_SIGNING_TOKEN",
"signing_url_expires_at": "2026-10-25T08:00:00Z",
"expires_at": "2026-11-23T08:00:00Z"
}
}
07 / Send a document
Import from a URL
Let SignKoala retrieve a document from your storage.
POST /documents
Send a JSON body with url and filename. Use a direct, publicly reachable HTTPS download on port 443. The filename must include a supported extension and match the document contents.
Signed query strings are supported. Ensure your download URL stays valid while the request is being handled. Links that require cookies, redirects, a login screen, or access to a private network cannot be imported.
- HTTPS only, using the standard port 443.
- No redirects, URL credentials, or private/reserved network addresses.
- The same 25 MiB and 100-page limits apply.
- Downloads have a 5-second connection timeout and a 30-second total timeout.
Import from a URL
Terminal · cURL
curl --fail-with-body --request POST \
'https://signkoala.com/api/v1/documents' \
--header "Authorization: Bearer $SIGNKOALA_API_KEY" \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{"url":"https://storage.example.com/agreement.pdf?signature=EXAMPLE","filename":"agreement.pdf"}'
Example JSON response
{
"data": {
"id": "01JEXAMPLE00000000000000000",
"status": "preparing",
"signing_url": "https://signkoala.com/invitation/EXAMPLE_SIGNING_TOKEN",
"signing_url_expires_at": "2026-10-25T08:00:00Z",
"expires_at": "2026-11-23T08:00:00Z"
}
}
08 / Complete the flow
Share & renew signing links
A private link gives one signer access to one document.
POST /documents/{id}/signing-links
Anyone holding the signing link can open its invitation page and continue to the document. Share it only with the intended signer. They review the document, place a signature, and confirm consent before completing it.
Links are valid for 24 hours, or until the document expires if sooner. Renew an eligible unfinished document’s link with POST /documents/{id}/signing-links. Save and share the new signing_url from the response.
Share & renew signing links
Terminal · cURL
curl --fail-with-body --request POST \
'https://signkoala.com/api/v1/documents/01JEXAMPLE00000000000000000/signing-links' \
--header "Authorization: Bearer $SIGNKOALA_API_KEY" \
--header 'Accept: application/json'
Example JSON response
{
"data": {
"signing_url": "https://signkoala.com/invitation/NEW_EXAMPLE_TOKEN",
"signing_url_expires_at": "2026-10-25T09:00:00Z"
}
}
09 / Complete the flow
Check document status
Follow preparation and signing without keeping a connection open.
GET /documents/{id}
Request the document by its ID. Check periodically, for example every 5 seconds, and stop when the document is completed, failed, cancelled, or expired. Increase the interval for long waits and respect rate limits.
A status response does not include the signing URL. Save it when you create the document or renew the signing link. A failure response contains a safe error description when processing fails.
When status is on_hold, the error field provides a general message that the document is awaiting resolution by the sender. Pause signing and download attempts until the sender resolves the hold. Hold reasons are not exposed by the API. An expired document returns expired even if a hold remains.
- preparing — the uploaded document is being converted and checked.
- ready — the document is available for the signer.
- on_hold — signing is paused while the sender resolves the request.
- finalizing — the completed PDF is being generated.
- completed — the signed PDF is ready to download.
- failed — preparation or finalization could not finish.
- cancelled — the signing request has been cancelled.
- expired — the document access period has ended.
Check document status
Terminal · cURL
curl --fail-with-body --request GET \
'https://signkoala.com/api/v1/documents/01JEXAMPLE00000000000000000' \
--header "Authorization: Bearer $SIGNKOALA_API_KEY" \
--header 'Accept: application/json'
Example JSON response
{
"data": {
"id": "01JEXAMPLE00000000000000000",
"status": "completed",
"expires_at": "2026-11-23T08:00:00Z",
"error": null
}
}
10 / Complete the flow
Download the signed PDF
Save the completed document in your own system.
GET /documents/{id}/download
Once status is completed, request GET /documents/{id}/download. The successful response contains PDF bytes, not JSON. Save those bytes as a .pdf file.
If the signed PDF is not available yet, the endpoint returns 409. Keep checking the document status before retrying. Access remains subject to document expiry and account eligibility.
Download the signed PDF
Terminal · cURL
curl --fail-with-body --request GET \
'https://signkoala.com/api/v1/documents/01JEXAMPLE00000000000000000/download' \
--header "Authorization: Bearer $SIGNKOALA_API_KEY" \
--header 'Accept: application/json' \
--output signed-agreement.pdf
Example JSON response
{
"data": {
"id": "01JEXAMPLE00000000000000000",
"status": "preparing",
"signing_url": "https://signkoala.com/invitation/EXAMPLE_SIGNING_TOKEN",
"signing_url_expires_at": "2026-10-25T08:00:00Z",
"expires_at": "2026-11-23T08:00:00Z"
}
}
11 / Reference
Handle errors
Use the HTTP status to choose the next step.
API errors are returned as JSON. Validation failures identify the invalid inputs. Fix the request before retrying; never retry an upload blindly because a network interruption can hide a successful creation.
Document IDs outside your account, and documents that were not created through the API, return 404. Do not expose keys, source URLs, or private signing links in error reporting.
A successful status lookup can return on_hold with a general error message. The hold requires sender resolution; the API does not disclose its reason. Actions such as renewing the signing link and downloading the document remain unavailable while it is on hold.
- 401 — the bearer key is missing, invalid, or revoked.
- 403 — API access or account eligibility is disabled.
- 404 — the document is not available to this account.
- 409 — the document is not in a state that allows this action.
- 410 — the document has expired or was cancelled.
- 422 — an input or document could not be accepted.
- 429 — rate limited; wait for the Retry-After interval.
- 5xx — a server error; retry reads with backoff.
Handle errors
Terminal · cURL
curl --fail-with-body --request GET \
'https://signkoala.com/api/v1/documents/01JEXAMPLE00000000000000000' \
--header "Authorization: Bearer $SIGNKOALA_API_KEY" \
--header 'Accept: application/json'
Example JSON response
{
"message": "The filename field is required when url is present.",
"errors": {
"filename": [
"The filename field is required when url is present."
]
}
}
12 / Reference
Limits & retries
Keep requests predictable as your integration grows.
The current limit is 60 API requests per minute per account, including at most 10 document uploads per minute. All keys belonging to an account share these limits.
When a request returns 429, wait for the number of seconds in the Retry-After header before retrying. Use a capped backoff for repeated failures and avoid tight polling loops.
- Maximum file size: 25 MiB (26,214,400 bytes).
- Maximum document length: 100 pages.
- One guest signer per API document.
- No webhooks or automatic signature application in v1.
Limits & retries
Terminal · cURL
curl --fail-with-body --request GET \
'https://signkoala.com/api/v1/documents/01JEXAMPLE00000000000000000' \
--header "Authorization: Bearer $SIGNKOALA_API_KEY" \
--header 'Accept: application/json'
Example JSON response
{
"data": {
"id": "01JEXAMPLE00000000000000000",
"status": "preparing",
"signing_url": "https://signkoala.com/invitation/EXAMPLE_SIGNING_TOKEN",
"signing_url_expires_at": "2026-10-25T08:00:00Z",
"expires_at": "2026-11-23T08:00:00Z"
}
}
13 / Reference
Expiry & retention
Treat response timestamps as the source of truth.
The current document retention period is 30 days. The service default is 30 days, and this page reflects the configured period. The expires_at value returned for each document tells you when its access ends; do not hardcode the sample dates shown in these examples.
The signing_url_expires_at value applies to the private signing link. Renewing a link does not extend the document’s retention period. Download and archive completed documents before expiry.
Expiry & retention
Terminal · cURL
curl --fail-with-body --request GET \
'https://signkoala.com/api/v1/documents/01JEXAMPLE00000000000000000' \
--header "Authorization: Bearer $SIGNKOALA_API_KEY" \
--header 'Accept: application/json'
Example JSON response
{
"data": {
"id": "01JEXAMPLE00000000000000000",
"status": "ready",
"expires_at": "2026-11-23T08:00:00Z",
"error": null
}
}