What is a contact?
A contact (referred to as a “person” in the API) is a record that stores information about an individual or a company. Every contact has apartyType that controls how it is classified:
Contacts also have a
contactType that categorizes their relationship to your business:
Contact fields
Locations
Each contact can have one or more locations (physical addresses). A location stores:- Street address, suite, city, postal code, state, and country
- A contact name and phone number for that location
- Flags for
isPrimary(the contact’s main address) andisBilling(used for billing)
primaryLocation and billingLocation fields on the contact detail response, and you can also retrieve the full list via GET /public/people/{ContactId}/location.
Why locations matter for proposals
Assigning a location to a proposal is how Portal.io determines the applicable sales tax rates. Portal.io uses theClientLocation method: it looks up tax rates for the address and applies them to the taxable parts of the proposal. Until you assign a location, tax totals on the proposal remain zero.
You must assign a contact to a proposal before you can assign a location. Attempting to assign a location to a proposal with no contact returns a 409 Conflict.
How contacts relate to proposals
A proposal can have one assigned contact and one assigned location. The relationship works like this:- You assign a contact using
POST /public/proposals/{ProposalId}/contact/{ContactId}. - If the contact has exactly one primary location, Portal.io automatically assigns that location to the proposal as well.
- If the contact has multiple locations, you assign the location separately using
POST /public/proposals/{ProposalId}/location/{LocationId}. The location must belong to the already-assigned contact. - Assigning or changing a location triggers an immediate tax recalculation on the proposal.
Creating contacts and locations
When you create a new contact,PartyType, ContactType, and FirstName are required. CompanyName is also required when PartyType is Company.
POST /public/people/{ContactId}/location. Street is the only required field, but if you supply a Country, State is also required.
Searching for contacts
TheGET /public/people endpoint returns a paged list of contacts for your account. You can filter by SearchText and ContactTypes, and control pagination with PageNumber and PageSize (both default to 1 and 10 respectively).
API operations reference
Search contacts
GET /public/peopleReturns a paged list of contacts. Supports search text, contact type filter, sort, and pagination.Create contact
POST /public/peopleCreates a new contact in your account.Get contact details
GET /public/people/{ContactId}Returns full contact details including primary and billing locations. Pass IncludeCounts=true to include proposal and payment counts.List contact locations
GET /public/people/{ContactId}/locationReturns all locations for a contact, ordered with primary first, then billing, then most recently modified.Create location
POST /public/people/{ContactId}/locationAdds a new location to an existing contact.Assign contact to proposal
POST /public/proposals/{ProposalId}/contact/{ContactId}Links a contact to a proposal. Auto-assigns the location if the contact has one primary location.Assign location to proposal
POST /public/proposals/{ProposalId}/location/{LocationId}Links a specific location to a proposal and triggers tax recalculation.