Skip to main content
POST
Add a contact
Adds a contact to one of your entities. Omit upstreamDownstreamAssociationId for an agency-wide contact that every one of your markets can see; supply it to confine the contact to one market relationship. When upstreamDownstreamAssociationId is given, the contact is added to that market’s contacts. When you name a market, the contact belongs to the entity that holds that market. Leave downstreamEntityId out and that entity is used. If you send a different downstreamEntityId, the request is refused with 400 and nothing is written.

Email addresses are unique across Turris, and this is the part to read

Contact email is unique platform-wide, not per agency. So an address you add may already belong to a contact another agency introduced first. When that happens, this endpoint attaches a new scope for your entity to the existing contact and returns it as normal. The response is indistinguishable from having created a fresh contact: it shows only your own scopes, and it reflects the name you sent.
That indistinguishability is deliberate and it is the reason this endpoint does not return 409 for a known address. A 409, or a response carrying somebody else’s stored name, would let you test any email against the platform and learn whose contact it is. We would rather the create tell you nothing than tell you that.
Two consequences worth planning for:

Your name is yours only

On a shared record the stored firstName and lastName stay as the first agency recorded them — a create must not rename a record two agencies share. You will not see theirs; the response echoes what you sent. Treat it as authoritative for your scopes, not as a read of the database.

A duplicate scope is a 409

Adding a scope you already hold, for the same entity and market, returns 409. That is a duplicate rather than a disclosure, and it is actionable.
A contact you added to a market before contacts started joining the market’s contacts may hold that market’s scope without appearing on the market. Sending the same request again returns 409, because you already hold the scope, so it cannot add the contact to the market; contact Turris support to have it added.

A market has one primary contact

isPrimary: true on a market that already has a primary contact returns 409, and nothing is written. Change the primary contact in Turris, then add this contact without isPrimary. On a market with no primary contact, isPrimary: true is accepted and makes this contact the market’s primary. This check reads only your own market, the one upstreamDownstreamAssociationId names, so it tells you nothing you cannot already see on that market’s contacts. Send an Idempotency-Key header. See Idempotency.

Authorizations

Authorization
string
header
required

Bearer authentication header of the form Bearer <token>, where <token> is your auth token.

Headers

idempotency-key
string

UUID to ensure idempotent request processing

Example:

"550e8400-e29b-41d4-a716-446655440000"

x-idempotency-key
string

Alternative UUID header for idempotent request processing

Example:

"550e8400-e29b-41d4-a716-446655440000"

Body

application/json
firstName
string
required

Given name. Stored only when this email is new to Turris; on an address the platform already knows, the existing record keeps its name and this value is echoed back to you unchanged.

Example:

"Jon"

lastName
string
required

Surname. Stored only when this email is new to Turris; on an address the platform already knows, the existing record keeps its name and this value is echoed back to you unchanged.

Example:

"Doe"

email
string
required

Email address. Unique across Turris and matched case-insensitively, so an address already known to the platform is attached to your agency rather than duplicated.

Example:

"example@test.com"

downstreamEntityId
string

Which of your entities this contact belongs to. With upstreamDownstreamAssociationId, defaults to the entity that holds that market, and a different entity is refused with 400. Without it, defaults to your own organization.

Example:

"6610b3d2c2e0a51b8c0d1f02"

upstreamDownstreamAssociationId
string

Confine the contact to one market relationship. Omit for an agency-wide contact, which every one of your markets can see.

Example:

"6627f1a9c2e0a51b8c0d4e3a"

businessRoles
enum<string>[]

Business roles this contact holds within the scope being created.

Available options:
Compliance Officer,
Principal Owner,
Account Manager,
Finance Manager,
Support Staff,
Contract Signatory,
Accounts Payable,
Policy Maintenance
Example:
isPrimary
boolean

Whether this is the primary contact for the scope being created. With upstreamDownstreamAssociationId, true is refused with 409 when that market already has a primary contact.

Example:

false

Response

The contact, with your scopes

data
object
required
requestId
string
required

Unique request identifier

Example:

"dev-2c5e7cf2-9acf-4c8c-ab2f-b81f39d775a8"

timestamp
string
required

Response timestamp

Example:

"2025-11-12T20:49:03.293Z"