Getting Started
Read-only HTTP/JSON access to your OrangeQC data. Built for BI tools (PowerBI, Tableau, Looker),
AI agents, and custom integrations. Authenticate with an API key, paginate with
page and
per_page,
get JSON back.
Overview
The Customer API gives you read-only programmatic access to your OrangeQC data. Anywhere you can make an HTTP request — a BI tool, an AI assistant, a Python notebook, a custom dashboard — you can pull live inspection data from your account. Common use cases:
- BI dashboards and reporting. Pull inspection data into PowerBI, Tableau, Looker, or Google Data Studio and refresh on a schedule. No need to maintain a copy of your data in a separate warehouse.
- AI agents and assistants. Connect Claude, ChatGPT, or an in-house LLM to your inspection history and ask questions in plain language.
- Third-party integrations. Feed inspection data into ticketing systems, asset management tools, CRMs, or any other system your operations depends on.
- Custom internal tools. Build operations command centers, executive scorecards, or one-off analytics scripts — in whatever stack your team already uses.
Everything is scoped to the user who issued the API key, with the same permissions they have in OrangeQC. There is nothing to install — generate an API key in Settings, paste it into your tool, and start pulling data.
Authentication
Customer API access is enabled per account by OrangeQC. Once enabled, any user in your account can generate their own API keys from Settings → API Keys.
- Go to Settings → API Keys in OrangeQC.
- Click Generate key, give it a memorable name (e.g. PowerBI, Claude, Internal dashboard).
- Copy the API key shown in the confirmation modal. This is the only time the plaintext key is visible — OrangeQC only stores a hash. If you lose it, generate a new one and delete the old key.
- Send the API key on every request as an
Authorization: Bearer <api-key>header.
The API key's permissions track the issuing user. If the user is deactivated, their account stops paying, or
the account's Customer API access is turned off, all keys belonging to that user start returning
401 or
403. Rotate keys by
generating a new one, swapping it into your client, and deleting the old one.
Pagination & lookback
List endpoints are page-based. Responses include a meta object describing the page you just received:
{
"inspections": [ ... ],
"meta": {
"page": 1,
"per_page": 50,
"total_pages": 12,
"total_entries": 587
}
}
page— 1-indexed. Default1.per_page— default50, maximum200. Values outside the range are clamped.- Lookback window: the API returns inspections from the past year. Older inspections are not returned even if you page past them.
Error envelope
Every error response follows the same shape. request_id correlates with our internal logs — include it when reporting issues.
{
"error": {
"code": "unauthorized",
"message": "Invalid or missing API key",
"request_id": "abc123-..."
}
}
401 unauthorized— missing or invalid API key, deactivated user, or expired account.403 forbidden— Customer API is not enabled for this account.404 not_found— resource does not exist (or you can't see it).429 too_many_requests— you've exceeded 600 requests per minute on this key. Honor theRetry-Afterheader and back off.500 internal_error— server-side bug; therequest_idis logged.
PowerBI example
Paste this into the PowerBI Desktop Advanced Editor
when creating a new Blank Query. Replace YOUR_API_KEY_HERE
with the API key you copied from OrangeQC. The query handles pagination automatically by walking until the
API stops returning new pages.
let
ApiKey = "YOUR_API_KEY_HERE",
BaseUrl = "https://api.orangeqc.com/v1/inspections",
PerPage = 200,
GetPage = (pageNumber as number) as record =>
let
Response = Json.Document(Web.Contents(
BaseUrl,
[
Query = [ page = Text.From(pageNumber), per_page = Text.From(PerPage) ],
Headers = [ Authorization = "Bearer " & ApiKey, Accept = "application/json" ]
]
))
in
Response,
FirstPage = GetPage(1),
TotalPages = FirstPage[meta][total_pages],
AllPages = List.Generate(
() => [ page = 1, data = FirstPage[inspections] ],
each [page] <= TotalPages,
each [ page = [page] + 1, data = GetPage([page] + 1)[inspections] ],
each [data]
),
Combined = List.Combine(AllPages),
AsTable = Table.FromList(Combined, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
Expanded = Table.ExpandRecordColumn(AsTable, "Column1",
{"id","name","score","points","deficient","flagged","started_at","ended_at","structure_path"},
{"id","name","score","points","deficient","flagged","started_at","ended_at","structure_path"})
in
Expanded
PowerBI gotchas to know about:
- When prompted for credentials, choose Anonymous (the API key is in the header, not in PowerBI's credential store).
- Set the data source Privacy Level to Organizational, otherwise PowerBI's Privacy Firewall will refuse to combine API data with other sources.
- For PowerBI Service refresh, you'll need to add a gateway data source with Anonymous auth pointing at
https://api.orangeqc.com.
curl example
Minimum viable request:
curl -sS https://api.orangeqc.com/v1/inspections \
-H "Authorization: Bearer YOUR_API_KEY_HERE" \
-H "Accept: application/json"
Paginated walk through every page using jq:
API_KEY="YOUR_API_KEY_HERE"
PAGE=1
while : ; do
RESPONSE=$(curl -sS "https://api.orangeqc.com/v1/inspections?page=${PAGE}&per_page=200" \
-H "Authorization: Bearer ${API_KEY}" \
-H "Accept: application/json")
echo "$RESPONSE" | jq -c '.inspections[]'
TOTAL=$(echo "$RESPONSE" | jq '.meta.total_pages')
[ "$PAGE" -ge "$TOTAL" ] && break
PAGE=$((PAGE + 1))
done
Python example
Using the standard requests library. Drop-in for Jupyter, scripts, or an ETL job.
import requests
API_KEY = "YOUR_API_KEY_HERE"
BASE_URL = "https://api.orangeqc.com/v1/inspections"
HEADERS = {
"Authorization": f"Bearer {API_KEY}",
"Accept": "application/json",
}
def fetch_all_inspections(per_page: int = 200):
page = 1
while True:
response = requests.get(
BASE_URL,
headers=HEADERS,
params={"page": page, "per_page": per_page},
timeout=30,
)
response.raise_for_status()
body = response.json()
yield from body["inspections"]
if page >= body["meta"]["total_pages"]:
break
page += 1
if __name__ == "__main__":
for inspection in fetch_all_inspections():
print(inspection["id"], inspection["score"], inspection["name"])
For long-running clients, add retry logic on 429 (honor the Retry-After header) and on transient 5xx errors.
Try it live
The interactive reference lets you authorize with your API key, expand any endpoint, and send real requests against your OrangeQC account.
Open the API Reference