Introduction
The Inkless API lets you programmatically create and send signing links (“envelopes”) based on your email templates and document templates, with signing order, merge fields, auditing, and expiry.
email_template_id
and all document_template_id
values must belong to the same company as the token.
Base URL
https://inkless.uk/api/service.php
Authentication
Include your API token in the Authorization
header:
Header
Authorization: Bearer YOUR_API_TOKEN
Credits
Each successful send (one API call that creates an envelope) consumes 1 company credit.
remaining_credits
.curl -sS -X POST "https://inkless.uk/api/service.php" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"type":"get_credits"}'
$h = @{ Authorization = "Bearer YOUR_API_TOKEN" }
Invoke-RestMethod -Method Post -Uri "https://inkless.uk/api/service.php" `
-Headers $h -ContentType "application/json" -Body '{"type":"get_credits"}'
const res = await fetch("https://inkless.uk/api/service.php", {
method:"POST",
headers:{Authorization:"Bearer YOUR_API_TOKEN","Content-Type":"application/json"},
body: JSON.stringify({type:"get_credits"})
});
console.log(await res.json());
<?php
$ch = curl_init("https://inkless.uk/api/service.php");
curl_setopt_array($ch, [
CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ["Authorization: Bearer YOUR_API_TOKEN","Content-Type: application/json"],
CURLOPT_POSTFIELDS => json_encode(["type"=>"get_credits"]),
]);
echo curl_exec($ch); curl_close($ch);
import requests, json
r = requests.post("https://inkless.uk/api/service.php",
headers={"Authorization":"Bearer YOUR_API_TOKEN","Content-Type":"application/json"},
data=json.dumps({"type":"get_credits"}))
print(r.json())
Send links (envelope)
/api/service.php
Creates secure links per recipient, attaches prepared PDFs, emails the first signing group, and logs an audit entry.
curl -sS -X POST "https://inkless.uk/api/service.php" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"type":"send_link",
"email_template_id":21,
"documents":[
{
"document_template_id":5,
"merge":{"first_name":"Shane","start_date":"2025-09-04"},
"recipients":[
{"recipient_number":1,"name":"Shane Lowe","email":"shane@example.com","phone":"07939647200"},
{"recipient_number":2,"name":"Manager","email":"manager@example.com"}
]
}
]
}'
$body = @{
type = "send_link"; email_template_id = 21;
documents = @(@{
document_template_id = 5
merge = @{ first_name = "Shane"; start_date = "2025-09-04" }
recipients = @(
@{ recipient_number=1; name="Shane Lowe"; email="shane@example.com"; phone="07939647200" },
@{ recipient_number=2; name="Manager"; email="manager@example.com" }
)
})
} | ConvertTo-Json -Depth 10 -Compress
Invoke-RestMethod -Method POST -Uri "https://inkless.uk/api/service.php" `
-Headers @{ Authorization = "Bearer YOUR_API_TOKEN" } `
-ContentType "application/json" -Body $body
const res = await fetch("https://inkless.uk/api/service.php", {
method:"POST",
headers:{Authorization:"Bearer YOUR_API_TOKEN","Content-Type":"application/json"},
body: JSON.stringify({
type:"send_link", email_template_id:21,
documents:[{
document_template_id:5,
merge:{first_name:"Shane",start_date:"2025-09-04"},
recipients:[
{recipient_number:1,name:"Shane Lowe",email:"shane@example.com",phone:"07939647200"},
{recipient_number:2,name:"Manager", email:"manager@example.com"}
]
}]
})
});
console.log(await res.json());
<?php
$payload = [
"type"=>"send_link","email_template_id"=>21,
"documents"=>[[
"document_template_id"=>5,
"merge"=>["first_name"=>"Shane","start_date"=>"2025-09-04"],
"recipients"=>[
["recipient_number"=>1,"name"=>"Shane Lowe","email"=>"shane@example.com","phone"=>"07939647200"],
["recipient_number"=>2,"name"=>"Manager","email"=>"manager@example.com"]
]
]]
];
$ch = curl_init("https://inkless.uk/api/service.php");
curl_setopt_array($ch,[
CURLOPT_POST=>true, CURLOPT_RETURNTRANSFER=>true,
CURLOPT_HTTPHEADER=>["Authorization: Bearer YOUR_API_TOKEN","Content-Type: application/json"],
CURLOPT_POSTFIELDS=>json_encode($payload),
]);
echo curl_exec($ch); curl_close($ch);
import requests, json
payload = {
"type":"send_link","email_template_id":21,
"documents":[{
"document_template_id":5,
"merge":{"first_name":"Shane","start_date":"2025-09-04"},
"recipients":[
{"recipient_number":1,"name":"Shane Lowe","email":"shane@example.com","phone":"07939647200"},
{"recipient_number":2,"name":"Manager","email":"manager@example.com"}
]
}]
}
r = requests.post("https://inkless.uk/api/service.php",
headers={"Authorization":"Bearer YOUR_API_TOKEN","Content-Type":"application/json"},
data=json.dumps(payload))
print(r.json())
The earliest signing group (lowest recipient_number
) is emailed immediately; subsequent signers are notified automatically after prior completion.
Payload & schema
Top-level
Field | Description |
---|---|
type | Must be send_link . |
email_template_id | Company-owned email template; its subject is used. |
documents | Array of document requests (see right). |
documents[]
Field | Description |
---|---|
document_template_id | Company-owned document template. |
merge | Object of merge fields for the template (optional). |
recipients[] | Per-document signer mapping. Each item has:
- recipient_number (int ≥ 1): signing order bucket
- name (required)
- email (required)
- phone (optional)
|
documents[].doc_id
, documents[].recipient_numbers
, and a top-level recipients
map.
Responses
200 OK
{
"ok": true,
"links": [
{
"secure_link_id": 271,
"token": "2c0c...e2f1",
"recipient": { "name": "Shane Lowe", "email": "shane@example.com" },
"expires_at": "2025-09-05 10:14:00",
"status": "sent",
"verify_url": "https://sign.inkless.uk/verify/2c0c...e2f1"
}
],
"docs": [
{ "doc_id": 5, "doc_token": "a1b2...c3d4", "name": "NDA", "version": 1, "pages": 3 }
],
"remaining_credits": 42
}
Common errors
HTTP | Error | Meaning |
---|---|---|
400 | documents is required | Provide a non-empty documents array. |
400 | email_template_id is required | Provide a valid template id. |
400 | no valid documents or recipients | Check doc IDs and recipients (name, email, and numbers). |
401 | — | Missing or invalid token. |
402 | insufficient_credits | Buy credits or top up. |
403 | email template not found for this company | Template ownership mismatch. |
403 | invalid_document_ids | One or more documents aren’t owned by your company. |
500 | server error | Unexpected failure (conversion, I/O). Retry or contact support. |
Error handling
We return a non-2xx HTTP status and a JSON body with ok: false
and an error
key. Your client should check response.ok
and handle these values.
Webhooks (optional)
Inkless can POST JSON to your webhook endpoint for events such as:
document_signing_link_sent
document_signed
archive_ready
link_resent
{
"event": "document_signed",
"company_id": 16,
"doc_token": "a1b2...c3d4",
"secure_link_id": 271,
"recipient": { "name": "Shane Lowe", "email": "shane@example.com" },
"signed_at": "2025-09-04T10:25:31Z",
"metadata": { "ip": "203.0.113.5", "user_agent": "..." }
}
Ask support to enable & configure your webhook URL. Use HTTPS. We can sign payloads and retry deliveries if needed.
List email templates
Returns active email templates (ID & name) for your company.
/api/service.php
with {"type":"list_email_templates"}
curl -sS -X POST "https://inkless.uk/api/service.php" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"type":"list_email_templates"}'
$h=@{Authorization="Bearer YOUR_API_TOKEN"}
Invoke-RestMethod -Method Post -Uri "https://inkless.uk/api/service.php" `
-Headers $h -ContentType "application/json" -Body '{"type":"list_email_templates"}'
const r=await fetch("https://inkless.uk/api/service.php",{
method:"POST",
headers:{Authorization:"Bearer YOUR_API_TOKEN","Content-Type":"application/json"},
body:JSON.stringify({type:"list_email_templates"})
}); console.log(await r.json());
<?php
$ch=curl_init("https://inkless.uk/api/service.php");
curl_setopt_array($ch,[CURLOPT_POST=>true,CURLOPT_RETURNTRANSFER=>true,
CURLOPT_HTTPHEADER=>["Authorization: Bearer YOUR_API_TOKEN","Content-Type: application/json"],
CURLOPT_POSTFIELDS=>'{"type":"list_email_templates"}']); echo curl_exec($ch); curl_close($ch);
import requests,json
r=requests.post("https://inkless.uk/api/service.php",
headers={"Authorization":"Bearer YOUR_API_TOKEN","Content-Type":"application/json"},
data=json.dumps({"type":"list_email_templates"}))
print(r.json())
Response: {"ok":true,"templates":[{"id":21,"name":"Default Signing Invite"},...]}
List document templates
Returns active non one-off document templates (ID & name) for your company.
/api/service.php
with {"type":"list_document_templates"}
curl -sS -X POST "https://inkless.uk/api/service.php" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"type":"list_document_templates"}'
$h=@{Authorization="Bearer YOUR_API_TOKEN"}
Invoke-RestMethod -Method Post -Uri "https://inkless.uk/api/service.php" `
-Headers $h -ContentType "application/json" -Body '{"type":"list_document_templates"}'
const r=await fetch("https://inkless.uk/api/service.php",{
method:"POST",
headers:{Authorization:"Bearer YOUR_API_TOKEN","Content-Type":"application/json"},
body:JSON.stringify({type:"list_document_templates"})
}); console.log(await r.json());
<?php
$ch=curl_init("https://inkless.uk/api/service.php");
curl_setopt_array($ch,[CURLOPT_POST=>true,CURLOPT_RETURNTRANSFER=>true,
CURLOPT_HTTPHEADER=>["Authorization: Bearer YOUR_API_TOKEN","Content-Type: application/json"],
CURLOPT_POSTFIELDS=>'{"type":"list_document_templates"}']); echo curl_exec($ch); curl_close($ch);
import requests,json
r=requests.post("https://inkless.uk/api/service.php",
headers={"Authorization":"Bearer YOUR_API_TOKEN","Content-Type":"application/json"},
data=json.dumps({"type":"list_document_templates"}))
print(r.json())
Response: {"ok":true,"templates":[{"id":5,"name":"Contract v1"},...]}
Get artifact (signed PDF / audit log / archive)
Returns the requested artifact for a document instance identified by doc_token
. File is base64 in JSON.
/api/service.php
with {"type":"get_artifact","doc_token":"...","artifact":"signed|audit|archive"}
curl -sS -X POST "https://inkless.uk/api/service.php" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"type":"get_artifact","doc_token":"DOC_TOKEN","artifact":"signed"}'
$h=@{Authorization="Bearer YOUR_API_TOKEN"}
$payload=@{type="get_artifact";doc_token="DOC_TOKEN";artifact="signed"}|ConvertTo-Json -Compress
$r=Invoke-RestMethod -Method Post -Uri "https://inkless.uk/api/service.php" -Headers $h -ContentType "application/json" -Body $payload
[IO.File]::WriteAllBytes($r.filename, [Convert]::FromBase64String($r.content_base64))
const r=await fetch("https://inkless.uk/api/service.php",{
method:"POST",
headers:{Authorization:"Bearer YOUR_API_TOKEN","Content-Type":"application/json"},
body:JSON.stringify({type:"get_artifact",doc_token:"DOC_TOKEN",artifact:"signed"})
});
const j=await r.json();
const buf=Buffer.from(j.content_base64,'base64');
const fs=await import('node:fs');
fs.writeFileSync(j.filename||'artifact.bin',buf);
<?php
$payload=["type"=>"get_artifact","doc_token"=>"DOC_TOKEN","artifact"=>"signed"];
$ch=curl_init("https://inkless.uk/api/service.php");
curl_setopt_array($ch,[CURLOPT_POST=>true,CURLOPT_RETURNTRANSFER=>true,
CURLOPT_HTTPHEADER=>["Authorization: Bearer YOUR_API_TOKEN","Content-Type: application/json"],
CURLOPT_POSTFIELDS=>json_encode($payload)]);
$j=json_decode(curl_exec($ch),true); curl_close($ch);
file_put_contents($j["filename"]??"artifact.bin", base64_decode($j["content_base64"]??""));
import requests, json, base64
r=requests.post("https://inkless.uk/api/service.php",
headers={"Authorization":"Bearer YOUR_API_TOKEN","Content-Type":"application/json"},
data=json.dumps({"type":"get_artifact","doc_token":"DOC_TOKEN","artifact":"signed"}))
j=r.json()
open(j.get("filename","artifact.bin"),"wb").write(base64.b64decode(j["content_base64"]))
409
with {"ok":false,"error":"not ready"}
until the artifact exists (e.g. signed PDF after all parties sign).
Changelog
- 2025-09-04 — Added docs for
get_credits
,list_email_templates
,list_document_templates
, andget_artifact
. Kept layout, added PHP/Python examples, generic tab & copy handling. - 2025-09-04 — Initial docs for
send_link
. Credits check & debit, ownership checks, audit logging, first-batch mailing.