curl --request POST \
--url https://www.closient.com/account/api/v1/organizations \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"country": "US",
"is_brand": true,
"name": "Acme Foods Inc."
}
'import requests
url = "https://www.closient.com/account/api/v1/organizations"
payload = {
"country": "US",
"is_brand": True,
"name": "Acme Foods Inc."
}
headers = {
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({country: 'US', is_brand: true, name: 'Acme Foods Inc.'})
};
fetch('https://www.closient.com/account/api/v1/organizations', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://www.closient.com/account/api/v1/organizations",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'country' => 'US',
'is_brand' => true,
'name' => 'Acme Foods Inc.'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://www.closient.com/account/api/v1/organizations"
payload := strings.NewReader("{\n \"country\": \"US\",\n \"is_brand\": true,\n \"name\": \"Acme Foods Inc.\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-Key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://www.closient.com/account/api/v1/organizations")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"country\": \"US\",\n \"is_brand\": true,\n \"name\": \"Acme Foods Inc.\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://www.closient.com/account/api/v1/organizations")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"country\": \"US\",\n \"is_brand\": true,\n \"name\": \"Acme Foods Inc.\"\n}"
response = http.request(request)
puts response.read_body{
"country": "US",
"id": "b2c3d4e5-f678-9012-abcd-ef2345678901",
"is_brand": true,
"metadata": {
"order_id": "6735"
},
"name": "Acme Foods Inc."
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}Create organization
Create a new organization for the authenticated user.
A signed-in caller becomes its OWNER; an API-key caller must send issue_api_key: true and receives the new organization’s own manager key, because a key acts only on the organization it belongs to. A data-retention policy is created for it (FSMA 204 requires one before any traceability record can be written), Stripe provisioning for the FREE tier is queued, and an analytics lifecycle event is emitted. No catalog onboarding happens — no product, brand or GTIN claim is created — so the organization is ready to invite members immediately.
A staff account or the catalog-import service account may set provision_billing: false to skip the Stripe task when seeding organizations in bulk; see that field. Any other caller sending it is rejected with 403, and a service account that omits it entirely is rejected with 422 — a script has to state its billing intent rather than inherit a default meant for interactive callers.
An organization created with the importer credential is marked as importer-provisioned: that credential may keep acting inside it, naming it in X-Closient-Organization, until a human owns it.
curl --request POST \
--url https://www.closient.com/account/api/v1/organizations \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"country": "US",
"is_brand": true,
"name": "Acme Foods Inc."
}
'import requests
url = "https://www.closient.com/account/api/v1/organizations"
payload = {
"country": "US",
"is_brand": True,
"name": "Acme Foods Inc."
}
headers = {
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({country: 'US', is_brand: true, name: 'Acme Foods Inc.'})
};
fetch('https://www.closient.com/account/api/v1/organizations', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://www.closient.com/account/api/v1/organizations",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'country' => 'US',
'is_brand' => true,
'name' => 'Acme Foods Inc.'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://www.closient.com/account/api/v1/organizations"
payload := strings.NewReader("{\n \"country\": \"US\",\n \"is_brand\": true,\n \"name\": \"Acme Foods Inc.\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-Key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://www.closient.com/account/api/v1/organizations")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"country\": \"US\",\n \"is_brand\": true,\n \"name\": \"Acme Foods Inc.\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://www.closient.com/account/api/v1/organizations")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"country\": \"US\",\n \"is_brand\": true,\n \"name\": \"Acme Foods Inc.\"\n}"
response = http.request(request)
puts response.read_body{
"country": "US",
"id": "b2c3d4e5-f678-9012-abcd-ef2345678901",
"is_brand": true,
"metadata": {
"order_id": "6735"
},
"name": "Acme Foods Inc."
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}Authorizations
Body
Organization name.
ISO 3166-1 alpha-2 country code.
2^[A-Za-z]{2}$Whether this organization is a brand owner.
Opt this organization into the global recall feed as an observer at creation time. No catalog onboarding (product, brand, or GTIN claim) is required — this is the complete signup path for an observer subscriber (C-4355).
Return a manager-role API key for the new organization in this response.
An API key acts only on the organization it belongs to, and keys cannot mint keys, so this is how an integrator that provisions organizations obtains a credential for each one. The key is scoped to the new organization only, is shown exactly once, and is never retrievable again — store it before doing anything else. Further keys must be created by a signed-in member.
Required when the caller is an API key, which must hold the manager role on its own organization: without it the caller would create an organization it can never read, change or remove.
Whether to queue Stripe provisioning for the new organization.
Left true (the default), creating an organization queues a task that creates a live Stripe Customer and Subscription on the FREE tier. That is right for a human signup and wrong for a bulk import: seeding one organization per imported retailer and brand would request thousands of Stripe objects for organizations with no human in them. Sending false skips only that task and records the omission on the organization, so the missing subscription is a visible state rather than a side effect nobody can account for. Everything else is unchanged: the caller still becomes OWNER, the retention policy is still created, and the organization is immediately invite-ready.
false requires a staff account or the catalog-import service account; any other caller sending it is rejected with 403.
A service account must send this field explicitly — true or false — and is rejected with 422 if it omits it. The default is for interactive callers and is not inherited by a script: an importer that simply forgot the flag would silently request thousands of live Stripe customers, which is the outcome the option exists to prevent.
Response
OK
URL-safe 22-character shortuuid encoding of the row's UUID primary key. Stable across the row's lifetime; suitable for sharing in URLs, log lines, and external SDK clients. Accepted on input as either the shortuuid form or the canonical UUID form (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx).
22^[23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{22}$Organization name.
ISO 3166-1 alpha-2 country code.
Whether this organization is a brand owner.
Whether this organization is subscribed to the global recall feed as an observer — webhook endpoints on this organization receive every recall lifecycle event, not just ones affecting products it owns. Independent of is_brand and of owning any products.
Developer-attached key/value data attached to this object. Up to 50 keys; key max 40 chars, value max 500 chars.
Show child attributes
Show child attributes
The new organization's founding API key (manager role), present only when the request sent issue_api_key: true. Shown once; it cannot be retrieved later.