A valid request URL is required to generate request examples{
"customer": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"name": "<string>",
"external_id": "<string>",
"created_at": "2023-11-07T05:31:56Z"
}
}{
"customer": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"name": "<string>",
"external_id": "<string>",
"created_at": "2023-11-07T05:31:56Z"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}Create or mirror a team
A team in the customer plane, created from your own backend.
Until this existed a team could only be born in a browser (POST /v1/contact/customers) or out of a CSV import — the right pair for a product whose teams are created by the people in them, and the wrong one for a B2B product whose accounts already live in your database. Without a team, everything the customer plane can answer about one has nothing to resolve against: entitlements, team-scoped onboarding steps, seat-based billing.
Send external_id and this is an upsert. Your own id for the account is what makes a nightly sync land on the same row instead of creating a second team with the same name every run — the same thing POST /v1/contacts does for people. The name is refreshed from yours on a repeat, because a team renamed in your product and not here is a name our widget shows that nobody recognises. Nothing else moves: the roster is ours to hold, and a sync that reset it would undo an invitation somebody accepted between two runs.
Without external_id it is a plain create, and a second call is a second team — the honest answer when you have given us no way to tell one from the other.
Answers 201 for a team that did not exist and 200 for one that did. customer.created is published only for the first.
A valid request URL is required to generate request examples{
"customer": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"name": "<string>",
"external_id": "<string>",
"created_at": "2023-11-07T05:31:56Z"
}
}{
"customer": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"name": "<string>",
"external_id": "<string>",
"created_at": "2023-11-07T05:31:56Z"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}Autorizações
An organization API key, uk_sk_live_… or uk_sk_test_…. The environment is resolved from the stored key row on every request, never from a request parameter.
Every route behind this credential is rate limited per key — 1000 requests a minute — with a second ceiling of 3000 a minute across all the keys of one environment, so splitting your traffic across keys isolates it and minting more keys does not buy more of it. A test key can never spend a live key's allowance. Every response carries the current state in headers; see the rate-limits guide.
Cabeçalhos
A key you choose — a UUID, or your own identifier for the operation — that makes this write safe to retry. Send the same key again and you get the same response back: the same status, the same body, and Idempotent-Replay: true. The handler does not run a second time.
The key is scoped to your API key and the route, so keys never collide between environments or tenants. It is remembered for 24 hours. Reusing it for a different request is refused (422), and a second request arriving while the first is still running is refused too (409) — retry that one in a moment.
A request that failed with a 5xx or was rate limited leaves the key spendable: retry it with the same key.
255Corpo
Resposta
The team already existed and its name was refreshed.
Show child attributes
Show child attributes