Your shop data.
Your next connection.
Connect RepairHQ to the tools your business runs on. Start with secure, read-only access to repairs, inventory, customers, and events.
https://www.repairhq.io/api/public/v1GETScoped to your store
Each token belongs to one business and one location.
Simple JSON responses
Four resources, explicit fields, and cursor pagination.
Signed event delivery
HMAC signatures and delivery IDs for reliable handling.
From token to first request
You’ll need a RepairHQ workspace and an owner or admin account to create a token.
Choose the business and location
Open your workspace, select the intended business and location, then go to More → API & integrations.
Create a scoped token
Under Scoped API access, enter an integration label, select the resources it needs, and choose an expiry from 1 to 90 days. Select Create scoped token and copy the returned token before closing it.
Make a request from your server
Store the token in a secret manager or server environment variable named
REPAIRHQ_TOKEN. Pick a resource below and copy the request example.
BlockChyp, Stripe, and Square credentials connect payment providers to your shop. A RepairHQ API token lets your own integration read RepairHQ records. Payment-provider keys cannot authenticate to this API.
One token. One location.
Send the token in the authorization header on every request. A token begins with rhq_ followed by 64 lowercase hexadecimal characters.
Authorization: Bearer <your-scoped-token>Resource permissions
Select only the scopes your integration needs:
repairs:readinventory:readcustomers:readevents:read
Business isolation
The token determines both business and location. There is no business or location override parameter. Each new store creates its own tokens; each location needs its own token.
Keep tokens on your server. Do not put them in URLs, public browser code, screenshots, or source control. The token list shows only its last four characters. Revoke a token in API & integrations to stop future requests.
To rotate, create a replacement token, update your integration, verify a read, then revoke the old token. Expiry does not renew automatically. Webhook signing secrets are separate from API tokens.
Read the records you need
One endpoint, four resources. All responses use application/json. These examples contain fictional data and run no requests from this page.
/api/public/v1?resource=repairsRepairs
Repair tickets, their current status, priority, and due date.
Required scope repairs:read
# Set REPAIRHQ_TOKEN securely in your local environment.
curl --fail-with-body --get \
'https://www.repairhq.io/api/public/v1' \
--data-urlencode 'resource=repairs' \
--header "Authorization: Bearer $REPAIRHQ_TOKEN"{
"resource": "repairs",
"data": [
{
"id": "11111111-1111-4111-8111-111111111111",
"number": "1042",
"device": "Sample laptop",
"status": "In repair",
"priority": "Normal",
"due_at": "2026-11-02",
"updated_at": "2026-10-27T14:30:00.000Z"
}
],
"next": null
}Response fields
| Field | Type | Description |
|---|---|---|
id | uuid | Repair ticket ID. |
number | string / integer | Ticket number. Accept a decimal string or integer; preserve large numbers as strings. |
device | string | Device description. |
status | string | Current workflow status. |
priority | string | Ticket priority. |
due_at | string / null | Due date, or null when unset. |
updated_at | date-time | Last recorded update. |
Version 1 supports list reads only. Invoice reads, staff/payroll access, payment processing, and create/update/delete operations are not public API endpoints. There is no record-by-ID endpoint or date filter. Use the workspace for those workflows.
Work through every page
Each response has resource, data, and next. A page contains up to 50 records. Send a non-null next value back as after with the same token and resource; stop when next is null.
| Parameter | Meaning |
|---|---|
resource | repairs, inventory, customers, or events. Defaults to repairs when omitted. |
after | UUID cursor returned as next. Omit it for the first page. |
Results are ordered by UUID, not by creation or update time. Pagination is not a frozen snapshot. New or changed records can be missed during an active traversal; restart from the beginning for a fresh reconciliation. Do not reuse an old final cursor as a change-feed watermark.
// Server-side Node.js. Start a new traversal without an after cursor.
let after = null;
do {
const url = new URL('https://www.repairhq.io/api/public/v1');
url.searchParams.set('resource', 'inventory');
if (after) url.searchParams.set('after', after);
const response = await fetch(url, {
headers: { Authorization: `Bearer ${process.env.REPAIRHQ_TOKEN}` }
});
if (!response.ok) throw new Error(`RepairHQ HTTP ${response.status}`);
const page = await response.json();
for (const item of page.data) console.log(item.id, item.quantity);
after = page.next;
if (after) await new Promise(resolve => setTimeout(resolve, 1100));
} while (after);The rate limit uses fixed minute windows and is shared by requests using the same token. Pace workers together. On 429, wait at least the Retry-After header (60 seconds), add jitter, and retry. The pagination snippet stops on errors so your application can apply its retry policy.
Handle failures deliberately
{ "error": "This token does not allow this resource" }| Status | What to do |
|---|---|
400 | Fix the resource name or malformed after cursor. |
401 | Check the bearer header, token expiry, and revocation status. |
403 | Create a token with the required resource scope. |
405 | Use GET. Writes are not supported; this response may have no JSON body. |
429 | Wait for Retry-After, then retry with jitter. |
500 | Retry with bounded exponential backoff. If it persists, report the time, endpoint, and status without credentials or customer data. |
Check the HTTP status before parsing a success response. Error messages can change; branch on status codes. Failed reads never authorize a payment or a record update.
Receive events from your shop
In API & integrations → Connected systems & webhooks, create a webhook endpoint with a public HTTPS destination and one event type. Then choose Activate / rotate signing key and save the returned secret securely.
Destinations must use standard HTTPS port 443 and resolve only to public internet addresses. Localhost, private addresses, URL credentials, fragments, and redirects are not supported. Each endpoint belongs to the selected business and location.
| Event | Trigger |
|---|---|
repair.updated | A repair ticket’s status changes. |
job.updated | A job activity event is recorded. |
invoice.paid | Recorded invoice totals meet the settlement condition after a payment-total change. Verify the invoice ledger before fulfillment; this is not a bank settlement confirmation. |
customer.created | A customer record is created. |
inventory.changed | An inventory item’s on-hand quantity changes. |
Payload and delivery identity
The payload identifies the event and related record; it does not include the complete record. id is the event ID. X-RHQ-Delivery-ID identifies this endpoint’s delivery and stays the same on retries.
{
"id": "44444444-4444-4444-8444-444444444444",
"type": "repair.updated",
"createdAt": "2026-10-27T14:30:00.000Z",
"businessId": "55555555-5555-4555-8555-555555555555",
"locationId": "66666666-6666-4666-8666-666666666666",
"recordId": "11111111-1111-4111-8111-111111111111",
"action": "Repair status changed"
}Verify the original bytes
The signature is v1= followed by the hex HMAC-SHA256 digest of this message, using the entire signing secret as the UTF-8 HMAC key:
X-RHQ-Delivery-ID + '.' + X-RHQ-Timestamp + '.' + raw_request_bodyX-RHQ-Timestamp is Unix time in seconds at delivery attempt time. Verify the signature with a constant-time comparison, require a recent timestamp, and deduplicate by delivery ID. Our Node.js helper accepts a five-minute clock window and compares the original request bytes before JSON parsing.
import { verifyRepairHQWebhook } from './webhook-node.mjs';
// rawBody is the original Buffer collected by your HTTP handler.
const valid = verifyRepairHQWebhook({
secret: process.env.REPAIRHQ_WEBHOOK_SECRET,
rawBody,
deliveryId: request.headers['x-rhq-delivery-id'],
timestamp: request.headers['x-rhq-timestamp'],
signature: request.headers['x-rhq-signature']
});
// Reject an invalid signature before parsing JSON.
// If valid, atomically deduplicate and durably queue the event
// before returning 2xx. The helper verifies; it does not store events.After verification, validate the expected business, location, and event type. Atomically store the delivery ID and event in a durable queue before returning 2xx. An already accepted delivery should also receive 2xx. The helper performs signature checks only; your receiver supplies durable storage and deduplication.
Timing, retries, and rotation
- Any
2xxresponse is accepted. A non-2xx response or an 8-second timeout marks the attempt failed. - Failed deliveries become eligible again after 15 minutes, up to five total attempts. Each worker run handles at most five due deliveries.
- Automatic processing currently runs once daily at 13:15 UTC. Owners and admins can use Retry due deliveries to process another due batch. Delivery is queued; it is not a real-time guarantee.
- Retries can duplicate a delivery and events can arrive out of order. Use durable deduplication and reconcile current record state when needed.
- Inspect delivery status and attempt counts in API & integrations. After five failed attempts, automatic retries stop.
- Rotating immediately replaces the signing secret. Coordinate the receiver change and keep the previous secret briefly in your receiver for in-flight requests. New attempts use the current secret. Disable delivery when retiring an endpoint.
Connect with confidence
The examples above are an offline reference. There is no public sandbox endpoint or special test token. For live testing, use an authorized workspace and location containing only test data, with a short-lived token and minimal scopes.
- Confirm the correct business, location, scopes, and expiry in API & integrations.
- Read one page, then verify pagination and the end-of-list null cursor.
- Check a disallowed resource returns 403 and a revoked token returns 401.
- For webhooks, use your own public HTTPS receiver. Generate an ordinary test event in that location and process due deliveries.
- Verify signature rejection for a changed body or stale timestamp, and acknowledge a duplicate without processing it twice.
- Before enabling a production integration, confirm it cannot read another store’s records and that its logs redact credentials and customer data.
A head start for your integration
After importing into Postman, set token in your private local environment or vault. Keep credentials out of shared collections and exports. Enable the after parameter only when following a returned cursor.
Built on a clear contract
Developer documentation launch
Documented the existing scoped read API and signed webhooks. Added OpenAPI, Postman, and a Node.js verifier. Invalid query values now return 400, rate-limit responses include Retry-After, and repair due dates use a timezone-independent YYYY-MM-DD value.
The public endpoint is versioned as /api/public/v1. Ignore unknown response fields so additive changes do not break your integration. Future write APIs and additional resources will be documented when available.