Skip to content

SignKoala for developers

API v1

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

Manage API keys

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.

Contact [email protected] to request API access.

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.

Open your API keys →
  • 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"
    }
}

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