Skip to main content
Technical Preview

Overview

Client-mode connectors for the Box Platform API that move plant files between the broker and Box. A typical flow writes a shift report, batch record or alarm snapshot as a JSON or CSV file into a plant folder, uploads today’s setpoint table as a new version of the same file, reads a recipe back when a line changes over, tags a batch record with metadata (line, batch, product, quality state) and releases it with a metadata update, finds files by metadata or by search, moves processed files to an archive folder, and shares a weekly report with a shared link. New files in an inbox folder can be picked up with a V2 webhook (needs a public HTTPS receiver) or by polling the user event stream with a stream position. Box serves uploads from a separate host, so the template file BoxRestApi.lot holds two connectors: The connectors carry 44 events (24 GET, 14 POST, 6 PUT; 18 writes, no delete). Topics use storage/box/<object>/<verb>; each response is published on <source topic>/response.
The template was checked against the Box OpenAPI spec (version 2024.0: host, method, path, path and required query parameters, required headers, request content type, and every example body, query and upload attribute against the request schema) and against a local mock of the API, upload and download hosts. Box checks the token before it connectors a request on api.box.com, so without a token every event answers 400 Malformed auth header (empty token) or 401 invalid_token (dummy token). On upload.box.com the two upload paths answered 401 while the same paths with a suffix answered 400 Invalid API request path. /oauth2/token was called live and rejected dummy client credentials and an unknown box_subject_type. Nothing has run with a real token yet, so the status stays blocked until an authenticated read and an upload pass.

Setup

  1. In the Box Developer Console, create a Platform App (Custom App) with Server Authentication (Client Credentials Grant). JWT server authentication works the same way, but the broker then needs a signed JWT assertion for each token request.
  2. Under App Access Level, keep App Access Only (the app works as its own service account) or pick App + Enterprise Access if it must act as a managed user. Under Application Scopes, enable Read all files and folders stored in Box and Write all files and folders stored in Box (root_readwrite), Manage webhooks (manage_webhook) for the webhook events, and Manage enterprise properties (manage_enterprise_properties) only if the broker reads enterprise metadata templates.
  3. Authorize the app in the Box Admin Console (free developer accounts authorize it automatically) and reauthorize it after every scope change.
  4. Note the Client ID and Client Secret (Configuration tab) and the Enterprise ID (General Settings). Keep them in broker secrets, for example BOX_CLIENT_ID, BOX_CLIENT_SECRET and BOX_ENTERPRISE_ID, and the current token in BOX_ACCESS_TOKEN. Inject them in a LoT action with GET SECRET.
  5. The service account has its own, empty root folder. Invite it (its login looks like AutomationUser_…@boxdevedition.com, returned by UserMe) as an Editor collaborator on the plant folders the broker should use, and use those folder ids in payloads.

Authentication

Every event except OAuthToken sends Authorization: Bearer <token> built from the access_token field of the payload:
Get the token with OAuthToken (storage/box/oauth/token/create). It sends no Authorization header; the client credentials travel in the form. Use box_subject_type enterprise with the enterprise id for the service account, or user with a user id for a managed user (needs App + Enterprise Access and Generate user access tokens):
Box answers with access_token and expires_in (about 3600 seconds). The Client Credentials Grant returns no refresh token, so request a new token before the old one expires. JWT apps send grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=<signed JWT>&client_id=...&client_secret=... instead.
The OAuthToken request carries the client secret and the response carries the access token. Restrict storage/box/oauth/# with ACLs, never retain those topics, and store the new token in the secret instead of passing it around on open topics.

Payloads

Send query as an empty string when you need no parameters; the connector then calls, for example, /2.0/users/me?. Use fields to keep responses small enough for MQTT.

Uploading files

