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
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.
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.
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.
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.
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).
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"
}
| Field | Description |
|---|
url | The signing URL for viewing and signing the contract |
signer | Who 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.
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
| Status | Meaning |
|---|
awaiting business signature | Business representative needs to sign first |
awaiting person signature | Business signed, waiting for the worker |
completed | Both parties have signed |
revoked | Contract 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.
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):
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.
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).
{
"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.
{
"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).
{
"id": "d52e4a13-7b6f-4c8d-a9e1-2f3b5c7d8e9a",
"status": "revoked",
"tenantKey": "cad95193904"
}
See Events for all event types and payload details.
Troubleshooting
| Issue | Cause | Solution |
|---|
401 Unauthorized | Invalid or missing API key | Check your API key in the Dashboard |
400 on create | Missing required fields | Ensure templateId, personId, and sender (with name and email) are provided |
| No templates returned | Templates not configured for your business | Create templates in the Dashboard under People > Contracts > Browse Templates |
| Signing URL expired | URL older than 336 hours | Generate a new signing URL with GET /v1/contracts/{id}/signingUrl |
Next Steps