Data API
Sites without a ready-made connection send their data themselves through the Data API; the same API lets you read the requests opened during calls and the calls themselves. All endpoints are under /api/v1/ and use a company API key (Authorization: Bearer rz_live_…). For authentication and scopes see Authentication; for endpoint details see the API reference.
What goes where
Section titled “What goes where”| Data | Endpoint | Scope | Plan |
|---|---|---|---|
| Products | PUT /api/v1/catalog/products, DELETE …/products/{item_ref} | ingest:catalog | every plan |
| Categories | PUT /api/v1/catalog/categories, DELETE …/categories/{kategori_id} | ingest:catalog | every plan |
| Knowledge content | PUT /api/v1/kb/articles | ingest:kb | every plan |
| Orders | PUT /api/v1/orders | ingest:orders | every plan |
| Carts | PUT / GET /api/v1/sepetler, DELETE …/sepetler/{dis_id} | ingest:carts, read:carts | Data API + Carts |
| Customers | PUT /api/v1/musteriler, DELETE …/musteriler/{dis_id} | ingest:customers | Data API + Carts |
| Requests (read) | GET /api/v1/requests | read:requests | Data API |
| Calls and topics (read) | GET /api/v1/cagrilar, GET /api/v1/konular/istatistik | calls:read | Data API (+ Topic analytics) |
Ingestion endpoints (products, categories, knowledge, orders) are on in every plan, because the assistant works with this data. Some paths and fields are Turkish words: sepetler = carts, musteriler = customers, urun_adi = product name, fiyat = price.
Basic rules
Section titled “Basic rules”- Upsert: records are inserted or updated by your own id (
item_ref,kategori_id,id,external_id,dis_id). A record whose content didn’t change isn’t rewritten (unchanged). - Batches: 1–1000 records per request (
items); the same id cannot appear twice in one request (422duplicate_key: …). Unknown fields return 422. - Full sync (
?full=true): records missing from the list are deactivated. The full list must be sent in one request (≤1000); for larger catalogs push incrementally and deactivate removed items withDELETE. - Out-of-order requests: an order payload whose
modified_atis older than the stored version isn’t written; newer data is never overwritten. - Embeddings: vectors for semantic search are generated in the background for changed products and knowledge; the request doesn’t wait.
- Limits: 120 requests per minute per key, body up to 5 MB. Errors and limits →
Example: sending products and orders
Section titled “Example: sending products and orders”export RZ_API="https://<your-console-host>"export RZ_KEY="rz_live_xxx"
curl -s -X PUT "$RZ_API/api/v1/catalog/products" \ -H "Authorization: Bearer $RZ_KEY" -H "Content-Type: application/json" \ -H "Idempotency-Key: urunler-2026-09-27-1" \ -d '{"items": [{"item_ref": "1234", "urun_adi": "Kablosuz Kulaklık X2", "marka": "Ornek", "kategori": "Ses > Kulaklık", "fiyat": 1899.90, "stokta": true, "url": "https://magaza.example.com/urun/x2"}]}'# {"dataset":"urun","inserted":1,"updated":0,"unchanged":0,"deactivated":0,"skipped":0}// Node 18+ (built-in fetch)const API = process.env.RZ_API;const KEY = process.env.RZ_KEY; // rz_live_xxx
async function putOrders(orders, idempotencyKey) { const res = await fetch(`${API}/api/v1/orders`, { method: 'PUT', headers: { Authorization: `Bearer ${KEY}`, 'Content-Type': 'application/json', 'Idempotency-Key': idempotencyKey, }, body: JSON.stringify({ items: orders }), }); if (res.status === 429) { const wait = Number(res.headers.get('Retry-After') ?? 60); await new Promise((r) => setTimeout(r, wait * 1000)); return putOrders(orders, idempotencyKey); // safe to retry with the same key } if (!res.ok) throw new Error(`${res.status} ${JSON.stringify(await res.json())}`); return res.json(); // { inserted, updated, unchanged, unmapped_statuses }}
await putOrders([{ external_id: '98765', number: '98765', status: 'processing', items: [{ name: 'Kablosuz Kulaklık X2', qty: 1, total: '1899.90', ref: '1234' }], total: '1899.90', carrier: 'Örnek Kargo', tracking_number: '123456789012', created_at: '2026-09-24T10:15:00+03:00', modified_at: '2026-09-24T12:00:00+03:00',}], 'siparis-98765-v3');<?php// Send an order to the Data API when it changes in WooCommerce (e.g. in a plugin).add_action('woocommerce_update_order', function ($order_id) { $o = wc_get_order($order_id); if (!$o) { return; } $items = []; foreach ($o->get_items() as $item) { $items[] = [ 'name' => $item->get_name(), 'qty' => $item->get_quantity(), 'total' => wc_format_decimal($item->get_total(), 2), 'ref' => (string) ($item->get_variation_id() ?: $item->get_product_id()), ]; } $body = ['items' => [[ 'external_id' => (string) $o->get_id(), 'number' => (string) $o->get_order_number(), 'status' => $o->get_status(), // e.g. processing 'customer_name' => trim($o->get_billing_first_name() . ' ' . $o->get_billing_last_name()), 'phone' => $o->get_billing_phone(), 'email' => $o->get_billing_email(), 'items' => $items, 'total' => wc_format_decimal($o->get_total(), 2), 'currency' => $o->get_currency(), 'created_at' => $o->get_date_created()->format(DATE_ATOM), 'modified_at' => $o->get_date_modified()->format(DATE_ATOM), ]]]; wp_remote_request(RZ_API . '/api/v1/orders', [ 'method' => 'PUT', 'timeout' => 10, 'headers' => [ 'Authorization' => 'Bearer ' . RZ_KEY, // rz_live_xxx; define it in wp-config.php 'Content-Type' => 'application/json', 'Idempotency-Key' => 'wc-' . $o->get_id() . '-' . $o->get_date_modified()->getTimestamp(), ], 'body' => wp_json_encode($body), ]);});If you use WooCommerce you usually don’t need this: the store connection and WooCommerce’s own webhook do the same without code.
import hashlib, json, os, requests
API, KEY = os.environ["RZ_API"], os.environ["RZ_KEY"] # rz_live_xxxs = requests.Session()s.headers["Authorization"] = f"Bearer {KEY}"
def put_products(items, *, full=False): """In batches of 1000; a full sync is only possible in a single batch.""" for i in range(0, len(items), 1000): batch = items[i:i + 1000] # Same key for the same batch: safe to resend after a network error. key = hashlib.sha256(json.dumps(batch, sort_keys=True).encode()).hexdigest() r = s.put(f"{API}/api/v1/catalog/products", params={"full": str(full).lower()}, json={"items": batch}, headers={"Idempotency-Key": key}, timeout=30) r.raise_for_status() print(r.json())
put_products([{"item_ref": "1234", "urun_adi": "Kablosuz Kulaklık X2", "fiyat": 1899.90, "stokta": True}])Pulling requests incrementally
Section titled “Pulling requests incrementally”GET /api/v1/requests returns requests in ascending updated_at order. Store next_cursor and send it as cursor next time; has_more=false means nothing new for now. Calls (/api/v1/cagrilar) are pulled the same way in created_at order.
cursor = load_cursor() # None the first timewhile True: r = s.get(f"{API}/api/v1/requests", params={"cursor": cursor, "limit": 100}, timeout=30).json() for item in r["items"]: handle(item) cursor = r["next_cursor"] save_cursor(cursor) if not r["has_more"]: breakFor instant notification use webhooks instead.
Personal data
Section titled “Personal data”© 2026 Erusoft