Code Examples
Complete workflows showing how to use the Draftory API from start to finish.
Complete Workflow
This example walks through the full lifecycle: verify your key, create a multi-party contract, and check its signing status.
Step 1: Verify your API key
Send a GET request to /status to confirm your API key is valid. The response includes your key info and subscription tier.
curl https://api.draftory.ca/api/external/v2/status \
-H "x-api-key: dft_live_your_key"
const response = await fetch('https://api.draftory.ca/api/external/v2/status', {
headers: { 'x-api-key': 'dft_live_your_key' }
});
const data = await response.json();
console.log(data.status); // "operational"
console.log(data.subscription.tier); // "startup"
import requests
response = requests.get(
'https://api.draftory.ca/api/external/v2/status',
headers={'x-api-key': 'dft_live_your_key'}
)
data = response.json()
print(data['status']) # "operational"
Step 2: Create a multi-party contract
Send a POST request to /contracts to create a new contract with multiple parties.
curl -X POST https://api.draftory.ca/api/external/v2/contracts \
-H "x-api-key: dft_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"parties": [
{ "role": "seller", "legalName": "Acme Corp", "email": "acme@example.com" },
{ "role": "buyer", "legalName": "Jane Smith", "email": "jane@example.com" }
],
"contractType": "nda",
"content": "MUTUAL NON-DISCLOSURE AGREEMENT\n\n1. PARTIES\nSeller: Acme Corp\nBuyer: Jane Smith\n\n2. TERMS\nBoth parties agree not to disclose confidential information.\nThis agreement remains in effect for 2 years.\n\n3. GOVERNING LAW\nProvince of Ontario, Canada.",
"senderName": "Acme Corp"
}'
const response = await fetch('https://api.draftory.ca/api/external/v2/contracts', {
method: 'POST',
headers: {
'x-api-key': 'dft_live_your_key',
'Content-Type': 'application/json'
},
body: JSON.stringify({
parties: [
{ role: 'seller', legalName: 'Acme Corp', email: 'acme@example.com' },
{ role: 'buyer', legalName: 'Jane Smith', email: 'jane@example.com' }
],
contractType: 'nda',
content: 'MUTUAL NON-DISCLOSURE AGREEMENT\n\n1. PARTIES\nSeller: Acme Corp\nBuyer: Jane Smith\n\n2. TERMS\nBoth parties agree not to disclose confidential information.',
senderName: 'Acme Corp'
})
});
const contract = await response.json();
console.log(contract);
import requests
response = requests.post(
'https://api.draftory.ca/api/external/v2/contracts',
headers={
'x-api-key': 'dft_live_your_key',
'Content-Type': 'application/json'
},
json={
'parties': [
{'role': 'seller', 'legalName': 'Acme Corp', 'email': 'acme@example.com'},
{'role': 'buyer', 'legalName': 'Jane Smith', 'email': 'jane@example.com'}
],
'contractType': 'nda',
'content': 'MUTUAL NON-DISCLOSURE AGREEMENT\n\n1. PARTIES\nSeller: Acme Corp\nBuyer: Jane Smith\n\n2. TERMS\nBoth parties agree not to disclose confidential information.',
'senderName': 'Acme Corp'
}
)
contract = response.json()
print(contract)
The response includes a shareUrl and signingProgress. Draftory automatically emails all parties:
{
"success": true,
"contract": {
"id": "contract-1711234567890-AbCdEfGh",
"contractNumber": "EXT-20260321-ABCDEFGH",
"shareToken": "abc123token",
"shareUrl": "https://draftory.ca/contract/abc123token",
"status": "pending_signature",
"contractType": "nda",
"parties": [
{ "role": "seller", "legalName": "Acme Corp", "email": "acme@example.com" },
{ "role": "buyer", "legalName": "Jane Smith", "email": "jane@example.com" }
],
"signingProgress": { "signed": 0, "total": 2, "pending": 2, "percentage": 0 },
"createdAt": "2026-03-21T12:00:00.000Z",
"expiresAt": "2026-04-04T12:00:00.000Z"
}
}
Step 3: Check signing progress
Send a GET request to /contracts/{id} using the ID from Step 2 to check which parties have signed.
curl https://api.draftory.ca/api/external/v2/contracts/contract-1711234567890-AbCdEfGh \
-H "x-api-key: dft_live_your_key"
const contractId = 'contract-1711234567890-AbCdEfGh';
const response = await fetch(
`https://api.draftory.ca/api/external/v2/contracts/${contractId}`,
{ headers: { 'x-api-key': 'dft_live_your_key' } }
);
const data = await response.json();
console.log(data.contract.status); // "partially_signed"
console.log(data.contract.signingProgress.signed); // 1
console.log(data.contract.signingProgress.percentage); // 50
// Check each party's signing status
data.contract.parties.forEach(party => {
console.log(`${party.role}: ${party.hasSigned ? 'signed' : 'pending'}`);
});
import requests
contract_id = 'contract-1711234567890-AbCdEfGh'
response = requests.get(
f'https://api.draftory.ca/api/external/v2/contracts/{contract_id}',
headers={'x-api-key': 'dft_live_your_key'}
)
data = response.json()
print(data['contract']['status']) # "partially_signed"
print(data['contract']['signingProgress']) # {"signed": 1, "total": 2, ...}
# Check each party
for party in data['contract']['parties']:
status = 'signed' if party['hasSigned'] else 'pending'
print(f'{party["role"]}: {status}')
Error Handling
Always handle errors gracefully. Check the HTTP status code and respond accordingly. Here are complete examples in JavaScript and Python.
async function createContract(data) {
try {
const response = await fetch(
'https://api.draftory.ca/api/external/v2/contracts',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': process.env.DRAFTORY_API_KEY
},
body: JSON.stringify(data)
}
);
if (!response.ok) {
const err = await response.json();
switch (response.status) {
case 401:
console.error('Check your API key:', err.error);
break;
case 429:
const retryAfter = response.headers.get('RateLimit-Reset');
console.error(`Rate limited, retry after ${retryAfter}s`);
break;
default:
console.error(`Error ${response.status}:`, err.error);
}
return null;
}
return await response.json();
} catch (error) {
console.error('Network error:', error.message);
return null;
}
}
import requests
import os
def create_contract(data):
try:
response = requests.post(
'https://api.draftory.ca/api/external/v2/contracts',
headers={
'Content-Type': 'application/json',
'x-api-key': os.environ['DRAFTORY_API_KEY']
},
json=data
)
response.raise_for_status()
return response.json()
except requests.exceptions.HTTPError as e:
status = e.response.status_code
err = e.response.json()
if status == 401:
print(f'Check your API key: {err["error"]}')
elif status == 429:
retry_after = e.response.headers.get('RateLimit-Reset')
print(f'Rate limited, retry after {retry_after}s')
else:
print(f'Error {status}: {err["error"]}')
return None
except requests.exceptions.ConnectionError as e:
print(f'Network error: {e}')
return None
Polling for Signing Completion
Poll the contract status endpoint to wait for all parties to sign. Here is a JavaScript example:
async function waitForSigning(contractId, pollIntervalMs = 10000) {
while (true) {
const response = await fetch(
`https://api.draftory.ca/api/external/v2/contracts/${contractId}`,
{ headers: { 'x-api-key': process.env.DRAFTORY_API_KEY } }
);
const data = await response.json();
const { signingProgress, status } = data.contract;
console.log(`Status: ${status} — ${signingProgress.signed}/${signingProgress.total} signed`);
if (status === 'signed') {
console.log('All parties signed!');
return data.contract;
}
if (status === 'expired' || status === 'cancelled') {
console.log(`Contract ${status} — stopping poll`);
return null;
}
await new Promise(r => setTimeout(r, pollIntervalMs));
}
}
// Usage
const result = await waitForSigning('contract-1711234567890-AbCdEfGh');