list_products, save_product, list_deal_line_items, update_deal_line_items, list_quotes, create_quote and update_quote. Workflows add products with the Add Product to Deal step.
Scopes
Products, line items and quotes are part of deals: reads needdeals:read, writes need deals:write. Line items and quotes follow the deal’s visibility: a credential that can’t see a deal (its pipeline is restricted, or record access limits it to other owners) can’t see its line items or quotes either.
Products
A SKU is unique among products that aren’t archived (
409 duplicate_sku). Unit prices take up to four decimals.
Line items
- A line is in its deal’s currency; it has none of its own. Adding a product priced in another currency needs
unit_pricein the deal’s currency (400 currency_mismatchotherwise). Changing a deal’s currency doesn’t convert its lines. amountis quantity × unit price less the discount, never below zero, rounded to cents. A percent discount is at most 100; anamountdiscount is off the whole line.recurring_interval(month,yearornull) is the same vocabulary as the deal’s own recurring revenue fields. A recurring line counts one period intotals.total;totals.recurringadds them up per interval andtotals.one_timethe rest.amount_from_line_items: truemakes the deal amount the lines’ total from then on: every change to the lines updates it (and sendsdeal.updated), and settingamountdirectly is overridden. The deal’srecurring_amountandrecurring_intervalfollow the recurring lines the same way: when they all bill on one interval the deal takes it and their sum; mixed monthly and yearly lines are converted to the deal’s own interval (×12 or ÷12); with no recurring line,recurring_amountisnull.falselets you set both by hand again.- A deal has up to 200 lines. A won or lost deal in a pipeline that locks closed deals refuses line changes (
422 closed_deal_locked) unless the credential’s owner is a workspace admin. - Archived products can’t be added.
Quotes
- Merging deals moves the merged deal’s quotes to the deal that is kept, so their links keep working; line items stay on the merged deal.
- Making a quote copies the deal’s line items, its primary contact and company as the buyer (
recipient), and the workspace and the credential’s owner assender. Later changes to the deal don’t change the quote.titledefaults to the deal name;termsandexpires_atdefault to the workspace’s quote settings (Settings → Products).expires_attakes a date (YYYY-MM-DD, valid through the end of that day, UTC) or an ISO 8601 date-time, ornullfor no expiry. - Sharing (
publish, orpublish: trueon create) turns a draft into anopenquote:public_urlstarts working and the quote can no longer change. A quote needs at least one line to be shared. Withinclude_payment_link, a Stripe payment link is created in the workspace’s own Stripe account at that moment (payment_link_url); one payment link carries up to 20 lines and can’t mix monthly and yearly lines. Whenpublish: trueon create is refused (Stripe, say), the draft still exists:details.quote_idnames it. - The public page shows the quote’s lines, totals, terms and expiry, and nothing else from your workspace. The buyer accepts with their name and email; the quote becomes
acceptedwithaccepted_name,accepted_emailandaccepted_at, and the page then shows Pay now when the quote has a payment link. An open quote pastexpires_atshows as expired (display_status: "expired") and can’t be accepted. Views are counted once an hour per viewer, so reloads don’t inflate them (view_count,first_viewed_at,last_viewed_at), and the deal’s owner is notified when the quote is accepted. - Voiding makes the page say the quote is no longer available and switches its payment link off in Stripe. A quote whose deal is deleted reads as no longer available too, until the deal is restored.
Stripe payment links
Payment links use your own Stripe account: payments go straight to it and Orbit never handles the money. A workspace admin connects it in Settings → Products with a Stripe restricted key that has Write access to Payment Links, Prices and Products and nothing else. The key is checked with Stripe, stored encrypted and never returned by any API. Secret keys (sk_...) are refused.
Webhooks
product.*, quote.* and deal.line_item_* events are listed on the events page, all behind deals:read.