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:
curl 'https://be.graph8.com/api/v1/quotes?status=sent&limit=10' \ -H "Authorization: Bearer $G8_API_KEY"import { g8 } from '@graph8/sdk';g8.init({ apiKey: process.env.G8_API_KEY! });
const { data } = await g8.quotes.list({ status: 'sent', limit: 10 });console.log(data); // → QuoteSummary[]g8 list-quotes --status sent --limit 10Ask your agent: “Show open quotes that are sent but not signed” → tool: g8_list_quotes.
Quick reference
| Endpoint | Method | Purpose |
|---|---|---|
/quotes | GET / POST | List / create |
/quotes/{id} | GET / PUT / DELETE | Read / update draft / delete draft |
/quotes/{id}/duplicate | POST | Copy into new draft |
/quotes/{id}/edit-as-draft | POST | Convert signed/sent → draft |
/quotes/{id}/send | POST | Send via email (signing + payment) |
/quotable-products | GET | List products available for line items |
/quote-settings | GET | Org-level currency / tax / providers / logo |
/contacts/{contact_id}/quotes | GET | Quotes linked to a contact |
/companies/{company_id}/quotes | GET | Quotes linked to a company |
Quote lifecycle
draft → sent → signed → (collected via Stripe payment link) ↘ declined / expired / voidedit-as-draft reverses signed/sent → draft 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.", 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
POST /api/v1/quotesContent-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
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
POST /api/v1/quotes/{quote_id}/sendContent-Type: application/json
{ "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
POST /api/v1/quotes/{id}/duplicate # copies line items into a new draftPOST /api/v1/quotes/{id}/edit-as-draft # status: signed/sent → draftDELETE /api/v1/quotes/{id} # draft onlySettings + products
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
GET /api/v1/contacts/{contact_id}/quotesGET /api/v1/companies/{company_id}/quotesReturns the full quote history for the contact / company.
Webhooks
Subscribe to quote lifecycle events via the Webhooks surface:
quote.sent— email delivered to recipientquote.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
| Operation | Credits |
|---|---|
| Read endpoints (list, get, settings, products, contact / company graph) | Free |
| Create / update / duplicate / edit-as-draft / delete | Free |
| Send (real email) | Free for the email itself; SES sending costs are absorbed |
| Stripe payment processing | Stripe fees apply on collection |
Errors
| Status | Cause | Fix |
|---|---|---|
401 | Missing or invalid Authorization: Bearer header | Get a key |
402 | Out of credits (waterfall enrichment, AI generation, voice minutes) | Top up in Settings → Billing, or switch to Platform |
404 | Resource ID doesn’t exist | List first to verify the ID |
422 | Validation error in request body | Inspect error.message + error.field in the response |
429 | Rate limit (5 rps per org) | Backoff per Retry-After header. See Rate Limits |
5xx | graph8 error | Retry 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
- SDK quotes methods — same surface in TypeScript
- CLI quote commands
- MCP quote tools
- Webhooks — quote lifecycle events