---
title: "Upsert a partner-managed-account relationship"
method: POST
path: "/portfolio_relationships"
tags: ["Portfolio Relationships"]
---

# Upsert a partner-managed-account relationship

`POST /portfolio_relationships`

## Request

- Base URL: `https://api.lassotech.com/api/v1/rest`
- URL: `https://api.lassotech.com/api/v1/rest/portfolio_relationships`
- Auth: API key in header `x-lasso-access-token`

Upserts a single partner-managed-account relationship and its metrics. The primary integration
point for a partner's managed-account data (for example, an agency's managed customer accounts). Upserted on
the partner and customer pairing; pushing the same pairing again updates the existing
relationship rather than creating a duplicate. `engagement_type` is a mutable
attribute of that relationship, so changing it updates the existing record in place.

A field the relationship object does not define (for example a misspelled `startDate`) fails
the row with `unknown_field` rather than being ignored. Requires `portfolio_write` permission.

## Request body

- PortfolioRelationshipRow
  - `partner` PortfolioRelationshipPartnerLookup, required: Find-or-fail partner identifier. Provide one field.
    - `lasso_partner_key` string: The partner's Lasso Partner Key (falls back to matching the slug)
    - `crm_account_id` string: An external ID already linked to the partner (Salesforce Account / HubSpot Company / Pipedrive Organization)
  - `customer` PortfolioRelationshipCustomerLookup, required: Find-or-create customer identifier. A create requires crm_account_id, external_id, or domain. Identifiers are recorded on every push, not just on create: an empty slot is filled from the values you send, while a populated slot, or an identifier another customer already holds, is left alone without failing the row.
    - `lasso_customer_key` string: An existing customer's Lasso key (find-only, never creates)
    - `crm_account_id` string: Your CRM's identifier for this customer. Stored as crm_record_id and also recorded as an external ID link on the customer (Salesforce account / HubSpot company / Pipedrive organization). Repeat pushes do not add a second link.
    - `crm_system` 'SALESFORCE' | 'HUBSPOT' | 'PIPEDRIVE': Which CRM crm_account_id came from. Optional; inferred from the account's CRM connector when omitted. Required to create a link on an account with more than one CRM connected. An unrecognized value fails the row with validation_failed.
    - `external_id` string: Your own external identifier for this customer. Use a key that is stable for the life of the customer: this is their identity, so changing it resolves to a different customer and creates a duplicate.
    - `domain` string: Customer's domain, normalized; personal email domains are never used as an identity key
    - `name` string: Customer display name, only written on create
  - `engagement_type` string, nullable: Key of an engagement type already configured for this account. Omitting the field leaves the current engagement type unchanged; sending an explicit null or an empty string clears it.
  - `started_at` string, date-time: When the relationship began. Defaults to now.
  - `status` string: Set to "inactive" to immediately expire the relationship. Any other value (or omitted) keeps it active.
  - `valid_until` string, date-time: Hard expiry, takes precedence over heartbeat_ttl_days and clears it.
  - `heartbeat_ttl_days` integer: Soft expiry in days. Defaults to the account's configured heartbeat window if neither this nor valid_until is provided.
  - `metrics` PortfolioMetric[]
    - `key` string, required: Must match a metric key already configured for this account
    - `value` number, required
    - `currency` string: ISO currency code, required if the metric's configured unit type is currency
    - `as_of` string, date-time: Defaults to request time

## Response `200`

Existing relationship updated

- PortfolioRelationshipResult
  - `index` integer: Position of this row in the batch request. Present on batch results only.
  - `status` 'created' | 'updated'
  - `customer_id` string: The customer's Lasso key
  - `customer_created` boolean
  - `relationship_id` integer
  - `warnings` object[]: Present only when part of the row was not applied although the row succeeded. `identifier_not_recorded`: a customer identifier you sent was not stored, because the customer already holds a different value, another customer already holds that one, or (for `domain`) it is a personal-email domain or not a usable domain. `crm_link_skipped`: no CRM link was created for `crm_account_id`, because the customer is already linked to a different record in the same CRM.
    - `code` 'identifier_not_recorded' | 'crm_link_skipped'
    - `detail` string

## Other responses

- `201`: Relationship created
- `401`: Missing or invalid API key
- `403`: API key lacks required permission
- `422`: The row failed. `error` is one of the row error codes listed on `PortfolioRelationshipRowError`.
- `429`: Rate limit exceeded. Wait the number of seconds in `Retry-After`, then retry.

---

[API](https://skmtc.dev/onelasso/apis/lasso-rest-api.md) · [All operations](https://skmtc.dev/onelasso/apis/lasso-rest-api/llms.txt) · [OpenAPI document](https://skmtc.dev/onelasso/apis/lasso-rest-api/revisions/bbc328f5e2d1?raw)
