Skip to main content
Cadana supports two contract flows: template-based contracts that are sent for electronic signature, and upload-based contracts where you upload an already-signed PDF. This guide covers both.

Prerequisites

1

Contracts enabled

Contracts must be enabled for your account. If you don’t see the Contracts section in the Dashboard, contact your account manager to enable it.
2

API key from Dashboard

Get your API key from the Cadana Dashboard. See Authentication.
3

Contract templates configured (template-based only)

If using template-based contracts, create your templates in the Dashboard under People > Contracts > Browse Templates before using the API. Not needed for uploaded contracts.
4

Onboarded workers

Workers must be onboarded as Persons — you’ll assign contracts using their personId. See Onboard Workers.

Option A: Template-Based Contracts

Use this flow when you want Cadana to handle electronic signatures. You select a contract template, Cadana generates the document, and both parties sign digitally.

List Available Templates

Retrieve the templates available for your business. Each template is scoped to a personType (employee or contractor) and country.
bash
curl -X GET 'https://api.cadanapay.com/v1/contract-templates' \
  -H 'Authorization: Bearer YOUR_API_KEY'
Response:
{
  "data": [
    {
      "id": "c47f3b21-9a8e-4d5c-b6f2-1e0a9d8c7b6a",
      "name": "Standard Global Contractor Agreement",
      "personType": "contractor",
      "type": "regular",
      "country": "US",
      "templateVariables": [
        {
          "name": "firstName",
          "label": "First Name",
          "ref": "person.firstName",
          "type": "string",
          "isRequired": true
        }
      ],
      "createdTimestamp": 1702002274,
      "lastUpdatedTimestamp": 1702002274
    }
  ]
}
Template variables (e.g., person.firstName) are auto-populated from the Person record when the contract is created.

Create a Contract

Create a contract from a template and assign it to a person. The sender is the business representative who will sign first.
bash
curl -X POST 'https://api.cadanapay.com/v1/contracts' \
  -H 'Authorization: Bearer YOUR_API_KEY'
Response:
{
  "id": "d52e4a13-7b6f-4c8d-a9e1-2f3b5c7d8e9a",
  "name": "Jane Doe - Standard Global Contractor Agreement",
  "personId": "8ef9a712-cdae-4110-b1ea-9ba95abbee6e",
  "templateId": "c47f3b21-9a8e-4d5c-b6f2-1e0a9d8c7b6a",
  "status": "awaiting business signature",
  "signatures": [
    {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "name": "HR Department",
      "emailAddress": "hr@example.com",
      "order": 0,
      "status": "unsigned",
      "signedAt": 0,
      "lastViewedAt": 0
    },
    {
      "id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
      "name": "Jane Doe",
      "emailAddress": "amara@example.com",
      "order": 1,
      "status": "unsigned",
      "signedAt": 0,
      "lastViewedAt": 0
    }
  ],
  "subject": "The contract is ready for signature",
  "title": "Your Company has sent you a contract for signature",
  "createdAt": 1689759850
}
To suppress the default email notification to the signer — for example, if you handle notifications through your own system — pass suppressNotification: true in the request body.

Get the Signing URL

Retrieve a URL that the next signer can use to view and sign the contract. The URL is valid for 336 hours (14 days).
bash
curl -X GET 'https://api.cadanapay.com/v1/contracts/d52e4a13-7b6f-4c8d-a9e1-2f3b5c7d8e9a/signingUrl' \
  -H 'Authorization: Bearer YOUR_API_KEY'
Response:
{
  "url": "https://<app-domain>/sign-contract?token=abc123&redirectUrl=https%3A%2F%2Fyourapp.com%2Fcontracts",
  "signer": "business"
}
FieldDescription
urlThe signing URL for viewing and signing the contract
signerWho needs to sign next: business or person
The domain in the URL is either app.cadanapay.com or your white-label domain, depending on your platform configuration. The optional redirectUrl query parameter specifies where to send the signer after they complete signing.
If you suppress email notifications (suppressNotification: true), you’re responsible for delivering the signing URL to each signer. Use the signing URL endpoint to generate links on demand.

Track Signature Status

List contracts to check their signature status. Optionally filter by personId.
bash
curl -X GET 'https://api.cadanapay.com/v1/contracts' \
  -H 'Authorization: Bearer YOUR_API_KEY'
