Skip to content

Quotes

The Quotes API exposes graph8’s quote-to-cash lifecycle: draft, edit, send (with signing + payment link), duplicate, convert signed-back-to-draft. Backed by a Stripe v4 quotes integration; payment is captured automatically when the recipient pays.

30-second start

List your quotes:

Terminal window
curl 'https://be.graph8.com/api/v1/quotes?status=sent&limit=10' \
-H "Authorization: Bearer $G8_API_KEY"

Quick reference

EndpointMethodPurpose
/quotesGET / POSTList / create
/quotes/{id}GET / PUT / DELETERead / update draft / delete draft
/quotes/{id}/duplicatePOSTCopy into new draft
/quotes/{id}/edit-as-draftPOSTConvert signed/sent → draft
/quotes/{id}/sendPOSTSend via email (signing + payment)
/quotable-productsGETList products available for line items
/quote-settingsGETOrg-level currency / tax / providers / logo
/contacts/{contact_id}/quotesGETQuotes linked to a contact
/companies/{company_id}/quotesGETQuotes linked to a company

Quote lifecycle

draft → sent → signed → (collected via Stripe payment link)
↘ declined / expired / void

edit-as-draft reverses signed/sentdraft for revisions. Each revision creates a new signing URL.

Quote shape

{
id: "quo_abc123",
name: "Acme Q3 Platform Subscription",
status: "draft" | "sent" | "signed" | "declined" | "expired" | "void",
contact_id: 5028106,
company_id: 8821,
line_items: [
{
product_id: "prod_platform",
name: "Platform subscription",
quantity: 1,
unit_price: 499,
currency: "USD",
recurring: true
},
{
name: "Onboarding (one-time)",
quantity: 1,
unit_price: 2500
}
],
currency: "USD",
total: 8488, // computed
expires_at: "2026-07-15T00:00:00Z",
notes: "Includes 90-day money-back guarantee.",
recipient_email: "jane@acme.com",
signing_url: "https://signing.graph8.com/quo_abc123_xyz",
payment_link_url: "https://buy.stripe.com/...",
signed_at: null,
sent_at: "2026-05-25T18:00:00Z",
created_at: "2026-05-25T17:30:00Z"
}

Create

Terminal window
POST /api/v1/quotes
Content-Type: application/json
{
"contact_id": 5028106,
"company_id": 8821,
"line_items": [
{ "product_id": "prod_platform", "quantity": 1, "unit_price": 499, "recurring": true },
{ "name": "Onboarding", "quantity": 1, "unit_price": 2500 }
],
"currency": "USD",
"expires_at": "2026-07-15T00:00:00Z",
"notes": "Includes 90-day money-back guarantee."
}

Line items can reference a catalog product_id (from /quotable-products) or be ad-hoc.

Update draft

Terminal window
PUT /api/v1/quotes/{quote_id}
Content-Type: application/json
{ "notes": "Updated to 12-month commit", "expires_at": "2026-08-30T00:00:00Z" }

Only quotes in status=draft can be updated. Use POST /{id}/edit-as-draft to convert a sent/signed quote back to draft first.

Send

Terminal window
POST /api/v1/quotes/{quote_id}/send
Content-Type: application/json
{
"recipient_email": "jane@acme.com",
"send_signing_link": true
}

Sends a real email with the PDF attached and a signing link. If the quote includes recurring line items, a Stripe payment link is also generated and embedded.

Duplicate / edit-as-draft / delete

Terminal window
POST /api/v1/quotes/{id}/duplicate # copies line items into a new draft
POST /api/v1/quotes/{id}/edit-as-draft # status: signed/sent → draft
DELETE /api/v1/quotes/{id} # draft only

Settings + products

Terminal window
GET /api/v1/quotable-products
# { data: [{ id, name, description, unit_price, currency, recurring }, ...] }
GET /api/v1/quote-settings
# { data: { default_currency, default_tax_rate, payment_providers, logo_url, signature_required } }

Settings come from the org’s Stripe + branding config. Update via the in-app Quote Settings UI (not via API).

Contact / company graph

Terminal window
GET /api/v1/contacts/{contact_id}/quotes
GET /api/v1/companies/{company_id}/quotes

Returns the full quote history for the contact / company.

Webhooks

Subscribe to quote lifecycle events via the Webhooks surface:

  • quote.sent — email delivered to recipient
  • quote.signed — recipient signed (and paid if a payment link was attached)
  • quote.declined / quote.expired / quote.void

Use these to trigger downstream automations (CRM stage move, Slack notification, sequence enrollment).

Credit costs

OperationCredits
Read endpoints (list, get, settings, products, contact / company graph)Free
Create / update / duplicate / edit-as-draft / deleteFree
Send (real email)Free for the email itself; SES sending costs are absorbed
Stripe payment processingStripe fees apply on collection

Errors

StatusCauseFix
401Missing or invalid Authorization: Bearer headerGet a key
402Out of credits (waterfall enrichment, AI generation, voice minutes)Top up in Settings → Billing, or switch to Platform
404Resource ID doesn’t existList first to verify the ID
422Validation error in request bodyInspect error.message + error.field in the response
429Rate limit (5 rps per org)Backoff per Retry-After header. See Rate Limits
5xxgraph8 errorRetry with exponential backoff (5s → 30s → 120s)

The full error envelope shape: { "error": { "code": "...", "message": "...", "field": "...", "request_id": "..." } }. Include the request_id in any support ticket. See Errors for the canonical reference.

See also