Developers

Connecting Your App or ERP to the QuoteCrest API

A developer walkthrough: register an OAuth application, run the PKCE authorization flow, and drive quotes, clients, and payments from your own software. Part 2 of 2.

Charles Martinez

QuoteCrest Team

In part 1 we configured a QuoteCrest workspace — Stripe, accounting sync, tax rates, terms, and an item library. Now we'll connect that workspace to your own application or ERP so quotes flow through your existing systems instead of a browser tab.

The QuoteCrest REST API gives Business-plan teams the full app surface: quotes and line items, clients, the item library, tax rates, terms templates, payments, the AI quote builder, and accounting sync triggers. The complete reference lives at quotecrest.com/api-docs; this post is the guided tour from zero to first API call.

Step 1: Register an OAuth application

In QuoteCrest, go to Settings → Developers and click Register application. You'll need three things:

  • Name — shown to your team on the authorization screen ("ERP Sync", "Acme Field App").
  • Redirect URI — where QuoteCrest sends users after they authorize. Must be HTTPS (localhost is allowed for development). One URI per line.
  • Scopesread for read access, write to create and update. Request only what you need.

Keep Confidential client enabled for server-side apps that can protect a secret. On creation you get a Client ID and — exactly once — a Client Secret. Copy the secret immediately; it's stored hashed and can't be shown again.

Step 2: Authorize with OAuth 2.0 + PKCE

QuoteCrest uses the Authorization Code grant with PKCE, required for every client. The flow:

1. Generate a code verifier and challenge. A random string, and its SHA-256 hash, base64url-encoded:

code_verifier  = random 43-128 char string
code_challenge = base64url( sha256(code_verifier) )

2. Send the user to the authorization screen:

GET https://quotecrest.com/oauth/authorize
    ?client_id=YOUR_CLIENT_ID
    &redirect_uri=https://yourapp.com/callback
    &response_type=code
    &scope=read+write
    &code_challenge=CODE_CHALLENGE
    &code_challenge_method=S256

The user signs in, sees what your app will be able to do, and approves. QuoteCrest redirects back to your redirect_uri with a ?code= parameter.

3. Exchange the code for tokens:

curl -X POST https://quotecrest.com/oauth/token \
  -d grant_type=authorization_code \
  -d client_id=YOUR_CLIENT_ID \
  -d client_secret=YOUR_CLIENT_SECRET \
  -d redirect_uri=https://yourapp.com/callback \
  -d code=AUTHORIZATION_CODE \
  -d code_verifier=CODE_VERIFIER

You receive an access_token (valid 2 hours), a refresh_token, and the granted scopes. Access tokens are bound to one team — the team of the user who authorized. Refresh tokens rotate on every use: each refresh returns a new pair, and the old refresh token is invalidated, so persist the newest pair atomically.

Step 3: Make your first call

Every request sends the token as a Bearer header. Start with /me, which returns the authorized team, its defaults (payment terms, quote expiry, pricing mode), and your token's scopes:

curl https://quotecrest.com/api/v1/me \
  -H "Authorization: Bearer ACCESS_TOKEN"

List endpoints paginate with page and per_page (max 100) and return a meta block with totals.

Step 4: The core ERP flow

A typical integration mirrors what a person does in the app — create the client, build the quote, send it, and watch for acceptance and payment.

Create a client:

curl -X POST https://quotecrest.com/api/v1/clients \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"client": {"name": "Meridian Property Group", "email": "ops@meridian.example"}}'

Create a quote — team defaults (terms template, expiry, payment terms, pricing mode) apply automatically to anything you omit:

curl -X POST https://quotecrest.com/api/v1/quotes \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"quote": {"title": "Lobby renovation", "client_id": 42, "payment_percentage": 30}}'

Add line items in one call with bulk_create, then send:

curl -X POST https://quotecrest.com/api/v1/quotes/7/line_items/bulk_create ...
curl -X POST https://quotecrest.com/api/v1/quotes/7/send \
  -H "Authorization: Bearer ACCESS_TOKEN"

send emails the client their portal link; use publish instead if your app delivers the link itself. The quote's portal_url field is the client-facing page, and GET /api/v1/quotes/7/pdf returns the rendered PDF for your own document store.

Track acceptance and payment by polling the quote (status, payment_status, payment_due) or listing /api/v1/payments — each payment carries the amount, fees, and net. When a quote is accepted with auto-sync on, the invoice lands in QuickBooks or Xero without another API call; you can also trigger a catalog pull anytime with POST /api/v1/integrations/quickbooks/sync (or xero).

Or skip the manual build entirely. One call to the AI quote builder turns a plain-language job description into a complete draft — title, scope of work, and priced line items that use your item library and categories:

curl -X POST https://quotecrest.com/api/v1/ai_quotes \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"prompt": "Replace 12 windows in a two-story office, energy-efficient double glazing", "client_id": 42}'

Errors, limits, and good citizenship

  • 401 — token missing, expired, or revoked. Refresh and retry.
  • 403 plan_required — the team isn't on Business. 403 feature_disabled — a feature flag (e.g. AI generation) is off for the team.
  • 402 insufficient_credits — the team's AI credit balance is exhausted.
  • 422 — validation errors, with details in the response body.
  • 429 — rate limited. General API traffic is limited per IP; AI generation is limited to 10 requests per minute per team. Back off and retry after the indicated delay.

Two habits will keep your integration boring (the good kind): treat the client secret and refresh tokens like passwords — server-side only, encrypted at rest — and build your sync around idempotency, checking for an existing record before creating, since your users can always edit things in QuoteCrest directly.

The full endpoint reference, schemas, and error formats are at quotecrest.com/api-docs. If you build something on the API, we'd genuinely like to hear about it.

English
Français
Español
Deutsch
Português
Italiano