Response:
{
  "data": [
    {
      "id": "d52e4a13-7b6f-4c8d-a9e1-2f3b5c7d8e9a",
      "name": "Jane Doe - Standard Global Contractor Agreement",
      "personId": "8ef9a712-cdae-4110-b1ea-9ba95abbee6e",
      "templateId": "c47f3b21-9a8e-4d5c-b6f2-1e0a9d8c7b6a",
      "status": "completed",
      "signatures": [
        {
          "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
          "name": "HR Department",
          "emailAddress": "hr@example.com",
          "order": 0,
          "status": "signed",
          "signedAt": 1689759900,
          "lastViewedAt": 1689759850
        },
        {
          "id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
          "name": "Jane Doe",
          "emailAddress": "amara@example.com",
          "order": 1,
          "status": "signed",
          "signedAt": 1689760200,
          "lastViewedAt": 1689760100
        }
      ],
      "createdAt": 1689759850,
      "customContractAttached": false
    }
  ]
}
Each signature includes signedAt (epoch timestamp, 0 if unsigned) and lastViewedAt so you can track engagement.

Contract Status Flow

StatusMeaning
awaiting business signatureBusiness representative needs to sign first
awaiting person signatureBusiness signed, waiting for the worker
completedBoth parties have signed
revokedContract was cancelled before completion
Contracts can only be revoked before both parties have signed. Once completed, the contract is final.

Option B: Upload a Signed Contract

Use this flow when you already have a signed contract PDF — for example, a contract signed offline or through a third-party e-signature tool.

Step 1: Upload the File

Upload the PDF using the two-step file upload flow. See Working with Files for the full process.
bash
curl -X POST 'https://api.cadanapay.com/v1/files/upload-url' \
  -H 'Authorization: Bearer YOUR_API_KEY'
Response:
{
  "fileId": "e63f5b24-8c7d-4a9e-b0f1-3d4e6f8a9b0c",
  "putUrl": "https://s3.amazonaws.com/...",
  "expiresIn": 900
}
Then upload the file to the putUrl within the expiry window (15 minutes):
Bash
curl -X PUT '<putUrl>' \
  -H 'Content-Type: application/pdf' \
  --data-binary '@/path/to/signed-contract.pdf'

Step 2: Create the Contract Record

Attach the uploaded file to the person’s record using the fileId from step 1.
bash
curl -X POST 'https://api.cadanapay.com/v1/contracts-upload' \
  -H 'Authorization: Bearer YOUR_API_KEY'
Response:
{
  "id": "f74a6c35-9d8e-4b0f-c1a2-4e5f7a8b9c0d",
  "name": "Contractor Agreement - Jane Doe",
  "personId": "8ef9a712-cdae-4110-b1ea-9ba95abbee6e",
  "status": "completed"
}
Uploaded contracts are created with status completed since they’re already signed. They appear alongside template-based contracts when you list contracts for a person.

Webhook Events

Cadana emits contract webhook events so you can track the signing lifecycle in real time. Subscribe via the Dashboard or see Webhooks for setup.

contract.created

Fired when a new contract is created (template-based or uploaded).
JSON
{
  "id": "d52e4a13-7b6f-4c8d-a9e1-2f3b5c7d8e9a",
  "personId": "8ef9a712-cdae-4110-b1ea-9ba95abbee6e",
  "templateId": "c47f3b21-9a8e-4d5c-b6f2-1e0a9d8c7b6a",
  "tenantKey": "cad95193904"
}

contract.signed

Fired each time a signature is collected. The isComplete field tells you whether all signatures are now in.
JSON
{
  "id": "d52e4a13-7b6f-4c8d-a9e1-2f3b5c7d8e9a",
  "signatureId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "name": "HR Department",
  "email": "hr@example.com",
  "isComplete": false,
  "tenantKey": "cad95193904"
}

contract.status.updated

Fired on status transitions (e.g., revoked).
JSON
{
  "id": "d52e4a13-7b6f-4c8d-a9e1-2f3b5c7d8e9a",
  "status": "revoked",
  "tenantKey": "cad95193904"
}
See Events for all event types and payload details.

Troubleshooting

IssueCauseSolution
401 UnauthorizedInvalid or missing API keyCheck your API key in the Dashboard
400 on createMissing required fieldsEnsure templateId, personId, and sender (with name and email) are provided
No templates returnedTemplates not configured for your businessCreate templates in the Dashboard under People > Contracts > Browse Templates
Signing URL expiredURL older than 336 hoursGenerate a new signing URL with GET /v1/contracts/{id}/signingUrl

Next Steps