Source: https://beezr.io/developers/api/ > Documentation index: https://beezr.io/developers/api/llms.txt # Overview The Beezr API connects your systems to the records and files in your workspace. Every endpoint is a POST with a JSON body and an `X-API-Key` header. ## Start here 1. [Create an API key](/developers/api/authentication/) in Designer → Account settings → API Integration. Keep it on your server. 2. [Find your module and field names](/developers/api/names/). Copy the table name from the module card and System names from its Fields page. 3. [Make your first query](/developers/api/quickstart/). Use the v4 read paths to get records with file references. 4. [Create a record](/developers/api/reference/create-record/). Writes use v1 paths. Add an idempotency key before you retry a create or update. 5. [Build your integration](/developers/api/guides-sync/), or [brief your AI assistant](/developers/api/build-with-ai/) with your module's names. ## One base, two path versions Every request goes to `https://services.beezr.io/generic` followed by the path. | Work | Path prefix | |---|---| | Create, update, delete and bulk writes | `/api/v1/records/` | | Query, get and download files | `/api/v4/records/` | Older read paths exist for existing integrations. These docs use v4. ## Plan for limits and failures A key acts for the whole workspace. All keys share the workspace limits: 60 requests per minute, 2,000 per hour and 2 at the same time. A bulk call counts as one request and handles up to 100 items. Check `success` in JSON responses and check `failed` in bulk results. A bulk call can succeed for some items and fail for others. See [Limits](/developers/api/limits/) and [Errors](/developers/api/errors/). ## Keep the rules close Use [plain Markdown, the documentation index and OpenAPI](/developers/api/ai-resources/) in your editor or AI assistant. [Brief your AI assistant](/developers/api/build-with-ai/) adds your module and field names, and never asks for your API key. --- Source: https://beezr.io/developers/api/quickstart/ > Documentation index: https://beezr.io/developers/api/llms.txt # Quickstart: your first call ## Get your key Create a key in Designer → Account settings → API Integration. Follow [the Designer API key guide](https://designer.beezr.io/docs/connect/api-keys/). Make `BEEZR_API_KEY` available in your server environment before running these samples. Never paste a real key into documentation or browser code. ## Find your names The module card shows the table name under the module name. Open the module's Fields page and copy each field's System name. These samples use `cm_equipment_requests_base`, `title` and `priority`; use the names from your own module. Use **Fill my values** to replace the host and module throughout the samples. ## Query your first page All calls use `Content-Type: application/json` and `X-API-Key`. This request returns a page of matching records. `id` always comes back, even if it isn't in `fields`. ```curl curl --fail-with-body --silent --show-error \ 'https://services.beezr.io/generic/api/v4/records/query' \ -H "X-API-Key: $BEEZR_API_KEY" \ -H 'Content-Type: application/json' \ --data '{ "module": "cm_equipment_requests_base", "fields": ["title","priority","needed_by"], "filters": {"and":[{"field":"priority","operator":"lte","value":2},{"field":"title","operator":"contains","value":"laptop"}]}, "sort": [{"field":"needed_by","direction":"asc"}], "limit": 20, "offset": 0 }' ``` A successful query returns `success: true`, an array in `data`, and `meta` with `total`, `limit`, `offset` and `returned`. Continue while `offset + returned < total`. ## Create your first record Send field System names as keys in `data`. Unknown fields are ignored; if none match, you get `INVALID_DATA`. Lookup, relation and user fields need an integer id. ```curl curl --fail-with-body --silent --show-error \ 'https://services.beezr.io/generic/api/v1/records/create' \ -H "X-API-Key: $BEEZR_API_KEY" \ -H 'Content-Type: application/json' \ --data '{ "module": "cm_equipment_requests_base", "data": {"title":"Laptop for new hire","priority":2} }' ``` A successful create returns HTTP 201 and the created record in `data`. Keep its integer `id` for later changes. Add an `Idempotency-Key` when retrying the same create; see [Safe retries](/developers/api/idempotency/). ## If your call fails For `AUTHENTICATION_FAILED`, check that the key exists and isn't paused. For `MODULE_NOT_FOUND`, copy the module's table name again. For `INVALID_FILTER`, use field System names and a supported operator. [Errors](/developers/api/errors/) lists the fixes. --- Source: https://beezr.io/developers/api/authentication/ > Documentation index: https://beezr.io/developers/api/llms.txt # Authentication ## Send the key Every endpoint requires `X-API-Key`. All requests are POST with a JSON body and `Content-Type: application/json`. ```curl -H "X-API-Key: $BEEZR_API_KEY" \ -H "Content-Type: application/json" ``` Create keys in Designer → Account settings → API Integration. See [Create and manage API keys](https://designer.beezr.io/docs/connect/api-keys/). ## Keep keys server-side A key acts for the whole workspace, across every module. Keep it on your server. Never put it in a browser or mobile app. Use one key per system so you can pause a system's key without replacing another system's key. If you suspect a key has leaked, pause it in the Designer. Paused and deleted keys return HTTP 401. ## Recognize an authentication failure ```json {"success":false,"error":{"code":"AUTHENTICATION_FAILED","message":"Invalid or missing API key"}} ``` HTTP 401 means the key is missing, invalid or paused. Check the environment variable and header before trying again. Changing a filter or module name won't fix authentication. Workspace limits are shared across keys. Creating another key does not give that workspace another request allowance. See [Limits](/developers/api/limits/). --- Source: https://beezr.io/developers/api/names/ > Documentation index: https://beezr.io/developers/api/llms.txt # Find your module and field names ## Find the module table name In the Designer, look at the module card. Its table name sits under the module name. Send that table name as `module`, for example `cm_equipment_requests_base`. The display name isn't the table name. If a call returns `MODULE_NOT_FOUND`, copy the table name again. ## Find field System names Open Designer → module → Fields. Copy the field's **System name**. Use these names in `data`, `fields`, `filters` and `sort`. For example, a field may use `needed_by`. Unknown field names in write `data` are ignored. If no fields match, the API returns `INVALID_DATA`. An invalid filter field returns `INVALID_FILTER`; if no sort field is valid, the API returns `INVALID_SORT`. ## Find a record id The record's `id` is an integer: the value of the module's key field. Query and get return `id`; keep it for update, delete and file downloads. ## Hand the names to your assistant To hand these names to an AI assistant, paste them into [Brief your AI assistant](/developers/api/build-with-ai/), with field types if you have them. Don't include an API key. --- Source: https://beezr.io/developers/api/records/ > Documentation index: https://beezr.io/developers/api/llms.txt # Records and field values ## Send only the fields you need `data` is an object keyed by field System name. Create returns the record id plus the fields sent. Update changes only the fields you send and returns the re-read record. If that re-read fails, update returns only the id. Unknown field names are ignored. When none of the fields match the module, the call returns HTTP 400 `INVALID_DATA`. Business rules still apply; read `error.message` if a write fails. ## Values by field type | Field type | How to send | How it comes back | |---|---|---| | Text and other text-valued fields | Text | Stored value as text | | Lookup | Integer id; `5` and `"5"` work | As shown in the Designer; confirm representation | | Relation (REL) | Integer id; `5` and `"5"` work | As shown in the Designer; confirm representation | | User | Integer id | As shown in the Designer; confirm representation | | INT, LONG | Integer id; `5` and `"5"` work | As shown in the Designer; confirm numeric representation | | Date | As shown in the Designer | As shown in the Designer | | Datetime | As shown in the Designer | As shown in the Designer | | Decimal | As shown in the Designer | As shown in the Designer | | Boolean | As shown in the Designer | As shown in the Designer | | CONTENT | One upload object | One file reference in v4 | | MULTI_CONTENT, MEDIA_IMG_GALLERY | Array of upload objects | Array of file references in v4 | `id` itself is always an integer. Other record fields are keyed by their System names. Don't infer their returned types from the input type. ## Upload object ```json {"fileName":"contract.pdf","contentType":"application/pdf","data":""} ``` Files are up to 10 MB each after decoding. `contentType` is informational; the extension comes from `fileName`. See [Files](/developers/api/files/). ## Bulk results need inspection Bulk create, update and delete process items separately, in order. These calls are not all-or-nothing. Inspect `failed` and `failures` before treating the batch as complete. Each batch accepts 1–100 items and counts as one request. --- Source: https://beezr.io/developers/api/filtering/ > Documentation index: https://beezr.io/developers/api/llms.txt # Filtering and sorting ## Choose fields and operators Use field System names from the module. A qualified `table.field` is accepted only if it matches the field's own table. Otherwise a filter returns `INVALID_FILTER`. | Operator | Meaning | Value | |---|---|---| | `eq` | Equal | One value | | `ne` | Not equal | One value | | `gt` | Greater than | One value | | `gte` | Greater than or equal | One value | | `lt` | Less than | One value | | `lte` | Less than or equal | One value | | `in` | In a set | Array | | `not_in` | Outside a set | Array | | `contains` | Contains text | Text | | `starts_with` | Starts with text | Text | | `ends_with` | Ends with text | Text | | `is_null` | Has no value | Omit `value` | | `is_not_null` | Has a value | Omit `value` | `contains`, `starts_with` and `ends_with` treat `%` and `_` literally. ## How conditions combine Conditions in `and` must all match. The conditions in `or` form one group, `(x OR y OR …)`, which is ANDed with the rest. Each entry in `groups` is built the same way, wrapped in brackets, and ANDed with the rest. So a filter is always an **AND of parts**, where each part is a condition or an OR-group of conditions. Groups can't be ORed with each other. ## Worked example 1 "status is Open **or** Pending, **and** amount over 1000": ```json { "and": [ {"field":"amount","operator":"gt","value":1000} ], "or": [ {"field":"status","operator":"eq","value":"Open"}, {"field":"status","operator":"eq","value":"Pending"} ] } ``` The same thing is shorter with `in`: `{"field":"status","operator":"in","value":["Open","Pending"]}`. ## Worked example 2 "priority 1 **or** (stage is Late **and** nobody is assigned)". This is `A OR (B AND C)`, which is the same as `(A OR B) AND (A OR C)`. Write it as two groups, each with an `or` list: ```json { "groups": [ { "or": [ {"field":"priority","operator":"eq","value":1}, {"field":"stage","operator":"eq","value":"Late"} ] }, { "or": [ {"field":"priority","operator":"eq","value":1}, {"field":"assigned_to","operator":"is_null"} ] } ] } ``` For anything more complex, run two queries and merge the results by `id`. ## Filter cookbook Use these as the `filters` object in a [query](/developers/api/reference/query-records/). Match field names to your module first. ### Priority is 1 ```json {"and":[{"field":"priority","operator":"eq","value":1}]} ``` ### Priority is at most 2 ```json {"and":[{"field":"priority","operator":"lte","value":2}]} ``` ### Title contains laptop ```json {"and":[{"field":"title","operator":"contains","value":"laptop"}]} ``` ### Title starts with Laptop ```json {"and":[{"field":"title","operator":"starts_with","value":"Laptop"}]} ``` ### Priority is 1 or 2 ```json {"and":[{"field":"priority","operator":"in","value":[1,2]}]} ``` ### Needed by has a value ```json {"and":[{"field":"needed_by","operator":"is_not_null"}]} ``` ## Sort your results Use module field names. `direction` is `asc` by default or `desc`. If no sort field is valid, the API returns `INVALID_SORT`. ```json {"sort":[{"field":"needed_by","direction":"asc"}]} ``` Sorting by a date field doesn't require sending a date value. For date, datetime, decimal and boolean filter values, use values as shown in the Designer. --- Source: https://beezr.io/developers/api/paging/ > Documentation index: https://beezr.io/developers/api/llms.txt # Paging through results ## Read the metadata `query` returns `data` as an array and `meta` with four fields. `meta` appears only on query responses. | Field | Meaning | |---|---| | `total` | Records that match | | `limit` | Page limit | | `offset` | Page offset | | `returned` | Records in this page | `limit` defaults to 20 and is clamped to 1–100. `offset` defaults to 0 and is never negative. There are more pages while `offset + returned < total`. Advance by `returned`, not by a guessed page size. ## Loop through pages These loops stop if the call fails or returns an empty page. Use [rate-limit handling](/developers/api/limits/) around each call in a running integration. Keep at most 2 calls in flight. ```curl # This shell loop uses Python to read JSON metadata. offset=0 while true; do body=$(printf '{"module":"cm_equipment_requests_base","fields":["title"],"limit":100,"offset":%s}' "$offset") response=$(curl --fail-with-body --silent --show-error \ "https://services.beezr.io/generic/api/v4/records/query" \ -H "X-API-Key: $BEEZR_API_KEY" -H "Content-Type: application/json" \ --data "$body") || break printf '%s\n' "$response" next=$(printf '%s' "$response" | python -c 'import json,sys; r=json.load(sys.stdin); m=r["meta"]; print(m["offset"]+m["returned"] if r["success"] and m["returned"] and m["offset"]+m["returned"]= total) break; } ``` ```python import os import requests offset = 0 while True: response = requests.post( "https://services.beezr.io/generic/api/v4/records/query", headers={"X-API-Key": os.environ["BEEZR_API_KEY"]}, json={"module": "cm_equipment_requests_base", "fields": ["title"], "limit": 100, "offset": offset}, ) response.raise_for_status() page = response.json() if not page["success"]: raise RuntimeError(page) print(page["data"]) meta = page["meta"] offset = meta["offset"] + meta["returned"] if not meta["returned"] or offset >= meta["total"]: break ``` ## Keep exports small Use `fields` to request only what you need. `id` always comes back. File fields in v4 are references, so a query doesn't include file bytes. Download files separately with [Download a file](/developers/api/reference/download-file/). The [export guide](/developers/api/guides-export/) puts these steps together. --- Source: https://beezr.io/developers/api/files/ > Documentation index: https://beezr.io/developers/api/llms.txt # Files ## Upload inside create or update A CONTENT field takes one upload object in `data`. MULTI_CONTENT and MEDIA_IMG_GALLERY fields take an array of upload objects. Use a field's System name, such as `contract_pdf`. ```json {"module":"cm_equipment_requests_base","data":{"title":"Laptop","contract_pdf":{"fileName":"contract.pdf","contentType":"application/pdf","data":""}}} ``` Send this body to create. For update, add the record `id` and send only the fields you want to change. Encode the file bytes as base64. Each file can be at most 10 MB after decoding. `contentType` is informational; the extension comes from `fileName`. If a file is rejected, the whole create or update stops with 400 and changes nothing: `INVALID_CONTENT_PAYLOAD` (the value isn't a file object, or an array for multi-file fields), `CONTENT_DECODE_FAILED` (`data` isn't valid base64) or `CONTENT_TOO_LARGE` (over 10 MB). The message names the field. In bulk calls, that item fails with the same message and the others carry on. To keep an existing file as it is during an update, leave its field out. ## Read file references Query and get on v4 return a reference for CONTENT fields and an array of references for MULTI_CONTENT or MEDIA_IMG_GALLERY fields. The reference carries `unstructuredId`, `fieldName`, `fileName`, `fileExtension`, `fileSize`, `module`, `objectId` and `context`. Use `fileExtension` exactly as returned. ## Download with the record id Take `unstructuredId` and `module` from the reference. Use the record's `id` as `objectId`, even if the reference has `objectId: 0`. ```curl curl --fail-with-body --silent --show-error \ 'https://services.beezr.io/generic/api/v4/records/content' \ -H "X-API-Key: $BEEZR_API_KEY" \ -H 'Content-Type: application/json' \ --data '{ "unstructuredId": "a1b2c3d4", "objectId": 482913, "unstructuredModel": {"module":"cm_equipment_requests_base"} }' \ --output contract.pdf ``` A successful call returns raw bytes, not a JSON envelope. Save the bytes to a file. A JSON error response must not be treated as a successful file download. ## Read download headers | Header | Meaning | |---|---| | `Content-Type` | `application/pdf`, `image/png`, `image/jpeg`, otherwise `application/octet-stream` | | `Content-Length` | Byte length | | `Content-Disposition` | `attachment; filename="..."` | | `X-Beezr-File-Name` | File name | | `X-Beezr-File-Extension` | Extension | Missing download fields return `MISSING_REQUIRED_FIELD`. If the file isn't attached to that record or bytes are unavailable, the response is `CONTENT_NOT_FOUND`. Files over 10 MB return `CONTENT_TOO_LARGE` on download. See [Attach and download a PDF](/developers/api/guides-pdf/). --- Source: https://beezr.io/developers/api/idempotency/ > Documentation index: https://beezr.io/developers/api/llms.txt # Safe retries (idempotency) ## Add an Idempotency-Key Create and update support `Idempotency-Key`: 1–128 visible ASCII characters. Keep the same key and the same body when you retry the same operation. Use a new key for a new operation. The same key with the same body returns the stored response with `Idempotency-Replayed: true`. Nothing runs twice. Keys are scoped per API key and operation: `records:create` or `records:update`. Bulk endpoints and delete don't support idempotency. Don't assume a repeated bulk create will be deduplicated. ## Handle conflicts | HTTP | Code | What to do | |---|---|---| | 400 | `INVALID_IDEMPOTENCY_KEY` | Send one key in the documented format, not two keys | | 409 | `IDEMPOTENCY_KEY_REUSED` | Don't change the body for an existing key; use a new key for a new operation | | 409 | `IDEMPOTENCY_IN_PROGRESS` | The first call is still running within 120 seconds; wait `Retry-After: 2` before checking again | | 409 | `IDEMPOTENCY_RESULT_UNKNOWN` | The first call crashed and its outcome is unknown; reconcile the record before starting another operation | Conflicts include `error.details` with `operation`, optional `recordId`, and `createdAt`. An unknown result isn't run again with the same key. ## Combine with rate-limit retries A 429 still needs a wait. Use `Retry-After` seconds for retryable rate limits, while keeping the idempotency key and body unchanged. For `MONTHLY_QUOTA_EXCEEDED`, stop until the 1st. See [Limits](/developers/api/limits/) for code in all three languages. --- Source: https://beezr.io/developers/api/limits/ > Documentation index: https://beezr.io/developers/api/llms.txt # Limits ## Limit layers These are the defaults. All workspace keys share the workspace limits. | Limit | Default | Scope | When exceeded | |---|---|---|---| | Requests per minute | 60 | Workspace | 429 `RATE_LIMIT_EXCEEDED`, `Retry-After` seconds | | Requests per hour | 2,000 | Workspace | 429 `RATE_LIMIT_EXCEEDED`, `Retry-After` | | Requests at the same time | 2 | Workspace | 429 `TOO_MANY_CONCURRENT_REQUESTS`, `Retry-After: 1` | | Requests per minute from one IP | 120 | Caller IP, before key check | 429 `RATE_LIMIT_EXCEEDED`, `Retry-After` | | Read calls per key | 1,000 per hour | Key, for query/get/content | 429 `RATE_LIMIT_EXCEEDED`, `X-RateLimit-Reset` | | Monthly API calls | Set by plan | Workspace, calendar month | 429 `MONTHLY_QUOTA_EXCEEDED` past 110% of allowance; resets on the 1st | | Records per bulk call | 100 | Request | 413 `PAYLOAD_TOO_LARGE` | | File size | 10 MB | File, upload and download | Upload: 400 `CONTENT_TOO_LARGE`; download: 413 `CONTENT_TOO_LARGE` | | Query page size | 1–100; default 20 | Query | Clamped, no error | A bulk call counts as one request for rate limits and the monthly count. If your integration needs higher limits, contact us. ## Decide when to retry All 429s are retryable after waiting, except `MONTHLY_QUOTA_EXCEEDED`: stop until the 1st of the next month. On other 429s, wait `Retry-After` seconds. For the per-key read window, `X-RateLimit-Reset` gives the reset time in epoch milliseconds. Keep at most 2 calls in flight. Batch writes with bulk endpoints and request only the fields you need. For create and update retries, keep the same [idempotency key](/developers/api/idempotency/) and body. ## Read the headers Read responses carry `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset` for the per-key hourly read limit. Write responses don't carry these headers. The per-key values don't describe the workspace minute limit. ## Retry code These helpers take an existing JSON request body. They bound retries, inspect the monthly error before waiting, and use the read reset header when Retry-After is absent. If neither wait header is present, they stop for the caller to inspect. A create or update caller must provide the same idempotency key on each attempt. Bulk calls don't support idempotency. ```curl # Bash helper; Python reads headers and JSON. Usage: beezr_post URL BODY [IDEMPOTENCY_KEY] beezr_post() ( url=$1; body=$2; key=${3:-} tmp=$(mktemp -d) trap 'rm -rf "$tmp"' EXIT extra=() [ -z "$key" ] || extra=(-H "Idempotency-Key: $key") for attempt in 1 2 3 4; do status=$(curl --silent --show-error -o "$tmp/body" -D "$tmp/headers" -w '%{http_code}' \ "$url" -H "X-API-Key: $BEEZR_API_KEY" -H "Content-Type: application/json" \ "${extra[@]}" --data "$body") || return 1 if [ "$status" != 429 ]; then cat "$tmp/body" [[ "$status" == 2* ]] && return 0 return 1 fi wait=$(python - "$tmp/body" "$tmp/headers" <<'PY' import json, sys, time with open(sys.argv[1]) as f: result = json.load(f) if result.get("error", {}).get("code") == "MONTHLY_QUOTA_EXCEEDED": sys.exit(1) with open(sys.argv[2]) as f: headers = dict(line.strip().split(": ", 1) for line in f if ": " in line) headers = {k.lower(): v for k, v in headers.items()} if "retry-after" in headers: print(max(0, float(headers["retry-after"]))) elif "x-ratelimit-reset" in headers: print(max(0, float(headers["x-ratelimit-reset"]) / 1000 - time.time())) else: sys.exit(1) PY ) || { cat "$tmp/body"; return 1; } [ "$attempt" -lt 4 ] || { cat "$tmp/body"; return 1; } sleep "$wait" done ) ``` ```javascript async function beezrPost(url, body, idempotencyKey) { const headers = { "X-API-Key": process.env.BEEZR_API_KEY, "Content-Type": "application/json" }; if (idempotencyKey) headers["Idempotency-Key"] = idempotencyKey; for (let attempt = 0; attempt < 4; attempt++) { const response = await fetch(url, { method: "POST", headers, body: JSON.stringify(body) }); const result = await response.json(); if (response.status !== 429) { if (!response.ok || !result.success) throw new Error(JSON.stringify(result)); return result; } if (result.error?.code === "MONTHLY_QUOTA_EXCEEDED" || attempt === 3) { throw new Error(JSON.stringify(result)); } const seconds = response.headers.get("Retry-After"); const reset = response.headers.get("X-RateLimit-Reset"); if (seconds === null && reset === null) throw new Error(JSON.stringify(result)); const wait = seconds !== null ? Number(seconds) * 1000 : Number(reset) - Date.now(); if (!Number.isFinite(wait)) throw new Error("Invalid retry header"); await new Promise(resolve => setTimeout(resolve, Math.max(0, wait))); } } ``` ```python import os import time import requests def beezr_post(url, body, idempotency_key=None): headers = {"X-API-Key": os.environ["BEEZR_API_KEY"]} if idempotency_key: headers["Idempotency-Key"] = idempotency_key for attempt in range(4): response = requests.post(url, headers=headers, json=body) result = response.json() if response.status_code != 429: response.raise_for_status() if not result.get("success"): raise RuntimeError(result) return result if result.get("error", {}).get("code") == "MONTHLY_QUOTA_EXCEEDED" or attempt == 3: raise RuntimeError(result) seconds = response.headers.get("Retry-After") reset = response.headers.get("X-RateLimit-Reset") if seconds is None and reset is None: raise RuntimeError(result) wait = float(seconds) if seconds is not None else float(reset) / 1000 - time.time() time.sleep(max(0, wait)) ``` ## Watch monthly usage Usage is visible in Designer → Usage (API calls) and Subscription. Emails go to the workspace alert address at 80% and 100% of allowance and when calls are blocked. See [Handle rate limits well](/developers/api/guides-limits/). --- Source: https://beezr.io/developers/api/errors/ > Documentation index: https://beezr.io/developers/api/llms.txt # Errors ## Read the error envelope ```json {"success":false,"error":{"code":"MODULE_NOT_FOUND","message":"...","details":null}} ``` `success: false` marks a failed JSON response. `error.code` is the machine-readable reason; `error.message` explains what happened. `details` is usually absent. Idempotency conflicts include operation details. A successful file download returns bytes instead of this envelope. ## Error codes | HTTP | Code | Meaning | How to fix | | --- | --- | --- | --- | | 400 | `MISSING_REQUIRED_FIELD` | A required body field is missing | Send the required module, data, ids or download fields. | | 400 | `INVALID_DATA` | No data fields match the module | Copy field System names from the Designer. | | 400 | `INVALID_FILTER` | Invalid filter field or operator | Use module field names and a supported operator. | | 400 | `INVALID_SORT` | No valid sort field | Use a field of the module. | | 400 | `INVALID_IDEMPOTENCY_KEY` | Bad idempotency header | Send one key: 1–128 visible ASCII characters. | | 400 | `KEY_FIELD_UNRESOLVED` | The module has no key field | Check the module key field in the Designer. | | 401 | `AUTHENTICATION_FAILED` | Missing, invalid or paused key | Check the server environment and X-API-Key header. | | 404 | `MODULE_NOT_FOUND` | Wrong module table name | Copy the table name under the module card name. | | 404 | `NOT_FOUND` | No record with that id | Check the record id used with get. | | 404 | `CONTENT_NOT_FOUND` | File not attached or bytes unavailable | Use the reference module and the record id. | | 409 | `IDEMPOTENCY_KEY_REUSED` | Same key, different body | Keep the body unchanged; use a new key for new work. | | 409 | `IDEMPOTENCY_IN_PROGRESS` | First call still running within 120 seconds | Wait Retry-After: 2 before checking again. | | 409 | `IDEMPOTENCY_RESULT_UNKNOWN` | The first outcome is unknown | Reconcile the record before starting new work. | | 413 | `PAYLOAD_TOO_LARGE` | More than 100 bulk items | Split the batch into at most 100 items. | | 400 | `INVALID_CONTENT_PAYLOAD` | A file field got something other than a file object | Send {"fileName", "data"}; multi-file fields take an array of them. | | 400 | `CONTENT_DECODE_FAILED` | File data is not valid base64 | Base64-encode the file bytes and send them as data. | | 400 · 413 | `CONTENT_TOO_LARGE` | File over 10 MB (400 on upload, 413 on download) | Keep each file within 10 MB. The message names the field. | | 429 | `RATE_LIMIT_EXCEEDED` | A rate limit was exceeded | Wait Retry-After seconds; use the read reset header where applicable. | | 429 | `TOO_MANY_CONCURRENT_REQUESTS` | Too many concurrent calls | Keep at most 2 in flight; wait Retry-After: 1. | | 429 | `MONTHLY_QUOTA_EXCEEDED` | Monthly allowance passed 110% | Stop retrying until the 1st. | | 409 · 422 · 500 | `CREATE_FAILED` | Refused or failed; error.message says why | 409: a record with this key already exists. 422: a workspace rule or plan limit refused it; fix the data, don't retry as is. 500: server problem; retry once. | | 409 · 422 · 500 | `UPDATE_FAILED` | Refused or failed; error.message says why | 409: a record with this key already exists. 422: a workspace rule or plan limit refused it; fix the data, don't retry as is. 500: server problem; retry once. | | 409 · 422 · 500 | `DELETE_FAILED` | Refused or failed; error.message says why | 409: a record with this key already exists. 422: a workspace rule or plan limit refused it; fix the data, don't retry as is. 500: server problem; retry once. | | 500 | `QUERY_FAILED` | The read failed | Retry once; contact us if it persists. | | 500 | `GET_FAILED` | The read failed | Retry once; contact us if it persists. | | 500 | `FIELD_LOAD_FAILED` | Server problem | Retry later. | | 500 | `INTERNAL_ERROR` | Server problem | Retry later. | ## Fix the cause before repeating a write Unknown field names in `data` are ignored. `INVALID_DATA` means none matched. Business rules can return `CREATE_FAILED`, `UPDATE_FAILED` or `DELETE_FAILED` with HTTP 500 today; read the message before repeating the operation. A 429 needs [limit-specific handling](/developers/api/limits/), and a 409 needs [idempotency conflict handling](/developers/api/idempotency/). Don't treat every non-200 response as permission to run a new create. --- Source: https://beezr.io/developers/api/reference/create-record/ > Documentation index: https://beezr.io/developers/api/llms.txt # Create a record `POST /api/v1/records/create` Creates one record in a module. Fields you don't send stay empty. Send an `Idempotency-Key` to make retries safe. ## Requirements | Requirement | Value | | --- | --- | | Auth | `X-API-Key` | | Counts as | 1 request | | Idempotency | supported | | Batch limit | n/a | | Files | up to 10 MB each | ## Headers | Parameter | Type | Presence | Description | | --- | --- | --- | --- | | `X-API-Key` | string | required | Read from your server environment. | | `Content-Type` | string | required | `application/json`. | | `Idempotency-Key` | string | optional | 1 to 128 visible ASCII characters. Repeat the same request with the same key and Beezr returns the first result instead of running it again (header `Idempotency-Replayed: true`). | ## Body parameters | Parameter | Type | Presence | Description | | --- | --- | --- | --- | | `module` | string | required | The module's table name, shown under the module name on its card in Beezr Designer (for example `cm_equipment_requests_base`). | | `data` | object | required | Field values keyed by each field's System name (Designer → module → Fields). Lookup, relation and user fields take the id of the chosen item. File fields take a FileUpload object (or an array for multi-file fields). Fields not in the module are ignored. | | `data..fileName` | string | required | — | | `data..contentType` | string | optional | Informational | | `data..data` | string | required | Base64 file bytes | ## Returns HTTP 201. Created. `data` is the new record. | Parameter | Type | Presence | Description | | --- | --- | --- | --- | | `success` | boolean | optional | — | | `data` | object | optional | A record. `id` is the record id; every other property is a field keyed by its System name. | | `data.id` | integer | optional | — | Field values come back in the same form the Designer shows them. ## Errors | HTTP | Code | What to do | | --- | --- | --- | | 400 | [`MISSING_REQUIRED_FIELD`](/developers/api/errors/#missing-required-field) | Send the required body fields. | | 400 | [`INVALID_DATA`](/developers/api/errors/#invalid-data) | Check field System names. | | 400 | [`INVALID_IDEMPOTENCY_KEY`](/developers/api/errors/#invalid-idempotency-key) | Send one visible ASCII key, 1–128 characters. | | 400 | [`KEY_FIELD_UNRESOLVED`](/developers/api/errors/#key-field-unresolved) | Check the module key field. | | 401 | [`AUTHENTICATION_FAILED`](/developers/api/errors/#authentication-failed) | Check the API key. | | 404 | [`MODULE_NOT_FOUND`](/developers/api/errors/#module-not-found) | Copy the module table name. | | 409 | [`IDEMPOTENCY_KEY_REUSED`](/developers/api/errors/#idempotency-key-reused) | Keep the original body. | | 409 | [`IDEMPOTENCY_IN_PROGRESS`](/developers/api/errors/#idempotency-in-progress) | Wait Retry-After: 2. | | 409 | [`IDEMPOTENCY_RESULT_UNKNOWN`](/developers/api/errors/#idempotency-result-unknown) | Reconcile before new work. | | 400 | [`INVALID_CONTENT_PAYLOAD`](/developers/api/errors/#invalid-content-payload) | Send a file object with fileName and data. | | 400 | [`CONTENT_DECODE_FAILED`](/developers/api/errors/#content-decode-failed) | Send valid base64 in data. | | 400 · 413 | [`CONTENT_TOO_LARGE`](/developers/api/errors/#content-too-large) | Keep files within 10 MB. | | 429 | [`RATE_LIMIT_EXCEEDED`](/developers/api/errors/#rate-limit-exceeded) | Wait for the rate-limit reset. | | 429 | [`TOO_MANY_CONCURRENT_REQUESTS`](/developers/api/errors/#too-many-concurrent-requests) | Wait; keep at most 2 in flight. | | 429 | [`MONTHLY_QUOTA_EXCEEDED`](/developers/api/errors/#monthly-quota-exceeded) | Stop retries until the 1st. | | 409 · 422 · 500 | [`CREATE_FAILED`](/developers/api/errors/#create-failed) | 409 duplicate key · 422 rule or plan limit, fix the data · 500 retry once. | | 500 | [`FIELD_LOAD_FAILED`](/developers/api/errors/#field-load-failed) | Retry later. | | 500 | [`INTERNAL_ERROR`](/developers/api/errors/#internal-error) | Retry later. | ## Request ```curl curl --fail-with-body --silent --show-error \ 'https://services.beezr.io/generic/api/v1/records/create' \ -H "X-API-Key: $BEEZR_API_KEY" \ -H 'Content-Type: application/json' \ --data '{ "module": "cm_equipment_requests_base", "data": {"title":"Laptop for new hire","priority":2} }' ``` ```javascript const response = await fetch("https://services.beezr.io/generic/api/v1/records/create", { method: "POST", headers: { "X-API-Key": process.env.BEEZR_API_KEY, "Content-Type": "application/json" }, body: JSON.stringify({ "module": "cm_equipment_requests_base", "data": {"title":"Laptop for new hire","priority":2} }) }); if (!response.ok) throw new Error(await response.text()); console.log(await response.json()); ``` ```python import os import requests response = requests.post( "https://services.beezr.io/generic/api/v1/records/create", headers={"X-API-Key": os.environ["BEEZR_API_KEY"]}, json={ "module": "cm_equipment_requests_base", "data": {"title":"Laptop for new hire","priority":2} } ) response.raise_for_status() print(response.json()) ``` ## Success response ```json { "success": true, "data": {"id":482913,"title":"Laptop for new hire"} } ``` ## Common error ```json {"success":false,"error":{"code":"AUTHENTICATION_FAILED","message":"Invalid or missing API key"}} ``` --- Source: https://beezr.io/developers/api/reference/bulk-create-records/ > Documentation index: https://beezr.io/developers/api/llms.txt # Create up to 100 records `POST /api/v1/records/bulk_create` Creates each record in order. Items succeed or fail independently; failed items are listed in `failures` with their index. ## Requirements | Requirement | Value | | --- | --- | | Auth | `X-API-Key` | | Counts as | 1 request | | Idempotency | not supported | | Batch limit | up to 100 | ## Headers | Parameter | Type | Presence | Description | | --- | --- | --- | --- | | `X-API-Key` | string | required | Read from your server environment. | | `Content-Type` | string | required | `application/json`. | ## Body parameters | Parameter | Type | Presence | Description | | --- | --- | --- | --- | | `module` | string | required | The module's table name, shown under the module name on its card in Beezr Designer (for example `cm_equipment_requests_base`). | | `dataList` | array of object | required | 1–100 items. | ## Returns HTTP 201. Processed. Check `failed` and `failures`. | Parameter | Type | Presence | Description | | --- | --- | --- | --- | | `success` | boolean | optional | — | | `data` | object | optional | — | | `data.total` | integer | optional | — | | `data.created` | integer | optional | — | | `data.failed` | integer | optional | — | | `data.records` | array of object | optional | — | | `data.records[].id` | integer | optional | — | | `data.failures` | array of object | optional | — | | `data.failures[].index` | integer | optional | Position in dataList (bulk create) | | `data.failures[].id` | integer | optional | Record id (bulk update and delete) | | `data.failures[].data` | object | optional | — | | `data.failures[].error` | string | optional | — | Field values come back in the same form the Designer shows them. ## Errors | HTTP | Code | What to do | | --- | --- | --- | | 400 | [`MISSING_REQUIRED_FIELD`](/developers/api/errors/#missing-required-field) | Send the required body fields. | | 400 | [`INVALID_DATA`](/developers/api/errors/#invalid-data) | Check field System names. | | 400 | [`KEY_FIELD_UNRESOLVED`](/developers/api/errors/#key-field-unresolved) | Check the module key field. | | 401 | [`AUTHENTICATION_FAILED`](/developers/api/errors/#authentication-failed) | Check the API key. | | 404 | [`MODULE_NOT_FOUND`](/developers/api/errors/#module-not-found) | Copy the module table name. | | 413 | [`PAYLOAD_TOO_LARGE`](/developers/api/errors/#payload-too-large) | Send at most 100 items. | | 429 | [`RATE_LIMIT_EXCEEDED`](/developers/api/errors/#rate-limit-exceeded) | Wait for the rate-limit reset. | | 429 | [`TOO_MANY_CONCURRENT_REQUESTS`](/developers/api/errors/#too-many-concurrent-requests) | Wait; keep at most 2 in flight. | | 429 | [`MONTHLY_QUOTA_EXCEEDED`](/developers/api/errors/#monthly-quota-exceeded) | Stop retries until the 1st. | | 500 | [`FIELD_LOAD_FAILED`](/developers/api/errors/#field-load-failed) | Retry later. | | 500 | [`INTERNAL_ERROR`](/developers/api/errors/#internal-error) | Retry later. | ## Request ```curl curl --fail-with-body --silent --show-error \ 'https://services.beezr.io/generic/api/v1/records/bulk_create' \ -H "X-API-Key: $BEEZR_API_KEY" \ -H 'Content-Type: application/json' \ --data '{ "module": "cm_equipment_requests_base", "dataList": [{"title":"Laptop","priority":2},{"title":"Monitor","priority":3}] }' ``` ```javascript const response = await fetch("https://services.beezr.io/generic/api/v1/records/bulk_create", { method: "POST", headers: { "X-API-Key": process.env.BEEZR_API_KEY, "Content-Type": "application/json" }, body: JSON.stringify({ "module": "cm_equipment_requests_base", "dataList": [{"title":"Laptop","priority":2},{"title":"Monitor","priority":3}] }) }); if (!response.ok) throw new Error(await response.text()); console.log(await response.json()); ``` ```python import os import requests response = requests.post( "https://services.beezr.io/generic/api/v1/records/bulk_create", headers={"X-API-Key": os.environ["BEEZR_API_KEY"]}, json={ "module": "cm_equipment_requests_base", "dataList": [{"title":"Laptop","priority":2},{"title":"Monitor","priority":3}] } ) response.raise_for_status() print(response.json()) ``` ## Success response ```json { "success": true, "data": {"total":2,"created":2,"failed":0,"records":[{"id":482913,"title":"Laptop"},{"id":482914,"title":"Monitor"}]} } ``` ## Common error ```json {"success":false,"error":{"code":"AUTHENTICATION_FAILED","message":"Invalid or missing API key"}} ``` --- Source: https://beezr.io/developers/api/reference/update-record/ > Documentation index: https://beezr.io/developers/api/llms.txt # Update a record `POST /api/v1/records/update` Changes only the fields you send. Returns the record as it is after the update. Send an `Idempotency-Key` to make retries safe. If the re-read fails, the result contains only the record id. ## Requirements | Requirement | Value | | --- | --- | | Auth | `X-API-Key` | | Counts as | 1 request | | Idempotency | supported | | Batch limit | n/a | | Files | up to 10 MB each | ## Headers | Parameter | Type | Presence | Description | | --- | --- | --- | --- | | `X-API-Key` | string | required | Read from your server environment. | | `Content-Type` | string | required | `application/json`. | | `Idempotency-Key` | string | optional | 1 to 128 visible ASCII characters. Repeat the same request with the same key and Beezr returns the first result instead of running it again (header `Idempotency-Replayed: true`). | ## Body parameters | Parameter | Type | Presence | Description | | --- | --- | --- | --- | | `module` | string | required | The module's table name, shown under the module name on its card in Beezr Designer (for example `cm_equipment_requests_base`). | | `id` | integer | required | Minimum 1. | | `data` | object | required | Field values keyed by each field's System name (Designer → module → Fields). Lookup, relation and user fields take the id of the chosen item. File fields take a FileUpload object (or an array for multi-file fields). Fields not in the module are ignored. | | `data..fileName` | string | required | — | | `data..contentType` | string | optional | Informational | | `data..data` | string | required | Base64 file bytes | ## Returns HTTP 200. Updated. `data` is the record after the update. | Parameter | Type | Presence | Description | | --- | --- | --- | --- | | `success` | boolean | optional | — | | `data` | object | optional | A record. `id` is the record id; every other property is a field keyed by its System name. | | `data.id` | integer | optional | — | Field values come back in the same form the Designer shows them. ## Errors | HTTP | Code | What to do | | --- | --- | --- | | 400 | [`MISSING_REQUIRED_FIELD`](/developers/api/errors/#missing-required-field) | Send the required body fields. | | 400 | [`INVALID_DATA`](/developers/api/errors/#invalid-data) | Check field System names. | | 400 | [`INVALID_IDEMPOTENCY_KEY`](/developers/api/errors/#invalid-idempotency-key) | Send one visible ASCII key, 1–128 characters. | | 400 | [`KEY_FIELD_UNRESOLVED`](/developers/api/errors/#key-field-unresolved) | Check the module key field. | | 401 | [`AUTHENTICATION_FAILED`](/developers/api/errors/#authentication-failed) | Check the API key. | | 404 | [`MODULE_NOT_FOUND`](/developers/api/errors/#module-not-found) | Copy the module table name. | | 409 | [`IDEMPOTENCY_KEY_REUSED`](/developers/api/errors/#idempotency-key-reused) | Keep the original body. | | 409 | [`IDEMPOTENCY_IN_PROGRESS`](/developers/api/errors/#idempotency-in-progress) | Wait Retry-After: 2. | | 409 | [`IDEMPOTENCY_RESULT_UNKNOWN`](/developers/api/errors/#idempotency-result-unknown) | Reconcile before new work. | | 400 | [`INVALID_CONTENT_PAYLOAD`](/developers/api/errors/#invalid-content-payload) | Send a file object with fileName and data. | | 400 | [`CONTENT_DECODE_FAILED`](/developers/api/errors/#content-decode-failed) | Send valid base64 in data. | | 400 · 413 | [`CONTENT_TOO_LARGE`](/developers/api/errors/#content-too-large) | Keep files within 10 MB. | | 429 | [`RATE_LIMIT_EXCEEDED`](/developers/api/errors/#rate-limit-exceeded) | Wait for the rate-limit reset. | | 429 | [`TOO_MANY_CONCURRENT_REQUESTS`](/developers/api/errors/#too-many-concurrent-requests) | Wait; keep at most 2 in flight. | | 429 | [`MONTHLY_QUOTA_EXCEEDED`](/developers/api/errors/#monthly-quota-exceeded) | Stop retries until the 1st. | | 409 · 422 · 500 | [`UPDATE_FAILED`](/developers/api/errors/#update-failed) | 409 duplicate key · 422 rule or plan limit, fix the data · 500 retry once. | | 500 | [`FIELD_LOAD_FAILED`](/developers/api/errors/#field-load-failed) | Retry later. | | 500 | [`INTERNAL_ERROR`](/developers/api/errors/#internal-error) | Retry later. | ## Request ```curl curl --fail-with-body --silent --show-error \ 'https://services.beezr.io/generic/api/v1/records/update' \ -H "X-API-Key: $BEEZR_API_KEY" \ -H 'Content-Type: application/json' \ --data '{ "module": "cm_equipment_requests_base", "id": 482913, "data": {"priority":1} }' ``` ```javascript const response = await fetch("https://services.beezr.io/generic/api/v1/records/update", { method: "POST", headers: { "X-API-Key": process.env.BEEZR_API_KEY, "Content-Type": "application/json" }, body: JSON.stringify({ "module": "cm_equipment_requests_base", "id": 482913, "data": {"priority":1} }) }); if (!response.ok) throw new Error(await response.text()); console.log(await response.json()); ``` ```python import os import requests response = requests.post( "https://services.beezr.io/generic/api/v1/records/update", headers={"X-API-Key": os.environ["BEEZR_API_KEY"]}, json={ "module": "cm_equipment_requests_base", "id": 482913, "data": {"priority":1} } ) response.raise_for_status() print(response.json()) ``` ## Success response ```json { "success": true, "data": {"id":482913,"title":"Laptop"} } ``` ## Common error ```json {"success":false,"error":{"code":"AUTHENTICATION_FAILED","message":"Invalid or missing API key"}} ``` --- Source: https://beezr.io/developers/api/reference/bulk-update-records/ > Documentation index: https://beezr.io/developers/api/llms.txt # Update up to 100 records `POST /api/v1/records/bulk_update` Applies each update in order. Items succeed or fail independently; failed items are listed in `failures` with their id. ## Requirements | Requirement | Value | | --- | --- | | Auth | `X-API-Key` | | Counts as | 1 request | | Idempotency | not supported | | Batch limit | up to 100 | ## Headers | Parameter | Type | Presence | Description | | --- | --- | --- | --- | | `X-API-Key` | string | required | Read from your server environment. | | `Content-Type` | string | required | `application/json`. | ## Body parameters | Parameter | Type | Presence | Description | | --- | --- | --- | --- | | `module` | string | required | The module's table name, shown under the module name on its card in Beezr Designer (for example `cm_equipment_requests_base`). | | `updates` | array of object | required | 1–100 items. | | `updates[].id` | integer | required | Minimum 1. | | `updates[].data` | object | required | Field values keyed by each field's System name (Designer → module → Fields). Lookup, relation and user fields take the id of the chosen item. File fields take a FileUpload object (or an array for multi-file fields). Fields not in the module are ignored. | ## Returns HTTP 200. Processed. Check `failed` and `failures`. | Parameter | Type | Presence | Description | | --- | --- | --- | --- | | `success` | boolean | optional | — | | `data` | object | optional | — | | `data.total` | integer | optional | — | | `data.updated` | integer | optional | — | | `data.failed` | integer | optional | — | | `data.records` | array of object | optional | — | | `data.records[].id` | integer | optional | — | | `data.failures` | array of object | optional | — | | `data.failures[].index` | integer | optional | Position in dataList (bulk create) | | `data.failures[].id` | integer | optional | Record id (bulk update and delete) | | `data.failures[].data` | object | optional | — | | `data.failures[].error` | string | optional | — | Field values come back in the same form the Designer shows them. ## Errors | HTTP | Code | What to do | | --- | --- | --- | | 400 | [`MISSING_REQUIRED_FIELD`](/developers/api/errors/#missing-required-field) | Send the required body fields. | | 400 | [`INVALID_DATA`](/developers/api/errors/#invalid-data) | Check field System names. | | 400 | [`KEY_FIELD_UNRESOLVED`](/developers/api/errors/#key-field-unresolved) | Check the module key field. | | 401 | [`AUTHENTICATION_FAILED`](/developers/api/errors/#authentication-failed) | Check the API key. | | 404 | [`MODULE_NOT_FOUND`](/developers/api/errors/#module-not-found) | Copy the module table name. | | 413 | [`PAYLOAD_TOO_LARGE`](/developers/api/errors/#payload-too-large) | Send at most 100 items. | | 429 | [`RATE_LIMIT_EXCEEDED`](/developers/api/errors/#rate-limit-exceeded) | Wait for the rate-limit reset. | | 429 | [`TOO_MANY_CONCURRENT_REQUESTS`](/developers/api/errors/#too-many-concurrent-requests) | Wait; keep at most 2 in flight. | | 429 | [`MONTHLY_QUOTA_EXCEEDED`](/developers/api/errors/#monthly-quota-exceeded) | Stop retries until the 1st. | | 500 | [`FIELD_LOAD_FAILED`](/developers/api/errors/#field-load-failed) | Retry later. | | 500 | [`INTERNAL_ERROR`](/developers/api/errors/#internal-error) | Retry later. | ## Request ```curl curl --fail-with-body --silent --show-error \ 'https://services.beezr.io/generic/api/v1/records/bulk_update' \ -H "X-API-Key: $BEEZR_API_KEY" \ -H 'Content-Type: application/json' \ --data '{ "module": "cm_equipment_requests_base", "updates": [{"id":482913,"data":{"priority":1}},{"id":482914,"data":{"priority":1}}] }' ``` ```javascript const response = await fetch("https://services.beezr.io/generic/api/v1/records/bulk_update", { method: "POST", headers: { "X-API-Key": process.env.BEEZR_API_KEY, "Content-Type": "application/json" }, body: JSON.stringify({ "module": "cm_equipment_requests_base", "updates": [{"id":482913,"data":{"priority":1}},{"id":482914,"data":{"priority":1}}] }) }); if (!response.ok) throw new Error(await response.text()); console.log(await response.json()); ``` ```python import os import requests response = requests.post( "https://services.beezr.io/generic/api/v1/records/bulk_update", headers={"X-API-Key": os.environ["BEEZR_API_KEY"]}, json={ "module": "cm_equipment_requests_base", "updates": [{"id":482913,"data":{"priority":1}},{"id":482914,"data":{"priority":1}}] } ) response.raise_for_status() print(response.json()) ``` ## Success response ```json { "success": true, "data": {"total":2,"updated":2,"failed":0,"records":[{"id":482913},{"id":482914}]} } ``` ## Common error ```json {"success":false,"error":{"code":"AUTHENTICATION_FAILED","message":"Invalid or missing API key"}} ``` --- Source: https://beezr.io/developers/api/reference/delete-record/ > Documentation index: https://beezr.io/developers/api/llms.txt # Delete a record `POST /api/v1/records/delete` Delete a record. ## Requirements | Requirement | Value | | --- | --- | | Auth | `X-API-Key` | | Counts as | 1 request | | Idempotency | not supported | | Batch limit | n/a | ## Headers | Parameter | Type | Presence | Description | | --- | --- | --- | --- | | `X-API-Key` | string | required | Read from your server environment. | | `Content-Type` | string | required | `application/json`. | ## Body parameters | Parameter | Type | Presence | Description | | --- | --- | --- | --- | | `module` | string | required | The module's table name, shown under the module name on its card in Beezr Designer (for example `cm_equipment_requests_base`). | | `id` | integer | required | Minimum 1. | ## Returns HTTP 200. Deleted. | Parameter | Type | Presence | Description | | --- | --- | --- | --- | | `success` | boolean | optional | — | | `data` | object | optional | — | | `data.deleted` | boolean | optional | — | | `data.id` | integer | optional | — | ## Errors | HTTP | Code | What to do | | --- | --- | --- | | 400 | [`MISSING_REQUIRED_FIELD`](/developers/api/errors/#missing-required-field) | Send the required body fields. | | 400 | [`KEY_FIELD_UNRESOLVED`](/developers/api/errors/#key-field-unresolved) | Check the module key field. | | 401 | [`AUTHENTICATION_FAILED`](/developers/api/errors/#authentication-failed) | Check the API key. | | 404 | [`MODULE_NOT_FOUND`](/developers/api/errors/#module-not-found) | Copy the module table name. | | 429 | [`RATE_LIMIT_EXCEEDED`](/developers/api/errors/#rate-limit-exceeded) | Wait for the rate-limit reset. | | 429 | [`TOO_MANY_CONCURRENT_REQUESTS`](/developers/api/errors/#too-many-concurrent-requests) | Wait; keep at most 2 in flight. | | 429 | [`MONTHLY_QUOTA_EXCEEDED`](/developers/api/errors/#monthly-quota-exceeded) | Stop retries until the 1st. | | 409 · 422 · 500 | [`DELETE_FAILED`](/developers/api/errors/#delete-failed) | 422 a rule refused it · 500 retry once. | | 500 | [`FIELD_LOAD_FAILED`](/developers/api/errors/#field-load-failed) | Retry later. | | 500 | [`INTERNAL_ERROR`](/developers/api/errors/#internal-error) | Retry later. | ## Request ```curl curl --fail-with-body --silent --show-error \ 'https://services.beezr.io/generic/api/v1/records/delete' \ -H "X-API-Key: $BEEZR_API_KEY" \ -H 'Content-Type: application/json' \ --data '{ "module": "cm_equipment_requests_base", "id": 482913 }' ``` ```javascript const response = await fetch("https://services.beezr.io/generic/api/v1/records/delete", { method: "POST", headers: { "X-API-Key": process.env.BEEZR_API_KEY, "Content-Type": "application/json" }, body: JSON.stringify({ "module": "cm_equipment_requests_base", "id": 482913 }) }); if (!response.ok) throw new Error(await response.text()); console.log(await response.json()); ``` ```python import os import requests response = requests.post( "https://services.beezr.io/generic/api/v1/records/delete", headers={"X-API-Key": os.environ["BEEZR_API_KEY"]}, json={ "module": "cm_equipment_requests_base", "id": 482913 } ) response.raise_for_status() print(response.json()) ``` ## Success response ```json { "success": true, "data": { "deleted": true, "id": 482913 } } ``` ## Common error ```json {"success":false,"error":{"code":"AUTHENTICATION_FAILED","message":"Invalid or missing API key"}} ``` --- Source: https://beezr.io/developers/api/reference/bulk-delete-records/ > Documentation index: https://beezr.io/developers/api/llms.txt # Delete up to 100 records `POST /api/v1/records/bulk_delete` Deletes each record in order. Items succeed or fail independently. ## Requirements | Requirement | Value | | --- | --- | | Auth | `X-API-Key` | | Counts as | 1 request | | Idempotency | not supported | | Batch limit | up to 100 | ## Headers | Parameter | Type | Presence | Description | | --- | --- | --- | --- | | `X-API-Key` | string | required | Read from your server environment. | | `Content-Type` | string | required | `application/json`. | ## Body parameters | Parameter | Type | Presence | Description | | --- | --- | --- | --- | | `module` | string | required | The module's table name, shown under the module name on its card in Beezr Designer (for example `cm_equipment_requests_base`). | | `ids` | array of integer | required | 1–100 items. | ## Returns HTTP 200. Processed. Check `failed` and `failures`. | Parameter | Type | Presence | Description | | --- | --- | --- | --- | | `success` | boolean | optional | — | | `data` | object | optional | — | | `data.total` | integer | optional | — | | `data.deleted` | integer | optional | — | | `data.failed` | integer | optional | — | | `data.ids` | array of integer | optional | — | | `data.failures` | array of object | optional | — | | `data.failures[].index` | integer | optional | Position in dataList (bulk create) | | `data.failures[].id` | integer | optional | Record id (bulk update and delete) | | `data.failures[].data` | object | optional | — | | `data.failures[].error` | string | optional | — | ## Errors | HTTP | Code | What to do | | --- | --- | --- | | 400 | [`MISSING_REQUIRED_FIELD`](/developers/api/errors/#missing-required-field) | Send the required body fields. | | 400 | [`KEY_FIELD_UNRESOLVED`](/developers/api/errors/#key-field-unresolved) | Check the module key field. | | 401 | [`AUTHENTICATION_FAILED`](/developers/api/errors/#authentication-failed) | Check the API key. | | 404 | [`MODULE_NOT_FOUND`](/developers/api/errors/#module-not-found) | Copy the module table name. | | 413 | [`PAYLOAD_TOO_LARGE`](/developers/api/errors/#payload-too-large) | Send at most 100 items. | | 429 | [`RATE_LIMIT_EXCEEDED`](/developers/api/errors/#rate-limit-exceeded) | Wait for the rate-limit reset. | | 429 | [`TOO_MANY_CONCURRENT_REQUESTS`](/developers/api/errors/#too-many-concurrent-requests) | Wait; keep at most 2 in flight. | | 429 | [`MONTHLY_QUOTA_EXCEEDED`](/developers/api/errors/#monthly-quota-exceeded) | Stop retries until the 1st. | | 500 | [`FIELD_LOAD_FAILED`](/developers/api/errors/#field-load-failed) | Retry later. | | 500 | [`INTERNAL_ERROR`](/developers/api/errors/#internal-error) | Retry later. | ## Request ```curl curl --fail-with-body --silent --show-error \ 'https://services.beezr.io/generic/api/v1/records/bulk_delete' \ -H "X-API-Key: $BEEZR_API_KEY" \ -H 'Content-Type: application/json' \ --data '{ "module": "cm_equipment_requests_base", "ids": [482913,482914] }' ``` ```javascript const response = await fetch("https://services.beezr.io/generic/api/v1/records/bulk_delete", { method: "POST", headers: { "X-API-Key": process.env.BEEZR_API_KEY, "Content-Type": "application/json" }, body: JSON.stringify({ "module": "cm_equipment_requests_base", "ids": [482913,482914] }) }); if (!response.ok) throw new Error(await response.text()); console.log(await response.json()); ``` ```python import os import requests response = requests.post( "https://services.beezr.io/generic/api/v1/records/bulk_delete", headers={"X-API-Key": os.environ["BEEZR_API_KEY"]}, json={ "module": "cm_equipment_requests_base", "ids": [482913,482914] } ) response.raise_for_status() print(response.json()) ``` ## Success response ```json { "success": true, "data": {"total":2,"deleted":2,"failed":0,"ids":[482913,482914]} } ``` ## Common error ```json {"success":false,"error":{"code":"AUTHENTICATION_FAILED","message":"Invalid or missing API key"}} ``` --- Source: https://beezr.io/developers/api/reference/query-records/ > Documentation index: https://beezr.io/developers/api/llms.txt # Query records `POST /api/v4/records/query` Returns a page of records that match your filters, in the order you choose. Pages hold 1 to 100 records (default 20). There are more pages while `offset + returned < total`. File fields come back as references; download a file with `/api/v4/records/content`. ## Requirements | Requirement | Value | | --- | --- | | Auth | `X-API-Key` | | Counts as | 1 request | | Idempotency | not supported | | Batch limit | n/a | ## Headers | Parameter | Type | Presence | Description | | --- | --- | --- | --- | | `X-API-Key` | string | required | Read from your server environment. | | `Content-Type` | string | required | `application/json`. | ## Body parameters | Parameter | Type | Presence | Description | | --- | --- | --- | --- | | `module` | string | required | The module's table name, shown under the module name on its card in Beezr Designer (for example `cm_equipment_requests_base`). | | `fields` | array of string | optional | Return only these fields (id always comes back) | | `filters` | object | optional | `and`: every condition must match. `or`: at least one must match (the OR group is ANDed with the rest). `groups`: nested groups, each ANDed with the rest. | | `filters.and` | array of object | optional | — | | `filters.and[].field` | string | required | A field's System name | | `filters.and[].operator` | string | required | Values: eq, ne, gt, gte, lt, lte, in, not_in, contains, starts_with, ends_with, is_null, is_not_null. | | `filters.and[].value` | value | optional | Not used by is_null / is_not_null. An array for in / not_in. | | `filters.or` | array of object | optional | — | | `filters.or[].field` | string | required | A field's System name | | `filters.or[].operator` | string | required | Values: eq, ne, gt, gte, lt, lte, in, not_in, contains, starts_with, ends_with, is_null, is_not_null. | | `filters.or[].value` | value | optional | Not used by is_null / is_not_null. An array for in / not_in. | | `filters.groups` | array of object | optional | — | | `sort` | array of object | optional | — | | `sort[].field` | string | required | — | | `sort[].direction` | string | optional | Default asc. Values: asc, desc. | | `limit` | integer | optional | Values outside 1–100 are clamped Minimum 1. Maximum 100. Default 20. | | `offset` | integer | optional | Minimum 0. Default 0. | ## Returns HTTP 200. A page of records. | Parameter | Type | Presence | Description | | --- | --- | --- | --- | | `success` | boolean | optional | — | | `data` | array of object | optional | — | | `data[].id` | integer | optional | — | | `meta` | object | optional | — | | `meta.total` | integer | optional | Records that match | | `meta.limit` | integer | optional | — | | `meta.offset` | integer | optional | — | | `meta.returned` | integer | optional | Records in this page | Field values come back in the same form the Designer shows them. File fields contain references in v4. Read `fileExtension` as returned. ## Errors | HTTP | Code | What to do | | --- | --- | --- | | 400 | [`MISSING_REQUIRED_FIELD`](/developers/api/errors/#missing-required-field) | Send the required body fields. | | 400 | [`INVALID_FILTER`](/developers/api/errors/#invalid-filter) | Check fields and operators. | | 400 | [`INVALID_SORT`](/developers/api/errors/#invalid-sort) | Use a module field. | | 400 | [`KEY_FIELD_UNRESOLVED`](/developers/api/errors/#key-field-unresolved) | Check the module key field. | | 401 | [`AUTHENTICATION_FAILED`](/developers/api/errors/#authentication-failed) | Check the API key. | | 404 | [`MODULE_NOT_FOUND`](/developers/api/errors/#module-not-found) | Copy the module table name. | | 429 | [`RATE_LIMIT_EXCEEDED`](/developers/api/errors/#rate-limit-exceeded) | Wait for the rate-limit reset. | | 429 | [`TOO_MANY_CONCURRENT_REQUESTS`](/developers/api/errors/#too-many-concurrent-requests) | Wait; keep at most 2 in flight. | | 429 | [`MONTHLY_QUOTA_EXCEEDED`](/developers/api/errors/#monthly-quota-exceeded) | Stop retries until the 1st. | | 500 | [`QUERY_FAILED`](/developers/api/errors/#query-failed) | Check the data you sent, then retry once. | | 500 | [`FIELD_LOAD_FAILED`](/developers/api/errors/#field-load-failed) | Retry later. | | 500 | [`INTERNAL_ERROR`](/developers/api/errors/#internal-error) | Retry later. | ## Request ```curl curl --fail-with-body --silent --show-error \ 'https://services.beezr.io/generic/api/v4/records/query' \ -H "X-API-Key: $BEEZR_API_KEY" \ -H 'Content-Type: application/json' \ --data '{ "module": "cm_equipment_requests_base", "fields": ["title","priority","needed_by"], "filters": {"and":[{"field":"priority","operator":"lte","value":2},{"field":"title","operator":"contains","value":"laptop"}]}, "sort": [{"field":"needed_by","direction":"asc"}], "limit": 20, "offset": 0 }' ``` ```javascript const response = await fetch("https://services.beezr.io/generic/api/v4/records/query", { method: "POST", headers: { "X-API-Key": process.env.BEEZR_API_KEY, "Content-Type": "application/json" }, body: JSON.stringify({ "module": "cm_equipment_requests_base", "fields": ["title","priority","needed_by"], "filters": {"and":[{"field":"priority","operator":"lte","value":2},{"field":"title","operator":"contains","value":"laptop"}]}, "sort": [{"field":"needed_by","direction":"asc"}], "limit": 20, "offset": 0 }) }); if (!response.ok) throw new Error(await response.text()); console.log(await response.json()); ``` ```python import os import requests response = requests.post( "https://services.beezr.io/generic/api/v4/records/query", headers={"X-API-Key": os.environ["BEEZR_API_KEY"]}, json={ "module": "cm_equipment_requests_base", "fields": ["title","priority","needed_by"], "filters": {"and":[{"field":"priority","operator":"lte","value":2},{"field":"title","operator":"contains","value":"laptop"}]}, "sort": [{"field":"needed_by","direction":"asc"}], "limit": 20, "offset": 0 } ) response.raise_for_status() print(response.json()) ``` ## Success response ```json { "success": true, "data": [{"id":482913,"title":"laptop"}], "meta": {"total":1,"limit":20,"offset":0,"returned":1} } ``` ## Common error ```json {"success":false,"error":{"code":"AUTHENTICATION_FAILED","message":"Invalid or missing API key"}} ``` --- Source: https://beezr.io/developers/api/reference/get-record/ > Documentation index: https://beezr.io/developers/api/llms.txt # Get a record `POST /api/v4/records/get` Returns one record by its id. ## Requirements | Requirement | Value | | --- | --- | | Auth | `X-API-Key` | | Counts as | 1 request | | Idempotency | not supported | | Batch limit | n/a | ## Headers | Parameter | Type | Presence | Description | | --- | --- | --- | --- | | `X-API-Key` | string | required | Read from your server environment. | | `Content-Type` | string | required | `application/json`. | ## Body parameters | Parameter | Type | Presence | Description | | --- | --- | --- | --- | | `module` | string | required | The module's table name, shown under the module name on its card in Beezr Designer (for example `cm_equipment_requests_base`). | | `id` | integer | required | Minimum 1. | | `fields` | array of string | optional | Return only these fields (id always comes back) | ## Returns HTTP 200. The record. | Parameter | Type | Presence | Description | | --- | --- | --- | --- | | `success` | boolean | optional | — | | `data` | object | optional | A record. `id` is the record id; every other property is a field keyed by its System name. | | `data.id` | integer | optional | — | Field values come back in the same form the Designer shows them. File fields contain references in v4. Read `fileExtension` as returned. ## Errors | HTTP | Code | What to do | | --- | --- | --- | | 400 | [`MISSING_REQUIRED_FIELD`](/developers/api/errors/#missing-required-field) | Send the required body fields. | | 400 | [`KEY_FIELD_UNRESOLVED`](/developers/api/errors/#key-field-unresolved) | Check the module key field. | | 401 | [`AUTHENTICATION_FAILED`](/developers/api/errors/#authentication-failed) | Check the API key. | | 404 | [`MODULE_NOT_FOUND`](/developers/api/errors/#module-not-found) | Copy the module table name. | | 404 | [`NOT_FOUND`](/developers/api/errors/#not-found) | Check the record id. | | 429 | [`RATE_LIMIT_EXCEEDED`](/developers/api/errors/#rate-limit-exceeded) | Wait for the rate-limit reset. | | 429 | [`TOO_MANY_CONCURRENT_REQUESTS`](/developers/api/errors/#too-many-concurrent-requests) | Wait; keep at most 2 in flight. | | 429 | [`MONTHLY_QUOTA_EXCEEDED`](/developers/api/errors/#monthly-quota-exceeded) | Stop retries until the 1st. | | 500 | [`FIELD_LOAD_FAILED`](/developers/api/errors/#field-load-failed) | Retry later. | | 500 | [`INTERNAL_ERROR`](/developers/api/errors/#internal-error) | Retry later. | ## Request ```curl curl --fail-with-body --silent --show-error \ 'https://services.beezr.io/generic/api/v4/records/get' \ -H "X-API-Key: $BEEZR_API_KEY" \ -H 'Content-Type: application/json' \ --data '{ "module": "cm_equipment_requests_base", "id": 482913 }' ``` ```javascript const response = await fetch("https://services.beezr.io/generic/api/v4/records/get", { method: "POST", headers: { "X-API-Key": process.env.BEEZR_API_KEY, "Content-Type": "application/json" }, body: JSON.stringify({ "module": "cm_equipment_requests_base", "id": 482913 }) }); if (!response.ok) throw new Error(await response.text()); console.log(await response.json()); ``` ```python import os import requests response = requests.post( "https://services.beezr.io/generic/api/v4/records/get", headers={"X-API-Key": os.environ["BEEZR_API_KEY"]}, json={ "module": "cm_equipment_requests_base", "id": 482913 } ) response.raise_for_status() print(response.json()) ``` ## Success response ```json { "success": true, "data": {"id":482913,"title":"Laptop"} } ``` ## Common error ```json {"success":false,"error":{"code":"AUTHENTICATION_FAILED","message":"Invalid or missing API key"}} ``` --- Source: https://beezr.io/developers/api/reference/download-file/ > Documentation index: https://beezr.io/developers/api/llms.txt # Download a file `POST /api/v4/records/content` Returns the bytes of one file attached to a record. Take `unstructuredId` and `module` from the file reference in the record, and use the record's `id` as `objectId`. Files are up to 10 MB. ## Requirements | Requirement | Value | | --- | --- | | Auth | `X-API-Key` | | Counts as | 1 request | | Idempotency | not supported | | Batch limit | n/a | | Files | up to 10 MB each | ## Headers | Parameter | Type | Presence | Description | | --- | --- | --- | --- | | `X-API-Key` | string | required | Read from your server environment. | | `Content-Type` | string | required | `application/json`. | ## Body parameters | Parameter | Type | Presence | Description | | --- | --- | --- | --- | | `unstructuredId` | string | required | From the file reference | | `objectId` | integer | required | The record's id | | `unstructuredModel` | object | required | — | | `unstructuredModel.module` | string | required | From the file reference | ## Returns HTTP 200. The file bytes. Raw file bytes. Content-Type is application/pdf, image/png, image/jpeg, otherwise application/octet-stream. Headers include Content-Length, Content-Disposition, X-Beezr-File-Name and X-Beezr-File-Extension. ## Errors | HTTP | Code | What to do | | --- | --- | --- | | 400 | [`MISSING_REQUIRED_FIELD`](/developers/api/errors/#missing-required-field) | Send the required body fields. | | 401 | [`AUTHENTICATION_FAILED`](/developers/api/errors/#authentication-failed) | Check the API key. | | 404 | [`CONTENT_NOT_FOUND`](/developers/api/errors/#content-not-found) | Check the reference and record id. | | 400 · 413 | [`CONTENT_TOO_LARGE`](/developers/api/errors/#content-too-large) | Keep files within 10 MB. | | 429 | [`RATE_LIMIT_EXCEEDED`](/developers/api/errors/#rate-limit-exceeded) | Wait for the rate-limit reset. | | 429 | [`TOO_MANY_CONCURRENT_REQUESTS`](/developers/api/errors/#too-many-concurrent-requests) | Wait; keep at most 2 in flight. | | 429 | [`MONTHLY_QUOTA_EXCEEDED`](/developers/api/errors/#monthly-quota-exceeded) | Stop retries until the 1st. | | 500 | [`FIELD_LOAD_FAILED`](/developers/api/errors/#field-load-failed) | Retry later. | | 500 | [`INTERNAL_ERROR`](/developers/api/errors/#internal-error) | Retry later. | ## Request ```curl curl --fail-with-body --silent --show-error \ 'https://services.beezr.io/generic/api/v4/records/content' \ -H "X-API-Key: $BEEZR_API_KEY" \ -H 'Content-Type: application/json' \ --data '{ "unstructuredId": "a1b2c3d4", "objectId": 482913, "unstructuredModel": {"module":"cm_equipment_requests_base"} }' \ --output contract.pdf ``` ```javascript import { writeFile } from "node:fs/promises"; const response = await fetch("https://services.beezr.io/generic/api/v4/records/content", { method: "POST", headers: { "X-API-Key": process.env.BEEZR_API_KEY, "Content-Type": "application/json" }, body: JSON.stringify({ "unstructuredId": "a1b2c3d4", "objectId": 482913, "unstructuredModel": {"module":"cm_equipment_requests_base"} }) }); if (!response.ok) throw new Error(await response.text()); await writeFile("contract.pdf", Buffer.from(await response.arrayBuffer())); ``` ```python import os import requests response = requests.post( "https://services.beezr.io/generic/api/v4/records/content", headers={"X-API-Key": os.environ["BEEZR_API_KEY"]}, json={ "unstructuredId": "a1b2c3d4", "objectId": 482913, "unstructuredModel": {"module":"cm_equipment_requests_base"} } ) response.raise_for_status() with open("contract.pdf", "wb") as output: output.write(response.content) ``` ## Success response ```text HTTP 200 Content-Type: application/pdf Content-Disposition: attachment; filename="contract.pdf" ``` ## Common error ```json {"success":false,"error":{"code":"AUTHENTICATION_FAILED","message":"Invalid or missing API key"}} ``` --- Source: https://beezr.io/developers/api/guides-export/ > Documentation index: https://beezr.io/developers/api/llms.txt # Export every record ## Choose the module and fields Copy your module table name and field System names from the Designer. Use `fields` to keep each result small; the integer `id` always comes back. ## Query a page Use v4 query. Set `limit` up to 100 and begin with `offset: 0`. Read the returned `data` array and save each record to your destination. File fields contain references instead of bytes. ```json {"module":"cm_equipment_requests_base","fields":["title"],"limit":100,"offset":0} ``` ## Continue while there are records Keep reading while `offset + returned < total`. Advance `offset` by the returned count. Stop on an empty page or an error so a failed request doesn't become an endless loop. The [paging loops](/developers/api/paging/) provide cURL, JavaScript and Python versions. ## Respect shared limits Keep at most 2 calls in flight across the workspace and wait after retryable 429s. Stop monthly-quota retries until the 1st. [Limits](/developers/api/limits/) includes retry helpers. ## Export attached files Use each record's `id` with the file reference's `unstructuredId` and `module` to [download its bytes](/developers/api/reference/download-file/). Don't use a reference's `objectId: 0`. Save the file only after a successful response. --- Source: https://beezr.io/developers/api/guides-sync/ > Documentation index: https://beezr.io/developers/api/llms.txt # Keep another system in sync ## Keep the names and ids Copy module and field System names from the Designer. Keep the Beezr record `id` alongside the corresponding record in your system so updates target the intended record. ## Make individual writes safe to retry For create and update, attach an `Idempotency-Key` and retain it with the exact request body until you know the result. The same key and body return the stored response. A changed body with the same key returns `IDEMPOTENCY_KEY_REUSED`. Use [Update a record](/developers/api/reference/update-record/) for copyable requests in cURL, JavaScript and Python. If the API reports `IDEMPOTENCY_RESULT_UNKNOWN`, reconcile the record before starting another write. Don't change keys to force an unknown operation to run again. ## Batch when you know the work Bulk create, update and delete handle 1–100 items per call and count as one request. Items run separately, in order. Inspect `failed` and `failures`; reconcile successes before resubmitting failed items. Bulk endpoints don't support idempotency, so don't blindly repeat an entire bulk create after an uncertain result. ```curl curl --fail-with-body --silent --show-error \ 'https://services.beezr.io/generic/api/v1/records/bulk_update' \ -H "X-API-Key: $BEEZR_API_KEY" \ -H 'Content-Type: application/json' \ --data '{ "module": "cm_equipment_requests_base", "updates": [{"id":482913,"data":{"priority":1}},{"id":482914,"data":{"priority":1}}] }' ``` ## Apply backpressure Keep at most 2 calls in flight. Wait `Retry-After` seconds on retryable 429s. Stop on `MONTHLY_QUOTA_EXCEEDED` until the 1st. Use the [retry helpers](/developers/api/limits/) and inspect business-rule messages before repeating HTTP 500 writes. ## Read back what you need Use v4 query or get with `fields` to keep reads small. Query returns pages; continue while `offset + returned < total`. See [Paging](/developers/api/paging/) and [Safe retries](/developers/api/idempotency/). --- Source: https://beezr.io/developers/api/guides-pdf/ > Documentation index: https://beezr.io/developers/api/llms.txt # Attach and download a PDF ## Prepare your field and file Copy the module table name and the CONTENT field's System name from the Designer. These examples use `contract_pdf`. Encode your PDF bytes as base64 and keep the decoded file at or below 10 MB. A larger file stops the request with 400 `CONTENT_TOO_LARGE`. ## Attach inside a write Send this as the create body. Replace `` with your encoded PDF; it is a placeholder, not file data. To attach it to an existing record, add its integer `id` and send the body to update. ```json {"module":"cm_equipment_requests_base","data":{"title":"Laptop","contract_pdf":{"fileName":"contract.pdf","contentType":"application/pdf","data":""}}} ``` For a multi-file field, wrap upload objects in an array. `contentType` is informational; the extension comes from `fileName`. Use an idempotency key on create or update if you need to retry the same write. ## Read the reference Call v4 get or query for the record and its file field. CONTENT returns one reference; multi-file fields return an array. Keep `unstructuredId` and `module` from the reference. ## Download the PDF Use the record's `id` for `objectId`. A reference can contain `objectId: 0`, which must not replace the record id. ```curl curl --fail-with-body --silent --show-error \ 'https://services.beezr.io/generic/api/v4/records/content' \ -H "X-API-Key: $BEEZR_API_KEY" \ -H 'Content-Type: application/json' \ --data '{ "unstructuredId": "a1b2c3d4", "objectId": 482913, "unstructuredModel": {"module":"cm_equipment_requests_base"} }' \ --output contract.pdf ``` A successful response is raw bytes. The samples save those bytes to `contract.pdf`. For errors, read the JSON envelope instead. `CONTENT_NOT_FOUND` means the file isn't attached to that record or the bytes are unavailable; `CONTENT_TOO_LARGE` means the download exceeds 10 MB. --- Source: https://beezr.io/developers/api/guides-limits/ > Documentation index: https://beezr.io/developers/api/llms.txt # Handle rate limits well ## Share a queue across the workspace Workspace keys share 60 requests per minute, 2,000 per hour and 2 concurrent requests. Use a queue with at most 2 in flight across your integration. Another key doesn't create another workspace allowance. ## Read the failure before scheduling a retry On HTTP 429, inspect `error.code`. `MONTHLY_QUOTA_EXCEEDED` is a stop condition until the 1st. Other 429s can be retried after waiting. Prefer `Retry-After` seconds. For the per-key read limit, `X-RateLimit-Reset` is epoch milliseconds. The [Limits page](/developers/api/limits/) has retry code in cURL, JavaScript and Python. If neither wait header is available, stop and inspect the response before scheduling more calls. ## Keep a retry the same operation A create or update retry should retain its `Idempotency-Key` and body. Check conflicts rather than choosing a new key to bypass them. Bulk endpoints don't support idempotency; inspect partial results and reconcile uncertain outcomes. ## Reduce the request count Bulk calls handle up to 100 items and count as one request. Request only the fields you need for reads. Download file bytes separately from v4 record references. ## Watch usage before the monthly boundary Read usage in Designer → Usage (API calls) and Subscription. Alerts go to the workspace alert address at 80%, 100% and when calls are blocked. If your integration needs higher limits, contact us. --- Source: https://beezr.io/developers/api/build-with-ai/ > Documentation index: https://beezr.io/developers/api/llms.txt # Brief your AI assistant ChatGPT and Claude write better integration code when they know two things: how the Beezr API works, and the names in your workspace. This page puts both into one brief you paste into the assistant. ## How it works 1. **Copy your names from the Designer.** Open your module: the table name is under its name on the module card, and each field's System name is on its Fields page. 2. **Paste them below.** We've filled in an example module, so you can see the brief it makes straight away. Replace it with yours. 3. **Give the brief to your assistant.** Copy it, or open it straight in Claude or ChatGPT, then say what you want built, for example "write a script that sends each new order from our shop into this module". Never put an API key in the brief. Your code reads the key from your server environment. ## Your module One field per line: the System name, then its type if you know it (`priority, INT`). Commas, tabs or wide spaces all work. Inputs: module table name, field rows (`system_name, type`) and one sentence describing what you are building. Output: API rules, your module and fields, create/query/update requests, limits and retry guidance. Use the interactive builder at https://beezr.io/developers/api/build-with-ai/. ## What the brief contains - How to call the API: the address, the key header, every endpoint and the response format. - Your module and fields, with how to send and read each type. - Ready create, filtered query and update requests that use your names. - The limits and when to retry. Check the requests before you run them, and replace sample values with real ones. For the complete documentation in one file, see [AI resources](/developers/api/ai-resources/). --- Source: https://beezr.io/developers/api/ai-resources/ > Documentation index: https://beezr.io/developers/api/llms.txt # Use the docs with AI ## Start with the index [llms.txt](/developers/api/llms.txt) lists the pages in navigation order, with descriptions and agent notes. [llms-full.txt](/developers/api/llms-full.txt) contains every page's Markdown in one document. ## Read one page as Markdown Every page has an `index.md` twin and a `.md` copy. Use the page actions to copy its full Markdown or open it in your assistant. Request and response examples are included. For the overview, use [index.md](/developers/api/index.md). ## Use the machine-readable spec Download [OpenAPI YAML](/developers/api/openapi.yaml) or [OpenAPI JSON](/developers/api/openapi.json). Use it with tools that read OpenAPI to inspect the request and response schemas. Writes use v1 paths; reads use v4. Authentication is always `X-API-Key` on the server. ## Add your workspace names To add your own module and field names, use [Brief your AI assistant](/developers/api/build-with-ai/). It combines the API rules with your names, ready requests, limits and retry rules. Send dates, numbers and yes/no values in the same form the Designer shows them.