quipteams API
quipteams REST API
v1Programmatic access to quotes, assets, devices, device actions, products, kits, employees, offices, scheduling links, and webhooks - 31 endpoints across 12 resources. Building with an AI assistant? Point it at /docs.md - this whole reference as one markdown file.
https://app.quipteams.com/api/v1curl https://app.quipteams.com/api/v1/quotes \
-H "Authorization: Bearer qt_live_your_api_key"Authentication
Every request is authenticated with an API key sent as a bearer token. Keys are issued by the quipteams team and are scoped to a single company. Live keys are prefixed qt_live_ and sandbox keys qt_sandbox_ (see Sandbox). Treat a key like a password - never expose it in client-side code.
curl https://app.quipteams.com/api/v1/quotes \
-H "Authorization: Bearer qt_live_your_api_key"Each key carries a set of scopes. An endpoint returns 403 FORBIDDEN if the key is missing the scope it requires.
quotes:readRead quotes, items, recipients, and alternatives.quotes:writeCreate quotes and accept/reject quote items.assets:readRead stored inventory assets.assets:writeAdd devices to inventory.device-actions:readRead logistics device actions.device-actions:writeCreate device actions (store, assign, reassign, sell, support).products:readRead the shared product catalog.kits:readRead kit bundles and their devices.roles:readRead company roles and their assigned kit ids.equip:writeEquip an employee with a kit — assigns stored devices when the whole kit is in stock, otherwise creates a quote.employees:readRead HRIS-synced employees.offices:readRead company offices.scheduling-links:readRead delivery scheduling links.webhooks:readList and inspect webhook endpoints.webhooks:writeCreate, update, delete, and test webhook endpoints.Sandbox
Sandbox keys (qt_sandbox_) run against an isolated copy of your workspace, pre-seeded with realistic demo data: quotes, assets, device actions, employees, kits, roles, offices, and scheduling links. Every endpoint behaves exactly like production and uses the same base URL - only the key decides which world you are in. Writes persist until the sandbox is reset. Create sandbox keys (and reset the data) from the API tab of the admin panel; your first sandbox key provisions the sandbox automatically.
curl https://app.quipteams.com/api/v1/quotes \
-H "Authorization: Bearer qt_sandbox_your_api_key"What happens on a sandbox write:
- Quotes and device actions go through the real operational pipeline - a task appears on our staging boards (prefixed
[SANDBOX]) just like a production order would. - Webhook endpoints registered with a sandbox key receive real, signed deliveries for sandbox events - the recommended way to develop and test your integration.
- No emails or Slack messages are ever sent from sandbox activity.
Two behaviors differ from production by design. Status transitions in the sandbox are driven by the API itself (for example accepting or rejecting a quote item) - operational updates that normally come from our logistics team are not simulated. And because sandbox stock is not linked to the purchasing catalogue, POST /v1/equip always resolves to mode: "quoted" rather than assigning a stored device.
Rate limiting
Two sliding windows apply to every request: a per-IP limit of 60 requests/minute and a per-key limit (default 60 requests/minute). Some write endpoints set a tighter per-key limit. Every response includes x-ratelimit-limit, x-ratelimit-remaining, and x-ratelimit-reset; a 429 also includes retry-after (seconds).
POST /quotes20 / minPOST /equip20 / minPATCH /quotes/{id}/items/{itemId}30 / minPOST /quotes/{id}/items/{itemId}/action30 / minPOST /device-actions30 / minPOST /device-actions/external30 / minPOST /webhooks/{id}/test30 / minPagination & limits
List endpoints return a data array and a meta object, and paginate with keyset cursors: meta.has_more says whether another page exists, meta.next_cursor is an opaque cursor to pass back as ?cursor=, and meta.total is the total row count for the current filters (null when unknown). limit defaults to 25 (max 100). Sortable lists take sort with a - prefix for descending (e.g. -created_at); a field outside the endpoint's allowlist returns 400 VALIDATION_ERROR. GET /products is the exception - it is unpaginated and its meta carries available_filters instead.
{
"data": [ /* ... */ ],
"meta": { "has_more": true, "next_cursor": "eyJpZCI6Ii4uLiJ9", "total": 42 }
}Errors
Errors use conventional HTTP status codes and a consistent body. The error.code is a stable string you can branch on; error.details carries structured context and is present only when set.
{
"error": {
"code": "VALIDATION_ERROR",
"message": "items must be a non-empty array"
}
}UNAUTHORIZED401Missing, malformed, invalid, expired, or revoked API key.FORBIDDEN403The key is valid but lacks the required scope, or a required feature is not enabled for your company.VALIDATION_ERROR400The request body or a query parameter failed validation. May carry a details payload.NOT_FOUND404The resource does not exist. Ids that belong to another company also read as not found.CONFLICT409The request conflicts with current state - e.g. a duplicate serial number, or an action already open on a device.RATE_LIMITED429Too many requests. Wait for the retry-after header before retrying.INTERNAL_ERROR500Unexpected server error. Safe to retry with backoff.BAD_GATEWAY502An upstream dependency failed. Safe to retry with backoff.Webhook signatures
Register endpoints with the Webhooks API. When an event fires, quipteams POSTs a JSON body { id, type, created_at, data } to your URL with these headers: X-Quip-Event, X-Quip-Delivery-Id, and X-Quip-Signature. The signature is sha256=<hex>, an HMAC-SHA256 of the raw request body keyed on the endpoint's whsec_ secret (returned once, when you create the endpoint). Verify it before trusting a payload.
import { createHmac, timingSafeEqual } from 'crypto'
function verify(rawBody: string, header: string, secret: string): boolean {
const expected = 'sha256=' + createHmac('sha256', secret).update(rawBody).digest('hex')
const a = Buffer.from(expected)
const b = Buffer.from(header)
return a.length === b.length && timingSafeEqual(a, b)
}You can subscribe to any of these events, or a wildcard:
Quotes
quote.createdquote.submittedquote.status_changedquote.pendingquote.acceptedquote.deliveredquote.alternative_offeredquote.response_addedquote.messagequote.action_requiredquote.tracking_addedquote.serial_addedDevice actions
device_action.statusdevice_action.requesteddevice_action.completeddevice_action.tracking_addeddevice_action.action_requireddevice_action.messageScheduling
scheduling.createdscheduling.submittedscheduling.reminderscheduling.cancelledInvoices
invoice.payment_markedinvoice.approvedWildcards
quote.*device_action.*scheduling.*invoice.**Resources
Create equipment quotes from catalog products or kit bundles, list them, read full detail, and accept or reject individual items.
Read your company inventory devices - in storage, in use, or both - by list or by id / serial number.
Add one or more devices to your company inventory. Each is created with status `in_use`.
Logistics operations on devices: Store, Assign, Reassign, Sell, Support. Use `/device-actions` for a device already in inventory, or `/device-actions/external` for one that is not.
Read the shared product catalog and its configurations. The catalog is global (no company scoping) and the list is unpaginated.
Read kit bundles (reusable equipment sets) and the devices they contain.
Read company defined roles. A role bundles one or more kits and is the input to equip by role.
Equip one employee with a saved kit in a single call. When every device in the kit has a new unit stored in the employee's region, the endpoint assigns those exact devices and sends the recipient a scheduling link. Used or returned warehouse stock is never assigned. When anything is missing it orders the whole kit as a quote instead — all-or-nothing, so a partially-stocked kit never splits into a half-shipment plus a half-order.
Read HRIS-synced employees for your company.
Read your company offices (used as delivery destinations). Pass an office id as office_id on a quote, device-action, or equip recipient to ship there — the office supplies the country and address, and no scheduling form is sent.
Read delivery scheduling links sent to recipients. This resource is read-only, and requires the `scheduling` and `scheduling_self_managed` features on your company (403 FORBIDDEN otherwise).
Register HTTPS endpoints to receive events. Each company may register up to 10 endpoints. See Webhook signatures for how deliveries are signed.