When you create a webhook subscription, you specify which event types you want to receive. Portal.io delivers a signed HTTP POST payload to your registered HTTPS endpoint each time a subscribed event occurs. This page documents every available event type and the shape of its payload.Documentation Index
Fetch the complete documentation index at: https://docs.portal.io/llms.txt
Use this file to discover all available pages before exploring further.
Your endpoint must respond with a
2xx status code to acknowledge receipt. If Portal.io does not receive a 2xx response, it retries the delivery on this schedule: 1 minute, 5 minutes, 30 minutes, 2 hours, 12 hours.Verifying Webhook Signatures
Every delivery includes anX-Webhook-Signature header you should use to verify the request came from Portal.io:
t— Unix timestamp when the webhook was generated.v1— HMAC-SHA256 hex digest.
- Read the raw request body exactly as received.
- Extract
tandv1from theX-Webhook-Signatureheader. - Rebuild the signed message:
t + "." + rawBody. - Compute
HMAC_SHA256(secretKey, signedMessage). - Compare your result to
v1. Reject the request if they do not match. - Reject the request if
tis more than 5 minutes old.
secretKey is the value returned in the secretKey field when you created the subscription.
Payload Envelope
All webhook events use a standard envelope format:| Field | Type | Description |
|---|---|---|
id | string | Unique webhook delivery identifier, prefixed with evt_. |
type | string | Event type identifier (dot-notation). |
created | string (ISO 8601) | UTC timestamp when the event was generated. |
data | object | Event-specific payload. |
Event Types
Use these values in the repeatedEvents body parameter when creating a webhook subscription.
proposal.build.status_update
AI proposal builder finishes or fails.
proposal.outline.status_update
AI outline generation completes or fails.
proposal.status_changed
A proposal’s status changes (e.g. Draft → Submitted).
proposal.build.status_update
Fired when the Portal.io AI builder finishes generating a proposal or encounters an error during generation. Subscribe to this event if you need to react when a build completes asynchronously.Payload Fields
Thedata object contains:
| Field | Type | Description |
|---|---|---|
data.status | string | Build result status. One of Building, Completed, Failed. |
data.proposal | object | Full proposal detail snapshot (see proposal object fields below). |
proposal.outline.status_update
Fired when Portal.io’s AI outline generation completes or fails. Useful for workflows that wait for an AI-generated scope before proceeding.Payload Fields
Thedata object contains:
| Field | Type | Description |
|---|---|---|
data.proposalId | integer | ID of the proposal whose outline changed. |
data.status | string | Outline generation status. One of Generating, Completed, Failed. |
data.outline | string or null | The generated outline text. Only populated when status is Completed. |
proposal.status_changed
Fired whenever a proposal’s status changes. Common transitions include Draft → Submitted, Submitted → Accepted, and Accepted → Completed.Payload Fields
Thedata object contains the full proposal detail. See Proposal Object Fields for the complete structure.
Proposal Object Fields
The proposal object included inproposal.build.status_update and proposal.status_changed payloads shares the same structure.
Top-Level Fields
| Field | Type | Description |
|---|---|---|
id | integer | Unique identifier for the proposal. |
number | integer | Human-readable proposal number, unique within the account. |
name | string | Display name of the proposal. |
status | string | Current proposal status (see proposal statuses). |
createdDate | string (ISO 8601) | When the proposal was created. |
lastSubmittedDate | string or null | When the proposal was last submitted to the client. |
clientLastOpenedDate | string or null | When the client last opened/viewed the proposal. |
clientLastDecisionDate | string or null | When the client last approved or declined. |
lastCompletedDate | string or null | When the proposal was last marked complete. |
lastModifiedDate | string (ISO 8601) | When the proposal was last modified by any actor. |
lastModifiedByUserDate | string (ISO 8601) | When the proposal was last modified by a human user (not system). |
coverpageImageUrl | string or null | URL of the proposal cover page image. |
aboutUs | string or null | ”About Us” text included in the proposal. |
projectDescription | string or null | Project description text. |
projectTerms | string or null | Terms and conditions text. |
lastModifiedUser | object | User who last modified the proposal (see user fields). |
customer | object or null | Customer contact (see customer fields). |
dealer | object | Dealer account (see dealer fields). |
financialSummary | object or null | Financial breakdown (see financial summary). |
areas | array or null | Proposal areas with options and line items (see area fields). |
profit | object or null | Profit breakdown (see profit fields). |
recurringServices | object or null | Recurring services summary (see recurring services). |
paymentSchedule | object or null | Payment schedule (see payment schedule). |
paymentRequests | array or null | Payment requests (see payment requests). |
changeOrders | array | Associated change orders (see change order fields). |
Proposal Statuses
| Value | Description |
|---|---|
Undefined | Unset/default status. |
Draft | Proposal is being edited, not yet sent to client. |
Submitted | Proposal has been sent to the client. |
ViewedByClient | Client has opened/viewed the proposal. |
Accepted | Client has accepted the proposal. |
Declined | Client has declined the proposal. |
Delayed | Proposal has been delayed. |
Completed | Proposal is marked complete. |
EmailFailed | Delivery email to client failed. |
Expired | Proposal has expired. |
Customer Fields
| Field | Type | Description |
|---|---|---|
id | integer | Contact ID. |
partyType | string | Person or Company. |
contactType | string | Contact classification (e.g. Client). |
firstName | string or null | First name. |
lastName | string or null | Last name. |
companyName | string or null | Company name. |
contactEmail | string or null | Primary email address. |
contactEmailCC | string or null | CC email address. |
contactPhone | string or null | Primary phone number. |
location | object or null | Primary location (see location fields). |
Location Fields
| Field | Type | Description |
|---|---|---|
id | integer or null | Location ID. |
street | string or null | Street address. |
suite | string or null | Suite or unit number. |
city | string or null | City. |
postalCode | string or null | ZIP or postal code. |
state | string or null | Full state name. |
stateAbbrev | string or null | Two-letter state abbreviation. |
country | string or null | Country name. |
phone | string or null | Location phone number. |
Dealer Fields
| Field | Type | Description |
|---|---|---|
companyName | string | Company name. |
location | object | Company location (see location fields). |
salesperson | object or null | Assigned salesperson (see salesperson fields). |
webSiteUrl | string or null | Company website URL. |
companyPhone | string or null | Company phone number. |
companyLogoUrl | string or null | URL of the company logo. |
Salesperson Fields
Extends user fields with:| Field | Type | Description |
|---|---|---|
firstName | string | First name. |
lastName | string or null | Last name. |
id | integer or null | User ID. |
email | string | Email address. |
User Fields
| Field | Type | Description |
|---|---|---|
firstName | string | First name. |
lastName | string or null | Last name. |
Financial Summary
| Field | Type | Description |
|---|---|---|
partsSubtotal | number | Subtotal for parts before discount. |
partsDiscountType | string or null | Discount type. One of Percentage, Fixed. |
partsDiscountPercentage | number or null | Discount percentage applied to parts. |
partsDiscount | number or null | Discount amount applied to parts. |
partsDiscountTaxable | number or null | Taxable portion of parts discount. |
partsDiscountTaxExempt | number or null | Tax-exempt portion of parts discount. |
partsTotal | number | Total for parts after discount. |
laborTotal | number | Total labor cost. |
feeTotal | number | Total fees. |
proposalSubtotal | number | Subtotal before tax. |
salesTax | object or null | Sales tax details (see sales tax). |
proposalTotal | number or null | Grand total including tax. |
currency | object or null | Currency with code (ISO 4217, e.g. USD) and symbol (e.g. $). |
Sales Tax
| Field | Type | Description |
|---|---|---|
taxStatus | string | One of Undefined, Ok, NoState, OutOfCountry, NoClient, NoClientAddress, IncompleteClientAddress, NoCompanyAddress, TaxableStateDeclined. |
total | number or null | Total sales tax amount. |
calculation | object or null | Tax calculation details (see tax calculation). |
Tax Calculation
| Field | Type | Description |
|---|---|---|
method | string | One of ClientLocation, CompanyLocation, FixedPercentage, None. |
applyTo | array<string> | Array of categories tax applies to. Each value is one of None, Parts, Labor, Fee. |
partsTax | number or null | Parts tax rate. |
partsTaxName | string or null | Parts tax label. |
laborTax | number or null | Labor tax rate. |
laborTaxName | string or null | Labor tax label. |
hasMultipleTaxSupport | boolean | Whether multiple tax rates are configured. |
partsTax2 | number or null | Second parts tax rate. |
partsTax2Name | string or null | Second parts tax label. |
laborTax2 | number or null | Second labor tax rate. |
laborTax2Name | string or null | Second labor tax label. |
feeTax | number or null | Fee tax rate. |
feeTaxName | string or null | Fee tax label. |
feeTax2 | number or null | Second fee tax rate. |
feeTax2Name | string or null | Second fee tax label. |
taxLocation | object or null | Tax jurisdiction location (see location fields). |
isTaxJarAvailable | boolean | Whether TaxJar integration is available. |
partsTotalTax | number or null | Calculated total tax on parts. |
laborTotalTax | number or null | Calculated total tax on labor. |
feeTotalTax | number or null | Calculated total tax on fees. |
Area Fields
| Field | Type | Description |
|---|---|---|
id | integer | Area ID. |
name | string | Area name. |
options | array | Area options (see area option fields). |
Area Option Fields
| Field | Type | Description |
|---|---|---|
id | integer | Option ID. |
status | string | Option status. One of Draft, Accepted, Declined. |
lastModifiedDate | string (ISO 8601) | When the option was last modified. |
clientDescription | string or null | Client-facing description. |
installerDescription | string or null | Installer-facing notes. |
items | array or null | Line items (see item fields). |
total | number | Option total amount. |
totalRecurringService | number | Recurring service total for this option. |
Item Fields
| Field | Type | Description |
|---|---|---|
id | integer | Item ID. |
parentId | integer or null | Parent item ID (for sub-items). |
itemType | string | One of Part, Labor, CustomItem, Fee. |
referencedItemId | integer | Catalog item ID reference. |
createdDate | string (ISO 8601) | When the item was added. |
lastModifiedDate | string (ISO 8601) | When the item was last modified. |
brand | string or null | Item brand. |
model | string or null | Item model. |
description | string or null | Full description. |
name | string or null | Item name. |
shortDescription | string or null | Short description. |
clientNote | string or null | Note visible to client. |
imageUrl | string or null | Item image URL. |
msrp | number or null | Manufacturer’s suggested retail price. |
sellPrice | number or null | Sell price per unit. |
cost | number or null | Cost per unit. |
costUpdateDate | string or null | When cost was last updated. |
supplier | string or null | Supplier name. |
quantity | number | Quantity. |
total | object | Item total with amount (number), currency (object or null), and isCombinedPrice (boolean or null). |
isTaxExempt | boolean or null | Whether the item is tax-exempt. |
isRecurringService | boolean or null | Whether this is a recurring service item. |
linkedOrders | array or null | Linked purchase orders (see linked order fields). |
Linked Order Fields
| Field | Type | Description |
|---|---|---|
orderId | integer | Order ID. |
orderNumber | integer | Order number. |
orderNumberSuffix | string | Order number suffix (e.g. A, B). |
supplier | string or null | Supplier name. |
supplierRef | string or null | Supplier reference/PO number. |
orderName | string | Order name. |
orderStatus | string | One of Undefined, Draft, Submitted, ViewedBySupplier, Accepted, Received, EmailFailed. |
Change Order Fields
| Field | Type | Description |
|---|---|---|
id | integer | Change order ID. |
number | integer | Change order number. |
name | string | Change order name. |
status | string | Status (see proposal statuses). |
total | object or null | Total with changeOrderTotal (number or null) and currency (object or null). |
customer | object or null | Customer contact (see customer fields). |
createdDate | string (ISO 8601) | When the change order was created. |
lastModifiedDate | string (ISO 8601) | When last modified. |
lastModifiedByUserDate | string or null | When last modified by a human user. |
Profit Fields
| Field | Type | Description |
|---|---|---|
total | number or null | Total profit amount. |
percentage | number or null | Overall profit percentage. |
partTotal | number or null | Profit on parts. |
partPercentage | number or null | Profit percentage on parts. |
laborTotal | number or null | Profit on labor. |
laborPercentage | number or null | Profit percentage on labor. |
isProfitIncludeCos | boolean or null | Whether profit calculation includes cost of sale. |
Recurring Services
| Field | Type | Description |
|---|---|---|
items | array | Recurring service items, each with name (string), sellPrice (number), quantity (number), totalSell (number). |
totalRecurringService | number | Total recurring service amount. |
Payment Schedule
| Field | Type | Description |
|---|---|---|
customerDescription | string or null | Customer-facing payment schedule description. |
payments | array or null | Scheduled payments, each with calculation (string or null), amount (number), and due object containing date (string or null) and milestone (string or null). |
Payment Requests
| Field | Type | Description |
|---|---|---|
id | integer | Payment request ID. |
status | string | Payment status. One of Undefined, Draft, Submitted, Viewed, Paid, Declined, Refunded, Pending, RequiresAction, Verifying, Cancelled. |
amount | number or null | Payment amount. |
dueDate | string (ISO 8601) | Payment due date. |
description | string or null | Payment description. |
paymentMethod | string or null | Payment method used. |