Overview
The Auliq API is a REST API over HTTPS. Requests and responses are JSON, identifiers are prefixed by resource type, and timestamps are ISO 8601 UTC.
Base URL
https://construction.auliq.net/api/v1Auth scheme
Bearer API key in the Authorization header.
Sandbox
Same base URL with a test key (aul_test_…).
Quickstart
Create an API key in Platform → API, then keep it server-side.
Authenticate every request with your key in the Authorization header.
curl -G "https://construction.auliq.net/api/v1/projects" \
-H "Authorization: Bearer aul_test_YOUR_KEY"Create your first resource — an employee record.
curl -X POST "https://construction.auliq.net/api/v1/employees" \
-H "Authorization: Bearer aul_test_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"full_name": "Dana Whitfield",
"email": "dana.whitfield@example.com",
"role": "foreman",
"project_id": "prj_01J8XK92M4"
}'Authentication
Every request is authenticated with an API key sent as a Bearer token. Keys are scoped and typed: secret keys act on production data, test keys on sandbox data.
# undefined header
Authorization: Bearer aul_sk_51HtXq2f...Secret key
aul_sk_…
Full access to live data. Keep it server-side only, never in browser code.
Test key
aul_test_…
Requests run against sandbox data and never touch production records.
Publishable key
aul_pk_…
Identifies your integration in browser contexts. Grants no write access.
Authorization scopes
Each key carries a set of scopes. A request whose endpoint needs an ungranted scope returns 403 insufficient_scope.
| Name | Type | Description |
|---|---|---|
employees:read | scope | List and retrieve employee records. |
employees:write | scope | Create, update and deactivate employees. |
projects:read | scope | List and retrieve projects. |
projects:write | scope | Create and update projects. |
rfis:read | scope | List and retrieve RFIs. |
rfis:write | scope | Create, answer and close RFIs. |
submittals:write | scope | Create submittals and update their review status. |
change_orders:read | scope | List and retrieve change orders. |
tasks:read | scope | List and retrieve tasks. |
tasks:write | scope | Create, assign and complete tasks. |
webhooks:write | scope | Create and delete webhook subscriptions. |
Endpoints
Fourteen endpoints across employees, projects, RFIs, submittals, change orders, tasks and webhooks. Select any endpoint to expand its full specification.
Employees
https://construction.auliq.net/api/v1/employeesCreates a new employee and assigns them to a project. Email addresses must be unique across the workspace; a duplicate returns 409 Conflict.
employees:writeRequest body schema
| Name | Type | Description |
|---|---|---|
full_namerequired | string | Full name of the employee. |
emailrequired | string | Unique work email address. |
rolerequired | string | Site role of the employee.laboreroperatorforemansupervisorengineerproject_manager |
project_idrequired | string | ID of the project the employee is assigned to. |
trade | string | Optional trade or specialty. |
hourly_rate | number | Billable hourly rate in USD. |
start_date | string (date) | First day on site, ISO 8601 date. |
Code example
curl -X POST "https://construction.auliq.net/api/v1/employees" \
-H "Authorization: Bearer aul_test_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"full_name": "Dana Whitfield",
"email": "dana.whitfield@example.com",
"role": "foreman",
"project_id": "prj_01J8XK92M4",
"trade": "carpentry",
"hourly_rate": 48.5,
"start_date": "2026-10-19"
}'Responses
| Name | Type | Description |
|---|---|---|
201 | Created | Employee created. Returns the employee object. |
400 | invalid_request | Malformed body or unknown project_id. |
401 | unauthorized | Missing or invalid API key. |
409 | conflict | An employee with this email already exists. |
422 | validation_error | One or more fields failed validation. |
{
"id": "emp_01J9F3WD8N",
"object": "employee",
"full_name": "Dana Whitfield",
"email": "dana.whitfield@example.com",
"role": "foreman",
"trade": "carpentry",
"project_id": "prj_01J8XK92M4",
"hourly_rate": 48.5,
"start_date": "2026-10-19",
"status": "active",
"created_at": "2026-10-10T09:41:07Z"
}Projects
RFIs
Submittals
Change orders
Tasks
Webhooks
Data schemas
Core objects returned by the API. Every object carries id, object, created_at and updated_at in addition to the fields listed.
Employee
| Name | Type | Description |
|---|---|---|
id | string | Unique identifier, prefixed emp_. |
object | string | Always "employee". |
full_name | string | Employee full name. |
email | string | Unique work email address. |
role | string | Site role.laboreroperatorforemansupervisorengineerproject_manager |
trade | string | Optional trade or specialty. |
project_id | string | Assigned project. |
hourly_rate | number | Billable hourly rate in USD. |
start_date | string | First day on site, ISO 8601 date. |
status | string | Employment status.activeinactive |
created_at | string | Creation timestamp, ISO 8601 UTC. |
Project
| Name | Type | Description |
|---|---|---|
id | string | Unique identifier, prefixed prj_. |
object | string | Always "project". |
name | string | Human-readable project name. |
code | string | Unique short project code. |
client | string | Client or owner organization. |
status | string | Project status.planningactivecompleted |
budget_amount | number | Approved contract budget in USD. |
percent_complete | number | Overall progress, 0-100. |
created_at | string | Creation timestamp, ISO 8601 UTC. |
Rfi
| Name | Type | Description |
|---|---|---|
id | string | Unique identifier, prefixed rfi_. |
reference | string | Human-readable number, e.g. RFI-0142. |
project_id | string | Project the RFI belongs to. |
subject | string | Short summary of the question. |
question | string | Full question text. |
answer | string | Answer text, set when answered. |
discipline | string | Discipline.architecturalstructuralmechanicalelectricalplumbingcivilgeneral |
priority | string | Response urgency.lowmediumhighurgent |
status | string | Workflow status.draftsubmittedansweredclosed |
due_date | string | Requested answer date, ISO 8601. |
created_at | string | Creation timestamp, ISO 8601 UTC. |
Submittal
| Name | Type | Description |
|---|---|---|
id | string | Unique identifier, prefixed sub_. |
reference | string | Human-readable number, e.g. SUB-0087. |
project_id | string | Project the submittal belongs to. |
title | string | Submittal title. |
type | string | Submittal type.materialproduct_datashop_drawingmockupsampleother |
discipline | string | Review discipline.architecturalstructuralmechanicalelectricalplumbingcivilgeneral |
vendor | string | Vendor or manufacturer. |
status | string | Review status.draftsubmittedunder_reviewapprovedrejected |
due_date | string | Review due date, ISO 8601. |
created_at | string | Creation timestamp, ISO 8601 UTC. |
ChangeOrder
| Name | Type | Description |
|---|---|---|
id | string | Unique identifier, prefixed co_. |
reference | string | Human-readable number, e.g. CO-0031. |
project_id | string | Project the change order belongs to. |
contract_reference | string | Contract the change modifies. |
description | string | Scope of the change. |
amount | number | Change amount in USD. |
status | string | Approval status.draftpending_approvalapprovedissued |
issued_date | string | Date issued, ISO 8601. |
created_at | string | Creation timestamp, ISO 8601 UTC. |
Task
| Name | Type | Description |
|---|---|---|
id | string | Unique identifier, prefixed tsk_. |
title | string | Task description. |
project_id | string | Project the task belongs to. |
assignee | string | Assignee email address. |
status | string | Task status.todoin_progressreviewdone |
priority | string | Task priority.lowmediumhigh |
due_date | string | Due date, ISO 8601. |
created_at | string | Creation timestamp, ISO 8601 UTC. |
Webhook
| Name | Type | Description |
|---|---|---|
id | string | Unique identifier, prefixed wh_. |
url | string | HTTPS endpoint receiving deliveries. |
events | array | Subscribed event types. |
status | string | Delivery state.enableddisabled |
secret | string | Signing secret, returned once at creation. |
created_at | string | Creation timestamp, ISO 8601 UTC. |
Errors
Auliq uses conventional HTTP status codes. Every error response shares one envelope and carries a request_id you can quote in support requests.
{
"error": {
"type": "validation_error",
"code": 422,
"message": "email is not a valid email address.",
"param": "email",
"request_id": "req_01J9M7DQ5B"
}
}| Name | Type | Description |
|---|---|---|
400 | invalid_request | The request is malformed: a bad query parameter, header or body. |
401 | unauthorized | No API key supplied, or the key is invalid or revoked. |
403 | insufficient_scope | The key is valid but lacks the scope this endpoint requires. |
404 | not_found | The requested resource does not exist or was archived. |
409 | conflict | The resource already exists, e.g. a duplicate employee email. |
422 | validation_error | One or more fields failed validation; error.param names the first offender. |
429 | rate_limited | Too many requests. Honor the Retry-After header. |
500 | internal_error | Unexpected error on our side. Retry with backoff. |
503 | service_unavailable | Temporary outage or maintenance window. Retry with backoff. |
Pagination, filtering & rate limits
List endpoints use cursor pagination, accept server-side filters and sorting, and are rate limited per API key.
Pagination
List responses return an object: "list" envelope with a meta.next_cursor. Pass that cursor as the cursor query parameter to fetch the next page, and stop when meta.has_more is false. limit defaults to 25 and maxes at 100.
{
"object": "list",
"data": [ /* up to limit objects */ ],
"meta": {
"next_cursor": "cur_01J9KQ",
"has_more": true
}
}Filtering & sorting
Filters are plain query parameters documented on each list endpoint (e.g. status=active, project_id=prj_…). Sorting uses sort with an optional descending prefix, e.g. sort=-created_at. Filtering, counting and sorting run server-side.
Rate limits
120 requests per minute per key, with a short burst of 20 requests per second. Exceeding the limit returns 429 rate_limited; back off per the Retry-After header.
| Name | Type | Description |
|---|---|---|
X-RateLimit-Limit | header | Requests allowed in the current window (120). |
X-RateLimit-Remaining | header | Requests left in the current window. |
X-RateLimit-Reset | header | Unix time when the window resets. |
Retry-After | header | Seconds to wait before retrying, sent with 429 responses. |
Webhooks
Subscribe to events over POST /webhooks and receive signed JSON payloads at your HTTPS endpoint when things happen in Auliq.
Event catalog
| Name | Type | Description |
|---|---|---|
employee.created | event | An employee record was created. |
project.created | event | A project was created. |
task.assigned | event | A task was assigned to a user. |
task.completed | event | A task was marked done. |
rfi.created | event | A new RFI was submitted. |
rfi.answered | event | An RFI received an answer. |
rfi.closed | event | An RFI was closed. |
submittal.reviewed | event | A submittal received a review decision. |
change_order.approved | event | A change order was approved. |
Payload structure
Deliveries are POSTs with a JSON body. Treat the payload id as unique; the same event is never delivered twice with the same id.
{
"id": "evt_01J9M9TN2C",
"event": "rfi.answered",
"api_version": "2026-09-01",
"created_at": "2026-10-11T09:30:00Z",
"data": {
"object": {
"id": "rfi_01J9G5TQ2P",
"object": "rfi",
"reference": "RFI-0142",
"project_id": "prj_01J8XK92M4",
"status": "answered",
"answer": "Penetration to be cored at 350mm; revised detail S-204-R2 issued."
}
}
}Verifying signatures
Every delivery includes an X-Auliq-Signature header of the form t=<timestamp>,v1=<signature>. The signature is an HMAC-SHA256 of {timestamp}.{rawBody} using your subscription's signing secret. Reject deliveries older than five minutes.
import crypto from "crypto";
// Raw request body as a string, and the X-Auliq-Signature header
const header = req.headers["x-auliq-signature"]; // e.g. "t=1760167800,v1=5f2a..."
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
const expected = crypto
.createHmac("sha256", process.env.AULIQ_WEBHOOK_SECRET)
.update(`${parts.t}.${rawBody}`)
.digest("hex");
const valid = crypto.timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected));
if (!valid) return res.status(400).end(); // reject forged deliveriesRetries
- Failed deliveries are retried up to 5 times with exponential backoff, starting at 10 seconds, over 24 hours.
- Subscriptions that fail every attempt for 3 consecutive days are disabled automatically.
- Respond with any 2xx status within 10 seconds to acknowledge a delivery.
SDKs & code examples
Official SDKs wrap authentication, retries and pagination so you work with plain objects instead of raw HTTP.
JavaScript / TypeScript
npm install @auliq/api
import { Auliq } from "@auliq/api";
const auliq = new Auliq(process.env.AULIQ_API_KEY);
const rfi = await auliq.rfis.create({
project_id: "prj_01J8XK92M4",
subject: "Slab penetration vs. duct routing",
question: "Detail S-204 shows a 300mm slab penetration where the duct is routed.",
priority: "high",
});
for await (const employee of auliq.employees.list({ project_id: "prj_01J8XK92M4" })) {
console.log(employee.full_name);
}Python
pip install auliq
from auliq import Auliq
client = Auliq(api_key=os.environ["AULIQ_API_KEY"])
employees = client.employees.list(project_id="prj_01J8XK92M4", limit=25)
for employee in employees.data:
print(employee["full_name"])Prefer plain HTTP? Every endpoint ships a copy-ready cURL example in the Endpoints section above, and the interactive sandbox generates snippets for you.
Interactive sandbox
Pick an endpoint, fill in parameters, and preview the exact request in cURL, JavaScript or Python. Sending runs a sandbox simulation that returns representative sample responses, including validation errors for missing required fields.
Create an employee record
curl -X POST "https://construction.auliq.net/api/v1/employees" \
-H "Authorization: Bearer aul_test_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"full_name": "Dana Whitfield",
"email": "dana.whitfield@example.com",
"role": "foreman",
"project_id": "prj_01J8XK92M4",
"trade": "carpentry",
"hourly_rate": 48.5,
"start_date": "2026-10-19"
}'Versioning & deprecation
The API is versioned twice: a URL version for breaking changes and a date-based specification version for behavior changes within a release.
- URL versioning. Breaking changes ship under a new path (
/v2);/v1keeps working unchanged. - Spec version. Pin a date-based behavior set with the
API-Versionheader (current: 2026-09-01). Omitting it uses the latest stable version. - Deprecation. Endpoints are announced 12 months before removal via the changelog and email, and responses carry
DeprecationandSunsetheaders with the removal date. - After the Sunset date a deprecated endpoint returns
410 Gonewith a pointer to its replacement.
HTTP/1.1 200 OK
Deprecation: version=v1; date="Wed, 01 Jun 2027 00:00:00 GMT"
Sunset: Wed, 01 Jun 2027 00:00:00 GMTChangelog
All notable changes to the API. Additive changes ship at any time; breaking changes only with a new URL version.
- Added webhook subscriptions for change orders (change_order.approved).
- Added submittal.reviewed event.
- Pagination cursors are now stable across concurrent writes.
- Added PATCH /rfis/{rfi_id} for answering and closing RFIs.
- Added the sort query parameter to all list endpoints.
- Error envelope now includes request_id on every response.
- Introduced test-mode keys (aul_test_) for sandbox requests.
- Rate limit headers standardized across all endpoints.
- DELETE /employees/{id} now archives instead of hard-deleting.
- Initial public release of the Auliq API.