Create client contact
POST /teams/{teamId}/clients/{clientId}/contacts
Adds a person to the client's contacts. Returns the new contact object with status 201. The contact then shows on the client's Contacts tab in the Hub, and team members can pick it as a recipient for briefings and setup links.
clients:write · Team permission:client_contacts.write · Rate limit: default (120 / 60s)The key holder's role must include Add and edit client contacts (Owner, Admin and Deputy Admin include it), and the key holder must have a seat in the team. See the permissions matrix.
402 PAYMENT_REQUIRED until the subscription is reactivated.Path parameters
Request body
[email protected]. It must be 100 characters or fewer after we remove spaces at the start and end. No other contact of the same client can have the same address. The same address can belong to contacts of different clients.- The API removes spaces at the start and end of each value. A value that has only spaces counts as empty. An empty
firstNameoremailreturns400. An emptylastName,jobTitleornoteis stored asnull. - A field that is not in the list above returns
400. For example, you cannot sendclientIdin the body. The client comes from the path.
Names, job titles and email addresses cannot contain line breaks or hidden characters, such as zero-width or text-direction characters. The note can contain line breaks, but no other hidden characters. Every field must be text or null; a number or a boolean returns 400.
{
"firstName": "Sarah",
"lastName": "Chen",
"email": "[email protected]",
"jobTitle": "Marketing Director",
"note": "Send spend reports only"
}
briefingCount can be more than 0 on a new contact. It counts the briefings on this client's dashboards that already send to the address, whether or not the contact existed when the briefing was set up.Request
curl -X POST https://api.twominutereports.com/v1/teams/0190f8b0-1a2b-7c3d-8e4f-5a6b7c8d9e0f/clients/0190f8c0-1a2b-7c3d-8e4f-5a6b7c8d9e0f/contacts \
-H "Authorization: Bearer tmrc_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"firstName": "Sarah", "lastName": "Chen", "email": "[email protected]", "jobTitle": "Marketing Director", "note": "Send spend reports only"}'
Response
Returns the new contact object.
{
"success": true,
"data": {
"id": "0190f8d2-6b7c-7d8e-9f0a-1b2c3d4e5f6a",
"clientId": "0190f8c0-1a2b-7c3d-8e4f-5a6b7c8d9e0f",
"client": {
"id": "0190f8c0-1a2b-7c3d-8e4f-5a6b7c8d9e0f",
"name": "Acme Corp",
"logoUrl": "https://assets.gox.ai/tmr/logos/acme.png"
},
"firstName": "Sarah",
"lastName": "Chen",
"email": "[email protected]",
"jobTitle": "Marketing Director",
"note": "Send spend reports only",
"briefingCount": 0,
"createdAt": "2026-10-11T10:20:00.000Z",
"updatedAt": null,
"createdBy": {
"id": "0190f8b7-3c4d-7e5f-9a0b-1c2d3e4f5a6b",
"name": "Priya Raman",
"firstName": "Priya",
"lastName": "Raman",
"avatarUrl": null,
"email": "[email protected]"
},
"updatedBy": null
}
}
Returned when a field breaks a rule above. The message names the field. Other messages include Enter a first name., Keep the note to 500 characters or fewer. and Unrecognized key: "clientId".
{
"success": false,
"error": { "code": "BAD_REQUEST", "message": "Validation error: Enter a valid email address using standard characters. at \"email\"" }
}
{
"success": false,
"error": { "code": "PAYMENT_REQUIRED", "message": "Your team's plan has been cancelled. Please reactivate your subscription to continue." }
}
The API key does not have the clients:write scope.
{
"success": false,
"error": { "code": "INSUFFICIENT_PERMISSIONS", "message": "This API key is missing the `clients:write` permission required for this endpoint. Grant it to the key under Settings → API Keys (https://hub.twominutereports.com/settings?tab=user-api-keys), or use a key that has it." }
}
The key holder's role does not include Add and edit client contacts.
{
"success": false,
"error": { "code": "INSUFFICIENT_ROLE", "message": "[email protected] is not allowed to use client_contacts.write. This needs a role that includes it; their role is editor." }
}
The key holder's role allows this, but they do not have a seat in the team.
{
"success": false,
"error": { "code": "SEAT_REQUIRED", "message": "[email protected] needs a seat in this team to use client_contacts.write. Their role allows it — an Admin can assign a seat in Team settings." }
}
Returned when the client does not exist or does not belong to this team.
{
"success": false,
"error": { "code": "NOT_FOUND", "message": "Client not found" }
}
Returned when another contact of the same client already has this email address.
{
"success": false,
"error": { "code": "CONFLICT", "message": "This email already belongs to Daniel Park at Acme Corp." }
}