Box takes uploads as multipart/form-data with two parts: attributes (JSON with name and, for a new file, parent.id) and then file. The attributes part must come first; otherwise Box answers 400 metadata_after_file_contents. The upload connector sets Content-Type: multipart/form-data; boundary=CorefluxBoxBoundary, so the payload field multipart must hold the whole body with that boundary and CRLF line ends:
As a JSON payload on storage/box/files/upload (build the string in a LoT action or on the publishing client; \r\n are the CRLF line ends):
Box answers 201 with a collection holding the new file (id, sha1, file_version). If a file with that name already exists in the folder, Box answers 409 item_name_in_use; upload a new version instead with FileVersionUpload (storage/box/files/versions/upload, same body, file_id in the payload, attributes with only name). Direct uploads accept up to 50 MB, but keep MQTT payloads small.

Examples

List a folder (storage/box/folders/items/list):
Read a recipe back on changeover (storage/box/files/download):
Box answers 302 with a short-lived dl.boxcloud.com link, which needs no token. The broker’s HTTP client must follow it to publish the file content. Keep downloads to text and JSON files that fit an MQTT message. Tag a batch record and release it later (storage/box/files/metadata/create, then storage/box/files/metadata/update with JSON Patch):
The test operation makes the update fail with 409 if somebody changed the value in the meantime. Find released batch records of line 2 (storage/box/metadata/query):
Archive a processed file instead of deleting it (storage/box/files/update):
Share a weekly report inside the company (storage/box/files/shared-link/add):
Watch an inbox folder for new files with a V2 webhook (storage/box/webhooks/create). The address must be HTTPS on port 443:
Or poll the event stream without a public endpoint (storage/box/events/list):
  1. Get the current position: {"access_token": "<token>", "query": "stream_position=now"} returns next_stream_position and no events.
  2. Ask for changes since then: {"access_token": "<token>", "query": "stream_type=changes&stream_position=<next_stream_position>&limit=100"}. Store the new next_stream_position after every call. Box may return an event more than once or out of order, so de-duplicate by event_id.

Events

Limits

  • Box allows about 1000 API requests per minute and 240 upload requests per minute per user, and 6 searches per second (60 per minute) per user. Above the limit it answers 429 with a retry-after header. Wait that long before you retry.
  • Direct uploads accept files up to 50 MB. Larger files need chunked upload sessions, which are not packaged.
  • FolderItemsList returns at most 1000 entries per page (use usemarker=true and marker), Search at most 200, EventsList at most 500.
  • One webhook per item and app, at most 1000 webhooks per app and user, HTTPS on port 443 only.
  • File versions are tracked on paid accounts only. Recent items cover the last 90 days or 1000 items.
  • Box indexes new and changed files with a delay, so Search may not find a file that was just uploaded. MetadataQuery and FolderItemsList see it right away.

Not packaged

  • Delete events on purpose: files, folders, trash (permanent delete), file versions, metadata instances, shared link removal, collaborations, comments, tasks and webhooks. Archive files with FileUpdate or FolderUpdate (move) instead.
  • Chunked upload sessions for files over 50 MB, the upload preflight check (OPTIONS /2.0/files/content), thumbnails, zip downloads and the long-poll real-time server (OPTIONS /2.0/events).
  • The As-User header (act on behalf of another user from an admin token); request a user token with box_subject_type=user instead. The If-Match / If-None-Match headers and the content-md5 upload header.
  • Collaboration create and update (granting access), users and groups administration, legal holds, retention, Shield, Sign, Box AI, Hubs, Doc Gen and enterprise events (admin_logs).
  • The webhook receiver. A receiver would be a separate ENABLE_SERVER REST_API connector on a public HTTPS address that checks BOX-SIGNATURE-PRIMARY / BOX-SIGNATURE-SECONDARY (HMAC-SHA256 of the body plus BOX-DELIVERY-TIMESTAMP with the app’s signature keys) and rejects old timestamps. EventsList covers the same need without a public endpoint.

Suggested branches

feat/rest-api-route-box for the broker template and feat/docs-rest-api-box for this page.
Last modified on October 21, 2026