Skip to content

blueclerk/api-docs

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

BlueClerk API

The BlueClerk Public API lets partners read and write contractor data — properties, jobs, tickets, estimates, invoices, and contacts — using OAuth 2.0.

This API powers integrations with Zapier, Make.com, n8n, custom internal tools, and partner apps like leads2jobs.

Status: v1 — generally available. Self-serve registration at app.blueclerk.com/developers.


Quick Start

  1. Register as a partner. Sign up at app.blueclerk.com/developers, create an OAuth app with your name, redirect URI, and scopes. You'll get a client_id and client_secret instantly — no waiting.
  2. Send your user through the OAuth consent flow. They authorize your app on their BlueClerk account.
  3. Exchange the auth code for an access token.
  4. Call the API with Authorization: Bearer <token>.

A full curl walkthrough is in examples/curl-walkthrough.sh.


Base URL

https://app.blueclerk.com/api/v1

(Future: https://api.blueclerk.com/v1 once the subdomain rewrite is live.)


Authentication — OAuth 2.0

BlueClerk uses the Authorization Code flow with PKCE.

Step 1 — Send user to the consent screen

https://app.blueclerk.com/oauth/authorize
  ?response_type=code
  &client_id=YOUR_CLIENT_ID
  &redirect_uri=YOUR_REDIRECT_URI
  &scope=leads:write+jobs:read
  &state=RANDOM_STRING
  &code_challenge=PKCE_CHALLENGE
  &code_challenge_method=S256

The user logs in, sees what permissions you're requesting, and clicks Allow. We redirect to your redirect_uri with ?code=AUTH_CODE&state=RANDOM_STRING.

Step 2 — Exchange code for tokens

curl -X POST https://app.blueclerk.com/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code" \
  -d "code=AUTH_CODE" \
  -d "redirect_uri=YOUR_REDIRECT_URI" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "client_secret=YOUR_CLIENT_SECRET" \
  -d "code_verifier=PKCE_VERIFIER"

Response:

{
  "access_token": "bc_at_...",
  "refresh_token": "bc_rt_...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "leads:write jobs:read"
}

Step 3 — Call the API

curl https://app.blueclerk.com/api/v1/me \
  -H "Authorization: Bearer bc_at_..."

Refreshing tokens

Access tokens expire after 1 hour. Refresh tokens last 90 days and rotate on every use.

curl -X POST https://app.blueclerk.com/oauth/token \
  -d "grant_type=refresh_token" \
  -d "refresh_token=bc_rt_..." \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "client_secret=YOUR_CLIENT_SECRET"

Important: Old refresh tokens are invalidated immediately on rotation. Reusing an old refresh token after rotation revokes the entire authorization as a token-theft countermeasure (RFC 6749).


Scopes

Request only the scopes your integration needs.

Scope What it allows
leads:write Push leads into BlueClerk (creates a Ticket on the contractor's account)
tickets:read Read tickets
tickets:write Create and update tickets
jobs:read Read jobs
properties:read Read properties
estimates:read Read estimates
invoices:read Read invoices
contacts:read Read homeowner and builder contact records
webhooks:manage Create, list, and delete webhooks for the authorizing company

Endpoints

All endpoints are scoped to the authorizing contractor company. You cannot access data from another company even if you have a valid token.

Leads

Method Path Scope Purpose
POST /leads leads:write Push a lead — creates a Ticket on the contractor's account

Request body:

{
  "businessName": "Smith Plumbing",
  "contactName": "Joe Smith",
  "email": "joe@smithplumbing.com",
  "phone": "+15125551234",
  "address": "123 Main St, Austin, TX 78701",
  "notes": "Needs water heater replacement",
  "source": "leads2jobs"
}

Response (201):

{ "ticketId": "ckxz...", "status": "OPEN" }

Tickets

Method Path Scope
GET /tickets tickets:read
GET /tickets/:id tickets:read
POST /tickets tickets:write
PATCH /tickets/:id tickets:write

GET /tickets query params: cursor, limit (default 25, max 100), updatedSince (ISO 8601).

Jobs

Method Path Scope
GET /jobs jobs:read
GET /jobs/:id jobs:read

Properties

Method Path Scope
GET /properties properties:read
GET /properties/:id properties:read

Estimates / Invoices / Contacts

Method Path Scope
GET /estimates estimates:read
GET /invoices invoices:read
GET /contacts contacts:read

Webhooks (manage your own subscriptions)

Method Path Scope
POST /webhooks webhooks:manage
GET /webhooks webhooks:manage
DELETE /webhooks/:id webhooks:manage

Pagination

List endpoints use cursor-based pagination. The response includes a nextCursor field; pass it back as ?cursor=... to get the next page.

curl "https://app.blueclerk.com/api/v1/jobs?limit=50&cursor=ckxz..." \
  -H "Authorization: Bearer bc_at_..."

Response:

{
  "data": [ ... ],
  "nextCursor": "ckab...",
  "hasMore": true
}

When hasMore is false, you've reached the end.


Filtering

All list endpoints support updatedSince for incremental sync:

curl "https://app.blueclerk.com/api/v1/jobs?updatedSince=2026-05-01T00:00:00Z" \
  -H "Authorization: Bearer bc_at_..."

Idempotency

POST and PATCH endpoints accept an Idempotency-Key header. Sending the same key twice within 24 hours returns the cached response instead of creating a duplicate.

curl -X POST https://app.blueclerk.com/api/v1/leads \
  -H "Authorization: Bearer bc_at_..." \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{ "businessName": "Smith Plumbing", ... }'

Recommended: use a UUID for every mutating request.


Webhooks

Subscribe to events to get push notifications instead of polling.

Subscribe

curl -X POST https://app.blueclerk.com/api/v1/webhooks \
  -H "Authorization: Bearer bc_at_..." \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://yourapp.com/webhooks/blueclerk",
    "events": ["job.created", "job.status_changed", "invoice.paid"]
  }'

Response includes a secret (returned once) — save it for signature verification.

Events

Event When it fires Payload includes
job.created A new Job is created id, title, status, propertyId, createdAt
job.status_changed Job.status changes id, oldStatus, newStatus, changedAt
ticket.created A new Ticket is created id, title, status, createdAt
estimate.sent An Estimate is sent to the customer id, estimateNumber, totalAmount, sentAt
estimate.approved An Estimate is accepted id, estimateNumber, approvedAt
property.created A new Property is created id, address, createdAt
invoice.paid An Invoice transitions to fully paid id, invoiceNumber, totalAmount, paidAt

Signature Verification

Every webhook delivery includes an X-BlueClerk-Signature header:

X-BlueClerk-Signature: t=1715284800,v1=abcd1234...

To verify:

  1. Extract t (timestamp) and v1 (HMAC-SHA256 hex digest)
  2. Build signed payload: {t}.{raw_request_body}
  3. Compute HMAC-SHA256 with your webhook secret
  4. Compare with v1 using constant-time comparison
  5. Reject if t is more than 5 minutes old (replay protection)

Example verifiers in examples/webhook-verifier.js (Node) and examples/webhook-verifier.py (Python).

Retries

Failed deliveries (non-2xx response or timeout) retry with exponential backoff:

  • Attempt 1: immediate
  • Attempt 2: 1 minute later
  • Attempt 3: 5 minutes later
  • Attempt 4: 30 minutes later
  • After 3 failures → marked dead, no more retries

Webhook timeout is 5 seconds. Respond with any 2xx status to acknowledge receipt.


Rate Limits

Rate limits are per company, not per token. Multiple integrations under the same contractor share the same bucket.

Plan Per-minute Per-day Monthly cap Webhook deliveries/day
Starter ($29/mo) 30 5,000 50,000 2,000
Pro 60 15,000 250,000 7,500
Business 120 50,000 1,500,000 25,000
Enterprise 300 200,000 unlimited 100,000

When you hit a limit, the API returns:

HTTP/1.1 429 Too Many Requests
Retry-After: 42

{
  "error": "rate_limit_exceeded",
  "scope": "min",
  "limit": 30,
  "remaining": 0,
  "resetAt": "2026-05-09T14:30:00Z"
}

Honor the Retry-After header.


Errors

All errors return JSON:

{ "error": "<code>", "message": "human readable" }
Status Error code Meaning
401 invalid_token Bearer token missing, expired, or invalid
403 insufficient_scope Token lacks required scope
403 plan_required Authorizing company is on free trial — paid plan required for API access
403 forbidden Cross-company access attempted
404 not_found Resource doesn't exist or belongs to a different company
409 conflict Idempotency key collision with different payload
429 rate_limit_exceeded See Rate Limits
500 server_error Try again with exponential backoff

Plan Gating

The API is available on paid plans only — Starter ($29/mo) and up. Companies on free trial cannot mint OAuth tokens; they receive 403 plan_required at the consent screen and the token endpoint.


Field Conventions

  • All timestamps are ISO 8601 UTC (2026-05-09T14:00:00Z).
  • All IDs are CUIDs (ckxz...).
  • All money fields are in the contractor's account currency, returned as decimal strings ("1234.56") to avoid float precision issues.
  • All addresses are returned as a single string field for now (structured address coming in v2).

OpenAPI Spec

The full OpenAPI 3.1 specification is available at:

https://app.blueclerk.com/api/openapi.json

You can also import openapi.json in this repo into Postman, Insomnia, or any code-gen tool to generate a client SDK in your language.


Postman Collection

Import postman/BlueClerk-API.postman_collection.json into Postman. Set environment variables:

  • base_url = https://app.blueclerk.com/api/v1
  • client_id = your client ID
  • client_secret = your client secret
  • access_token = the token you got from /oauth/token

Brand Assets — "Connect to BlueClerk" Button

Use the official assets in brand/ to add a "Connect to BlueClerk" button to your app:

<a href="https://app.blueclerk.com/oauth/authorize?response_type=code&client_id=YOUR_CLIENT_ID&...">
  <img src="https://github.com/blueclerk/api-docs/raw/main/brand/connect-button-light.svg"
       alt="Connect to BlueClerk" height="44" />
</a>

Three button styles available (light, dark, pill) plus full logo variants. See brand/README.md for usage rules.


Support

About

API documentation for BlueClerk

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors