curl --request POST \
--url http://localhost:3500/v1/suppliers \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "<string>"
}
'const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({name: '<string>'})
};
fetch('http://localhost:3500/v1/suppliers', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "http://localhost:3500/v1/suppliers"
payload = { "name": "<string>" }
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text){
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"name": "<string>",
"organization_number": "<string>",
"org_country": "<string>",
"email": "<string>",
"website": "<string>",
"address": {
"street": "<string>",
"city": "<string>",
"state": "<string>",
"postal_code": "<string>",
"country_code": "<string>"
},
"domain": "<string>",
"relationships": {
"invoice_count": 1,
"agreement_count": 1,
"pending_alert_count": 1,
"blocking_invoice_count": 1,
"blocking_agreement_count": 1,
"can_delete": true
},
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z"
}{
"error": {
"code": "validation_error",
"message": "Invalid request format, parameters, or body. Details contain up to 20 actionable field errors; the complete encoded request body must be at most 2 MiB (2,097,152 bytes).",
"request_id": "req_example"
}
}{
"error": {
"code": "invalid_token",
"message": "Missing or invalid bearer credential.",
"request_id": "req_example"
}
}{
"error": {
"code": "forbidden",
"message": "Access denied: forbidden, token_disabled, organization_required, insufficient_role, or mfa_required. Check the error code and effective permissions.",
"request_id": "req_example"
}
}{
"error": {
"code": "conflict",
"message": "An existing party has the same normalized organization number and issuing country (missing countries share one group), or both parties lack a number and have the same normalized name. No records are merged. existing_party identifies an authorized conflicting record when available. The entire write is rolled back.",
"request_id": "req_example"
}
}{
"error": {
"code": "rate_limit_exceeded",
"message": "The IP or authenticated credential exceeded its request limit.",
"request_id": "req_example"
}
}{
"error": {
"code": "internal_error",
"message": "Unexpected server failure. Include the request ID when contacting support.",
"request_id": "req_example"
}
}{
"error": {
"code": "service_unavailable",
"message": "Authentication infrastructure is unavailable or rate limited. Honor Retry-After when provided.",
"request_id": "req_example"
}
}Create a supplier
Create a canonical party. Only name is required. Omitted contact fields are stored as null; a missing registration country may be inferred as described below. Websites must be absolute HTTP(S) URLs. Organization numbers use the shared country-specific format and checksum rules described on organization_number. Recognized valid wrappers are accepted and checksum-verified identifiers are stored canonically. A supplied registration country is authoritative; otherwise a recognized prefix is checked before the address country. Countries are inferred only after checksum success, and a failed recognized prefix never falls back to the address. Unsupported and format-only identifiers receive basic input validation without country inference. No idempotency key is required; repeating a create returns a duplicate conflict.
curl --request POST \
--url http://localhost:3500/v1/suppliers \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "<string>"
}
'const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({name: '<string>'})
};
fetch('http://localhost:3500/v1/suppliers', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "http://localhost:3500/v1/suppliers"
payload = { "name": "<string>" }
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text){
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"name": "<string>",
"organization_number": "<string>",
"org_country": "<string>",
"email": "<string>",
"website": "<string>",
"address": {
"street": "<string>",
"city": "<string>",
"state": "<string>",
"postal_code": "<string>",
"country_code": "<string>"
},
"domain": "<string>",
"relationships": {
"invoice_count": 1,
"agreement_count": 1,
"pending_alert_count": 1,
"blocking_invoice_count": 1,
"blocking_agreement_count": 1,
"can_delete": true
},
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z"
}{
"error": {
"code": "validation_error",
"message": "Invalid request format, parameters, or body. Details contain up to 20 actionable field errors; the complete encoded request body must be at most 2 MiB (2,097,152 bytes).",
"request_id": "req_example"
}
}{
"error": {
"code": "invalid_token",
"message": "Missing or invalid bearer credential.",
"request_id": "req_example"
}
}{
"error": {
"code": "forbidden",
"message": "Access denied: forbidden, token_disabled, organization_required, insufficient_role, or mfa_required. Check the error code and effective permissions.",
"request_id": "req_example"
}
}{
"error": {
"code": "conflict",
"message": "An existing party has the same normalized organization number and issuing country (missing countries share one group), or both parties lack a number and have the same normalized name. No records are merged. existing_party identifies an authorized conflicting record when available. The entire write is rolled back.",
"request_id": "req_example"
}
}{
"error": {
"code": "rate_limit_exceeded",
"message": "The IP or authenticated credential exceeded its request limit.",
"request_id": "req_example"
}
}{
"error": {
"code": "internal_error",
"message": "Unexpected server failure. Include the request ID when contacting support.",
"request_id": "req_example"
}
}{
"error": {
"code": "service_unavailable",
"message": "Authentication infrastructure is unavailable or rate limited. Honor Retry-After when provided.",
"request_id": "req_example"
}
}Authorizations
Personal API key. Send X-Organization-Id. The required cumulative level is listed in x-watchdog-permission.
Headers
Required for personal API keys. Target one organization you have access to. Migrated keys may omit it to use their original organization. For Clerk sessions, it must match the active organization.
Body
500Registration identifier, at most 100 characters. Recognized country-specific formats and checksums are validated using the registration country, recognized prefix, or address country. Valid identifiers are stored canonically, preserving leading zeros and identifier families. Invalid supported identifiers and placeholders are rejected. Unsupported and format-only identifiers receive basic character validation without country inference. Null or blank clears the number.
100Country issuing the organization number. Missing countries are inferred only after checksum validation, using a recognized prefix before the address country. Existing countries are preserved unless explicitly changed. Null clears the country and suppresses inference for this write; later ingestion may infer it again.
^([A-Za-z]{2})?$3202000Show child attributes
Show child attributes
Response
Current canonical party master record. Invoice party fields remain captured invoice snapshots.
Country issuing the organization number; null when unknown.
Show child attributes
Show child attributes
Derived company domain; not editable.
Show child attributes
Show child attributes