InkTick

Developers

The InkTick API

Read what is in a company file, push dockets in from your own systems, and be told the moment a claim moves. One rule carries over from the product: the API can snap, only a person can tick.

Authentication

The owner makes a key under Settings → API and webhooks. Keys are read-only or read + capture, shown once, and stored hashed. Send it as a bearer token. 120 requests a minute per key.

curl https://app.inktick.com/api/v1/ping \
  -H "Authorization: Bearer itk_live_…"

Endpoints

GET/api/v1/pingreadConfirms the key and names the company file.
GET/api/v1/claimsreadList claims. Filters: status, since, until (ISO-8601), limit (≤200), cursor.
GET/api/v1/claims/{id}readOne claim with lines, custom fields, originals and every timestamp.
POST/api/v1/claimswriteCapture a docket: { filename, mimeType, contentBase64 } or { text }, plus kind and note. Lands as NEEDS_CONFIRM.
GET/api/v1/files/{id}readThe original, byte for byte. SHA-256 in X-InkTick-SHA256.
GET/api/v1/suppliersreadSuppliers with aliases, default coding, standing split and registry check.
GET/api/v1/expense-reportsreadBundles with their claims and totals. Filter: status.

Money is integer cents with the currency beside it. Dates printed on a docket are YYYY-MM-DD; everything that happened in InkTick is an ISO-8601 UTC timestamp. Lists are newest first and page with nextCursor.

{
  "id": "clm_…", "object": "claim", "status": "APPROVED", "kind": "STAFF_CLAIM",
  "merchant": "Bunnings", "amount": { "cents": 8790, "currency": "AUD" },
  "tax": { "cents": 799, "code": "INPUT" }, "issuedAt": "2026-09-02",
  "accountCode": "310", "supplier": { "id": "…", "name": "Bunnings", "verified": true },
  "lines": [], "customFields": { "Job number": "JOB-1042" },
  "originals": [{ "id": "…", "sha256": "…", "url": "…/api/v1/files/…" }],
  "ledger": null,
  "timestamps": { "createdAt": "…", "confirmedAt": "…", "approvedAt": "…", "publishedAt": null }
}

Webhooks

Add an https:// address under Settings → API and webhooks and pick events. Each delivery is a JSON POST carrying the same claim shape as the API. Events:

claim.capturedclaim.confirmedclaim.submittedclaim.approvedclaim.rejectedclaim.publishedclaim.reimbursedreport.submittedreport.approved

Every delivery is signed. Rebuild the signature from the raw body and compare before you trust it; reject anything older than five minutes.

X-InkTick-Event:     claim.approved
X-InkTick-Timestamp: 1788862800
X-InkTick-Signature: sha256=<hex HMAC-SHA256(secret, timestamp + "." + rawBody)>
X-InkTick-Delivery:  <uuid>

// Node
const crypto = require("crypto");
function verify(secret, headers, rawBody) {
  const ts = headers["x-inktick-timestamp"];
  if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false;
  const expected = crypto.createHmac("sha256", secret).update(ts + "." + rawBody).digest("hex");
  const given = String(headers["x-inktick-signature"]).replace(/^sha256=/, "");
  return expected.length === given.length &&
    crypto.timingSafeEqual(Buffer.from(expected, "hex"), Buffer.from(given, "hex"));
}

Answer 2xx quickly and do the work afterwards. A failed delivery is retried once after two seconds; after twenty failures in a row the webhook pauses itself and the owner sees why in Settings.

What the API will not do

  • Approve, reject or publish a claim. Those are human ticks, recorded against a person.
  • Move money. Payment files are downloads the owner takes to their own bank.
  • Read another company file. A key belongs to exactly one file.

The API is in beta while InkTick is pre-launch: shapes may gain fields, never lose them without notice. Questions: developers@inktick.com

Developers · InkTick