Skip to content
NewZATCA Phase 2 e-invoicing is now built in
Tapat.link

// API reference

Tapat.link REST API

Every document in Tapat.link is available over a secure, predictable REST API. Use it to connect stores, banks, logistics providers and your own apps.

Base URLhttps://<company>.tapat.link/api

Authentication

Authenticate every request with an API key and secret, generated per user under Settings → API access. Requests run with that user's permissions, so create a dedicated integration user with only the roles it needs.

Verify your credentials
curl "https://acme.tapat.link/api/method/ping" \  -H "Authorization: token $API_KEY:$API_SECRET"

Keep your API secret on the server. Never embed it in a browser or mobile app.

Resources

Each document type is a resource. Standard endpoints follow the same pattern for every resource:

MethodEndpointDescription
GET/api/resource/{doctype}List records
GET/api/resource/{doctype}/{name}Get one record
POST/api/resource/{doctype}Create a record
PUT/api/resource/{doctype}/{name}Update a record
DELETE/api/resource/{doctype}/{name}Delete a draft record
Get a sales invoice
curl "https://acme.tapat.link/api/resource/Sales%20Invoice/INV-2026-01842" \  -H "Authorization: token $API_KEY:$API_SECRET"
Create a customer
curl -X POST "https://acme.tapat.link/api/resource/Customer" \  -H "Authorization: token $API_KEY:$API_SECRET" \  -H "Content-Type: application/json" \  -d '{ "customer_name": "Gulf Fresh Foods", "tax_id": "300987654300003" }'
Update a customer
curl -X PUT "https://acme.tapat.link/api/resource/Customer/Gulf%20Fresh%20Foods" \  -H "Authorization: token $API_KEY:$API_SECRET" \  -H "Content-Type: application/json" \  -d '{ "credit_limit": 250000 }'
Delete a draft item
curl -X DELETE "https://acme.tapat.link/api/resource/Item/SAMPLE-ITEM" \  -H "Authorization: token $API_KEY:$API_SECRET"

Filtering & pagination

List endpoints accept fields, filters, order_by, limit_start and limit_page_length parameters. Filters are JSON arrays of [field, operator, value].

List unpaid invoices
# List the 20 most recent unpaid invoicescurl -G "https://acme.tapat.link/api/resource/Sales%20Invoice" \  -H "Authorization: token $API_KEY:$API_SECRET" \  --data-urlencode 'fields=["name","customer","grand_total","status"]' \  --data-urlencode 'filters=[["status","=","Unpaid"]]' \  --data-urlencode 'order_by=posting_date desc' \  --data-urlencode 'limit_page_length=20'
  • Operators: =, !=, >, <, >=, <=, like, in, not in, between
  • Default page size is 20; the maximum is 500
  • Use limit_start to page through results

Webhooks

Subscribe to events under Settings → Webhooks. Tapat.link sends a signed POST request to your URL whenever an event occurs, and retries with exponential backoff for up to 24 hours.

Example payload
{  "event": "sales_invoice.cleared",  "created_at": "2026-09-28T10:42:17+03:00",  "data": {    "name": "INV-2026-01842",    "customer": "Riyadh Build Supplies",    "grand_total": 44160.0,    "zatca_status": "CLEARED"  }}

Verify the X-Signature header, an HMAC-SHA256 of the raw body using your webhook secret, before trusting a payload.

Rate limits

Requests are limited per API key. Every response includes X-RateLimit-Limit and X-RateLimit-Remaining headers.

PlanRequests per minute
Starter60 (read-only)
Business300
EnterpriseCustom

Errors

Errors use standard HTTP status codes and a consistent JSON body.

Error response
{  "error": {    "status": 422,    "code": "validation_error",    "message": "Customer tax ID must be 15 digits",    "field": "tax_id"  }}
StatusMeaning
400Malformed request
401Missing or invalid credentials
403The user lacks permission for this action
404Record not found
422Validation failed
429Rate limit exceeded