Customer Entities
curl --request GET \
--url https://api.nozle.app/engine/api/v1/customers/{customer_id}/entities \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.nozle.app/engine/api/v1/customers/{customer_id}/entities"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.nozle.app/engine/api/v1/customers/{customer_id}/entities', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.nozle.app/engine/api/v1/customers/{customer_id}/entities"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}require 'uri'
require 'net/http'
url = URI("https://api.nozle.app/engine/api/v1/customers/{customer_id}/entities")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.nozle.app/engine/api/v1/customers/{customer_id}/entities",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}HttpResponse<String> response = Unirest.get("https://api.nozle.app/engine/api/v1/customers/{customer_id}/entities")
.header("Authorization", "Bearer <token>")
.asString();Product Credits
Customer Entities
Create, list, update, suspend, reactivate, and delete customer Entities
GET
/
engine
/
api
/
v1
/
customers
/
{customer_id}
/
entities
Customer Entities
curl --request GET \
--url https://api.nozle.app/engine/api/v1/customers/{customer_id}/entities \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.nozle.app/engine/api/v1/customers/{customer_id}/entities"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.nozle.app/engine/api/v1/customers/{customer_id}/entities', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.nozle.app/engine/api/v1/customers/{customer_id}/entities"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}require 'uri'
require 'net/http'
url = URI("https://api.nozle.app/engine/api/v1/customers/{customer_id}/entities")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.nozle.app/engine/api/v1/customers/{customer_id}/entities",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}HttpResponse<String> response = Unirest.get("https://api.nozle.app/engine/api/v1/customers/{customer_id}/entities")
.header("Authorization", "Bearer <token>")
.asString();Base URL:
The response is
The response wraps the Entity in
An unknown customer returns
The upsert payload is a complete snapshot. When changing only status, send the current
Bulk upsert returns
Delete returns
https://api.nozle.app/engine/api/v1.
Auth: secret key only. Reads require entity:read and mutations require entity:write. Publishable keys cannot read the Entity directory.
List Entities with an optional status (active, suspended, or deleted), limit, and opaque cursor. limit is an integer from 1 to 200. Omitted, empty, or 0 uses the default of 50. Any other value returns 400 invalid_request.
GET /customers/workspace_123/entities?status=active&limit=50
Authorization: Bearer sk_...
{ "customer_id", "entities": [...], "next_cursor" }. next_cursor is null on the last page.
Read one Entity:
GET /customers/workspace_123/entities/user_42
Authorization: Bearer sk_...
entity:
{
"entity": {
"id": "0e7c5a7e-3b8f-4c6a-9f1d-2a4b6c8d0e1f",
"customer_id": "workspace_123",
"external_id": "user_42",
"name": "Asha",
"status": "active",
"metadata": { "role": "agent" },
"created_at": "2026-07-22T10:00:00Z",
"updated_at": "2026-07-22T10:00:00Z",
"deleted_at": null
}
}
404 customer_not_found. An unknown Entity returns 404 entity_not_found.
Create or replace its display fields and status:
PUT /customers/workspace_123/entities/user_42
Authorization: Bearer sk_...
Idempotency-Key: entity-user-42-v1
Content-Type: application/json
{
"name": "Asha",
"status": "active",
"metadata": { "role": "agent" }
}
name and metadata so they are not cleared.
status is required. name is at most 255 characters. metadata is a JSON object of at most 64 KiB. Unknown fields return 400 invalid_request. These status changes are allowed: active to suspended or deleted, suspended to active or deleted, and deleted to active. Any other change returns 422 entity_status_transition_invalid.
A new Entity returns 201. An update, an unchanged Entity, or a replay returns 200. The body is { "action", "entity", "replayed" }. action is one of created, updated, unchanged, activated, reactivated, suspended, or deleted.
Entity lifecycle operations never create billing events. If your product bills
per seat, your backend must track that seat separately through the Events API.
Bulk upsert accepts 1 to 500 unique external IDs:
POST /customers/workspace_123/entities/bulk-upsert
Authorization: Bearer sk_...
Idempotency-Key: entity-import-2026-07-22
Content-Type: application/json
{
"entities": [
{ "external_id": "user_42", "name": "Asha", "status": "active", "metadata": {} },
{ "external_id": "user_43", "name": "Ben", "status": "suspended", "metadata": {} }
]
}
200 with { "customer_id", "entities": [{ "action", "entity" }], "counts", "replayed" }. counts has one integer per action. An empty list, more than 500 items, or a duplicate external_id returns 400 invalid_request.
Delete through the lifecycle endpoint:
DELETE /customers/workspace_123/entities/user_42
Authorization: Bearer sk_...
Idempotency-Key: delete-user-42
200 with { "action", "entity", "replayed" }.
Deletion is not a financial cascade. It preserves all source, allocation, operation, and audit rows. Retry an uncertain mutation with the same idempotency key and identical payload.
Every mutation requires an Idempotency-Key of at most 255 bytes. A missing or longer key returns 400 invalid_request. Reusing a key with a different request returns 409 idempotency_key_reused. A retryable failure returns 503 with Retry-After and code entity_service_temporarily_unavailable. If the Entity was saved but its credit grants could not be scheduled, PUT and bulk upsert return 503 entity_grant_scheduling_unavailable. Retry both with the same key.