# Create agents Source: https://developer.box.com/guides/ai-studio/ai-studio-agents/create-agents Create a custom AI agent using the Box AI Studio API. Box AI Studio is available only for Enterprise Advanced accounts. The `POST /2.0/ai_agents` endpoint creates a new custom AI agent with configurable capabilities for asking questions, generating text, or extracting metadata. ## Before you start Make sure you have completed the steps in Getting started with AI Studio to create a platform app and generate a developer token. ## Send a request ```typescript Node/TypeScript v10 theme={null} await client.aiStudio.createAiAgent({ name: agentName, accessState: 'enabled', ask: new AiStudioAgentAsk({ accessState: 'enabled', description: 'desc1' }), } satisfies CreateAiAgentInput); ``` ```python Python v10 theme={null} client.ai_studio.create_ai_agent( agent_name, "enabled", ask=AiStudioAgentAsk(access_state="enabled", description="desc1"), ) ``` ```cs .NET v10 theme={null} await client.AiStudio.CreateAiAgentAsync(requestBody: new CreateAiAgent(name: agentName, accessState: "enabled") { Ask = new AiStudioAgentAsk(accessState: "enabled", description: "desc1") }); ``` ```swift Swift v10 theme={null} try await client.aiStudio.createAiAgent(requestBody: CreateAiAgent(name: agentName, accessState: "enabled", ask: AiStudioAgentAsk(accessState: "enabled", description: "desc1"))) ``` ```java Java v10 theme={null} client.getAiStudio().createAiAgent(new CreateAiAgent.Builder(agentName, "enabled").ask(new AiStudioAgentAsk("enabled", "desc1")).build()) ``` ### Parameters To make a call, you must pass the following parameters. Mandatory parameters are in **bold**. | Parameter | Description | Example | | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | | **`type`** | The type of agent used to handle queries. | `ai_agent` | | **`name`** | The name of the AI Agent. | `My AI Agent` | | **`access_state`** | The state of the AI Agent. Value is one of `enabled` `disabled`. | `enabled` | | `icon_reference` | The icon reference of the AI Agent. It should have format of the URL `https://cdn01.boxcdn.net/app-assets/aistudio/avatars/` , where the possible values of `file_name` are: `logo_boxAi.png`,`logo_stamp.png`, `logo_legal.png`,`logo_finance.png`,`logo_config.png`,`logo_handshake.png` `logo_analytics.png`,`logo_classification.png`. | `https://cdn01.boxcdn.net/app-assets/aistudio/avatars/logo_analytics.svg` | | `allowed_entities` | List of allowed users or groups. | | | `ask` | The AI Agent to be used for ask. | `ask` | | `extract` | The AI Agent to be used for extraction. | | | `text_gen` | The AI agent used for generating text. | | # Delete AI agents Source: https://developer.box.com/guides/ai-studio/ai-studio-agents/delete-agents Permanently delete a custom AI agent using the Box AI Studio API. Box AI Studio is available only for Enterprise Advanced accounts. The `DELETE /2.0/ai_agents/{id}` endpoint permanently removes a custom AI agent. This action cannot be undone. ## Before you start Make sure you have completed the steps in Getting started with AI Studio to create a platform app and generate a developer token. ## Send a request ```sh cURL theme={null} curl -L DELETE "https://api.box.com/2.0/ai_agents/12345" \ -H 'Authorization: Bearer ' ``` ```typescript Node/TypeScript v10 theme={null} await client.aiStudio.deleteAiAgentById(createdAgent.id); ``` ```python Python v10 theme={null} client.ai_studio.delete_ai_agent_by_id(created_agent.id) ``` ```cs .NET v10 theme={null} await client.AiStudio.DeleteAiAgentByIdAsync(agentId: createdAgent.Id); ``` ```swift Swift v10 theme={null} try await client.aiStudio.deleteAiAgentById(agentId: createdAgent.id) ``` ```java Java v10 theme={null} client.getAiStudio().deleteAiAgentById(createdAgent.getId()) ``` ### Parameters To make a call, you must pass the following parameters. Mandatory parameters are in **bold**. | Parameter | Description | Example | | -------------- | ------------------------------ | ------- | | **`agent_id`** | The ID of the agent to delete. | `1234` | # Get AI agent by ID Source: https://developer.box.com/guides/ai-studio/ai-studio-agents/get-agent-id Retrieve a specific AI agent's configuration using the Box AI Studio API. Box AI Studio is available only for Enterprise Advanced accounts. The `GET /2.0/ai_agents/{id}` endpoint returns the configuration for a specific AI agent. ## Before you start Make sure you have completed the steps in Getting started with AI Studio to create a platform app and generate a developer token. ## Send a request ```sh cURL theme={null} curl -i -X GET "https://api.box.com/2.0/ai_agents/1234567890" \ -H "authorization: Bearer " ``` ```typescript Node/TypeScript v10 theme={null} await client.aiStudio.getAiAgentById(createdAgent.id, { queryParams: { fields: ['ask'] } satisfies GetAiAgentByIdQueryParams, } satisfies GetAiAgentByIdOptionalsInput); ``` ```python Python v10 theme={null} client.ai_studio.get_ai_agent_by_id(created_agent.id, fields=["ask"]) ``` ```cs .NET v10 theme={null} await client.AiStudio.GetAiAgentByIdAsync(agentId: createdAgent.Id, queryParams: new GetAiAgentByIdQueryParams() { Fields = Array.AsReadOnly(new [] {"ask"}) }); ``` ```swift Swift v10 theme={null} try await client.aiStudio.getAiAgentById(agentId: createdAgent.id, queryParams: GetAiAgentByIdQueryParams(fields: ["ask"])) ``` ```java Java v10 theme={null} client.getAiStudio().getAiAgentById(createdAgent.getId(), new GetAiAgentByIdQueryParams.Builder().fields(Arrays.asList("ask")).build()) ``` ### Parameters To make a call, you must pass the following parameters. Mandatory parameters are in **bold**. | Parameter | Description | Example | | -------------- | ------------------------------------- | ------- | | **`agent_id`** | The agent id to get. | `1234` | | `fields` | The fields to return in the response. | `ask` | # List agents Source: https://developer.box.com/guides/ai-studio/ai-studio-agents/get-agents List all AI agents in your enterprise using the Box AI Studio API. Box AI Studio is available only for Enterprise Advanced accounts. The `GET /2.0/ai_agents` endpoint lists all AI agents in your enterprise, with optional filters for mode, state, and fields. ## Before you start Make sure you have completed the steps in Getting started with AI Studio to create a platform app and generate a developer token. ## Send a request ```sh cURL theme={null} curl -i -X GET "https://api.box.com/2.0/ai_agents" \ -H "authorization: Bearer " ``` ```typescript Node/TypeScript v10 theme={null} await client.aiStudio.getAiAgents(); ``` ```python Python v10 theme={null} client.ai_studio.get_ai_agents() ``` ```csharp .NET v10 theme={null} await client.AiStudio.GetAiAgentsAsync(); ``` ```swift Swift v10 theme={null} try await client.aiStudio.getAiAgents() ``` ```java Java v10 theme={null} client.getAiStudio().getAiAgents() ``` ### Parameters To make a call, you can pass the following parameters. | Parameter | Description | Example | | --------------------- | ------------------------------------------------------------------------------------------------------------ | --------------------------------------------------- | | `mode` | The mode to filter the agent configuration to return. Possible values are: `ask`, `text_gen`, and `extract`. | `ask` | | `fields` | The fields to return in the response. Value is one of `ask`, `text_gen`, `extract`. | `ask` | | `agent_state` | The state of the agent to return. Value is one of `enabled`, `disabled`. | `enabled` | | `include_box_default` | Whether to include the Box default agents in the response. | `true` | | `limit` | The maximum number of items to return per page. | `1000` | | `marker` | Defines the position marker at which to begin returning results. | `JV9IRGZmieiBasejOG9yDCRNgd2ymoZIbjsxbJMjIs3kioVii` | # AI Studio agents Source: https://developer.box.com/guides/ai-studio/ai-studio-agents/index Create, list, update, and delete custom AI agents through the Box AI Studio API. Box AI Studio is available only for Enterprise Advanced accounts. The AI Studio API provides full CRUD operations for managing custom AI agents. Each agent can be configured with specific capabilities (`ask`, `text_gen`, `extract`), access controls, and custom instructions. `POST /2.0/ai_agents`: define a new agent with capabilities, access state, and allowed entities. `GET /2.0/ai_agents`: retrieve agents filtered by mode, state, or fields. `GET /2.0/ai_agents/{id}`: fetch a specific agent's configuration. `PUT /2.0/ai_agents/{id}`: modify an agent's name, state, or capabilities. `DELETE /2.0/ai_agents/{id}`: permanently remove an agent. # Update AI agents Source: https://developer.box.com/guides/ai-studio/ai-studio-agents/update-agents Update a custom AI agent's configuration using the Box AI Studio API. Box AI Studio is available only for Enterprise Advanced accounts. The `PUT /2.0/ai_agents/{id}` endpoint updates a custom AI agent's name, state, capabilities, or access controls. ## Before you start Make sure you have completed the steps in Getting started with AI Studio to create a platform app and generate a developer token. ## Send a request ```sh cURL theme={null} curl -i -X PUT "https://api.box.com/2.0/ai_agents/1234567890" \ -H "authorization: Bearer " ``` ```typescript Node/TypeScript v10 theme={null} await client.aiStudio.updateAiAgentById(createdAgent.id, { name: agentName, accessState: 'enabled', ask: new AiStudioAgentAsk({ accessState: 'disabled', description: 'desc2' }), } satisfies CreateAiAgentInput); ``` ```python Python v10 theme={null} client.ai_studio.update_ai_agent_by_id( created_agent.id, agent_name, "enabled", ask=AiStudioAgentAsk(access_state="disabled", description="desc2"), ) ``` ```cs .NET v10 theme={null} await client.AiStudio.UpdateAiAgentByIdAsync(agentId: createdAgent.Id, requestBody: new CreateAiAgent(name: agentName, accessState: "enabled") { Ask = new AiStudioAgentAsk(accessState: "disabled", description: "desc2") }); ``` ```swift Swift v10 theme={null} try await client.aiStudio.updateAiAgentById(agentId: createdAgent.id, requestBody: CreateAiAgent(name: agentName, accessState: "enabled", ask: AiStudioAgentAsk(accessState: "disabled", description: "desc2"))) ``` ```java Java v10 theme={null} client.getAiStudio().updateAiAgentById(createdAgent.getId(), new CreateAiAgent.Builder(agentName, "enabled").ask(new AiStudioAgentAsk("disabled", "desc2")).build()) ``` ### Parameters To make a call, you must pass the following parameters. Mandatory parameters are in **bold**. | Parameter | Description | Example | | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | | **`type`** | The type of agent used to handle queries. | \`\`\`\` | | **`name`** | The name of the AI Agent. | My AI Agent | | **`access_state`** | The state of the AI Agent. Value is one of `enabled` `disabled`. | `enabled` | | `icon_reference` | The icon reference of the AI Agent. It should have format of the URL `https://cdn01.boxcdn.net/app-assets/aistudio/avatars/`, where possible values of `file_name` are: `logo_boxAi.png`,`logo_stamp.png`,`logo_legal.png`,`logo_finance.png`,`logo_config.png`,`logo_handshake.png`,`logo_analytics.png`,`logo_classification.png` | `https://cdn01.boxcdn.net/app-assets/aistudio/avatars/logo_analytics.svg` | | `allowed_entities` | List of allowed users or groups. | | | `ask` | The AI Agent to be used for ask. | `ask` | | `extract` | The AI Agent to be used for extraction. | | | `text_gen` | The AI agent used for generating text. | | # Get started with AI Studio Source: https://developer.box.com/guides/ai-studio/getting-started-ai-studio Set up a platform app and authenticate to start creating custom AI agents with the Box AI Studio API. Box AI Studio is available only for Enterprise Advanced accounts. To create custom AI agents with AI Studio, you need a platform application with the Box AI scope enabled and a token to authenticate your API calls. The setup steps below are similar to the Box AI API prerequisites. If you have already completed those steps, confirm that the **Manage AI** scope is enabled and that your admin has enabled AI Studio, then skip ahead to [next steps](#next-steps). Create a platform application to make API calls. Follow the guide on creating platform apps. Ask a Box admin to enable AI Studio in the Admin Console. For admin instructions, see [Enabling Box AI Studio and Managing Agents][enable]. To interact with the Box AI API, add the `ai.readwrite` scope to your application. 1. Open your application in the Developer Console. 2. Go to **Configuration** > **Required Access Scopes** > **Content Actions**. 3. Select **Manage AI**. box ai scopes If you do not see the **Manage AI** option, contact your admin to grant access to the Box AI API. If you see the scope checked and grayed out, the app owner has it enabled but you cannot change the setting. Submit your app for authorization or enablement. If you are enabling Box AI for an existing application, you must re-authorize it. Generate a developer token to authenticate your requests. 1. Go to **Developer Console** > **My Platform Apps**. 2. Hover over a platform app and select the **Options menu** button (...) on the right. 3. Select **Generate Developer Token**. The token is automatically copied to your clipboard. A developer token is only valid for one hour. In production, use your app's configured authentication method (for example, OAuth 2.0 or Client Credentials Grant). For more details, see developer tokens. ## Next steps With your application configured and a token generated, you can start creating custom AI agents. Use cURL, Postman, or any of the Box SDKs to make API calls. Define a custom AI agent with specific capabilities and access controls. Retrieve all AI agents in your enterprise. [enable]: https://support.box.com/hc/en-us/articles/37228079461267-Enabling-Box-AI-Studio-and-Managing-Agents/#h_01JH9HAMP43YYN6VWM51QCK413 # Box AI Studio Source: https://developer.box.com/guides/ai-studio/index Create, manage, and deploy custom AI agents through the Box AI Studio API. Box AI Studio is available only for Enterprise Advanced accounts. Box AI Studio lets you create custom AI agents through the API. Unlike the standard Box AI API endpoints that use Box's default agent configurations, AI Studio agents let you define purpose-built agents with custom instructions, model selections, and access controls. For example, you can create an agent that acts as a compliance consultant -- answering questions about customer documentation with FedRAMP Moderate compliance in mind -- and restricts access to specific users or groups. ## Enabling Box AI Studio Enable Box AI Studio in the Admin Console to start creating agents. For admin instructions, see Enabling Box AI Studio and Managing Agents. Step-by-step instructions are available in the Get started with AI Studio guide. ## How Box AI Studio relates to Box AI | Feature | Box AI API | Box AI Studio | | ----------------- | ------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------- | | **Use case** | Provides endpoints for Q\&A, text generation, and metadata extraction against files in Box | Lets you create and manage custom AI agents with tailored behavior | | **Customization** | Override model and prompt per-request using the `ai_agent` parameter | Define persistent agent configurations with custom instructions, models, and access controls | | **Access** | Business plans and above | Enterprise Advanced only | | **API endpoints** | `POST /ai/ask`, `POST /ai/text_gen`, `POST /ai/extract`, `POST /ai/extract_structured` | `POST /ai_agents`, `GET /ai_agents`, `GET /ai_agents/{id}`, `PUT /ai_agents/{id}`, `DELETE /ai_agents/{id}` | ## Capabilities You can configure AI Studio agents for the following modes: | Mode | Parameter | Description | | ------------------- | ---------- | ----------------------------------------------- | | **Ask** | `ask` | Answer user questions about documents | | **Text generation** | `text_gen` | Generate text based on file content and prompts | | **Extraction** | `extract` | Extract metadata from documents | ai agent capabilities ## Get started Create a platform app, enable the AI scope, and generate credentials to start making AI Studio API calls. Use `POST /ai_agents` to create a custom AI agent with specific capabilities and access controls. Retrieve all AI agents in your enterprise, filtered by mode or state. Get, update, and delete agents by ID. For admin setup instructions, see [Enabling Box AI Studio and Managing Agents][ai-studio]. [ai-studio]: https://support.box.com/hc/en-us/articles/37228079461267-Enabling-Box-AI-Studio-and-Managing-Agents # Add content to Box Archive Source: https://developer.box.com/guides/archives/add-content To add content to an archive, you need to create it first. If you have not done this yet, use the Create Archive endpoint. ## Add file or folder to archive Use the `PUT /files/:id` API endpoint to add a file to an archive, or the `PUT /folders/:id` endpoint to add a folder. The `id` parameter is the ID of the file/folder you want to add to the archive. To specify the destination, use the `parent.id` parameter in the request body. This can be either an ID of an archive or the ID of a folder that is inside an archive. [Update parent id of file]: /reference/put-files-id/#param-parent-id # Box Archive Source: https://developer.box.com/guides/archives/index Box Archive is available only for Enterprise Advanced accounts. Box Archive allows you to create and manage archives. An archive is a folder dedicated to storing content that is redundant, outdated, or trivial. Content in an archive is owned by the enterprise, and it is not accessible to previous owner and collaborators. ## Archives are folders Archives are a special type of folders. Box Archive APIs allow you to create, list, update and delete archives. However, there are other APIs that also work with archives or with content within archives. For a full list of supported APIs, see the Supported APIs guide. ## Required scopes Before using any of the Box Archive APIs, make sure you can access [Box Archive in Admin Console][Box Archive in Admin Console]. Your Box Platform app must have the `GCM` and `Read and write all files and folders` scopes enabled. If you plan to only view archives and not modify them, use the `Read all files and folders` instead of the `Read and write all files and folders` scope. Additionally, to be able to assign storage policy to an archive during its creation, your enterprise must have access to the Box Zones feature and your app must have the `Manage users` scope. The `GCM` scope is not available in the Developer Console and needs to be enabled by contacting customer support. [Box Archive in Admin Console]: https://support.box.com/hc/en-us/p/Product_Page_2023?section-id=40168863437843 # Restore content from Box Archive Source: https://developer.box.com/guides/archives/restore-content This guide describes how to restore content that you archived by mistake. ## Restore file or folder from archive Use the `PUT /files/:id` API endpoint to restore a file from an archive, or the `PUT /folders/:id` endpoint to restore a folder from an archive. The `id` parameter is the ID of the file/folder you want to restore from an archive. To specify the destination, use the `parent.id` parameter in the request body. This is the ID of a folder (can be owned by any user) where you want to restore the file/folder. To restore a file/folder to user's root folder, use `0` as the `parent.id` value. Additionally, pass the ID of the user in the `parent.user_id` parameter in the request body. [Update parent id of file]: /reference/put-files-id/#param-parent-id [Update parent user id of file]: /reference/put-files-id/#param-parent-user_id # Supported APIs for Box Archive Source: https://developer.box.com/guides/archives/supported-apis The basic Box Archive APIs allow you to create, list, update and delete archives, but you can use other APIs to interact with an archive or its content. See the table below for the full list of those APIs. Those APIs require the `GCM` scope to be enabled in your application. This scope is not available in the Developer Console and needs to be enabled by contacting customer support. Additionally, some of the below APIs need to be enabled by contacting customer support to properly work with Box Archive. When contacting customer support, specify the user ID you plan to use those APIs with. | API Endpoint | Description | | ------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `POST /archives` | Create an archive. | | `GET /archives` | List all archives. | | `PUT /archives/:id` | Update an archive. | | `DELETE /archives/:id` | Delete an archive. | | `PUT /files/:id` | Add a file to an archive, restore a file from an archive, or move a file within/between archives. Other updates to the file are not allowed. Requires contacting customer support to enable. | | `PUT /folders/:id` | Add a folder to an archive, restore a folder from an archive, move a folder within/between archives, or rename and change the description of a folder in an archive. Other updates to the folder are not allowed. Requires contacting customer support to enable. | | `POST /files/content` | Upload a file to an archive or to a folder within an archive. Requires contacting customer support to enable. | | `GET /files/:id/content` | Download a file from an archive or from a folder within an archive. | | `POST /zip_downloads` | Download a zip file of an archive or of a folder within an archive. | | `POST /folders` | Create a folder within an archive. Requires contacting customer support to enable. | | `GET /files/:id` | Get details of a file within an archive. | | `GET /folders/:id` | Get details of an archive or of a folder within an archive. | | `GET /folders/:id/items` | List items within an archive or items in a folder within an archive. | | `POST /files/:id/copy` | Copy a file to an archive. | | `POST /folders/:id/copy` | Copy a folder to an archive. | | `DELETE /files/:id` | Permanently delete a file within an archive. | | `DELETE /folders/:id` | Permanently delete a folder within an archive. Requires contacting customer support to enable. | | `POST /files/:id/metadata/:scope/:template_key` | Create a metadata instance attached to a file within an archive. | | `GET /files/:id/metadata/:scope/:template_key` | View a metadata instance attached to a file within an archive. | | `GET /files/:id/metadata` | List all metadata instances attached to a file within an archive. | | `PUT /files/:id/metadata/:scope/:template_key` | Update a metadata instance attached to a file within an archive. | | `DELETE /files/:id/metadata/:scope/:template_key` | Delete a metadata instance attached to a file within an archive. | | `POST securityClassification` | Create a classification label for a file within an archive. | | `GET securityClassification` | View a classification label of a file within an archive. | | `PUT securityClassification` | Update a classification label for a file within an archive. | | `DELETE securityClassification` | Delete a classification label from a file within an archive. | # Override AI model configuration Source: https://developer.box.com/guides/box-ai/ai-agents/ai-agent-overrides Full ai_agent parameter reference with sample configurations and parameter details. The `ai_agent` configuration allows you to override the default AI model configuration. It is available for the following endpoints: * `POST ai/ask` * `POST ai/text_gen` * `POST ai/extract` * `POST ai/extract_structured` Use the `GET ai_agent_default` endpoint to fetch the default configuration before applying overrides. The override examples include: * Replacing the default AI model with a custom one based on your organization's needs. * Tweaking the base `prompt` to allow a more customized user experience. * Changing a parameter, such as `temperature`, to make the results more or less creative. ## Sample configuration A complete configuration for `ai/ask` is as follows: ```sh theme={null} { "type": "ai_agent_ask", "basic_text": { "llm_endpoint_params": { "type": "openai_params", "frequency_penalty": 1.5, "presence_penalty": 1.5, "stop": "<|im_end|>", "temperature": 0, "top_p": 1 }, "model": "azure__openai__gpt_4o_mini", "num_tokens_for_completion": 8400, "prompt_template": "It is `{current_date}`, consider these travel options `{content}` and answer the `{user_question}`.", "system_message": "You are a helpful travel assistant specialized in budget travel" }, "basic_text_multi": { "llm_endpoint_params": { "type": "openai_params", "frequency_penalty": 1.5, "presence_penalty": 1.5, "stop": "<|im_end|>", "temperature": 0, "top_p": 1 }, "model": "azure__openai__gpt_4o_mini", "num_tokens_for_completion": 8400, "prompt_template": "It is `{current_date}`, consider these travel options `{content}` and answer the `{user_question}`.", "system_message": "You are a helpful travel assistant specialized in budget travel" }, "long_text": { "embeddings": { "model": "openai__text_embedding_ada_002", "strategy": { "id": "basic", "num_tokens_per_chunk": 64 } }, "llm_endpoint_params": { "type": "openai_params", "frequency_penalty": 1.5, "presence_penalty": 1.5, "stop": "<|im_end|>", "temperature": 0, "top_p": 1 }, "model": "azure__openai__gpt_4o_mini", "num_tokens_for_completion": 8400, "prompt_template": "It is `{current_date}`, consider these travel options `{content}` and answer the `{user_question}`.", "system_message": "You are a helpful travel assistant specialized in budget travel" }, "long_text_multi": { "embeddings": { "model": "openai__text_embedding_ada_002", "strategy": { "id": "basic", "num_tokens_per_chunk": 64 } }, "llm_endpoint_params": { "type": "openai_params", "frequency_penalty": 1.5, "presence_penalty": 1.5, "stop": "<|im_end|>", "temperature": 0, "top_p": 1 }, "model": "azure__openai__gpt_4o_mini", "num_tokens_for_completion": 8400, "prompt_template": "It is `{current_date}`, consider these travel options `{content}` and answer the `{user_question}`.", "system_message": "You are a helpful travel assistant specialized in budget travel" } } ``` ### Differences in parameter sets The set of parameters available for `ask`, `text_gen`, `extract`, `extract_structured` differs slightly, depending on the API call. * The agent configuration for the `ask` endpoint includes `basic_text`, `basic_text_multi`, `long_text` and `long_text_multi` parameters. This is because of the `mode` parameter you use to specify if the request is for a single item or multiple items. If you selected `multiple_item_qa` as the `mode`, you can also use `multi` parameters for overrides. * The agent configuration for `text_gen` includes the `basic_gen` parameter that is used to generate text. ### LLM endpoint params The `llm_endpoint_params` configuration options differ depending on the overall AI model being Google, OpenAI or AWS based. For example, both `llm_endpoint_params` objects accept a `temperature` parameter, but the outcome differs depending on the model. For Google and AWS models, the [`temperature`][google-temp] is used for sampling during response generation, which occurs when `top-P` and `top-K` are applied. Temperature controls the degree of randomness in the token selection. For OpenAI models, [`temperature`][openai-temp] is the sampling temperature with values between 0 and 2. Higher values like 0.8 make the output more random, while lower values like 0.2 make it more focused and deterministic. When introducing your own configuration, use `temperature` or or `top_p` but not both. ### System message The `system_message` parameter's aim is to help the LLM understand its role and what it’s supposed to do. For example, if your solution is processing travel itineraries, you can add a system message saying: ```sh theme={null} You are a travel agent aid. You are going to help support staff process large amounts of schedules, tickets, etc. ``` This message is separate from the content you send in, but it can improve the results. ### Number of tokens for completion The `num_tokens_for_completion` parameter represents the number of [tokens][openai-tokens] Box AI can return. This number can vary based on the model used. [openai-tokens]: https://help.openai.com/en/articles/4936856-what-are-tokens-and-how-to-count-them [google-temp]: https://ai.google.dev/gemini-api/docs/models/generative-models#model-parameters [openai-temp]: https://community.openai.com/t/temperature-top-p-and-top-k-for-chatbot-responses/295542 # AI agent configuration versioning Source: https://developer.box.com/guides/box-ai/ai-agents/ai-agent-versioning See how Box versions AI agent snapshots, the 12-month support guarantee, and transition timelines. Box updates the default models across the endpoints on a regular basis in order to stay up to date with the most advanced options. If a default model is updated, it will be posted in the developer changelog. AI agent configuration versioning gives the developers more control over AI agent versioning and ensures consistent responses. AI agent configuration versioning adopts the following principles: * Each AI agent snapshot is supported for at least 12 months, unless there are factors outside of Box's control. For example, a Large Language Model (LLM) may get deprecated. * An AI agent snapshot is available unless a new, stable agent version is released * A 6-month window is provided to test and transition to the new snapshot. ## Historical AI agent configuration The values in the default agent configuration used by the LLM gateway often change to achieve the best possible answer quality. To make sure your configurations are not affected in a negative way, you can use the historical AI agent configuration provided below to override the default one. ``````json theme={null} { "ask": { "type": "ai_agent_ask", "longText": { "model": "azure__openai__gpt_4o_mini", "systemMessage": "", "promptTemplate": "Reply as if it's {current_date}.\nI will ask you for help and provide subsections of one document delimited by five backticks (`````) at the beginning and at the end.\nIf I make a reference to \"this\", I am referring to the document I provided between the five backticks. I may ask you a question where the answer is contained within the document. In that case, do your best to answer using only the document, but if you cannot, feel free to mention that you couldn't find an answer in the document, but you have some answer from your general knowledge.\nI may ask you to perform some kind of computation or symbol manipulation such as filtering a list, counting something, summing, averaging, and other aggregation/grouping functions or some combination of them. In these cases, first list the plan of how you plan to perform such a computation, then follow that plan step by step, keeping track of intermediate results, and at the end tell me the final answer.\nI may ask you to enumerate or somehow list people, places, characters, or other important things from the document, if I do so, please only use the document provided to list them.\nTEXT FROM DOCUMENT STARTS\n`````\n{content}\n`````\nTEXT FROM DOCUMENT ENDS\nNever mention five backticks in your response. Unless you are told otherwise, a one paragraph response is sufficient for any requested summarization tasks.\nHere is how I need help from you: {user_question}", "numTokensForCompletion": 6000, "llmEndpointParams": { "type": "openai_params", "temperature": 0.0, "topP": 1.0, "frequencyPenalty": 0.0, "presencePenalty": 1.5, "stop": "<|im_end|>" }, "embeddings": { "model": "azure__openai__text_embedding_ada_002", "strategy": { "id": "basic", "numTokensPerChunk": 64 } } }, "basicText": { "model": "azure__openai__gpt_4o_mini", "systemMessage": "", "promptTemplate": "Reply as if it's {current_date}.\nI will ask you for help and provide the entire text of one document delimited by five backticks (`````) at the beginning and at the end.\nIf I make a reference to \"this\", I am referring to the document I provided between the five backticks. I may ask you a question where the answer is contained within the document. In that case, do your best to answer using only the document, but if you cannot, feel free to mention that you couldn't find an answer in the document, but you have some answer from your general knowledge.\nI may ask you to perform some kind of computation or symbol manipulation such as filtering a list, counting something, summing, averaging, and other aggregation/grouping functions or some combination of them. In these cases, first list the plan of how you plan to perform such a computation, then follow that plan step by step, keeping track of intermediate results, and at the end tell me the final answer.\nI may ask you to enumerate or somehow list people, places, characters, or other important things from the document, if I do so, please only use the document provided to list them.\nTEXT FROM DOCUMENT STARTS\n`````\n{content}\n`````\nTEXT FROM DOCUMENT ENDS\nNever mention five backticks in your response. Unless you are told otherwise, a one paragraph response is sufficient for any requested summarization tasks.\nHere is how I need help from you: {user_question}", "numTokensForCompletion": 6000, "llmEndpointParams": { "type": "openai_params", "temperature": 0.0, "topP": 1.0, "frequencyPenalty": 0.0, "presencePenalty": 1.5, "stop": "<|im_end|>" } }, "longTextMulti": { "model": "azure__openai__gpt_4o_mini", "systemMessage": "Role and Goal: You are an assistant designed to analyze and answer a question based on provided snippets from multiple documents, which can include business-oriented documents like docs, presentations, PDFs, etc. The assistant will respond concisely, using only the information from the provided documents.\n\nConstraints: The assistant should avoid engaging in chatty or extensive conversational interactions and focus on providing direct answers. It should also avoid making assumptions or inferences not supported by the provided document snippets.\n\nGuidelines: When answering, the assistant should consider the file's name and path to assess relevance to the question. In cases of conflicting information from multiple documents, it should list the different answers with citations. For summarization or comparison tasks, it should concisely answer with the key points. It should also consider the current date to be the date given.\n\nPersonalization: The assistant's tone should be formal and to-the-point, suitable for handling business-related documents and queries.\n", "promptTemplate": "Current date: {current_date}\n\nTEXT FROM DOCUMENTS STARTS\n{content}\nTEXT FROM DOCUMENTS ENDS\n\nHere is how I need help from you: {user_question}\n.", "numTokensForCompletion": 6000, "llmEndpointParams": { "type": "openai_params", "temperature": 0.0, "topP": 1.0, "frequencyPenalty": 0.0, "presencePenalty": 1.5, "stop": "<|im_end|>" }, "embeddings": { "model": "azure__openai__text_embedding_ada_002", "strategy": { "id": "basic", "numTokensPerChunk": 64 } } }, "basicTextMulti": { "model": "azure__openai__gpt_4o_mini", "systemMessage": "", "promptTemplate": "Current date: {current_date}\n\nTEXT FROM DOCUMENTS STARTS\n{content}\nTEXT FROM DOCUMENTS ENDS\n\nHere is how I need help from you: {user_question}\n.", "numTokensForCompletion": 6000, "llmEndpointParams": { "type": "openai_params", "temperature": 0.0, "topP": 1.0, "frequencyPenalty": 0.0, "presencePenalty": 1.5, "stop": "<|im_end|>" } }, }, "extract": { "type": "ai_agent_extract", "longText": { "model": "google__gemini_1_5_flash_001", "systemMessage": "Respond only in valid json. You are extracting metadata that is name, value pairs from a document. Only output the metadata in valid json form, as {\"name1\":\"value1\",\"name2\":\"value2\"} and nothing else. You will be given the document data and the schema for the metadata, that defines the name, description and type of each of the fields you will be extracting. Schema is of the form {\"fields\": [{\"key\": \"key_name\", \"displayName\": \"key display name\", \"type\": \"string\", \"description\": \"key description\"}]}. Leverage key description and key display name to identify where the key and value pairs are in the document. In certain cases, key description can also indicate the instructions to perform on the document to obtain the value. Prompt will be in the form of Schema is ``schema`` \n document is ````document````", "promptTemplate": "If you need to know today's date to respond, it is {current_date}. Schema is ``{user_question}`` \n document is ````{content}````", "numTokensForCompletion": 4096, "llmEndpointParams": { "type": "google_params", "temperature": 0.0, "topP": 1.0, "frequencyPenalty": 0.0, "presencePenalty": 0.0 }, "embeddings": { "model": "azure__openai__text_embedding_ada_002", "strategy": { "id": "basic", "numTokensPerChunk": 64 } } }, "basicText": { "model": "google__gemini_1_5_flash_001", "systemMessage": "Respond only in valid json. You are extracting metadata that is name, value pairs from a document. Only output the metadata in valid json form, as {\"name1\":\"value1\",\"name2\":\"value2\"} and nothing else. You will be given the document data and the schema for the metadata, that defines the name, description and type of each of the fields you will be extracting. Schema is of the form {\"fields\": [{\"key\": \"key_name\", \"displayName\": \"key display name\", \"type\": \"string\", \"description\": \"key description\"}]}. Leverage key description and key display name to identify where the key and value pairs are in the document. In certain cases, key description can also indicate the instructions to perform on the document to obtain the value. Prompt will be in the form of Schema is ``schema`` \n document is ````document````", "promptTemplate": "If you need to know today's date to respond, it is {current_date}. Schema is ``{user_question}`` \n document is ````{content}````", "numTokensForCompletion": 4096, "llmEndpointParams": { "type": "google_params", "temperature": 0.0, "topP": 1.0, "frequencyPenalty": 0.0, "presencePenalty": 0.0 } } }, "textGen": { "type": "ai_agent_text_gen", "basicGen": { "model": "azure__openai__gpt_4o_mini", "systemMessage": "\nIf you need to know today's date to respond, it is {current_date}.\nThe user is working in a collaborative document creation editor called Box Notes.\nAssume that you are helping a business user create documents or to help the user revise existing text.\nYou can help the user in creating templates to be reused or update existing documents, you can respond with text that the user can use to place in the document that the user is editing.\nIf the user simply asks to \"improve\" the text, then simplify the language and remove jargon, unless the user specifies otherwise.\nDo not open with a preamble to the response, just respond.\n", "promptTemplate": "{user_question}", "numTokensForCompletion": 12000, "llmEndpointParams": { "type": "openai_params", "temperature": 0.1, "topP": 1.0, "frequencyPenalty": 0.75, "presencePenalty": 0.75, "stop": "<|im_end|>" }, "embeddings": { "model": "azure__openai__text_embedding_ada_002", "strategy": { "id": "basic", "numTokensPerChunk": 64 } }, "contentTemplate": "`````{content}`````" } }, "extractStructured": { "type": "ai_agent_extract_structured", "longText": { "model": "google__gemini_1_5_flash_001", "systemMessage": "Respond only in valid json. You are extracting metadata that is name, value pairs from a document. Only output the metadata in valid json form, as {\"name1\":\"value1\",\"name2\":\"value2\"} and nothing else. You will be given the document data and the schema for the metadata, that defines the name, description and type of each of the fields you will be extracting. Schema is of the form {\"fields\": [{\"key\": \"key_name\", \"prompt\": \"prompt to extract the value\", \"type\": \"date\"}]}. Leverage prompt for each key to identify where the key and value pairs are in the document. In certain cases, prompt can also indicate the instructions to perform on the document to obtain the value. Prompt will be in the form of Schema is ``schema`` \n document is ````document````", "promptTemplate": "If you need to know today's date to respond, it is {current_date}. Schema is ``{user_question}`` \n document is ````{content}````", "numTokensForCompletion": 4096, "llmEndpointParams": { "type": "google_params", "temperature": 0.0, "topP": 1.0, "frequencyPenalty": 0.0, "presencePenalty": 0.0 }, "embeddings": { "model": "google__textembedding_gecko_003", "strategy": { "id": "basic", "numTokensPerChunk": 64 } } }, "basicText": { "model": "google__gemini_1_5_flash_001", "systemMessage": "Respond only in valid json. You are extracting metadata that is name, value pairs from a document. Only output the metadata in valid json form, as {\"name1\":\"value1\",\"name2\":\"value2\"} and nothing else. You will be given the document data and the schema for the metadata, that defines the name, description and type of each of the fields you will be extracting. Schema is of the form {\"fields\": [{\"key\": \"key_name\", \"prompt\": \"prompt to extract the value\", \"type\": \"date\"}]}. Leverage prompt for each key to identify where the key and value pairs are in the document. In certain cases, prompt can also indicate the instructions to perform on the document to obtain the value. Prompt will be in the form of Schema is ``schema`` \n document is ````document````", "promptTemplate": "If you need to know today's date to respond, it is {current_date}. Schema is ``{user_question}`` \n document is ````{content}````", "numTokensForCompletion": 4096, "llmEndpointParams": { "type": "google_params", "temperature": 0.0, "topP": 1.0, "frequencyPenalty": 0.0, "presencePenalty": 0.0 } } } } `````` # Get default AI agent configuration Source: https://developer.box.com/guides/box-ai/ai-agents/get-agent-default-config Fetch the current default agent configuration for ask, text_gen, extract, and extract_structured modes. The `GET /2.0/ai_agent_default` endpoint allows you to fetch the default configuration for AI services. Once you get the configuration details you can override them using the `ai_agent` parameter. ## Send a request To send a request, use the `GET /2.0/ai_agent_default` endpoint. Make sure you have generated the developer token to authorize your app. See getting started with Box AI for details. ```sh cURL theme={null} curl -L GET "https://api.box.com/2.0/ai_agent_default?mode=text_gen" \ -H 'Authorization: Bearer ' ``` ```typescript Node/TypeScript v10 theme={null} await client.ai.getAiAgentDefaultConfig({ mode: 'ask' as GetAiAgentDefaultConfigQueryParamsModeField, language: 'en-US', } satisfies GetAiAgentDefaultConfigQueryParams); ``` ```python Python v10 theme={null} client.ai.get_ai_agent_default_config(GetAiAgentDefaultConfigMode.ASK, language="en-US") ``` ```cs .NET v10 theme={null} await client.Ai.GetAiAgentDefaultConfigAsync(queryParams: new GetAiAgentDefaultConfigQueryParams(mode: GetAiAgentDefaultConfigQueryParamsModeField.Ask) { Language = "en-US" }); ``` ```swift Swift v10 theme={null} try await client.ai.getAiAgentDefaultConfig(queryParams: GetAiAgentDefaultConfigQueryParams(mode: GetAiAgentDefaultConfigQueryParamsModeField.ask, language: "en-US")) ``` ```java Java v10 theme={null} client.getAi().getAiAgentDefaultConfig(new GetAiAgentDefaultConfigQueryParams.Builder(GetAiAgentDefaultConfigQueryParamsModeField.ASK).language("en-US").build()) ``` ```java Java v5 theme={null} BoxAIAgentConfig config = BoxAI.getAiAgentDefaultConfig( api, BoxAIAgent.Mode.ASK, "en", "openai__gpt_3_5_turbo" ); ``` ```python Python v4 theme={null} config = client.get_ai_agent_default_config( mode='text_gen', language='en', model='openai__gpt_3_5_turbo' ) print(config) ``` ```javascript Node v4 theme={null} client.ai.getAiAgentDefaultConfig({ mode: 'ask', language: 'en', model:'openai__gpt_3_5_turbo' }).then(response => { /* response -> { "type": "ai_agent_ask", "basic_text": { "llm_endpoint_params": { "type": "openai_params", "frequency_penalty": 1.5, "presence_penalty": 1.5, "stop": "<|im_end|>", "temperature": 0, "top_p": 1 }, "model": "openai__gpt_3_5_turbo", "num_tokens_for_completion": 8400, "prompt_template": "It is `{current_date}`, and I have $8000 and want to spend a week in the Azores. What should I see?", "system_message": "You are a helpful travel assistant specialized in budget travel" }, ... } */ }); ``` ### Parameters To make a call, you must pass the following parameters. Mandatory parameters are in **bold**. | Parameter | Description | Example | | ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------- | | `language` | The language code the agent configuration is returned for. If the language is not supported, the default configuration is returned. | `ja-JP` | | **`mode`** | The mode used to filter the agent configuration. The value can be `ask`, `text_gen`, `extract`, or `extract_structured` depending on the result you want to achieve. | `ask` | | `model` | The model you want to get the configuration for. To make sure your chosen model is supported, see the list of models. | `azure__openai__gpt_4o_mini` | ## Responses The responses to the call may vary depending on the `mode` parameter value you choose. When you set the `mode` parameter to `ask` the response will be as follows: ```sh theme={null} { "type": "ai_agent_ask", "basic_text": { "model": "azure__openai__gpt_4o_mini", "system_message": "", "prompt_template": "prompt_template": "{user_question}Write it in an informal way.{content}" }, "num_tokens_for_completion": 6000, "llm_endpoint_params": { "temperature": 0, "top_p": 1, "frequency_penalty": 0, "presence_penalty": 1.5, "stop": "<|im_end|>", "type": "openai_params" } }, "long_text": { "model": "azure__openai__gpt_4o_mini", "system_message": "", "prompt_template": "prompt_template": "{user_question}Write it in an informal way.{content}" }, "num_tokens_for_completion": 6000, "llm_endpoint_params": { "temperature": 0, "top_p": 1, "frequency_penalty": 0, "presence_penalty": 1.5, "stop": "<|im_end|>", "type": "openai_params" }, "embeddings": { "model": "azure__openai__text_embedding_ada_002", "strategy": { "id": "basic", "num_tokens_per_chunk": 64 } } }, "basic_text_multi": { "model": "azure__openai__gpt_4o_mini", "system_message": "", "prompt_template": "Current date: {current_date}\n\nTEXT FROM DOCUMENTS STARTS\n{content}\nTEXT FROM DOCUMENTS ENDS\n\nHere is how I need help from you: {user_question}\n.", "num_tokens_for_completion": 6000, "llm_endpoint_params": { "temperature": 0, "top_p": 1, "frequency_penalty": 0, "presence_penalty": 1.5, "stop": "<|im_end|>", "type": "openai_params" } }, "long_text_multi": { "model": "azure__openai__gpt_4o_mini", "system_message": "Role and Goal: You are an assistant designed to analyze and answer a question based on provided snippets from multiple documents, which can include business-oriented documents like docs, presentations, PDFs, etc. The assistant will respond concisely, using only the information from the provided documents.\n\nConstraints: The assistant should avoid engaging in chatty or extensive conversational interactions and focus on providing direct answers. It should also avoid making assumptions or inferences not supported by the provided document snippets.\n\nGuidelines: When answering, the assistant should consider the file's name and path to assess relevance to the question. In cases of conflicting information from multiple documents, it should list the different answers with citations. For summarization or comparison tasks, it should concisely answer with the key points. It should also consider the current date to be the date given.\n\nPersonalization: The assistant's tone should be formal and to-the-point, suitable for handling business-related documents and queries.\n", "prompt_template": "Current date: {current_date}\n\nTEXT FROM DOCUMENTS STARTS\n{content}\nTEXT FROM DOCUMENTS ENDS\n\nHere is how I need help from you: {user_question}\n.", "num_tokens_for_completion": 6000, "llm_endpoint_params": { "temperature": 0, "top_p": 1, "frequency_penalty": 0, "presence_penalty": 1.5, "stop": "<|im_end|>", "type": "openai_params" }, "embeddings": { "model": "azure__openai__text_embedding_ada_002", "strategy": { "id": "basic", "num_tokens_per_chunk": 64 } } } } ``` When you set the `mode` parameter to `text_gen` the response will be as follows: ``````sh theme={null} { "type": "ai_agent_text_gen", "basic_gen": { "model": "azure__openai__gpt_4o_mini", "system_message": "\nIf you need to know today's date to respond, it is {current_date}.\nThe user is working in a collaborative document creation editor called Box Notes.\nAssume that you are helping a business user create documents or to help the user revise existing text.\nYou can help the user in creating templates to be reused or update existing documents, you can respond with text that the user can use to place in the document that the user is editing.\nIf the user simply asks to \"improve\" the text, then simplify the language and remove jargon, unless the user specifies otherwise.\nDo not open with a preamble to the response, just respond.\n", "prompt_template": "{user_question}", "num_tokens_for_completion": 12000, "llm_endpoint_params": { "temperature": 0.1, "top_p": 1, "frequency_penalty": 0.75, "presence_penalty": 0.75, "stop": "<|im_end|>", "type": "openai_params" }, "embeddings": { "model": "azure__openai__text_embedding_ada_002", "strategy": { "id": "basic", "num_tokens_per_chunk": 64 } }, "content_template": "`````{content}`````" } } `````` When you set the `mode` parameter to `extract` the response will be as follows: `````sh theme={null} { "type": "ai_agent_extract", "basic_text": { "model": "google__gemini_1_5_flash_001", "system_message": "Respond only in valid json. You are extracting metadata that is name, value pairs from a document. Only output the metadata in valid json form, as {\"name1\":\"value1\",\"name2\":\"value2\"} and nothing else. You will be given the document data and the schema for the metadata, that defines the name, description and type of each of the fields you will be extracting. Schema is of the form {\"fields\": [{\"key\": \"key_name\", \"displayName\": \"key display name\", \"type\": \"string\", \"description\": \"key description\"}]}. Leverage key description and key display name to identify where the key and value pairs are in the document. In certain cases, key description can also indicate the instructions to perform on the document to obtain the value. Prompt will be in the form of Schema is ``schema`` \n document is ````document````", "prompt_template": "If you need to know today's date to respond, it is {current_date}. Schema is ``{user_question}`` \n document is ````{content}````", "num_tokens_for_completion": 4096, "llm_endpoint_params": { "temperature": 0, "top_p": 1, "top_k": null, "type": "google_params" } }, "long_text": { "model": "google__gemini_1_5_flash_001", "system_message": "Respond only in valid json. You are extracting metadata that is name, value pairs from a document. Only output the metadata in valid json form, as {\"name1\":\"value1\",\"name2\":\"value2\"} and nothing else. You will be given the document data and the schema for the metadata, that defines the name, description and type of each of the fields you will be extracting. Schema is of the form {\"fields\": [{\"key\": \"key_name\", \"displayName\": \"key display name\", \"type\": \"string\", \"description\": \"key description\"}]}. Leverage key description and key display name to identify where the key and value pairs are in the document. In certain cases, key description can also indicate the instructions to perform on the document to obtain the value. Prompt will be in the form of Schema is ``schema`` \n document is ````document````", "prompt_template": "If you need to know today's date to respond, it is {current_date}. Schema is ``{user_question}`` \n document is ````{content}````", "num_tokens_for_completion": 4096, "llm_endpoint_params": { "temperature": 0, "top_p": 1, "top_k": null, "type": "google_params" }, "embeddings": { "model": "azure__openai__text_embedding_ada_002", "strategy": { "id": "basic", "num_tokens_per_chunk": 64 } } } } ````` When you set the `mode` parameter to `extract_structured` the response will be as follows: `````sh theme={null} { "type": "ai_agent_extract_structured", "basic_text": { "model": "google__gemini_1_5_flash_001", "system_message": "Respond only in valid json. You are extracting metadata that is name, value pairs from a document. Only output the metadata in valid json form, as {\"name1\":\"value1\",\"name2\":\"value2\"} and nothing else. You will be given the document data and the schema for the metadata, that defines the name, description and type of each of the fields you will be extracting. Schema is of the form {\"fields\": [{\"key\": \"key_name\", \"prompt\": \"prompt to extract the value\", \"type\": \"date\"}]}. Leverage prompt for each key to identify where the key and value pairs are in the document. In certain cases, prompt can also indicate the instructions to perform on the document to obtain the value. Prompt will be in the form of Schema is ``schema`` \n document is ````document````", "prompt_template": "If you need to know today's date to respond, it is {current_date}. Schema is ``{user_question}`` \n document is ````{content}````", "num_tokens_for_completion": 4096, "llm_endpoint_params": { "temperature": 0, "top_p": 1, "top_k": null, "type": "google_params" } }, "long_text": { "model": "google__gemini_1_5_flash_001", "system_message": "Respond only in valid json. You are extracting metadata that is name, value pairs from a document. Only output the metadata in valid json form, as {\"name1\":\"value1\",\"name2\":\"value2\"} and nothing else. You will be given the document data and the schema for the metadata, that defines the name, description and type of each of the fields you will be extracting. Schema is of the form {\"fields\": [{\"key\": \"key_name\", \"prompt\": \"prompt to extract the value\", \"type\": \"date\"}]}. Leverage prompt for each key to identify where the key and value pairs are in the document. In certain cases, prompt can also indicate the instructions to perform on the document to obtain the value. Prompt will be in the form of Schema is ``schema`` \n document is ````document````", "prompt_template": "If you need to know today's date to respond, it is {current_date}. Schema is ``{user_question}`` \n document is ````{content}````", "num_tokens_for_completion": 4096, "llm_endpoint_params": { "temperature": 0, "top_p": 1, "top_k": null, "type": "google_params" }, "embeddings": { "model": "google__textembedding_gecko_003", "strategy": { "id": "basic", "num_tokens_per_chunk": 64 } } } } ````` [override-tutorials]: /guides/box-ai/ai-agents/ai-agent-overrides # AI model overrides Source: https://developer.box.com/guides/box-ai/ai-agents/index Override the default AI model, prompt, and LLM parameters used by Box AI API endpoints. These guides explain how to inspect and customize the AI agent configurations that Box AI uses behind the scenes. For an overview of the override system, including when to use overrides, the configuration structure by endpoint, and LLM parameter differences by provider, see the Box AI overview. Full `ai_agent` parameter reference with sample payloads for `ask`, `text_gen`, `extract`, and `extract_structured`. Fetch the current defaults with `GET /2.0/ai_agent_default` so you know what you are overriding. See how Box versions agent snapshots, the 12-month support guarantee, and transition timelines. Full list of core and customer-enabled models with capability tiers, compliance badges, and API names. # AWS Claude Haiku 4.5 Source: https://developer.box.com/guides/box-ai/ai-models/aws-claude-4-5-haiku-model-card The **AWS Claude Haiku 4.5** model is optimized for high-volume, low-latency applications. It provides strong coding performance with improved speed and cost efficiency compared to larger models. ## Model details | Item | Value | Description | | --------------------- | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Model name | **AWS Claude Haiku 4.5** | The name of the model. | | Model category | **Standard** | The category of the model: Standard or Premium. | | API model name | `aws__claude_4_5_haiku` | The name of the model that is used in the Box AI API for model overrides. The user must provide this exact name for the API to work. | | Compliance | **ISMAP, FedRAMP Moderate** | Government compliance frameworks and authorizations applicable to this model. | | Hosting layer | **Amazon Web Services (AWS)** | The trusted organization that securely hosts the LLM. | | Model provider | **Anthropic** | The organization that provides this model. | | Release date | **October 15th, 2025** | The release date for the model. | | Knowledge cutoff date | **February 2025** | The date after which the model does not get any information updates. | | Input context window | **200k tokens** | The number of tokens supported by the input context window. | | Maximum output tokens | **64k tokens** | The number of tokens that can be generated by the model in a single request. | | Empirical throughput | **Not specified** | The number of tokens the model can generate per second. | | Open source | **No** | Specifies if the model's code is available for public use. | ## Additional documentation For additional information, see [official AWS Claude Haiku 4.5 documentation][aws-claude]. [aws-claude]: https://aws.amazon.com/bedrock/anthropic/ # AWS Claude Opus 4.5 Source: https://developer.box.com/guides/box-ai/ai-models/aws-claude-4-5-opus-model-card The **AWS Claude Opus 4.5** model is designed for developers building sophisticated AI agents that can reason, plan, and perform complex tasks with minimal oversight. ## Model details | Item | Value | Description | | --------------------- | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Model name | **AWS Claude Opus 4.5** | The name of the model. | | Model category | **Premium** | The category of the model: Standard or Premium. | | API model name | `aws__claude_4_5_opus` | The name of the model that is used in the Box AI API for model overrides. The user must provide this exact name for the API to work. | | Compliance | **ISMAP, FedRAMP Moderate** | Government compliance frameworks and authorizations applicable to this model. | | Hosting layer | **Amazon Web Services (AWS)** | The trusted organization that securely hosts the LLM. | | Model provider | **Anthropic** | The organization that provides this model. | | Release date | **November 24th, 2025** | The release date for the model. | | Knowledge cutoff date | **March 2025** | The date after which the model does not get any information updates. | | Input context window | **200k tokens** | The number of tokens supported by the input context window. | | Maximum output tokens | **64k tokens** | The number of tokens that can be generated by the model in a single request. | | Empirical throughput | **Not specified** | The number of tokens the model can generate per second. | | Open source | **No** | Specifies if the model's code is available for public use. | ## Additional documentation For additional information, see [official AWS Claude Opus 4.5 documentation][aws-claude]. [aws-claude]: https://aws.amazon.com/bedrock/anthropic/ # AWS Claude Sonnet 4.5 Source: https://developer.box.com/guides/box-ai/ai-models/aws-claude-4-5-sonnet-model-card The **AWS Claude Sonnet 4.5** model is a high-performance model designed for building complex agents, delivering leading coding capabilities, and executing across development tasks. It excels at autonomously planning and executing complex, multi-step workflows and is particularly effective in areas like finance, research, and cybersecurity. ## Model details | Item | Value | Description | | --------------------- | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Model name | **AWS Claude Sonnet 4.5** | The name of the model. | | Model category | **Premium** | The category of the model: Standard or Premium. | | API model name | `aws__claude_4_5_sonnet` | The name of the model that is used in the Box AI API for model overrides. The user must provide this exact name for the API to work. | | Compliance | **ISMAP, FedRAMP Moderate** | Government compliance frameworks and authorizations applicable to this model. | | Hosting layer | **Amazon Web Services (AWS)** | The trusted organization that securely hosts the LLM. | | Model provider | **Anthropic** | The organization that provides this model. | | Release date | **September 29th, 2025** | The release date for the model. | | Knowledge cutoff date | **January 2025** | The date after which the model does not get any information updates. | | Input context window | **200k tokens** | The number of tokens supported by the input context window. | | Maximum output tokens | **64k tokens** | The number of tokens that can be generated by the model in a single request. | | Empirical throughput | **Not specified** | The number of tokens the model can generate per second. | | Open source | **No** | Specifies if the model's code is available for public use. | ## Additional documentation For additional information, see [official AWS Claude Sonnet 4.5 documentation][aws-claude]. [aws-claude]: https://aws.amazon.com/bedrock/anthropic/ # AWS Claude Opus 4.6 Source: https://developer.box.com/guides/box-ai/ai-models/aws-claude-4-6-opus-model-card **AWS Claude Opus 4.6** is the next generation of Anthropic's most intelligent model designed for coding, enterprise agents, and professional work. ## Model details | Item | Value | Description | | --------------------- | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Model name | **AWS Claude Opus 4.6** | The name of the model. | | Model category | **Premium** | The category of the model: Standard or Premium. | | API model name | `aws__claude_4_6_opus` | The name of the model that is used in the Box AI API for model overrides. The user must provide this exact name for the API to work. | | Compliance | **ISMAP, FedRAMP Moderate** | Government compliance frameworks and authorizations applicable to this model. | | Hosting layer | **Amazon Web Services (AWS)** | The trusted organization that securely hosts the LLM. | | Model provider | **Anthropic** | The organization that provides this model. | | Release date | **February 5th, 2026** | The release date for the model. | | Knowledge cutoff date | **May 2025** | The date after which the model does not get any information updates. | | Input context window | **200k tokens** | The number of tokens supported by the input context window. | | Maximum output tokens | **128k tokens** | The number of tokens that can be generated by the model in a single request. | | Empirical throughput | **Not specified** | The number of tokens the model can generate per second. | | Open source | **No** | Specifies if the model's code is available for public use. | ## Additional documentation For additional information, see [official AWS Claude Opus 4.6 documentation][aws-claude]. [aws-claude]: https://platform.claude.com/docs/en/about-claude/models/overview # AWS Claude Sonnet 4.6 Source: https://developer.box.com/guides/box-ai/ai-models/aws-claude-4-6-sonnet-model-card ## Overview **AWS Claude Sonnet 4.6** is a powerful, versatile model built for daily use, scaled production, and complex tasks across coding, agents, and professional workflows. ## Model details | Item | Value | Description | | --------------------- | ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Model name | **AWS Claude Sonnet 4.6** | The name of the model. | | Model category | **Premium** | The category of the model: Standard or Premium. | | API model name | `aws__claude_4_6_sonnet` | The name of the model that is used in the Box AI API for model overrides. You must provide this exact name for the API to work. | | Compliance | **ISMAP, FedRAMP Moderate** | Government compliance frameworks and authorizations applicable to this model. | | Hosting layer | **Amazon Web Services (AWS)** | The trusted organization that securely hosts the LLM. | | Model provider | **Anthropic** | The organization that provides this model. | | Release date | **February 17th, 2026** | The release date for the model. | | Knowledge cutoff date | **August 2025** | The date after which the model does not get any information updates. | | Input context window | **1m tokens** | The number of tokens supported by the input context window. | | Maximum output tokens | **64k tokens** | The number of tokens that can be generated by the model in a single request. | | Empirical throughput | **Not specified** | The number of tokens the model can generate per second. | | Open source | **No** | Specifies if the model's code is available for public use. | ## Additional documentation For additional information, see official AWS Claude documentation. # AWS Claude Opus 4.7 Source: https://developer.box.com/guides/box-ai/ai-models/aws-claude-4-7-opus-model-card **AWS Claude Opus 4.7** is a highly autonomous model which performs well on long-horizon agentic work, knowledge work, vision tasks, and memory tasks. ## Model details | Item | Value | Description | | --------------------- | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Model name | **AWS Claude Opus 4.7** | The name of the model. | | Model category | **Premium** | The category of the model: Standard or Premium. | | API model name | `aws__claude_4_7_opus` | The name of the model that is used in the Box AI API for model overrides. The user must provide this exact name for the API to work. | | Compliance | **ISMAP, FedRAMP Moderate** | Government compliance frameworks and authorizations applicable to this model. | | Hosting layer | **Amazon Web Services (AWS)** | The trusted organization that securely hosts the LLM. | | Model provider | **Anthropic** | The organization that provides this model. | | Release date | **April 16th, 2026** | The release date for the model. | | Knowledge cutoff date | **January 2026** | The date after which the model does not get any information updates. | | Input context window | **1m tokens** | The number of tokens supported by the input context window. | | Maximum output tokens | **128k tokens** | The number of tokens that can be generated by the model in a single request. | | Empirical throughput | **Not specified** | The number of tokens the model can generate per second. | | Open source | **No** | Specifies if the model's code is available for public use. | ## Additional documentation For additional information, see [official AWS Claude Opus 4.7 documentation][aws-claude]. [aws-claude]: https://aws.amazon.com/bedrock/anthropic/ # AWS Claude 4 Opus Source: https://developer.box.com/guides/box-ai/ai-models/aws-claude-4-opus-model-card The **AWS Claude 4 Opus** model excels at coding and complex problem-solving, powering frontier agent products. It's possible to run Claude Code in the background, enabling developers to assign long-running coding tasks for Opus to handle independently. ## Model details | Item | Value | Description | | --------------------- | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Model name | **AWS Claude 4 Opus** | The name of the model. | | Model category | **Premium** | The category of the model: Standard or Premium. | | API model name | `aws__claude_4_opus` | The name of the model that is used in the Box AI API for model overrides. The user must provide this exact name for the API to work. | | Compliance | **ISMAP, FedRAMP Moderate** | Government compliance frameworks and authorizations applicable to this model. | | Hosting layer | **Amazon Web Services (AWS)** | The trusted organization that securely hosts the LLM. | | Model provider | **Anthropic** | The organization that provides this model. | | Release date | **March 4th, 2024** | The release date for the model. | | Knowledge cutoff date | **August 2023** | The date after which the model does not get any information updates. | | Input context window | **200k tokens** | The number of tokens supported by the input context window. | | Maximum output tokens | **32k tokens** | The number of tokens that can be generated by the model in a single request. | | Empirical throughput | **Not specified** | The number of tokens the model can generate per second. | | Open source | **No** | Specifies if the model's code is available for public use. | ## Additional documentation For additional information, see [official AWS Claude 4 Opus documentation][aws-claude]. [aws-claude]: https://aws.amazon.com/bedrock/claude/ # AWS Claude 4 Sonnet Source: https://developer.box.com/guides/box-ai/ai-models/aws-claude-4-sonnet-model-card The **AWS Claude 4 Sonnet** model delivers superior coding and reasoning while responding more precisely to your instructions, and brings frontier performance to everyday use cases. ## Model details | Item | Value | Description | | --------------------- | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Model name | **AWS Claude 4 Sonnet** | The name of the model. | | Model category | **Premium** | The category of the model: Standard or Premium. | | API model name | `aws__claude_4_sonnet` | The name of the model that is used in the Box AI API for model overrides. The user must provide this exact name for the API to work. | | Compliance | **ISMAP, FedRAMP Moderate** | Government compliance frameworks and authorizations applicable to this model. | | Hosting layer | **Amazon Web Services (AWS)** | The trusted organization that securely hosts the LLM. | | Model provider | **Anthropic** | The organization that provides this model. | | Release date | **May 22nd, 2025** | The release date for the model. | | Knowledge cutoff date | **November 2024** | The date after which the model does not get any information updates. | | Input context window | **200k tokens** | The number of tokens supported by the input context window. | | Maximum output tokens | **64k tokens** | The number of tokens that can be generated by the model in a single request. | | Empirical throughput | **Not specified** | The number of tokens the model can generate per second. | | Open source | **No** | Specifies if the model's code is available for public use. | ## Additional documentation For additional information, see [official AWS Claude 4 Sonnet documentation][aws-claude]. [aws-claude]: https://aws.amazon.com/bedrock/claude/ # AWS Titan Text Lite Source: https://developer.box.com/guides/box-ai/ai-models/aws-titan-text-lite-model-card The **AWS Titan Text Lite** model is designed for advanced language processing, capable of handling extensive contexts, making it suitable for complex tasks, although the model itself is lightweight. ## Model details | Item | Value | Description | | --------------------- | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Model name | **AWS Titan Text Lite** | The name of the model. | | Model category | **Standard** | The category of the model: Standard or Premium. | | API model name | `aws__titan_text_lite` | The name of the model that is used in the Box AI API for model overrides. The user must provide this exact name for the API to work. | | Compliance | **ISMAP, FedRAMP Moderate** | Government compliance frameworks and authorizations applicable to this model. | | Hosting layer | **Amazon Web Services (AWS)** | The trusted organization that securely hosts the LLM. | | Model provider | **Anthropic** | The organization that provides this model. | | Release date | **September 2024** | The release date for the model. | | Knowledge cutoff date | **Not provided** | The date after which the model does not get any information updates. | | Input context window | **128k tokens** | The number of tokens supported by the input context window. | | Maximum output tokens | **4k tokens** | The number of tokens that can be generated by the model in a single request. | | Empirical throughput | **Not specified** | The number of tokens the model can generate per second. | | Open source | **No** | Specifies if the model's code is available for public use. | ## Additional documentation For additional information, see [official AWS Titan documentation][aws-titan]. [aws-titan]: https://aws.amazon.com/bedrock/titan/ # Azure OpenAI GPT-4.1 mini Source: https://developer.box.com/guides/box-ai/ai-models/azure-openai-gpt-4-1-mini-model-card **Azure OpenAI GPT-4.1 mini** is a multimodal model designed to handle lightweight tasks. ## Model details | Item | Value | Description | | --------------------- | -------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Model name | **GPT-4.1 mini** | The name of the model. | | Model category | **Standard** | The category of the model: Standard or Premium. | | API model name | `azure__openai__gpt_4.1_mini` | The name of the model that is used in the Box AI API for model overrides. The user must provide this exact name for the API to work. | | Compliance | **ISMAP, FedRAMP Moderate, FedRAMP High, DoD IL2** | Government compliance frameworks and authorizations applicable to this model. | | Hosting layer | **Microsoft Azure** | The trusted organization that securely hosts the LLM. | | Model provider | **Microsoft Azure** | The organization that provides this model. | | Release date | **April 14th, 2025** | The release date for the model. | | Knowledge cutoff date | **May 2024** | The date after which the model does not get any information updates. | | Input context window | **1m tokens** | The number of tokens supported by the input context window. | | Maximum output tokens | **32k tokens** | The number of tokens that can be generated by the model in a single request. | | Empirical throughput | **87.5** | The number of tokens the model can generate per second. | | Open source | **No** | Specifies if the model's code is available for public use. | ## Additional documentation For additional information, see [official Azure OpenAI GPT-4o documentation][azure-ai-mini-4o-model]. [azure-ai-mini-4o-model]: https://learn.microsoft.com/en-us/azure/ai-services/openai/concepts/models?tabs=python-secure#gpt-4o-and-gpt-4-turbo # Azure OpenAI GPT-4.1 Source: https://developer.box.com/guides/box-ai/ai-models/azure-openai-gpt-4-1-model-card **Azure OpenAI GPT-4.1** is a multimodal model, highly efficient in handling complex, multi-step tasks. ## Model details | Item | Value | Description | | --------------------- | -------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Model name | **GPT-4.1** | The name of the model. | | Model category | **Premium** | The category of the model: Standard or Premium. | | API model name | `azure__openai__gpt_4_1` | The name of the model that is used in the Box AI API for model overrides. The user must provide this exact name for the API to work. | | Compliance | **ISMAP, FedRAMP Moderate, FedRAMP High, DoD IL2** | Government compliance frameworks and authorizations applicable to this model. | | Hosting layer | **Microsoft Azure** | The trusted organization that securely hosts the LLM. | | Model provider | **Microsoft Azure** | The organization that provides this model. | | Release date | **April 14th, 2025** | The release date for the model. | | Knowledge cutoff date | **May 2024** | The date after which the model does not get any information updates. | | Input context window | **1m tokens** | The number of tokens supported by the input context window. | | Maximum output tokens | **32k tokens** | The number of tokens that can be generated by the model in a single request. | | Empirical throughput | **87.5** | The number of tokens the model can generate per second. | | Open source | **No** | Specifies if the model's code is available for public use. | ## Additional documentation For additional information, see [official Azure OpenAI GPT-4o documentation][azure-ai-mini-4o-model]. [azure-ai-mini-4o-model]: https://learn.microsoft.com/en-us/azure/ai-services/openai/concepts/models?tabs=python-secure#gpt-4o-and-gpt-4-turbo # Azure OpenAI GPT-4o Mini Source: https://developer.box.com/guides/box-ai/ai-models/azure-openai-gpt-4o-mini-model-card **Azure OpenAI GPT-4o Mini** is a multimodal model designed to handle lightweight tasks. ## Model details | Item | Value | Description | | --------------------- | -------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Model name | **GPT-4o mini** | The name of the model. | | Model category | **Standard** | The category of the model: Standard or Premium. | | API model name | `azure__openai__gpt_4o_mini` | The name of the model that is used in the Box AI API for model overrides. The user must provide this exact name for the API to work. | | Compliance | **ISMAP, FedRAMP Moderate, FedRAMP High, DoD IL2** | Government compliance frameworks and authorizations applicable to this model. | | Hosting layer | **Microsoft Azure** | The trusted organization that securely hosts the LLM. | | Model provider | **Microsoft Azure** | The organization that provides this model. | | Release date | **July 18th, 2024** | The release date for the model. | | Knowledge cutoff date | **October 2023** | The date after which the model does not get any information updates. | | Input context window | **128k tokens** | The number of tokens supported by the input context window. | | Maximum output tokens | **16k tokens** | The number of tokens that can be generated by the model in a single request. | | Empirical throughput | **85.4** | The number of tokens the model can generate per second. | | Open source | **No** | Specifies if the model's code is available for public use. | ## Usage Box Webapp uses this model to cover the following use cases: * Creating content * Editing content * Creating summaries * Single doc Q\&A on text Box AI API uses this model to cover the following use cases: * Creating content * Editing content * Creating summaries * Single doc Q\&A on text * Extracting metadata ## Additional documentation For additional information, see [official Azure OpenAI GPT-4o Mini documentation][azure-ai-mini-4o-model]. [azure-ai-mini-4o-model]: https://learn.microsoft.com/en-us/azure/ai-services/openai/concepts/models?tabs=python-secure#gpt-4o-and-gpt-4-turbo # Azure OpenAI GPT-4o Source: https://developer.box.com/guides/box-ai/ai-models/azure-openai-gpt-4o-model-card **Azure OpenAI GPT-4o** is a multimodal model designed to handle lightweight tasks. ## Model details | Item | Value | Description | | --------------------- | -------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Model name | **GPT-4o** | The name of the model. | | Model category | **Premium** | The category of the model: Standard or Premium. | | API model name | `azure__openai__gpt_4o` | The name of the model that is used in the Box AI API for model overrides. The user must provide this exact name for the API to work. | | Compliance | **ISMAP, FedRAMP Moderate, FedRAMP High, DoD IL2** | Government compliance frameworks and authorizations applicable to this model. | | Hosting layer | **Microsoft Azure** | The trusted organization that securely hosts the LLM. | | Model provider | **Microsoft Azure** | The organization that provides this model. | | Release date | **May 13th, 2024** | The release date for the model. | | Knowledge cutoff date | **September 2023** | The date after which the model does not get any information updates. | | Input context window | **128k tokens** | The number of tokens supported by the input context window. | | Maximum output tokens | **2k tokens** | The number of tokens that can be generated by the model in a single request. | | Empirical throughput | **87.5** | The number of tokens the model can generate per second. | | Open source | **No** | Specifies if the model's code is available for public use. | ## Additional documentation For additional information, see [official Azure OpenAI GPT-4o documentation][azure-ai-mini-4o-model]. [azure-ai-mini-4o-model]: https://learn.microsoft.com/en-us/azure/ai-services/openai/concepts/models?tabs=python-secure#gpt-4o-and-gpt-4-turbo # Azure text-embedding-ada-002 Source: https://developer.box.com/guides/box-ai/ai-models/azure-text-embedding-ada-002-model-card **Azure text-embedding-ada-002** is a multimodal model designed to handle lightweight tasks. ## Model details | Item | Value | Description | | --------------------- | -------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Model name | **text-embedding-ada-002** | The name of the model. | | Model category | **Standard** | The category of the model: Standard or Premium. | | API model name | `azure__openai__text_embedding_ada_002` | The name of the model that is used in the Box AI API for model overrides. The user must provide this exact name for the API to work. | | Compliance | **ISMAP, FedRAMP Moderate, FedRAMP High, DoD IL2** | Government compliance frameworks and authorizations applicable to this model. | | Hosting layer | **Microsoft Azure** | The trusted organization that securely hosts the LLM. | | Model provider | **Microsoft Azure** | The organization that provides this model. | | Release date | **December 2022** | The release date for the model. | | Knowledge cutoff date | **September 2021** | The date after which the model does not get any information updates. | | Input context window | **8k tokens** | The number of tokens supported by the input context window. | | Maximum output tokens | **Not applicable** | The number of tokens that can be generated by the model in a single request. | | Empirical throughput | **1000** | The number of tokens the model can generate per second. | | Open source | **No** | Specifies if the model's code is available for public use. | ## Additional documentation For additional information, see [official Azure Embeddings models documentation][azure-ai-embeddings]. [azure-ai-embeddings]: https://learn.microsoft.com/en-us/azure/ai-services/openai/concepts/models#embeddings # Google Gemini 2.0 Flash Source: https://developer.box.com/guides/box-ai/ai-models/google-gemini-2-0-flash-001-model-card **Google Gemini 2.0 Flash** is a multimodal model designed for optimal for high-volume, high-frequency tasks at scale. It capable of multimodal reasoning and has a context window of 1 million tokens. ## Model details | Item | Value | Description | | --------------------- | -------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Model name | **Google Gemini 2.0 Flash** | The name of the model. | | Model category | **Standard** | The category of the model: Standard or Premium. | | API model name | `google__gemini_2_0_flash_001` | The name of the model that is used in the Box AI API for model overrides. The user must provide this exact name for the API to work. | | Compliance | **ISMAP, FedRAMP Moderate, FedRAMP High, DoD IL5** | Government compliance frameworks and authorizations applicable to this model. | | Hosting layer | **Google** | The trusted organization that securely hosts the LLM. | | Model provider | **Google** | The organization that provides this model. | | Release date | **February 5th 2025** | The release date for the model. | | Knowledge cutoff date | **June 2024** | The date after which the model does not get any information updates. | | Input context window | **1m tokens** | The number of tokens supported by the input context window. | | Maximum output tokens | **8k tokens** | The number of tokens that can be generated by the model in a single request. | | Empirical throughput | **168** | The number of tokens the model can generate per second. | | Open source | **No** | Specifies if the model's code is available for public use. | ## Additional documentation For additional information, see [official Google Gemini 2.0 Flash documentation][vertex-ai-gemini-models]. [vertex-ai-gemini-models]: https://cloud.google.com/vertex-ai/generative-ai/docs/learn/models#gemini-models # Google Gemini 2.0 Flash Lite Source: https://developer.box.com/guides/box-ai/ai-models/google-gemini-2-0-flash-lite-preview-02-05 **Google Gemini 2.0 Flash Lite** is a multimodal model designed to handle lightweight tasks. It is designed for high-volume, low-latency tasks, making it highly efficient for large-scale use cases like summarization, multimodal processing, and categorization but with higher quality than Gemini 1.5 Flash. ## Model details | Item | Value | Description | | --------------------- | -------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Model name | **Google Gemini 2.0 Flash Lite** | The name of the model. | | Model category | **Standard** | The category of the model: Standard or Premium. | | API model name | `google__gemini_2_0_flash_lite_preview` | The name of the model that is used in the Box AI API for model overrides. The user must provide this exact name for the API to work. | | Compliance | **ISMAP, FedRAMP Moderate, FedRAMP High, DoD IL5** | Government compliance frameworks and authorizations applicable to this model. | | Hosting layer | **Google** | The trusted organization that securely hosts the LLM. | | Model provider | **Google** | The organization that provides this model. | | Release date | **February 5th 2025** | The release date for the model. | | Knowledge cutoff date | **June 2024** | The date after which the model does not get any information updates. | | Input context window | **1m tokens** | The number of tokens supported by the input context window. | | Maximum output tokens | **8k tokens** | The number of tokens that can be generated by the model in a single request. | | Empirical throughput | **168** | The number of tokens the model can generate per second. | | Open source | **No** | Specifies if the model's code is available for public use. | ## Additional documentation For additional information, see [official Google Gemini 2.0 Flash Lite documentation][vertex-ai-gemini-models]. [vertex-ai-gemini-models]: https://cloud.google.com/vertex-ai/generative-ai/docs/learn/models#gemini-models # Google Gemini 2.5 Flash Source: https://developer.box.com/guides/box-ai/ai-models/google-gemini-2-5-flash-model-card **Google Gemini 2.5 Flash** is a multimodal model, offering well-rounded capabilities. It features thinking capabilities, which lets you see the thinking process the model goes through when generating its response. ## Model details | Item | Value | Description | | --------------------- | -------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Model name | **Google Gemini 2.5 Flash** | The name of the model. | | Model category | **Standard** | The category of the model: Standard or Premium. | | API model name | `google__gemini_2_5_flash` | The name of the model that is used in the Box AI API for model overrides. The user must provide this exact name for the API to work. | | Compliance | **ISMAP, FedRAMP Moderate, FedRAMP High, DoD IL5** | Government compliance frameworks and authorizations applicable to this model. | | Hosting layer | **Google** | The trusted organization that securely hosts the LLM. | | Model provider | **Google** | The organization that provides this model. | | Release date | **June 17th 2025** | The release date for the model. | | Knowledge cutoff date | **January 2025** | The date after which the model does not get any information updates. | | Input context window | **1m tokens** | The number of tokens supported by the input context window. | | Maximum output tokens | **64k tokens** | The number of tokens that can be generated by the model in a single request. | | Empirical throughput | **Estimated between 163 - 300** | The number of tokens the model can generate per second. | | Open source | **No** | Specifies if the model's code is available for public use. | ## Additional documentation For additional information, see [official Google Gemini 2.5 Flash documentation][vertex-ai-gemini-models]. [vertex-ai-gemini-models]: https://cloud.google.com/vertex-ai/generative-ai/docs/learn/models#gemini-models # Google Gemini 2.5 Pro Source: https://developer.box.com/guides/box-ai/ai-models/google-gemini-2-5-pro-model-card **Google Gemini 2.5 Pro** is a multimodal model capable of solving complex problems. It can comprehend vast datasets and challenging problems from different information sources, including text, audio, images, video, and even entire code repositories. ## Model details | Item | Value | Description | | --------------------- | -------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Model name | **Google Gemini 2.5 Pro** | The name of the model. | | Model category | **Premium** | The category of the model: Standard or Premium. | | API model name | `google__gemini_2_5_pro` | The name of the model that is used in the Box AI API for model overrides. The user must provide this exact name for the API to work. | | Compliance | **ISMAP, FedRAMP Moderate, FedRAMP High, DoD IL5** | Government compliance frameworks and authorizations applicable to this model. | | Hosting layer | **Google** | The trusted organization that securely hosts the LLM. | | Model provider | **Google** | The organization that provides this model. | | Release date | **June 17th 2025** | The release date for the model. | | Knowledge cutoff date | **January 2025** | The date after which the model does not get any information updates. | | Input context window | **1m tokens** | The number of tokens supported by the input context window. | | Maximum output tokens | **65k tokens** | The number of tokens that can be generated by the model in a single request. | | Empirical throughput | **Not specified** | The number of tokens the model can generate per second. | | Open source | **No** | Specifies if the model's code is available for public use. | ## Additional documentation For additional information, see [official Google Gemini 2.5 Pro documentation][vertex-ai-gemini-2-5-pro]. [vertex-ai-gemini-2-5-pro]: https://cloud.google.com/vertex-ai/generative-ai/docs/models/gemini/2-5-pro # Google Gemini 3.1 Flash Lite Source: https://developer.box.com/guides/box-ai/ai-models/google-gemini-3-1-flash-lite-model-card **Google Gemini 3.1 Flash Lite** is a multimodal model designed for high-speed, cost-efficient tasks like basic summarization, Q\&A, and structured data extraction. It is a standard-tier model suited to high-volume, low-complexity use cases. ## Model details | Item | Value | Description | | --------------------- | -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Model name | **Google Gemini 3.1 Flash Lite** | The name of the model. | | Model category | **Standard** | The category of the model: Standard or Premium. | | API model name | `google__gemini_3_1_flash_lite` | The name of the model that is used in the Box AI API for model overrides. You must provide this exact name for the API to work. | | Compliance | **N/A** | Government compliance frameworks and authorizations applicable to this model. | | Hosting layer | **Google** | The trusted organization that securely hosts the LLM. | | Model provider | **Google** | The organization that provides this model. | | Release date | **March 4th, 2026** | The release date for the model. | | Knowledge cutoff date | **January 2025** | The date after which the model does not receive information updates. | | Input context window | **1m tokens** | The number of tokens supported by the input context window. | | Maximum output tokens | **65k tokens** | The number of tokens that can be generated by the model in a single request. | | Empirical throughput | **Not specified** | The number of tokens the model can generate per second. | | Open source | **No** | Specifies whether the model's code is available for public use. | | Compliance | **N/A** | The compliance certifications applicable to this model. | ## Additional documentation For more information, see official Google Gemini 3.1 Flash Lite documentation. # Google Gemini 3.1 Pro Source: https://developer.box.com/guides/box-ai/ai-models/google-gemini-3-1-pro-model-card ## Overview **Google Gemini 3.1 Pro** is designed for complex tasks, with advanced reasoning and a large context window for processing text, audio, images, video, and code. ## Model details | Item | Value | Description | | --------------------- | ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Model name | **Google Gemini 3.1 Pro** | The name of the model. | | Model category | **Premium** | The category of the model: Standard or Premium. | | API model name | `google__gemini_3_1_pro` | The name of the model that is used in the Box AI API for model overrides. You must provide this exact name for the API to work. | | Compliance | **N/A** | Government compliance frameworks and authorizations applicable to this model. | | Hosting layer | **Google** | The trusted organization that securely hosts the LLM. | | Model provider | **Google** | The organization that provides this model. | | Release date | **February 19th, 2026** | The release date for the model. | | Knowledge cutoff date | **January 2025** | The date after which the model does not get any information updates. | | Input context window | **1m tokens** | The number of tokens supported by the input context window. | | Maximum output tokens | **65k tokens** | The number of tokens that can be generated by the model in a single request. | | Empirical throughput | **Not specified** | The number of tokens the model can generate per second. | | Open source | **No** | Specifies if the model's code is available for public use. | ## Additional documentation For additional information, see official Google Gemini 3.1 Pro documentation. # Google Gemini 3 Flash Source: https://developer.box.com/guides/box-ai/ai-models/google-gemini-3-flash-model-card **Google Gemini 3 Flash** is a natively multimodal model designed for speed and efficiency across a wide range of tasks. Delivers strong performance across text, image, and code generation while maintaining cost-effectiveness. ## Model details | Item | Value | Description | | --------------------- | ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Model name | **Google Gemini 3 Flash** | The name of the model. | | Model category | **Standard** | The category of the model: Standard or Premium. | | API model name | `google__gemini_3_flash` | The name of the model that is used in the Box AI API for model overrides. The user must provide this exact name for the API to work. | | Compliance | **N/A** | Government compliance frameworks and authorizations applicable to this model. | | Hosting layer | **Google** | The trusted organization that securely hosts the LLM. | | Model provider | **Google** | The organization that provides this model. | | Release date | **December 17th, 2025** | The release date for the model. | | Knowledge cutoff date | **January 2025** | The date after which the model does not get any information updates. | | Input context window | **1m tokens** | The number of tokens supported by the input context window. | | Maximum output tokens | **65k tokens** | The number of tokens that can be generated by the model in a single request. | | Empirical throughput | **Not specified** | The number of tokens the model can generate per second. | | Open source | **No** | Specifies if the model's code is available for public use. | ## Additional documentation For additional information, see [official Google Gemini 3 Pro documentation][vertex-ai-gemini-3-flash]. [vertex-ai-gemini-3-flash]: https://docs.cloud.google.com/vertex-ai/generative-ai/docs/models/gemini/3-flash # Google Gemini 3 Pro Source: https://developer.box.com/guides/box-ai/ai-models/google-gemini-3-pro-model-card **Google Gemini 3 Pro** is a natively multimodal model for complex tasks, which can comprehend vast datasets and solve challenging problems by processing different information sources, including text, audio, images, video, and entire code repositories. ## Model details | Item | Value | Description | | --------------------- | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Model name | **Google Gemini 3 Pro** | The name of the model. | | Model category | **Premium** | The category of the model: Standard or Premium. | | API model name | `google__gemini_3_pro` | The name of the model that is used in the Box AI API for model overrides. The user must provide this exact name for the API to work. | | Compliance | **N/A** | Government compliance frameworks and authorizations applicable to this model. | | Hosting layer | **Google** | The trusted organization that securely hosts the LLM. | | Model provider | **Google** | The organization that provides this model. | | Release date | **November 18th, 2025** | The release date for the model. | | Knowledge cutoff date | **January 2025** | The date after which the model does not get any information updates. | | Input context window | **1m tokens** | The number of tokens supported by the input context window. | | Maximum output tokens | **65k tokens** | The number of tokens that can be generated by the model in a single request. | | Empirical throughput | **Not specified** | The number of tokens the model can generate per second. | | Open source | **No** | Specifies if the model's code is available for public use. | ## Additional documentation For additional information, see [official Google Gemini 3 Pro documentation][vertex-ai-gemini-3-pro]. [vertex-ai-gemini-3-pro]: https://docs.cloud.google.com/vertex-ai/generative-ai/docs/models/gemini/3-pro # IBM Llama 3.2 Vision Instruct Source: https://developer.box.com/guides/box-ai/ai-models/ibm-llama-3-2-90b-vision-instruct-model-card **IBM Llama 3.2 Vision Instruct** is a model built for image-in, text-out use cases such as document-level understanding, interpretation of charts and graphs, and captioning of images. ## Model details | Item | Value | Description | | -------------------------- | ------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Model name | **IBM Llama 3.2 Vision Instruct** | The name of the model. | | Model category | **Standard** | The category of the model: Standard or Premium. | | API model name | `ibm__llama__3_2_90b_vision_instruct` | The name of the model that is used in the Box AI API for model overrides. The user must provide this exact name for the API to work. | | Compliance | **N/A** | Government compliance frameworks and authorizations applicable to this model. | | Hosting layer | **IBM** | The trusted organization that securely hosts the LLM. | | Model provider | **Meta** | The organization that provides this model. | | Release date | **September 25th 2024** | The release date for the model. | | Knowledge cutoff date | **December 2023** | The date after which the model does not get any information updates. | | Input context window | **128k** | The number of tokens supported by the input context window. | | Maximum output tokens | **Not specified** | The number of tokens that can be generated by the model in a single request. | | Empirical throughput | **Not specified** | The number of tokens the model can generate per second. | | Open source | **Yes** | Specifies if the model's code is available for public use. | | IP infringement protection | **No** | Use of this model does not come with any intellectual property rights assurances or protections from Box. Please consider any potential IP issues that might arise from using the model’s outputs. | ## Additional documentation For additional information, see [official IBM Llama 3.2 Vision Instruct documentation][IBM]. [IBM]: https://www.ibm.com/docs/en/watsonx/w-and-w/2.1.0?topic=models-third-party-foundation#llama-3-2-vision # IBM Llama 4 Maverick Source: https://developer.box.com/guides/box-ai/ai-models/ibm-llama-4-maverick-model-card **IBM Llama 4 Maverick** is a natively multimodal AI model using a mixture-of-experts architecture, designed for high-performance text and image understanding with support for 12 languages. ## Model details | Item | Value | Description | | -------------------------- | ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Model name | **IBM Llama 4 Maverick** | The name of the model. | | Model category | **Standard** | The category of the model: Standard or Premium. | | API model name | `ibm__llama_4_maverick` | The name of the model that is used in the [Box AI API for model overrides]. The user must provide this exact name for the API to work. | | Compliance | **N/A** | Government compliance frameworks and authorizations applicable to this model. | | Hosting layer | **IBM** | The trusted organization that securely hosts the LLM. | | Model provider | **Meta** | The organization that provides this model. | | Release date | **April 5th, 2025** | The release date for the model. | | Knowledge cutoff date | **August 2024** | The date after which the model does not get any information updates. | | Input context window | **1m** | The number of tokens supported by the input context window. | | Maximum output tokens | **Not specified** | The number of tokens that can be generated by the model in a single request. | | Empirical throughput | **Not specified** | The number of tokens the model can generate per second. | | Open source | **Yes** | Specifies if the model's code is available for public use. | | IP infringement protection | **No** | Use of this model does not come with any intellectual property rights assurances or protections from Box. Please consider any potential IP issues that might arise from using the model’s outputs. | ## Additional documentation For additional information, see [official IBM Llama 4 Scout documentation][IBM]. [Box AI API for model overrides]: /guides/box-ai/ai-agents/ai-agent-overrides [IBM]: https://www.ibm.com/docs/en/watsonx/w-and-w/2.2.0?topic=models-third-party-foundation#llama-4 # IBM Llama 4 Scout Source: https://developer.box.com/guides/box-ai/ai-models/ibm-llama-4-scout-model-card **IBM Llama 4 Scout** is an auto-regressive language model that uses a mixture-of-experts (MoE) architecture and incorporates early fusion for native multimodality. ## Model details | Item | Value | Description | | -------------------------- | --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Model name | **IBM Llama 4 Scout** | The name of the model. | | Model category | **Standard** | The category of the model: Standard or Premium. | | API model name | `ibm__llama_4_scout` | The name of the model that is used in the Box AI API for model overrides. The user must provide this exact name for the API to work. | | Compliance | **N/A** | Government compliance frameworks and authorizations applicable to this model. | | Hosting layer | **IBM** | The trusted organization that securely hosts the LLM. | | Model provider | **Meta** | The organization that provides this model. | | Release date | **April 5th 2025** | The release date for the model. | | Knowledge cutoff date | **August 2024** | The date after which the model does not get any information updates. | | Input context window | **10m** | The number of tokens supported by the input context window. | | Maximum output tokens | **Not specified** | The number of tokens that can be generated by the model in a single request. | | Empirical throughput | **Not specified** | The number of tokens the model can generate per second. | | Open source | **Yes** | Specifies if the model's code is available for public use. | | IP infringement protection | **No** | Use of this model does not come with any intellectual property rights assurances or protections from Box. Please consider any potential IP issues that might arise from using the model’s outputs. | ## Additional documentation For additional information, see [official IBM Llama 4 Scout documentation][IBM]. [IBM]: https://www.ibm.com/docs/en/watsonx/w-and-w/2.1.0?topic=models-third-party-foundation # IBM Mistral Medium 3 Source: https://developer.box.com/guides/box-ai/ai-models/ibm-mistral-medium-3-model-card The **IBM Mistral Medium 3** model is a high-performance enterprise-grade model that delivers frontier-level capabilities, excelling in coding, STEM reasoning, and multimodal understanding. ## Model details | Item | Value | Description | | -------------------------- | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Model name | **IBM Mistral Medium 3** | The name of the model. | | Model category | **Standard** | The category of the model: Standard or Premium. | | API model name | `ibm__mistral_medium_2505` | The name of the model that is used in the Box AI API for model overrides. The user must provide this exact name for the API to work. | | Compliance | **N/A** | Government compliance frameworks and authorizations applicable to this model. | | Hosting layer | **IBM** | The trusted organization that securely hosts the LLM. | | Model provider | **Mistral AI** | The organization that provides this model. | | Release date | **May 2025** | The release date for the model. | | Knowledge cutoff date | **Not specified** | The date after which the model does not get any information updates. | | Input context window | **128k tokens** | The number of tokens supported by the input context window. | | Maximum output tokens | **Not specified** | The number of tokens that can be generated by the model in a single request. | | Empirical throughput | **Not specified** | The number of tokens the model can generate per second. | | Open source | **No** | Specifies if the model's code is available for public use. | | IP infringement protection | **No** | Use of this model does not come with any intellectual property rights assurances or protections from Box. Please consider any potential IP issues that might arise from using the model’s outputs. | ## Additional documentation For additional information, see [official Mistral AI documentation][mistral-ai]. [mistral-ai]: https://docs.mistral.ai/getting-started/models/models_overview/ # IBM Mistral Small 3.1 Source: https://developer.box.com/guides/box-ai/ai-models/ibm-mistral-small-3-1-model-card The **IBM Mistral Small 3.1** model is a fast, efficient open-source model with multimodal capabilities and extended context window. It delivers strong performance across text and vision tasks while maintaining low latency, making it suitable for a wide range of applications from conversational AI to document processing. ## Model details | Item | Value | Description | | -------------------------- | ------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Model name | **IBM Mistral Small 3.1** | The name of the model. | | Model category | **Standard** | The category of the model: Standard or Premium. | | API model name | `ibm__mistral_small_3_1_24b_instruct_2503` | The name of the model that is used in the Box AI API for model overrides. The user must provide this exact name for the API to work. | | Compliance | **N/A** | Government compliance frameworks and authorizations applicable to this model. | | Hosting layer | **IBM** | The trusted organization that securely hosts the LLM. | | Model provider | **Mistral AI** | The organization that provides this model. | | Release date | **March 2025** | The release date for the model. | | Knowledge cutoff date | **Not specified** | The date after which the model does not get any information updates. | | Input context window | **128k tokens** | The number of tokens supported by the input context window. | | Maximum output tokens | **Not specified** | The number of tokens that can be generated by the model in a single request. | | Empirical throughput | **150** | The number of tokens the model can generate per second. | | Open source | **Yes** | Specifies if the model's code is available for public use. | | IP infringement protection | **No** | Use of this model does not come with any intellectual property rights assurances or protections from Box. Please consider any potential IP issues that might arise from using the model’s outputs. | ## Additional documentation For additional information, see [official Mistral AI documentation][mistral-ai]. [mistral-ai]: https://docs.mistral.ai/getting-started/models/models_overview/ # Supported AI models Source: https://developer.box.com/guides/box-ai/ai-models/index Core and customer-enabled AI models available in Box AI, with access levels, capability tiers, and API names. Box supports a variety of AI models, categorized along two dimensions: [access level](#access-levels) and [capability tier](#capability-tiers). ## Access levels | Level | Description | Configuration Required | | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- | | [**Core models**](#core-box-ai-models) | Built into Box AI and available by default for all customers | None | | [**Customer-enabled models**](#customer-enabled-models) | Require activation by Box admins in the Admin Console or a request to Box. Some models may be subject to additional terms or pricing. | Yes | ## Capability tiers | Tier | Description | Best For | | ------------------- | --------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | | **Standard models** | High-speed, cost-efficient performance | Basic summarization, Q\&A, structured data extraction from shorter or simpler documents. High-volume, low-complexity use cases | | **Premium models** | Advanced reasoning, larger context windows, better performance on complex content | Multi-step reasoning, large taxonomies, lengthy or unstructured documents, domain-specific content | A model can be both customer-enabled and premium, or core and standard. In other words, access level and capability tiers are independent categorizations (for example, models can be either capability tier regardless of access level). The two categorizations are complementary. ## Using models How to use the supported AI models: * Get the default AI agent configuration. * Override the AI agent configuration used in `POST 2.0/ai/ask`, `POST 2.0/ai/text_gen`, `POST 2.0/ai/extract`, `POST 2.0/ai/extract_structured` endpoints. When using the `model` parameter in your API calls, use the **API Name** visible on each model card listed below. For example, to get the AI agent configuration for a specific model, use the model parameter and provide the `azure__openai__gpt_4o_mini` API name. Make sure you use **two underscores** after the provider name. The list may change depending on the model availability. A free developer account gives you access to these AI models through the Box AI API. Start making API calls to test summarization, extraction, and more. ## Core models Box AI is powered by the following AI models. These models are integrated with Box AI to facilitate various use cases while adhering to enterprise grade standards. Below, you’ll find information about each model, including its capabilities, intended applications, and applicable usage guidelines. Models offered in **Preview** mode have not been fully performance-tested at scale. You may experience variability in output quality, availability, and accuracy. Frontier model for the most complex professional work Premium Compatible with Box Agent Multimodal model for both broad general-purpose work and most coding tasks Premium Compatible with Box Agent Multimodal model for coding and agentic tasks across various industries Premium Compatible with Box Agent Multimodal model with enterprise-grade performance and adaptive reasoning Premium Multimodal model with advanced reasoning and long-context understanding Premium Model designed for well-defined tasks and precise prompts, suitable for lightweight tasks Standard Multimodal model, highly efficient in handling complex, multi-step tasks Premium ISMAP FedRAMP Moderate FedRAMP High DoD IL2 Multimodal model designed to handle lightweight tasks and precise prompts Standard ISMAP FedRAMP Moderate FedRAMP High DoD IL2 Multimodal model, highly efficient in handling complex, multi-step tasks Premium ISMAP FedRAMP Moderate FedRAMP High DoD IL2 Multimodal model for lightweight tasks and precise prompts, best suited for focused tasks Standard ISMAP FedRAMP Moderate FedRAMP High DoD IL2 2nd-generation embedding model for text search, code search, and sentence similarity Embeddings Standard ISMAP FedRAMP Moderate FedRAMP High DoD IL2 Multimodal model with a 1 million token context window and advanced reasoning capabilities Premium ISMAP FedRAMP Moderate FedRAMP High DoD IL5 Multimodal model offering well-round capabilites, including thinking capabilities Standard ISMAP FedRAMP Moderate FedRAMP High DoD IL5 Multimodal model designed for optimal high-volume, high-frequency tasks at scale Standard ISMAP FedRAMP Moderate FedRAMP High DoD IL5 Multimodal model designed to handle lightweight tasks Standard ISMAP FedRAMP Moderate FedRAMP High DoD IL5 Multimodal model for coding, enterprise agents, and professional work Premium ISMAP FedRAMP Moderate Compatible with Box Agent Multimodal model for complex tasks with a 1 million token context window Premium ISMAP FedRAMP Moderate Compatible with Box Agent Multimodal model for complex tasks with a 1 million token context window Premium ISMAP FedRAMP Moderate Compatible with Box Agent Premium model combining maximum intelligence with practical performance Premium ISMAP FedRAMP Moderate Compatible with Box Agent Model that excels at complex agents, coding, and autonomous multi-step workflows Premium ISMAP FedRAMP Moderate Compatible with Box Agent Fast and cost-efficient model with near-frontier intelligence best for low-latency applications Standard ISMAP FedRAMP Moderate Compatible with Box Agent Model that excels at coding and complex problem-solving, powering frontier agents Premium ISMAP FedRAMP Moderate Model that brings frontier performance to everyday use cases Premium ISMAP FedRAMP Moderate Language model for advanced text processing and complex tasks with large context Standard ISMAP FedRAMP Moderate Multimodal model with a 1 million token context window and advanced reasoning capabilities Standard Natively multimodal, mixture-of-experts (MoE) model designed to handle lightweight tasks Standard Multimodal model designed to handle lightweight tasks Standard High-performance enterprise model for coding and advanced reasoning Preview Standard Fast open-source multimodal model with low latency Preview Standard ## Customer-enabled models Certain Box AI customers may enable additional AI models upon their request or upon the models otherwise being made available through their Admin Console. Use of these models may be subject to additional terms. By selecting a customer-enabled model, the customer acknowledges that their data may be processed by additional [subprocessors][subprocessors] of their choice. Models offered in **Beta** mode are provided on an as-is basis. Multimodal model, highly efficient in handling complex, multi-step tasks Beta Premium Model for complex tasks with advanced reasoning and a large context window Beta Premium Gemini multimodal model for high-speed and cost-efficient tasks Beta Standard Multimodal model for complex tasks with a 1 million token context window Beta Premium Multimodal model designed for speed and efficiency across a wide range of tasks Beta Standard Multimodal model for complex tasks with a 1 million token context window Beta Premium Multimodal model for complex tasks with a 1 million token context window Beta Premium ## Default models The following tables list the default AI models used when you do not override the agent configuration. The model that runs depends on the agent type, the provider, and the capability tier. Default settings shown below may not be applicable for certain customers with specific configurations or requirements. ### Legacy agents Legacy agents represent the initial generation of Box AI capabilities, designed to handle basic, single-step tasks such as simple Q\&A and document summarization. The table below specifies available models for a particular use case. | Use case | Provider | Model for Standard Version | Model for Advanced or Enhanced Version | | ----------------------------------- | ---------------- | ----------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | | Q\&A for Documents, Notes, and Hubs | OpenAI (Default) | GPT-5 mini | GPT-5.2 | | | Claude | Claude 4.5 Sonnet | Claude 4.5 Opus | | | Llama | Llama 4 Maverick | Llama 4 Maverick | ### Box agents Box agents are the next generation of intelligent assistants built with advanced reasoning and orchestration, capable of planning and executing complex, multi-step workflows across your entire Box content ecosystem. The table below specifies available models for each specialized agent type. | Agent | Model for Standard Version | Model for Pro or Enhanced Version | | ----------------------------- | ------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------- | | Box Agent | GPT 5.4 | Claude Sonnet 4.6 | | Extract Agent | Gemini 2.5 Flash | Gemini 2.5 Pro | | Security Classification Agent | Gemini 2.5 Flash | N/A | | Threat Analysis Agent | Gemini 2.5 Flash | N/A | [azure-ai-mini-4o-model]: https://learn.microsoft.com/en-us/azure/ai-services/openai/concepts/models?tabs=python-secure#gpt-4o-and-gpt-4-turbo [vertex-ai-model]: https://cloud.google.com/vertex-ai/generative-ai/docs/learn/models#models [vertex-ai-gemini-models]: https://cloud.google.com/vertex-ai/generative-ai/docs/learn/models#gemini-models [vertex-text-models]: https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/text [azure-ai-embeddings]: https://learn.microsoft.com/en-us/azure/ai-services/openai/concepts/models#embeddings [aws-claude]: https://aws.amazon.com/bedrock/claude/ [aws-titan]: https://aws.amazon.com/bedrock/titan/ [subprocessors]: https://www.box.com/legal/subprocessors # OpenAI GPT-5.1 Source: https://developer.box.com/guides/box-ai/ai-models/openai-gpt-5-1-model-card **OpenAI GPT-5.1** is a multimodal model designed for coding and agentic tasks with configurable reasoning effort. ## Model details | Item | Value | Description | | --------------------- | ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Model name | **GPT-5.1** | The name of the model. | | Model category | **Premium** | The category of the model: Standard or Premium. | | API model name | `openai__gpt_5_1` | The name of the model that is used in the Box AI API for model overrides. The user must provide this exact name for the API to work. | | Compliance | **N/A** | Government compliance frameworks and authorizations applicable to this model. | | Hosting layer | **OpenAI** | The trusted organization that securely hosts the LLM. | | Model provider | **OpenAI** | The organization that provides this model. | | Release date | **November 13th, 2025** | The release date for the model. | | Knowledge cutoff date | **September 30th, 2024** | The date after which the model does not get any information updates. | | Input context window | **400k tokens** | The number of tokens supported by the input context window. | | Maximum output tokens | **128k tokens** | The number of tokens that can be generated by the model in a single request. | | Empirical throughput | **Not specified** | The number of tokens the model can generate per second. | | Open source | **No** | Specifies if the model's code is available for public use. | ## Additional documentation For additional information, see [official OpenAI GPT-5 documentation][openai-gpt-5-model]. [openai-gpt-5-model]: https://platform.openai.com/docs/models/gpt-5.1 # OpenAI GPT-5.2 Source: https://developer.box.com/guides/box-ai/ai-models/openai-gpt-5-2-model-card **OpenAI GPT-5.2** is a multimodal model designed for complex tasks that require broad world knowledge. ## Model details | Item | Value | Description | | --------------------- | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Model name | **GPT-5.2** | The name of the model. | | Model category | **Premium** | The category of the model: Standard or Premium. | | API model name | `openai__gpt_5_2` | The name of the model that is used in the Box AI API for model overrides. The user must provide this exact name for the API to work. | | Compliance | **N/A** | Government compliance frameworks and authorizations applicable to this model. | | Hosting layer | **OpenAI** | The trusted organization that securely hosts the LLM. | | Model provider | **OpenAI** | The organization that provides this model. | | Release date | **December 11th, 2025** | The release date for the model. | | Knowledge cutoff date | **August 31st, 2025** | The date after which the model does not get any information updates. | | Input context window | **400k tokens** | The number of tokens supported by the input context window. | | Maximum output tokens | **128k tokens** | The number of tokens that can be generated by the model in a single request. | | Empirical throughput | **Not specified** | The number of tokens the model can generate per second. | | Open source | **No** | Specifies if the model's code is available for public use. | ## Additional documentation For additional information, see [official OpenAI GPT-5.2 documentation][openai-gpt-5-model]. [openai-gpt-5-model]: https://platform.openai.com/docs/models/gpt-5.2 # OpenAI GPT-5.4 Source: https://developer.box.com/guides/box-ai/ai-models/openai-gpt-5-4-model-card **OpenAI GPT-5.4** is a frontier model, unifying the Codex and GPT lines into a single system. It features a 1m+ token context window with support for text and image inputs, enabling high-context reasoning, coding, and multimodal analysis within the same workflow. ## Model details | Item | Value | Description | | --------------------- | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Model name | **GPT-5.4** | The name of the model. | | Model category | **Premium** | The category of the model: Standard or Premium. | | API model name | `openai__gpt_5_4` | The name of the model that is used in the Box AI API for model overrides. You must provide this exact name for the API to work. | | Compliance | **N/A** | Government compliance frameworks and authorizations applicable to this model. | | Hosting layer | **OpenAI** | The trusted organization that securely hosts the LLM. | | Model provider | **OpenAI** | The organization that provides this model. | | Release date | **March 5th, 2026** | The release date for the model. | | Knowledge cutoff date | **August 31st, 2025** | The date after which the model does not get any information updates. | | Input context window | **1m tokens** | The number of tokens supported by the input context window. | | Maximum output tokens | **128k tokens** | The number of tokens that can be generated by the model in a single request. | | Empirical throughput | **Not specified** | The number of tokens the model can generate per second. | | Open source | **No** | Specifies if the model's code is available for public use. | ## Additional documentation For additional information, see official OpenAI GPT-5.4 documentation. # OpenAI GPT-5.5 Source: https://developer.box.com/guides/box-ai/ai-models/openai-gpt-5-5-model-card **OpenAI GPT-5.5** is a frontier model for the most complex professional work. It raises the baseline for complex production workflows. It is a strong fit for coding use cases, tool-heavy agents, grounded assistants, long-context retrieval, product-spec-to-plan workflows, and customer-facing workflows where execution quality and response polish are critical. ## Model details | Item | Value | Description | | --------------------- | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Model name | **GPT-5.5** | The name of the model. | | Model category | **Premium** | The category of the model: Standard or Premium. | | API model name | `openai__gpt_5_5` | The name of the model that is used in the Box AI API for model overrides. You must provide this exact name for the API to work. | | Compliance | **N/A** | Government compliance frameworks and authorizations applicable to this model. | | Hosting layer | **OpenAI** | The trusted organization that securely hosts the LLM. | | Model provider | **OpenAI** | The organization that provides this model. | | Release date | **April 23, 2026** | The release date for the model. | | Knowledge cutoff date | **December 01, 2025** | The date after which the model does not get any information updates. | | Input context window | **1m tokens** | The number of tokens supported by the input context window. | | Maximum output tokens | **128k tokens** | The number of tokens that can be generated by the model in a single request. | | Empirical throughput | **Not specified** | The number of tokens the model can generate per second. | | Open source | **No** | Specifies if the model's code is available for public use. | ## Additional documentation For additional information, see official OpenAI GPT-5.5 documentation. # OpenAI GPT-5 mini Source: https://developer.box.com/guides/box-ai/ai-models/openai-gpt-5-mini-model-card **OpenAI GPT-5 mini** is a faster, more cost-efficient version of GPT-5 ideal for well-defined tasks and precise prompts. ## Model details | Item | Value | Description | | --------------------- | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Model name | **GPT-5 mini** | The name of the model. | | Model category | **Standard** | The category of the model: Standard or Premium. | | API model name | `openai__gpt_5_mini` | The name of the model that is used in the Box AI API for model overrides. The user must provide this exact name for the API to work. | | Compliance | **N/A** | Government compliance frameworks and authorizations applicable to this model. | | Hosting layer | **OpenAI** | The trusted organization that securely hosts the LLM. | | Model provider | **OpenAI** | The organization that provides this model. | | Release date | **August 7th, 2025** | The release date for the model. | | Knowledge cutoff date | **May 31st, 2024** | The date after which the model does not get any information updates. | | Input context window | **400k tokens** | The number of tokens supported by the input context window. | | Maximum output tokens | **128k tokens** | The number of tokens that can be generated by the model in a single request. | | Empirical throughput | **Not specified** | The number of tokens the model can generate per second. | | Open source | **No** | Specifies if the model's code is available for public use. | ## Additional documentation For additional information, see [official OpenAI GPT-5 mini documentation][openai-gpt-5-mini-model]. [openai-gpt-5-mini-model]: https://platform.openai.com/docs/models/gpt-5-mini # OpenAI GPT-5 Source: https://developer.box.com/guides/box-ai/ai-models/openai-gpt-5-model-card **OpenAI GPT-5** is a multimodal model with advanced reasoning and long-context understanding. ## Model details | Item | Value | Description | | --------------------- | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Model name | **GPT-5** | The name of the model. | | Model category | **Premium** | The category of the model: Standard or Premium. | | API model name | `openai__gpt_5` | The name of the model that is used in the Box AI API for model overrides. The user must provide this exact name for the API to work. | | Compliance | **N/A** | Government compliance frameworks and authorizations applicable to this model. | | Hosting layer | **OpenAI** | The trusted organization that securely hosts the LLM. | | Model provider | **OpenAI** | The organization that provides this model. | | Release date | **August 7th, 2025** | The release date for the model. | | Knowledge cutoff date | **October 2024** | The date after which the model does not get any information updates. | | Input context window | **1m tokens** | The number of tokens supported by the input context window. | | Maximum output tokens | **100k tokens** | The number of tokens that can be generated by the model in a single request. | | Empirical throughput | **Not specified** | The number of tokens the model can generate per second. | | Open source | **No** | Specifies if the model's code is available for public use. | ## Additional documentation For additional information, see [official OpenAI GPT-5 documentation][openai-gpt-5-model]. [openai-gpt-5-model]: https://openai.com/index/introducing-gpt-5/ # OpenAI GPT o3 Source: https://developer.box.com/guides/box-ai/ai-models/openai-gpt-o3-model-card **OpenAI GPT o3** is specifically designed to tackle reasoning and problem-solving tasks with increased focus and capability. It spends more time processing and understanding the user's request, making it exceptionally strong in areas like science, coding, and math compared to previous iterations. ## Model details | Item | Value | Description | | --------------------- | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Model name | **GPT o3** | The name of the model. | | Model category | **Premium** | The category of the model: Standard or Premium. | | API model name | `openai__gpt_o3` | The name of the model that is used in the Box AI API for model overrides. The user must provide this exact name for the API to work. | | Compliance | **N/A** | Government compliance frameworks and authorizations applicable to this model. | | Hosting layer | **OpenAI** | The trusted organization that securely hosts the LLM. | | Model provider | **OpenAI** | The organization that provides this model. | | Release date | **April 16th, 2025** | The release date for the model. | | Knowledge cutoff date | **May 2024** | The date after which the model does not get any information updates. | | Input context window | **200k tokens** | The number of tokens supported by the input context window. | | Maximum output tokens | **100k tokens** | The number of tokens that can be generated by the model in a single request. | | Empirical throughput | **Not specified** | The number of tokens the model can generate per second. | | Open source | **No** | Specifies if the model's code is available for public use. | ## Additional documentation For additional information, see [official OpenAI GPT o3 documentation][openai-o3-model]. [openai-o3-model]: https://openai.com/index/introducing-o3-and-o4-mini/ # xAI Grok 3 Beta Source: https://developer.box.com/guides/box-ai/ai-models/xai-grok-3-beta-model-card **xAI Grok 3 Beta** is a model that excels at enterprise use cases like data extraction, coding, and text summarization. Possesses deep domain knowledge in finance, healthcare, law, and science. ## Model details | Item | Value | Description | | -------------------------- | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Model name | **xAI Grok 3 Beta** | The name of the model. | | Model category | **Premium** | The category of the model: Standard or Premium. | | API model name | `xai__grok_3_beta` | The name of the model that is used in the Box AI API for model overrides. The user must provide this exact name for the API to work. | | Compliance | **N/A** | Government compliance frameworks and authorizations applicable to this model. | | Hosting layer | **xAI** | The trusted organization that securely hosts the LLM. | | Model provider | **xAI** | The organization that provides this model. | | Release date | **April 17th 2025** | The release date for the model. | | Knowledge cutoff date | **January 2025** | The date after which the model does not get any information updates. | | Input context window | **1m tokens** | The number of tokens supported by the input context window. | | Maximum output tokens | **131k tokens** | The number of tokens that can be generated by the model in a single request. | | Empirical throughput | **Not specified** | The number of tokens the model can generate per second. | | Open source | **No** | Specifies if the model's code is available for public use. | | IP infringement protection | **No** | Use of this model does not come with any intellectual property rights assurances or protections from Box. Please consider any potential IP issues that might arise from using the model’s outputs. | ## Additional documentation For additional information, see [official xAI Grok 3 Mini Beta documentation][xai-grok-models]. [xai-grok-models]: https://docs.x.ai/docs/models # xAI Grok 3 Mini Reasoning Beta Source: https://developer.box.com/guides/box-ai/ai-models/xai-grok-3-mini-beta-model-card **xAI Grok 3 Mini Reasoning Beta** is a lightweight model that thinks before responding. Fast, smart, and great for logic-based tasks that do not require deep domain knowledge. The raw thinking traces are accessible. ## Model details | Item | Value | Description | | -------------------------- | ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Model name | **xAI Grok 3 Mini Reasoning Beta** | The name of the model. | | Model category | **Standard** | The category of the model: Standard or Premium. | | API model name | `xai__grok_3_mini_reasoning_beta` | The name of the model that is used in the Box AI API for model overrides. The user must provide this exact name for the API to work. | | Compliance | **N/A** | Government compliance frameworks and authorizations applicable to this model. | | Hosting layer | **xAI** | The trusted organization that securely hosts the LLM. | | Model provider | **xAI** | The organization that provides this model. | | Release date | **April 9th 2025** | The release date for the model. | | Knowledge cutoff date | **unknown** | The date after which the model does not get any information updates. | | Input context window | **131k tokens** | The number of tokens supported by the input context window. | | Maximum output tokens | **131k tokens** | The number of tokens that can be generated by the model in a single request. | | Empirical throughput | **Not specified** | The number of tokens the model can generate per second. | | Open source | **No** | Specifies if the model's code is available for public use. | | IP infringement protection | **No** | Use of this model does not come with any intellectual property rights assurances or protections from Box. Please consider any potential IP issues that might arise from using the model’s outputs. | ## Additional documentation For additional information, see [official xAI Grok 3 Mini Beta documentation][xai-grok-models]. [xai-grok-models]: https://docs.x.ai/docs/models # Ask questions to Box AI Source: https://developer.box.com/guides/box-ai/ai-tutorials/ask-questions Use the POST /ai/ask endpoint to ask questions about one or more files stored in Box. Box AI API is available to all customers Business and above. Box AI API allows you to ask a question about a supplied file or a set of files, and get a response based on the content. For example, while viewing a document in Box, you can ask Box AI to summarize the content. ## Before you start Make sure you followed the steps listed in getting started with Box AI to create a platform app and authenticate. ## Send a request To send a request containing your question, use the `POST /2.0/ai/ask` endpoint and provide the mandatory parameters. ```sh cURL theme={null} curl -i -L POST "https://api.box.com/2.0/ai/ask" \ -H "content-type: application/json" \ -H "authorization: Bearer " \ -d '{ "mode": "single_item_qa", "prompt": "What is the value provided by public APIs based on this document?", "items": [ { "type": "file", "id": "9842787262" } ], "dialogue_history": [ { "prompt": "Make my email about public APIs sound more professional", "answer": "Here is the first draft of your professional email about public APIs", "created_at": "2013-12-12T10:53:43-08:00" } ], "include_citations": true, "ai_agent": { "type": "ai_agent_ask", "long_text": { "model": "azure__openai__gpt_4o_mini", "prompt_template": "It is `{current_date}`, and I have $8000 and want to spend a week in the Azores. What should I see?", }, "basic_text": { "model": "azure__openai__gpt_4o_mini", } } }' ``` ```typescript Node/TypeScript v10 theme={null} await client.ai.createAiAsk({ mode: 'single_item_qa' as AiAskModeField, prompt: 'which direction sun rises', items: [ { id: fileToAsk.id, type: 'file' as AiItemAskTypeField, content: 'Sun rises in the East', } satisfies AiItemAsk, ], aiAgent: aiAskAgentConfig, } satisfies AiAsk); ``` ```python Python v10 theme={null} client.ai.create_ai_ask( CreateAiAskMode.SINGLE_ITEM_QA, "which direction sun rises", [ AiItemAsk( id=file_to_ask.id, type=AiItemAskTypeField.FILE, content="Sun rises in the East", ) ], ai_agent=ai_ask_agent_config, ) ``` ```cs .NET v10 theme={null} await client.Ai.CreateAiAskAsync(requestBody: new AiAsk(mode: AiAskModeField.SingleItemQa, prompt: "which direction sun rises", items: Array.AsReadOnly(new [] {new AiItemAsk(id: fileToAsk.Id, type: AiItemAskTypeField.File) { Content = "Sun rises in the East" }}))); ``` ```swift Swift v10 theme={null} try await client.ai.createAiAsk(requestBody: AiAsk(mode: AiAskModeField.singleItemQa, prompt: "which direction sun rises", items: [AiItemAsk(id: fileToAsk.id, type: AiItemAskTypeField.file, content: "Sun rises in the East")])) ``` ```java Java v10 theme={null} client.getAi().createAiAsk(new AiAsk.Builder(AiAskModeField.SINGLE_ITEM_QA, "which direction sun rises", Arrays.asList(new AiItemAsk.Builder(fileToAsk.getId(), AiItemAskTypeField.FILE).content("Sun rises in the East").build())).aiAgent(aiAskAgentConfig).build()) ``` ```java Java v5 theme={null} BoxAIResponse response = BoxAI.sendAIRequest( api, "What is the content of the file?", Collections.singletonList("123456", BoxAIItem.Type.FILE), BoxAI.Mode.SINGLE_ITEM_QA ); ``` ```python Python v4 theme={null} items = [{ "id": "1582915952443", "type": "file", "content": "More information about public APIs" }] ai_agent = { 'type': 'ai_agent_ask', 'basic_text_multi': { 'model': 'openai__gpt_3_5_turbo' } } answer = client.send_ai_question( items=items, prompt="What is this file?", mode="single_item_qa", ai_agent=ai_agent ) print(answer) ``` ```cs .NET v6 theme={null} BoxAIResponse response = await client.BoxAIManager.SendAIQuestionAsync( new BoxAIAskRequest { Prompt = "What is the name of the file?", Items = new List() { new BoxAIAskItem() { Id = "12345" } }, Mode = AiAskMode.single_item_qa }; ); ``` ```javascript Node v4 theme={null} client.ai.ask( { prompt: 'What is the capital of France?', items: [ { type: 'file', id: '12345' } ], mode: 'single_item_qa' }) .then(response => { /* response -> { "answer": "Paris", "created_at": "2021-10-01T00:00:00Z", "completion_reason": "done" } */ }); ``` ### Parameters To make a call, you need to pass the following parameters. Mandatory parameters are in **bold**. | Parameter | Description | Available values | Example | | ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **`mode`** | The type of request. Use `single_item_qa` for a single file (the `items` array must contain exactly one element) or `multiple_item_qa` for up to 25 files. For full details on file size, image, and prompt limits, see input limits. | `single_item_qa`, `multiple_item_qa` | `single_item_qa` | | **`prompt`** | The question about your document or content. Maximum 10,000 characters. | | `What is this document about?` | | `dialogue_history.prompt` | The prompt previously provided by the client and answered by the Large Language Model (LLM). | `Make my email about public APIs sound more professional` | | | `dialogue_history.answer` | The answer previously provided by the LLM. | `Here is a draft of your professional email about public APIs.` | | | `dialogue_history.created_at` | The ISO date formatted timestamp of when the previous answer to the prompt was created. | `2012-12-12T10:53:43-08:00` | | | `include_citations` | Specifies if the citations should be returned in the answer. | `true`, `false` | `true` | | **`items.id`** | The Box file ID you want to provide as input. | | `112233445566` | | **`items.type`** | The type of the provided input. Currently, it can be a single file or multiple files. | `file` | `file` | | `items.content` | The content of the item. Usually it is the text representation. | | `An application programming interface (API) is a way for two or more computer programs or components to communicate with each other. It is a type of software interface...` | | `ai_agent` | Override the default model configuration. Lets you change the model, prompt template, system message, or LLM parameters. See the override system for how it works and AI model overrides for examples. | | | ## Use cases ## Ask questions about an item This example shows how to ask a question about one or more items using the `POST ask/ai` API. When using this endpoint, remember to specify the `mode` parameter depending on the number of items you want to supply. ```sh theme={null} curl -i -L POST "https://api.box.com/2.0/ai/ask" \ -H "content-type: application/json" \ -H "authorization: Bearer " \ -d '{ "mode": "single_item_qa", "items": [ { "id": "12345678", "type": "file" } ], "prompt": "List the guidelines on creating questions in Box AI for Documents" }' ``` The response will be as follows: ```sh theme={null} { "answer": "The guidelines for working with questions in Box AI for Documents are as follows:\n\n1. Box AI pulls information only from the document loaded in preview.\n2. If questions fall outside the scope of the document, Box AI will inform you that it cannot answer.\n3. Be specific when asking questions; use parameters like numbered lists, brevity, tables, and central themes or key points.\n4. Aim to stay within the scope of the document.\n5. Focus on text-based responses only.", "created_at": "2024-11-04T02:30:09.557-08:00", "completion_reason": "done" } ``` ## Ask questions with `content` parameter If you use the `content` parameter as the source of input for Box AI, it will use it as the primary source. ```sh theme={null} curl -i -L POST "https://api.box.com/2.0/ai/ask" \ -H "content-type: application/json" \ -H "authorization: Bearer " \ -d '{ "mode": "single_item_qa", "items": [ { "id": "12345678", "type": "file", "content": "This is a document about Box AI For documents. It consists of the functionality summary and guidelines on how to work with Box AI. Additionally, it provides a set of best practices for creating questions." } ], "prompt": "List the guidelines on creating questions in Box AI for Documents" }' ``` The response to this request is based on the `content` parameter instead of the file's content: ```sh theme={null} { "answer": "The document does not provide specific guidelines on working with questions in Box AI for Documents. It only mentions that it includes a set of best practices for creating questions, but the details of those guidelines are not included in the text provided. If you have more information or another document, I can help further!", "created_at": "2024-11-04T02:31:51.125-08:00", "completion_reason": "done" } ``` ## Ask questions with `citations` parameter Setting the `citations` parameter to `true` causes the response to include excerpts from source file or files Box AI used to compile the answer. ```sh theme={null} curl -i -L POST "https://api.box.com/2.0/ai/ask" \ -H "content-type: application/json" \ -H "authorization: Bearer " \ -d '{ "mode": "multiple_item_qa", "include_citations": true, "items": [ { "id": "12345678", "type": "file" } ], "prompt": "List the guidelines on working with responses in Box AI for Documents" }' ``` The resulting answer includes the source file and direct content citations. ```sh theme={null} { "answer": "The guidelines for working with questions in Box AI for Documents are as follows:\n\n1. Box AI pulls information only from the document loaded in preview, and cannot answer questions outside its scope.\n2. Be specific when asking questions; use parameters like numbered lists, brevity, tables, and central themes or key points.\n3. Examples of better phrasing include asking for a numbered list of key points instead of just \"list key points,\" and requesting a succinct outline of important points rather than a general inquiry about the document's purpose.\n4. Stay within the scope of the document and focus on text-based responses only.", "created_at": "2024-11-04T02:35:00.578-08:00", "completion_reason": "done", "citations": [ { "type": "file", "id": "12345678", "name": "Box AI for Documents.docx", "content": "Guidelines for Box AI questions\nBox AI pulls information only from the document you loaded in preview." }, { "type": "file", "id": "12345678", "name": "Box AI for Documents.docx", "content": "If you ask any questions outside of the scope of the document, Box AI informs you that it cannot answer the question with the information provided." }, { "type": "file", "id": "12345678", "name": "Box AI for Documents.docx", "content": "As you ask Box AI to analyze your document, consider these suggestions:\n· Be as specific as possible." }, { "type": "file", "id": "12345678", "name": "Box AI for Documents.docx", "content": "Box AI for Documents\n\nWhen viewing a document in Box, you can ask Box AI to summarize document content, search key points, and write outline drafts based on your document files." } ] } ``` # Override AI model configuration Source: https://developer.box.com/guides/box-ai/ai-tutorials/default-agent-overrides Step-by-step examples of overriding prompts and models for ask, text_gen, and extract endpoints. ## Before you start Make sure you followed the steps listed in getting started with Box AI to create a platform app and authenticate. To get more context, read about agent overrides. ## Override prompt This example shows how to use the `prompt_template` parameter to change the query result. The first step is to ask Box AI to summarize a document about Box AI for Documents. The `mode` parameter is set to `single_item_qa` because only one document is supplied. ```sh theme={null} curl -i -L POST "https://api.box.com/2.0/ai/ask" \ -H "content-type: application/json" \ -H "authorization: " \ -d '{ "mode": "single_item_qa", "prompt": "Summarize this article about Box AI for Documents", "items": [ { "type": "file", "id": "123467890" } ] }' ``` You will get a response similar to the following: ```sh theme={null} { "answer": "Box AI for Documents is a tool that enhances document analysis by allowing users to summarize content, identify key points, and draft outlines directly from files in Box. It supports various file types, including text documents, spreadsheets, and presentation slides. Users can initiate interactions with Box AI through the web app, where they can select suggestions or type specific questions. Responses are generated in real time, and users have options to save or clear chat history. The document also provides guidelines for effective inquiries and troubleshooting tips for potential issues with using Box AI.", "created_at": "2024-10-08T00:29:07.283-07:00", "completion_reason": "done" } ``` To further improve the result, you can use the `prompt_template` parameter to add some more instructions for Box AI. In this example, let's change the tone of the response. ```sh theme={null} { "prompt": "Summarize this article about Box AI for Documents", "mode": "single_item_qa", "items": [ { "id": "123467890", "type": "file" } ], "ai_agent": { "type": "ai_agent_ask", "basic_text": { "prompt_template": "prompt_template": "{user_question} Write the summary in an informal way.{content}" }, } } } ``` The response would be slightly less formal: ```sh theme={null} { "answer": "Box AI for Documents is a tool that helps you analyze and gain insights from your documents in Box. You can use it to summarize content, identify key points, and draft outlines, making it easier to handle meeting notes, reports, and marketing materials. To get started, just open a file in the Box web app and click the Box AI button. It offers quick suggestions like summarizing the document or checking for next steps. Responses are generated in real time, and you can save them or clear chat history as needed. Just remember, Box AI only pulls info from the document you're viewing, so be specific with your questions!", "created_at": "2024-10-08T00:38:01.767-07:00", "completion_reason": "done" } ``` ## Override AI model (text generation) This example shows you how changing the AI model in the `ai_agent` options can influence the way the text is generated. First let's generate some text using the `POST ai/text_gen` endpoint. This endpoint is using the OpenAI 3.5 turbo model by default. ```sh theme={null} curl -i -L POST "https://api.box.com/2.0/ai/text_gen" \ -H "content-type: application/json" \ -H "authorization: Bearer TOKEN" \ -d '{ "prompt": "Write a short post about Box AI for documents.Make it highlight the benefits of the solution. You can add some emoticons.", "items": [ { "id": "123467890", "type": "file" } ] } ``` The response is as follows: ```sh theme={null} { "answer": "🌟 Exciting News! 🌟\n\nIntroducing Box AI for documents - your new best friend in creating smarter, more efficient content! 🤖💡\n\n🔹 Say goodbye to manual searching and organizing - Box AI does it all for you!\n🔹 Enjoy lightning-fast document analysis and categorization.\n🔹 Boost productivity with automated suggestions and smart recommendations.\n🔹 Collaborate seamlessly with real-time insights and intelligent tagging.\n\nExperience the future of document creation with Box AI - making work easier, faster, and more fun! 🚀💻 #BoxAI #SmartDocuments", "created_at": "2024-10-08T01:19:06.22-07:00", "completion_reason": "done" } ``` Let's change the model using the `ai_agent` configuration: ```sh theme={null} curl -i -L POST "https://api.box.com/2.0/ai/text_gen" \ -H "content-type: application/json" \ -H "authorization: Bearer TOKEN" \ -d '{ "prompt": "Write a short post about Box AI for documents.Make it highlight the benefits of the solution. You can add some emoticons.", "items": [ { "id": "123467890", "type": "file" } ], "ai_agent": { "type": "ai_agent_text_gen", "basic_gen": { "model": "openai__gpt_4o_2024_05_13" } } } ``` After the model switch, the response is slightly different: ```sh theme={null} { "answer": "🚀 **Boost Your Productivity with Box AI for Documents!** 📄✨\n\nSay goodbye to tedious document creation and editing! With Box AI, you can streamline your workflow and focus on what truly matters. Here’s why you’ll love it:\n\n1. **Smart Suggestions** 🤖: Get real-time recommendations to enhance your content.\n2. **Automated Formatting** 📝: Ensure consistency across all your documents effortlessly.\n3. **Collaboration Made Easy** 👥: Work seamlessly with your team, no matter where they are.\n4. **Time-Saving Templates** ⏳: Use pre-built templates to speed up document creation.\n5. **Enhanced Accuracy** ✅: Reduce errors with intelligent proofreading.\n\nTransform the way you work with documents and experience a new level of efficiency with Box AI! 🌟", "created_at": "2024-10-08T01:28:36.777-07:00", "completion_reason": "done" } ``` As you can see the responses differ to some extent. Thanks to the model switch, you can optimize your interaction with Box AI and choose the most suitable model for your needs. ## Override AI model (metadata extraction) Switching models can also give us different results for metadata extraction. Let's use a sample contract to extract the metadata. In this example, the model used is Google Gemini. ```sh theme={null} curl -i -L 'https://api.box.com/2.0/ai/extract' \ -H 'content-type: application/json' \ -H 'authorization: Bearer TOKEN' \ -d '{ "prompt": "Extract any data that would be good metadata to save for future contracts.", "items": [ { "type": "file", "id": "123456789" } ] }' ``` The response is a set of metadata: ```sh theme={null} { "answer": "{\"Buyer Legal Entity Name\": \"Acme Retail Corp.\", \"Supplier Legal Entity Name\": \"Acme Manufacturing Inc.\", \"Buyer Contact Person\": \"Jane Doe\", \"Supplier Contact Person\": \"Eva Smith\", \"Payment Term\": \"payment in full before pickup of goods\", \"Invoice Currency\": \"Euro\", \"Incoterm\": \"FCA Amsterdam\", \"Governing Law\": \"laws state jurisdiction in which supplier is located\", \"Effective Date\": \"March 27, 2024\", \"Buyer Signature Date\": \"March 28th, 2024\", \"Supplier Signature Date\": \"March 28th, 2024\"}", "created_at": "2024-10-08T01:53:14.993-07:00", "completion_reason": "done" } ``` Let's change the model to the most recent OpenAI option: ```sh theme={null} curl -i -L 'https://api.box.com/2.0/ai/extract' \ -H 'content-type: application/json' \ -H 'authorization: Bearer TOKEN' \ -d '{ "prompt": "Extract any data that would be good metadata to save for future contracts.", "items": [ { "type": "file", "id": "123456789" } ], "ai_agent": { "type": "ai_agent_extract", "basic_text": { "model": "openai__gpt_4o_2024_05_13" } } }' ``` Using this model results in a response listing more metadata entries: ```sh theme={null} { "answer": "{\"Effective Date\": \"March 27, 2024\", \"Supplier Legal Entity Name\": \"Acme Manufacturing Inc.\", \"Supplier Registered Office Address\": \"123 Main Street\", \"Supplier Contact Person(s)\": \"Eva Smith\", \"Buyer Legal Entity Name\": \"Acme Retail Corp.\", \"Buyer Registered Office Address\": \"456 Market Avenue\", \"Buyer Contact Person(s)\": \"Jane Doe\", \"Incoterm\": \"FCA Amsterdam\", \"Payment Term\": \"payment in full before pickup of goods\", \"Invoice Currency\": \"Euro\", \"Buyer Printed Name\": \"Jane Doe\", \"Buyer Date\": \"March 28th, 2024\", \"Buyer Title / Position\": \"CEO\", \"Seller Printed Name\": \"Eve Smith\", \"Seller Date\": \"March 28th, 2024\", \"Seller Title / Position\": \"Sales Manager\"}", "created_at": "2024-10-08T01:54:28.099-07:00", "completion_reason": "done" } ``` # Extract metadata from file (freeform) Source: https://developer.box.com/guides/box-ai/ai-tutorials/extract-metadata Use the POST /ai/extract endpoint to extract metadata from documents using natural language prompts. Box AI API allows you to query a document and extract metadata based on a provided prompt. **Freeform** means that the prompt can include a stringified version of formats such as JSON or XML, or even plain text. The **Extract metadata (freeform)** endpoint doesn't support OCR. To extract metadata from image files (TIFF, PNG, JPEG) or documents in languages other than English, use the Extract metadata (structured) endpoint. ## Before you start Make sure you followed the steps listed in getting started with Box AI to create a platform app and authenticate. ## Send a request To send a request, use the `POST /2.0/ai/extract` endpoint. ```sh cURL theme={null} curl -i -L 'https://api.box.com/2.0/ai/extract' \ -H 'content-type: application/json' \ -H 'authorization: Bearer ' \ -d '{ "prompt": "Extract data related to contract conditions", "items": [ { "type": "file", "id": "1497741268097" } ], "ai_agent": { "type": "ai_agent_extract", "long_text": { "model": "azure__openai__gpt_4o_mini", "prompt_template": "It is `{current_date}`, and I have $8000 and want to spend a week in the Azores. What should I see?", }, "basic_text": { "model": "azure__openai__gpt_4o_mini", } } }' ``` ```typescript Node/TypeScript v10 theme={null} await client.ai.createAiExtract({ prompt: 'firstName, lastName, location, yearOfBirth, company', items: [new AiItemBase({ id: file.id })], aiAgent: agentIgnoringOverridingEmbeddingsModel, } satisfies AiExtract); ``` ```python Python v10 theme={null} client.ai.create_ai_extract( "firstName, lastName, location, yearOfBirth, company", [AiItemBase(id=file.id)], ai_agent=agent_ignoring_overriding_embeddings_model, ) ``` ```cs .NET v10 theme={null} await client.Ai.CreateAiExtractAsync(requestBody: new AiExtract(prompt: "firstName, lastName, location, yearOfBirth, company", items: Array.AsReadOnly(new [] {new AiItemBase(id: file.Id)}))); ``` ```swift Swift v10 theme={null} try await client.ai.createAiExtract(requestBody: AiExtract(prompt: "firstName, lastName, location, yearOfBirth, company", items: [AiItemBase(id: file.id)])) ``` ```java Java v10 theme={null} client.getAi().createAiExtract(new AiExtract.Builder("firstName, lastName, location, yearOfBirth, company", Arrays.asList(new AiItemBase(file.getId()))).aiAgent(agentIgnoringOverridingEmbeddingsModel).build()) ``` ```java Java v5 theme={null} BoxAIResponse response = BoxAI.extractMetadataFreeform( api, "firstName, lastName, location, yearOfBirth, company", Collections.singletonList(new BoxAIItem("123456", BoxAIItem.Type.FILE)) ); ``` ### Parameters To make a call, you must pass the following parameters. Mandatory parameters are in **bold**. The `items` array must contain exactly one element. For prompt and file limits, see input limits. | Parameter | Description | Example | | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------- | | **`prompt`** | The request for Box AI to extract metadata. Maximum 10,000 characters. | Create a meeting agenda for a weekly sales meeting. | | **`items.id`** | Box file ID of the document. The ID must reference an actual file with an extension. | `1233039227512` | | **`items.type`** | The type of the supplied input. | `file` | | `items.content` | The content of the item, often the text representation. | `This article is about Box AI`. | | `ai_agent` | Override the default model configuration. Lets you change the model, prompt template, system message, or LLM parameters. See the override system for how it works and AI model overrides for examples. | | ## Use cases This example shows you how to extract metadata from a sample invoice. ### Create the request To get the response from Box AI, call `POST /2.0/ai/extract` endpoint with the following parameters: * `prompt` that can be a query, or a structured or unstructured list of fields to extract. * `type` and `id` of the file to extract the data from. ### Create the prompt Depending on the use case and the level of detail, you can construct various prompts. #### Use plain text Because this endpoint allows freeform prompts, you can use plain text to get the information. ```bash theme={null} curl --location 'https://api.box.com/2.0/ai/extract' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer ' \ --data '{ "prompt": "find the document type (invoice or po), vendor, total, and po number", "items": [ { "type": "file", "id": "1443721424754" } ] }' ``` In such a case, the response will be based on the keywords included in the text: ```bash theme={null} { "answer": "{\"Document Type\": \"Invoice\", \"Vendor\": \"Quasar Innovations\", \"Total\": \"$1,050\", \"PO Number\": \"003\"}", "created_at": "2024-05-31T10:30:51.223-07:00", "completion_reason": "done" } ``` #### Use specific terms If you don't want to write the entire sentence, the prompt can consist of terms that you expect to find in an invoice: ```bash theme={null} curl --location 'https://api.box.com/2.0/ai/extract' \ --header 'Content-Type: application/json' \ --header 'Authorization: ' \ --data '{ "prompt": "{\"vendor\",\"total\",\"doctype\",\"date\",\"PO\"}", "items": [ { "type": "file", "id": "1443721424754" } ] }' ``` Using this approach results in a list of terms provided in the request and their values: ```bash theme={null} { "answer": "{\"vendor\": \"Quasar Innovations\", \"total\": \"$1,050\", \"doctype\": \"Invoice\", \"PO\": \"003\"}", "created_at": "2024-05-31T10:28:51.906-07:00", "completion_reason": "done" } ``` #### Use key-value pairs The prompt can also be a list of key-value pairs that helps Box AI to come up with the metadata structure. This approach requires listing the key-value pairs within a `fields` array. ```bash theme={null} curl --location 'https://api.box.com/2.0/ai/extract' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer ' \ --data '{ "prompt": "{\"fields\": [{\"key\":\"vendor\",\"displayName\":\"Vendor\",\"type\":\"string\",\"description\":\ "Vendorname\"},{\"key\":\"documentType\",\"displayName\":\"Type\",\"type\":\"string\",\"description\":\"\"}]}", "items": [ { "type": "file", "id": "1443721424754" } ] }' ``` The response includes the `fields` present in the file, along with their values: ```bash theme={null} { "answer": "{\"vendor\": \"Quasar Innovations\", \"documentType\": \"Invoice\"}", "created_at": "2024-05-31T10:15:38.17-07:00", "completion_reason": "done" } ``` # Extract metadata from file (structured) Source: https://developer.box.com/guides/box-ai/ai-tutorials/extract-metadata-structured Use the POST /ai/extract_structured endpoint to extract metadata using templates, field definitions, or the Enhanced Extract Agent. With Box AI API, you can extract metadata from the provided file and get the result in the form of key-value pairs. As input, you can either create a structure using the `fields` parameter, or use an already defined metadata template. To learn more about creating templates, see [Creating metadata templates in the Admin Console][templates-console] or use the metadata template API. You can also [autofill metadata in templates][autofill-metadata] using our Standard or Enhanced Extraction Agent. ## Supported file formats The endpoint supports the following file formats: * PDF * DOC * DOCX * GDOC * ODT * Box Note * TEXT * RTF * XDW * AS * TIFF * TIF * PNG * JPEG * JPG * WEBP * PPT * PPTX * GSLIDE * GSLIDES * ODP * OTP * XLS * XLSX * XLSM * ODS * CSV * Languages: `.js`, `.py`, `.css`, `.php`, `.sql` * JSON * HTML * XML * MD Box AI automatically applies optical character recognition (OCR) when processing image files (TIFF, PNG, JPEG) and scanned documents. This eliminates the need to convert images to PDF before extraction, saving time and simplifying your integration. ## Supported languages Box AI can extract metadata from documents in the following languages: * English * Japanese * Chinese * Korean - Cyrillic-based languages (such as Russian, Ukrainian, Bulgarian, and Serbian) No additional configuration is required to use different languages or image formats. Box AI automatically detects the language and applies OCR when needed. ## Before you start Make sure you followed the steps listed in getting started with Box AI to create a platform app and authenticate. ## Send a request To send a request, use the `POST /2.0/ai/extract_structured` endpoint. ```sh cURL theme={null} curl -i -L 'https://api.box.com/2.0/ai/extract_structured' \ -H 'content-type: application/json' \ -H 'authorization: Bearer ' \ -d '{ "items": [ { "id": "12345678", "type": "file", "content": "This is file content." } ], "metadata_template": { "template_key": "", "type": "metadata_template", "scope": "" }, "fields": [ { "key": "name", "description": "The name of the person.", "displayName": "Name", "prompt": "The name is the first and last name from the email address.", "type": "string", "options": [ { "key": "First Name" }, { "key": "Last Name" ] } ], "ai_agent": { "type": "ai_agent_extract_structured", "long_text": { "model": "azure__openai__gpt_4o_mini" }, "basic_text": { "model": "azure__openai__gpt_4o_mini" } } }' ``` ```typescript Node/TypeScript v10 theme={null} await client.ai.createAiExtractStructured({ fields: [ { key: 'firstName', displayName: 'First name', description: 'Person first name', prompt: 'What is the your first name?', type: 'string', } satisfies AiExtractStructuredFieldsField, { key: 'lastName', displayName: 'Last name', description: 'Person last name', prompt: 'What is the your last name?', type: 'string', } satisfies AiExtractStructuredFieldsField, { key: 'dateOfBirth', displayName: 'Birth date', description: 'Person date of birth', prompt: 'What is the date of your birth?', type: 'date', } satisfies AiExtractStructuredFieldsField, { key: 'age', displayName: 'Age', description: 'Person age', prompt: 'How old are you?', type: 'float', } satisfies AiExtractStructuredFieldsField, { key: 'hobby', displayName: 'Hobby', description: 'Person hobby', prompt: 'What is your hobby?', type: 'multiSelect', options: [ { key: 'guitar' } satisfies AiExtractStructuredFieldsOptionsField, { key: 'books' } satisfies AiExtractStructuredFieldsOptionsField, ], } satisfies AiExtractStructuredFieldsField, ], items: [new AiItemBase({ id: file.id })], aiAgent: agentIgnoringOverridingEmbeddingsModel, } satisfies AiExtractStructured); ``` ```python Python v10 theme={null} client.ai.create_ai_extract_structured( [AiItemBase(id=file.id)], fields=[ CreateAiExtractStructuredFields( key="firstName", display_name="First name", description="Person first name", prompt="What is the your first name?", type="string", ), CreateAiExtractStructuredFields( key="lastName", display_name="Last name", description="Person last name", prompt="What is the your last name?", type="string", ), CreateAiExtractStructuredFields( key="dateOfBirth", display_name="Birth date", description="Person date of birth", prompt="What is the date of your birth?", type="date", ), CreateAiExtractStructuredFields( key="age", display_name="Age", description="Person age", prompt="How old are you?", type="float", ), CreateAiExtractStructuredFields( key="hobby", display_name="Hobby", description="Person hobby", prompt="What is your hobby?", type="multiSelect", options=[ CreateAiExtractStructuredFieldsOptionsField(key="guitar"), CreateAiExtractStructuredFieldsOptionsField(key="books"), ], ), ], ai_agent=agent_ignoring_overriding_embeddings_model, ) ``` ```cs .NET v10 theme={null} await client.Ai.CreateAiExtractStructuredAsync(requestBody: new AiExtractStructured(items: Array.AsReadOnly(new [] {new AiItemBase(id: file.Id)})) { Fields = Array.AsReadOnly(new [] {new AiExtractStructuredFieldsField(key: "firstName") { DisplayName = "First name", Description = "Person first name", Prompt = "What is the your first name?", Type = "string" },new AiExtractStructuredFieldsField(key: "lastName") { DisplayName = "Last name", Description = "Person last name", Prompt = "What is the your last name?", Type = "string" },new AiExtractStructuredFieldsField(key: "dateOfBirth") { DisplayName = "Birth date", Description = "Person date of birth", Prompt = "What is the date of your birth?", Type = "date" },new AiExtractStructuredFieldsField(key: "age") { DisplayName = "Age", Description = "Person age", Prompt = "How old are you?", Type = "float" },new AiExtractStructuredFieldsField(key: "hobby") { DisplayName = "Hobby", Description = "Person hobby", Prompt = "What is your hobby?", Type = "multiSelect", Options = Array.AsReadOnly(new [] {new AiExtractStructuredFieldsOptionsField(key: "guitar"),new AiExtractStructuredFieldsOptionsField(key: "books")}) }}) }); ``` ```swift Swift v10 theme={null} try await client.ai.createAiExtractStructured(requestBody: AiExtractStructured(fields: [AiExtractStructuredFieldsField(key: "firstName", displayName: "First name", description: "Person first name", prompt: "What is the your first name?", type: "string"), AiExtractStructuredFieldsField(key: "lastName", displayName: "Last name", description: "Person last name", prompt: "What is the your last name?", type: "string"), AiExtractStructuredFieldsField(key: "dateOfBirth", displayName: "Birth date", description: "Person date of birth", prompt: "What is the date of your birth?", type: "date"), AiExtractStructuredFieldsField(key: "age", displayName: "Age", description: "Person age", prompt: "How old are you?", type: "float"), AiExtractStructuredFieldsField(key: "hobby", displayName: "Hobby", description: "Person hobby", prompt: "What is your hobby?", type: "multiSelect", options: [AiExtractStructuredFieldsOptionsField(key: "guitar"), AiExtractStructuredFieldsOptionsField(key: "books")])], items: [AiItemBase(id: file.id)])) ``` ```java Java v10 theme={null} client.getAi().createAiExtractStructured(new AiExtractStructured.Builder(Arrays.asList(new AiItemBase(file.getId()))).fields(Arrays.asList(new AiExtractStructuredFieldsField.Builder("firstName").description("Person first name").displayName("First name").prompt("What is the your first name?").type("string").build(), new AiExtractStructuredFieldsField.Builder("lastName").description("Person last name").displayName("Last name").prompt("What is the your last name?").type("string").build(), new AiExtractStructuredFieldsField.Builder("dateOfBirth").description("Person date of birth").displayName("Birth date").prompt("What is the date of your birth?").type("date").build(), new AiExtractStructuredFieldsField.Builder("age").description("Person age").displayName("Age").prompt("How old are you?").type("float").build(), new AiExtractStructuredFieldsField.Builder("hobby").description("Person hobby").displayName("Hobby").prompt("What is your hobby?").type("multiSelect").options(Arrays.asList(new AiExtractStructuredFieldsOptionsField("guitar"), new AiExtractStructuredFieldsOptionsField("books"))).build())).aiAgent(agentIgnoringOverridingEmbeddingsModel).build()) ``` ```java Java v5 theme={null} BoxAIExtractMetadataTemplate template = new BoxAIExtractMetadataTemplate("templateKey", "enterprise"); BoxAIExtractStructuredResponse result = BoxAI.extractMetadataStructured( api, Collections.singletonList(new BoxAIItem("123456", BoxAIItem.Type.FILE)), template ); JsonObject sourceJson = result.getSourceJson(); ``` ### Parameters To make a call, you must pass the following parameters. Mandatory parameters are in **bold**. The `items` array must contain exactly one element. For prompt and file limits, see input limits. | Parameter | Description | Example | | ------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- | | **`metadata_template`** | The metadata template containing the fields to extract. For your request to work, you must provide either `metadata_template` or `fields`, but not both. | | | **`metadata_template.type`** | The type of metadata template. | `metadata_template` | | **`metadata_template.scope`** | The scope of the metadata template that can either be `global` or `enterprise`. Global templates are those available to any Box enterprise, whereas `enterprise` templates are bound to a specific enterprise. | `metadata_template` | | **`metadata_template.template_key`** | The name of your metadata template. | `invoice` | | **`items.id`** | Box file ID of the document. The ID must reference an actual file with an extension. | `1233039227512` | | **`items.type`** | The type of the supplied input. | `file` | | `ai_agent` | Override the default model configuration. Lets you change the model, prompt template, system message, or LLM parameters. See the override system for how it works and AI model overrides for examples. | | | `include_confidence_score` | A flag to indicate whether to include the confidence score for every extracted field. | `true` | | `include_reference` | A flag to indicate whether to include references for every extracted field. | `true` | | `items.content` | The content of the item, often the text representation. | `This article is about Box AI`. | | `fields.description` | A description of the field. | `The person's name.` | | `fields.displayName` | The display name of the field. | `Name` | | `fields.key` | A unique identifier for the field. | `name` | | `fields.namespace` | The namespace of the taxonomy source. Required if using `taxonomy` type field from an existing taxonomy. | `string` | | `fields.options` | A list of options for this field. This is most often used in combination with the `enum` and `multiSelect` field types. | `[{"key":"First Name"},{"key":"Last Name"}]` | | `fields.options.key` | A unique identifier for the field. | `First Name` | | `fields.prompt` | Additional context about the key (identifier) that can include how to find and format it. | `Name is the first and last name from the email address` | | `fields.type` | The type of the field. It includes but is not limited to `string`, `float`, `date`, `enum`, `multiSelect`, `struct`, `table`. | `string` | | `fields.taxonomy_key` | The identifier for a taxonomy, which corresponds to the `key` of the taxonomy source. Required if using `taxonomy` type field. | `string` | ### `struct` and `table` field types The Box AI `extract_structured` API supports two complex field types — `struct` and `table` in addition to the existing scalar types (`string`, `float`, `date`, `enum`, `multiSelect`). The `struct` and `table` types allow you to extract grouped and repeating structured data from documents. For best results, use the [enhanced extract agent](/guides/box-ai/ai-agents/enhanced-extract-agent). #### `struct` field type Use the `struct` type to group multiple related sub-fields into a single named JSON object. This is useful when you want to extract a set of related values that belong together and receive them as one structured object rather than separate flat fields. Example: an address or a person's contact details. A `struct` field requires a `fields` array that defines its sub-fields. Each sub-field is an object with the following properties: * `key`: The unique identifier for the sub-field. * `type`: The type of the sub-field. Supported types are `string`, `text`, `number`, `float`, `boolean`, `date`, `enum`, `multiSelect`, and `array[]` (e.g. `array[string]`). Nested `struct` or `table` types are not supported as sub-fields. * `displayName`: The display name of the sub-field. * `description`: A description of the sub-field. * `prompt`: Additional context about the sub-field that can include how to find and format it. You can add a prompt at the `struct` field level when instructions apply to the whole grouped object. The output is a single JSON object containing the extracted sub-field values. **Example request for the `struct` field type** ```json theme={null} { "fields": [ { "key": "address", "displayName": "Address", "type": "struct", "fields": [ { "key": "street_name", "type": "string" }, { "key": "home_number", "type": "string" }, { "key": "postal_code", "type": "string" }, { "key": "city", "type": "string" } ] } ] } ``` **Response:** ```json theme={null} { "answer": { "address": { "street_name": "Main St", "home_number": "123", "postal_code": "94105", "city": "San Francisco" } } } ``` #### `table` field type Use the `table` type to extract repeating rows of structured data as an array of JSON objects, where each object represents one row. This is useful when a document contains multiple instances of the same data structure, for example: line items in an invoice or entries in a tax table. A `table` field requires a `fields` array that defines the columns (sub-fields) of each row. The sub-field properties and supported types are identical to those of `struct`. Table extraction is not limited to visually formatted tables. The `table` type correctly extracts repeating data whether it appears as a grid, key-value pairs, a form layout, or plain prose. The output is an array of JSON objects, where each object represents one extracted row. **Example request for the `table` field type** ```json theme={null} { "fields": [ { "key": "line_items", "displayName": "Line Items", "type": "table", "fields": [ { "key": "description", "type": "string" }, { "key": "quantity", "type": "float" }, { "key": "amount", "type": "float" } ] } ] } ``` **Response:** ```json theme={null} { "answer": { "line_items": [ { "description": "Desk", "quantity": 2.0, "amount": 399.99 }, { "description": "Chair", "quantity": 4.0, "amount": 149.99 } ] } } ``` #### Supported sub-field types The following types are supported within both struct and table fields. | Type | Notes | | ------------- | ------------------------- | | `string` | Scalar or array\[string] | | `text` | Scalar or array\[text] | | `number` | Scalar or array\[number] | | `float` | Scalar or array\[float] | | `boolean` | Scalar or array\[boolean] | | `date` | Scalar or array\[date] | | `enum` | Single occurrence only | | `multiSelect` | Single occurrence only | Nested `struct` and `table` types are not supported as sub-fields. ## Use cases This example shows you how to extract metadata from a sample invoice in a structured way. Let's assume you want to extract the vendor name, invoice number, and a few more details. sample invoice ### Create the request To get the response from Box AI, call `POST /2.0/ai/extract_structured` endpoint with the following parameters: * `items.type` and `items.id` to specify the file to extract the data from. * `fields` to specify the data that you want to extract from the given file. * `metadata_template` to supply an already existing metadata template. You can use either `fields` or `metadata_template` to specify your structure, but not both. ### Use `fields` parameter The `fields` parameter allows you to specify the data you want to extract. Each `fields` object has a subset of parameters you can use to add more information about the searched data. For example, you can add the field type, description, or even a prompt with some additional context. ```bash theme={null} curl --location 'https://api.box.com/2.0/ai/extract_structured' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer '' \ --data '{ "items": [ { "id": "1517628697289", "type": "file" } ], "fields": [ { "key": "document_type", "type": "enum", "prompt": "what type of document is this?", "options": [ { "key": "Invoice" }, { "key": "Purchase Order" }, { "key": "Unknown" } ] }, { "key": "document_date", "type": "date" }, { "key": "vendor", "description": "The name of the entity.", "prompt": "Which vendor is sending this document.", "type": "string" }, { "key": "document_total", "type": "float" } ] }' ``` The response lists the specified fields and their values: ```bash theme={null} { "document_date": "2024-02-13", "vendor": "Quasar Innovations", "document_total": $1050, "document_type": "Purchase Order" } ``` ### Use metadata template If you prefer to use a metadata template, you can provide its `template_key`, `type`, and `scope`. ```bash theme={null} curl --location 'https://api.box.com/2.0/ai/extract_structured' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer ' \ --data '{ "items": [ { "id": "1517628697289", "type": "file" } ], "metadata_template": { "template_key": "rbInvoicePO", "type": "metadata_template", "scope": "enterprise_1134207681" } }' ``` The response lists the fields included in the metadata template and their values: ```bash theme={null} { "documentDate": "February 13, 2024", "total": "$1050", "documentType": "Purchase Order", "vendor": "Quasar Innovations", "purchaseOrderNumber": "003" } ``` ### Enhanced Extract Agent To use the Enhanced Extract Agent, specify the `ai_agent` object as follows: ```bash theme={null} { "ai_agent": { "type": "ai_agent_id", "id": "enhanced_extract_agent" } } ``` To extract data using the Enhanced Extract Agent you need one of the following: * [Inline field definitions][inline-field] (best when fields change frequently) * [Metadata template][metadata-template] (best when fields stay consistent) See the sample code snippet using Box Python SDK: ```Python theme={null} from box_sdk_gen import ( AiAgentReference, AiAgentReferenceTypeField, AiItemBase, AiItemBaseTypeField, BoxClient, BoxCCGAuth, CCGConfig, CreateAiExtractStructuredMetadataTemplate ) # Create your client credentials grant config from the developer console ccg_config = CCGConfig( client_id="my_box_client_id", # replace with your client id client_secret="my_box_client_secret", # replace with your client secret user_id="my_box_user_id", # replace with the box user id that has access # to the file you are referencing ) auth = BoxCCGAuth(config=ccg_config) client = BoxClient(auth=auth) # Create the agent config referencing the enhanced extract agent enhanced_extract_agent_config = AiAgentReference( id="enhanced_extract_agent", type=AiAgentReferenceTypeField.AI_AGENT_ID ) # Use the Box SDK to call the extract_structured endpoint box_ai_response = client.ai.create_ai_extract_structured( # Create the items array containing the file information to extract from items=[ AiItemBase( id="my_box_file_id", # replace with the file id type=AiItemBaseTypeField.FILE ) ], # Reference the Box Metadata template metadata_template=CreateAiExtractStructuredMetadataTemplate( template_key="InvoicePO", scope="enterprise" ), # Attach the agent config you created earlier ai_agent=enhanced_extract_agent_config, ) print(f"box_ai_response: {box_ai_response.answer}") ``` [templates-console]: https://support.box.com/hc/en-us/articles/360044194033-Customizing-Metadata-Templates [changelog]: https://developer.box.com/changelog [blog]: https://medium.com/box-developer-blog [inline-field]: #use-fields-parameter [metadata-template]: #use-metadata-template [autofill-metadata]: https://support.box.com/hc/en-us/articles/360044196173-Using-Metadata#h_01JJSRYKDKXHGJT9ZHCW1E9RX5 See structured extraction in action. Build an end-to-end automation that watches a folder, extracts invoice fields, and writes metadata back to each file. # Extract APIs overview and use cases Source: https://developer.box.com/guides/box-ai/ai-tutorials/extract-use-cases Explore use cases for the Box AI Extract API, including structured and freeform metadata extraction across industries. Data extraction can be challenging because source content varies widely with different layouts, templates, and file types. The Box Extract API provides two AI-powered endpoints: structured extraction and freeform extraction that standardize how you extract metadata from files in Box. With these endpoints, you can: * Extract specific fields into a consistent schema or Box metadata template (structured extraction). * Use enhanced extraction for more complex use cases and improved accuracy powered by advanced AI models (structured extraction). * Extract content when the target fields are not known ahead of time (freeform extraction). * Run extractions without building your own orchestration, permission checks, or throttling logic around the extraction workflow. * Extract data from documents in various languages, file formats, scanned documents, or photos. To explore the possibilities of these endpoints, discover the following use cases in various industries: **Recommended endpoint:** structured metadata extraction (`POST /2.0/ai/extract_structured`) Ideal for high-volume, standardized documents where you need predictable data types: * **Automated data entry:** Structured metadata extraction ensures consistent JSON response every time thanks to a preconfigured metadata template. * **Invoices and purchase orders:** Extract line items, totals, and dates. * **Client contracts:** Parse standardized fields like "Effective Date" or "Total Contract Value" to update CRM records. **Recommended endpoint:** freeform metadata extraction (`POST /2.0/ai/extract`) Ideal for queries where document structure is not known ahead of time or varies: * **HR onboarding:** Extract key personal details from diverse offer letters or candidate resumes. * **NDA clauses:** Extract specific NDA clauses from legal documents. Use advanced features like Optical Character Recognition (OCR) and enhanced extraction agent for regulated sectors: * **Know Your Customer (KYC) documents:** Verify user’s identity by extracting text from scanned passports or driver's licenses. * **Loan origination:** Automate income verification by pulling data from scanned utility bills or pay stubs. * **Clinical Trial Enrollment:** Extract patient criteria from medical forms to match candidates with trials. * **Regulatory submissions:** Organize and validate the data required for submissions such as FDA or EMA. * **Permit applications:** Accelerate zoning approvals by validating required documentation. * **Public records requests:** Automatically classify and prioritize documents for public requests such as Freedom of Information Act (FOIA). ## Core benefits of using the Box Extract API * **Managed scaling:** The Box Extract API is designed to handle queues and rate limits, so you can run high-volume processing. * **No defensive code:** The Box Extract API is model-agnostic, which enables switching between supported LLMs with minimal code changes and minimizing vendor lock-in. * **Security and compliance:** All extracted data inherits the enterprise-grade security and governance policies of the Box platform. ## Try it yourself Follow a step-by-step walkthrough that builds a working accounts payable automation: watch a folder for new invoices, extract structured fields, and write metadata back to each file. ## Next steps Get started with the Box Extract API with practical example-led quick starts guides, API reference pages, and extensive developer guides: # Generate text with Box AI Source: https://developer.box.com/guides/box-ai/ai-tutorials/generate-text Use the POST /ai/text_gen endpoint to generate or refine text based on file content stored in Box. Box AI API is available to all customers Business and above. You can use Box AI to generate text based on provided content. For example, you can ask Box AI to generate a template based on the content you read or create in Box Notes. Then you can embed the generated text directly into your document. ## Before you start Make sure you followed the steps listed in getting started with Box AI to create a platform app and authenticate. ## Send a request To send a request, use the `POST /2.0/ai/text_gen` endpoint. ```sh cURL theme={null} curl -i -L POST "https://api.box.com/2.0/ai/text_gen" \ -H "content-type: application/json" \ -H "authorization: Bearer " \ -d '{ "prompt": "Write a social media post about protein powder.", "items": [ { "id": "12345678", "type": "file", "content": "More information about protein powders" }, ], "dialogue_history": [ { "prompt": "Can you add some more information?", "answer": "Public API schemas provide necessary information to integrate with APIs...", "created_at": "2013-12-12T11:20:43-08:00" } ], "ai_agent": { "type": "ai_agent_text_gen", "basic_gen": { "model": "azure__openai__gpt_4o_mini" } } }' ``` ```typescript Node/TypeScript v10 theme={null} await client.ai.createAiTextGen({ prompt: 'Parapharse the document.s', items: [ new AiTextGenItemsField({ id: fileToAsk.id, type: 'file' as AiTextGenItemsTypeField, content: 'The Earth goes around the sun. Sun rises in the East in the morning.', }), ], dialogueHistory: [ { prompt: 'What does the earth go around?', answer: 'The sun', createdAt: dateTimeFromString('2021-01-01T00:00:00Z'), } satisfies AiDialogueHistory, { prompt: 'On Earth, where does the sun rise?', answer: 'East', createdAt: dateTimeFromString('2021-01-01T00:00:00Z'), } satisfies AiDialogueHistory, ], aiAgent: aiTextGenAgentConfig, } satisfies AiTextGen); ``` ```python Python v10 theme={null} client.ai.create_ai_text_gen( "Parapharse the document.s", [ CreateAiTextGenItems( id=file_to_ask.id, type=CreateAiTextGenItemsTypeField.FILE, content="The Earth goes around the sun. Sun rises in the East in the morning.", ) ], dialogue_history=[ AiDialogueHistory( prompt="What does the earth go around?", answer="The sun", created_at=date_time_from_string("2021-01-01T00:00:00Z"), ), AiDialogueHistory( prompt="On Earth, where does the sun rise?", answer="East", created_at=date_time_from_string("2021-01-01T00:00:00Z"), ), ], ai_agent=ai_text_gen_agent_config, ) ``` ```cs .NET v10 theme={null} await client.Ai.CreateAiTextGenAsync(requestBody: new AiTextGen(prompt: "Parapharse the document.s", items: Array.AsReadOnly(new [] {new AiTextGenItemsField(id: fileToAsk.Id, type: AiTextGenItemsTypeField.File) { Content = "The Earth goes around the sun. Sun rises in the East in the morning." }})) { DialogueHistory = Array.AsReadOnly(new [] {new AiDialogueHistory() { Prompt = "What does the earth go around?", Answer = "The sun", CreatedAt = Utils.DateTimeFromString(dateTime: "2021-01-01T00:00:00Z") },new AiDialogueHistory() { Prompt = "On Earth, where does the sun rise?", Answer = "East", CreatedAt = Utils.DateTimeFromString(dateTime: "2021-01-01T00:00:00Z") }}) }); ``` ```swift Swift v10 theme={null} try await client.ai.createAiTextGen(requestBody: AiTextGen(prompt: "Parapharse the document.s", items: [AiTextGenItemsField(id: fileToAsk.id, type: AiTextGenItemsTypeField.file, content: "The Earth goes around the sun. Sun rises in the East in the morning.")], dialogueHistory: [AiDialogueHistory(prompt: "What does the earth go around?", answer: "The sun", createdAt: try Utils.Dates.dateTimeFromString(dateTime: "2021-01-01T00:00:00Z")), AiDialogueHistory(prompt: "On Earth, where does the sun rise?", answer: "East", createdAt: try Utils.Dates.dateTimeFromString(dateTime: "2021-01-01T00:00:00Z"))])) ``` ```java Java v10 theme={null} client.getAi().createAiTextGen(new AiTextGen.Builder("Parapharse the document.s", Arrays.asList(new AiTextGenItemsField.Builder(fileToAsk.getId()).type(AiTextGenItemsTypeField.FILE).content("The Earth goes around the sun. Sun rises in the East in the morning.").build())).dialogueHistory(Arrays.asList(new AiDialogueHistory.Builder().prompt("What does the earth go around?").answer("The sun").createdAt(dateTimeFromString("2021-01-01T00:00:00Z")).build(), new AiDialogueHistory.Builder().prompt("On Earth, where does the sun rise?").answer("East").createdAt(dateTimeFromString("2021-01-01T00:00:00Z")).build())).aiAgent(aiTextGenAgentConfig).build()) ``` ```java Java v5 theme={null} List dialogueHistory = new ArrayList<>(); dialogueHistory.add( new BoxAIDialogueEntry( "Make my email about public APIs sound more professional", "Here is the first draft of your professional email about public APIs.", BoxDateFormat.parse("2013-05-16T15:26:57-07:00") ) ); BoxAIResponse response = BoxAI.sendAITextGenRequest( api, "Write an email to a client about the importance of public APIs.", Collections.singletonList(new BoxAIItem("123456", BoxAIItem.Type.FILE)), dialogueHistory ); ``` ```python Python v4 theme={null} items = [{ "id": "1582915952443", "type": "file", "content": "More information about public APIs" }] dialogue_history = [{ "prompt": "Make my email about public APIs sound more professional", "answer": "Here is the first draft of your professional email about public APIs", "created_at": "2013-12-12T10:53:43-08:00" }, { "prompt": "Can you add some more information?", "answer": "Public API schemas provide necessary information to integrate with APIs...", "created_at": "2013-12-12T11:20:43-08:00" }] ai_agent = { 'type': 'ai_agent_text_gen', 'basic_gen': { 'model': 'openai__gpt_3_5_turbo_16k' } } answer = client.send_ai_text_gen( dialogue_history=dialogue_history, items=items, prompt="Write an email to a client about the importance of public APIs.", ai_agent=ai_agent ) print(answer) ``` ```cs .NET v6 theme={null} BoxAIResponse response = await client.BoxAIManager.SendAITextGenRequestAsync( new BoxAITextGenRequest { Prompt = "What is the name of the file?", Items = new List() { new BoxAITextGenItem() { Id = "12345" } }, DialogueHistory = new List() { new BoxAIDialogueHistory() { Prompt = "What is the name of the file?", Answer = "MyFile", CreatedAt = DateTimeOffset.Parse("2024-05-16T15:26:57-07:00") } new BoxAIDialogueHistory() { Prompt = "What is the size of the file?", Answer = "10kb", CreatedAt = DateTimeOffset.Parse("2024-05-16T15:26:57-07:00") } } }; ); ``` ```javascript Node v4 theme={null} client.ai.textGen( { prompt: 'What is the capital of France?', items: [ { type: 'file', id: '12345' } ], dialogue_history: [ { prompt: 'What is the capital of France?', answer: 'Paris', created_at: '2021-10-01T00:00:00Z' }, { prompt: 'What is the capital of Germany?', answer: 'Berlin', created_at: '2021-10-01T00:00:00Z' } ] }) .then(response => { /* response -> { "answer": "The capital of France is Paris.", "created_at": "2021-10-01T00:00:00Z", "completion_reason": "done" } */ }); ``` ### Parameters To make a call, you must pass the following parameters. Mandatory parameters are in **bold**. The `items` array must contain exactly one element. For full details on prompt and file limits, see input limits. | Parameter | Description | Example | | ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- | | **`prompt`** | The request for Box AI to generate or refine the text. Maximum 10,000 characters. | Create a meeting agenda for a weekly sales meeting. | | **`items.id`** | Box file ID of the document. | `1233039227512` | | **`items.type`** | The type of the supplied input. | `file` | | `items.content` | The content of the item, often the text representation. | `This article is about Box AI`. | | `dialogue_history.prompt` | The prompt previously provided by the client and answered by the Large Language Model (LLM). | `Make my email about public APIs sound more professional` | | `dialogue_history.answer` | The answer previously provided by the LLM. | `Here is a draft of your professional email about public APIs.` | | `dialogue_history.created_at` | The ISO date formatted timestamp of when the previous answer to the prompt was created. | `2012-12-12T10:53:43-08:00` | | `ai_agent` | Override the default model configuration. Lets you change the model, prompt template, system message, or LLM parameters. See the override system for how it works and AI model overrides for examples. | | ## Use cases Generate text based on the provided file content and a prompt. ```sh theme={null} curl -i -L POST "https://api.box.com/2.0/ai/text_gen" \ -H "content-type: application/json" \ -H "authorization: Bearer " \ -d '{ "items": [ { "id": "12345678", "type": "file" } ], "prompt": "Create a short blog post that provides information on Box AI for Documents and focuses on best practices for asking questions. You can add emoticons, but not too many." }' ``` The result will be as follows: ```sh theme={null} { "answer": "📝 **Box AI for Documents: Best Practices for Asking Questions** 🤔\n\n---\n\nWelcome to our blog post on Box AI for Documents! 🎉 Today, we're going to dive into some best practices when it comes to asking questions within this innovative platform.\n\n1. **Be Clear and Concise**: When formulating a question in Box Notes, make sure your query is clear and to the point. This helps Box AI understand exactly what you're looking for.\n\n2. **Provide Context**: Giving context around your question can significantly improve the accuracy of the response generated by Box AI. Include relevant details or background information.\n\n3. **Use Keywords**: Utilize keywords related to your query within the question itself. This can help Box AI better identify the main topic of your inquiry.\n\n4. **Avoid Ambiguity**: Try to avoid vague or ambiguous questions that could lead to misunderstandings. The more precise you are, the better Box AI can assist you.\n\n5. **Review Suggestions Carefully**: After receiving suggestions from Box AI, take the time to review them carefully before incorporating them into your document. Ensure they align with your intended message.\n\nBy following these best practices, you can maximize the effectiveness of Box AI for Documents and streamline your workflow like never before! 💼✨\n\nStay tuned for more tips and tricks on leveraging technology for enhanced productivity! 👩‍💻🚀", "created_at": "2024-11-04T02:46:23.459-08:00", "completion_reason": "done" } ``` # Box AI tutorials Source: https://developer.box.com/guides/box-ai/ai-tutorials/index Step-by-step guides for using the Box AI API to ask questions, generate text, extract metadata, and override model configuration. These tutorials walk you through each Box AI API endpoint with working code examples. For input limits, model behavior, and the `ai_agent` override system, see the Box AI overview. Start with the prerequisites to set up authentication, then follow the guide for the capability you need. Create a platform app, enable the AI scope, and generate a developer token. Use `POST /ai/ask` to query files in single or multi-item mode. Includes dialogue history and citation examples. Use `POST /ai/text_gen` to create content from file-based prompts with iterative refinement through dialogue history. Change the AI model, prompt template, or LLM parameters to customize results for your use case. Explore industry-specific extraction scenarios for sales, legal, HR, financial services, and more. Use `POST /ai/extract` with natural language prompts to pull key-value pairs from documents. Use `POST /ai/extract_structured` with metadata templates or field definitions. Includes OCR and Enhanced Extract Agent examples. # Get started with Box AI Source: https://developer.box.com/guides/box-ai/ai-tutorials/prerequisites Create a platform app, enable the AI scope, and generate a developer token to start using the Box AI API. To implement Box AI API in your solutions, you need to make sure you have access to the functionality. You will also need a platform application with enabled Box AI scope, and a developer token to authenticate your calls. A free developer account gives you access to the Box AI API. Try document summarization, question answering, and metadata extraction through the API. To use Box AI API, make sure it is enabled by an admin in the Admin Console. If you want to use the Box AI APIs in your sandbox, request access from the Box AI team using [this form][form]. ## Create a platform application First you need to create a platform application you will use to make calls. To create an application, follow the guide on creating platform apps. ## Enable Box AI API access To interact with Box AI API, you need the `ai.readwrite` scope added for your application. Before you add the scope, make sure that the Box Admin has granted you the access to Box AI API. If you can't see the **Manage AI** option in your app configuration settings, contact your admin. To add a scope: 1. Open your application in Developer Console. 2. Go to **Configuration** > **Required Access Scopes** > **Content Actions** 3. Select the **Manage AI** scope. Box Platform will automatically include the scope when making the call. If you are added as an collaborator for a given app, but do not have Box AI API access, you will see the **Manage AI** scope checked and grayed out. This means the app owner has the AI scope enabled but you cannot change this setting. box ai scopes 4. Submit your app for authorization or enablement. If you want to enable Box AI API for an existing application, you must re-authorize it. ## Generate a developer token You need a developer token to authenticate your app when sending requests. To generate a token: 1. Go to **Developer Console** > **My Platform Apps**. 2. Click the **Options menu** button (…) on the right. 3. Select **Generate Developer Token**. The token will be automatically generated and saved to clipboard. generate token You can also open your app, go to **Configuration** > **Developer Token** and generate the token. A developer token is only valid for one hour. For additional details, see developer token. After you generate the token, you can use it in cURL or other clients, such as Postman, to make calls. [oauthscopes]: /guides/api-calls/permissions-and-errors/scopes#scopes-oauth-2-authorization [form]: https://forms.gle/Nsh3TwM3W8qg4U35A # Box AI Source: https://developer.box.com/guides/box-ai/index Technical reference for Box AI request handling, input limits, model behavior, and the agent override system. This section contains developer guides for working with Box AI. For a summary of API capabilities, quick starts, and reference links, see the [Box AI API](/ai/box-ai-api) page. The below guides cover what you need to know before you start writing code: how Box AI processes requests, what limits apply to different endpoints, how to control model behavior through agent overrides, and where to find the specific tutorial for your use case. A free developer account gives you access to the Box AI API, Developer Console, and everything you need to start building. ## How requests are processed When you send a request to a Box AI endpoint, Box handles the model infrastructure for you. Your request flows through the following stages: * **File retrieval**: Box reads the file content from the `items` array you provide. If you include the optional `content` parameter, that text is used as the primary input instead of the file's stored content. * **Representation generation**: For text-based files, Box converts the document into a text representation. For images, Box applies OCR automatically on supported endpoints. * **Model routing**: Box routes the request to the default model for that endpoint and mode. You can override this with the `ai_agent` parameter. * **Response generation**: The LLM processes your prompt against the file content and returns a result. Box handles token windowing for long documents (splitting content into chunks with embeddings for `long_text` configurations). Box AI does not support multi-modal requests. If you send both images and text in the same request, only the text is processed. ## Input limits The limits below apply across Box AI endpoints. Exceeding these limits does not produce an error in most cases; Box truncates to the limit and processes what it can. ### Text and prompt limits | Constraint | Limit | | -------------------------------------------------- | ----------------------------------------------- | | Prompt length | 10,000 characters | | Single file text representation (`single_item_qa`) | 2 MB of text. Content beyond 2 MB is truncated. | | Multiple files (`multiple_item_qa`) | Up to 25 files | | Items array for `text_gen` | Exactly 1 file | | Items array for `extract` and `extract_structured` | Exactly 1 file | ### Image limits | Constraint | Limit | | ----------------------------------- | -------------------------------------------------------- | | Resolution | 1024 x 1024 pixels | | Maximum images or pages per request | 5. If more are provided, only the first 5 are processed. | ### OCR and file format support OCR is **not** available on all endpoints. | Endpoint | OCR | Supported file formats | | ----------------------------- | --------------- | ---------------------- | | `POST /ai/text_gen` | No | Text-based files | | `POST /ai/extract` | No | Text-based files | | `POST /ai/extract_structured` | Yes (automatic) | PDF, TIFF, PNG, JPEG | ### Language support Box AI works in English, Japanese, French, Spanish, and many other languages. However, the underlying models are primarily trained on English, so prompts in other languages may return lower quality results. The `extract_structured` endpoint has explicit multilingual support for: * English, Japanese, Chinese, Korean * Cyrillic-based languages (Russian, Ukrainian, Bulgarian, Serbian) Switch the language to Japanese to get better results for this language. ## The `ai_agent` override system The following Box AI endpoints accept an optional `ai_agent` parameter that lets you override the default model configuration: `POST /ai/ask`, `POST /ai/text_gen`, `POST /ai/extract`, and `POST /ai/extract_structured`. This is how you control which LLM runs, how it behaves, and what instructions it receives. ### When to use overrides * **Pinning a model version**: Box updates default models regularly. If your downstream process depends on consistent output, pin to a specific model to avoid unexpected changes. * **Switching models**: Different models produce different results. You can switch to any model in the supported models list to optimize for your use case. * **Customizing prompts**: The `prompt_template` and `system_message` parameters let you steer the LLM's behavior without changing your application code. * **Tuning creativity**: Adjust `temperature` and other `llm_endpoint_params` to control how deterministic or creative the output is. ### How it works Call `GET /2.0/ai_agent_default` with the `mode` you want (`ask`, `text_gen`, `extract`, or `extract_structured`) to retrieve the current defaults. Change the fields you need: `model`, `prompt_template`, `system_message`, `llm_endpoint_params`, or `num_tokens_for_completion`. Leave other fields unchanged. Include the modified configuration as the `ai_agent` parameter in your `POST` request. Box uses your overrides for that request only. ### Configuration structure by endpoint The `ai_agent` object structure varies by endpoint because each handles content differently: | Endpoint | Agent type | Configuration keys | | ----------------------------- | ----------------------------- | ---------------------------------------------------------------- | | `POST /ai/ask` | `ai_agent_ask` | `basic_text`, `basic_text_multi`, `long_text`, `long_text_multi` | | `POST /ai/text_gen` | `ai_agent_text_gen` | `basic_gen` | | `POST /ai/extract` | `ai_agent_extract` | `basic_text`, `long_text` | | `POST /ai/extract_structured` | `ai_agent_extract_structured` | `basic_text`, `long_text` | The `ask` endpoint has four configuration keys because it handles both single-item and multi-item modes, and both short and long documents. When using `multiple_item_qa` mode, the `_multi` variants apply. For `long_text` configurations, Box splits the content into chunks using an embeddings model. You can configure the embeddings model and chunking strategy as part of the override. ### LLM parameter differences by provider The `llm_endpoint_params` options depend on the model provider: | Provider | Param type | Key difference | | ----------------------------------------------------------------------------- | --------------- | ----------------------------------------------------------------- | | OpenAI | `openai_params` | Use `temperature` **or** `top_p`, not both | | Google | `google_params` | `temperature` works with `top_p` and `top_k` together | | AWS | `aws_params` | Same as Google: `temperature` works alongside `top_p` and `top_k` | For detailed override examples, see the AI model overrides guide and the override tutorial. ### Model versioning Box guarantees each AI agent configuration snapshot for at least 12 months, with a 6-month transition window when a new version is released. Default model changes are posted in the developer changelog. To avoid disruption, pin your agent configuration to a specific model version using overrides. For full details, see AI agent configuration versioning. ## Box AI for UI Elements The Box AI for UI Elements integration embeds question-answering directly into Content Preview within your application. This lets end users interact with Box AI without leaving your UI. ## User Activity Reports [User Activity Reports][uar] track Box AI interactions. Box admins can filter for the following action types: | Action type | Description | | ------------------- | ------------------------------------------------------ | | **AI query** | The user queried Box AI and received a response | | **Failed AI query** | The user queried Box AI but did not receive a response | [uar]: https://support.box.com/hc/en-us/articles/4415012490387-User-Activity-Report ## Guides in this section Step-by-step guides for each endpoint: ask, text generation, extraction, and model overrides. Override default models, prompts, and LLM parameters. Includes the default configuration reference and versioning policy. Full list of core and customer-enabled models with capability tiers, compliance badges, and API names. Get up and running in minutes with Python SDK walkthroughs for summarization and extraction. ## See Box AI in action These end-to-end tutorials show how to combine Box AI with other platform capabilities to build production-ready automations. Use Box AI Extract and metadata to automate accounts payable - extract vendors, totals, and dates from every invoice. Build an AI-powered knowledge base with Box Hubs and let sales reps query approved proposals in natural language. # Extract structured data with Box AI in Python Source: https://developer.box.com/guides/box-ai/quick-start/box-ai-extract Learn how to use Box AI to automatically extract structured data from documents and store it as searchable metadata using the Box Python SDK. Box AI exposes intelligent extraction capabilities that enable developers to automatically extract structured key-value pairs from documents through a single API call. This powerful feature transforms unstructured document content into actionable metadata without manual data entry, streamlining document processing workflows for invoices, forms, contracts, and other business documents. This quick start demonstrates how to configure the Box Python SDK, create a metadata template, and use Box AI to extract invoice data and store it as searchable metadata in Box. A free developer account gives you access to the Box AI API. Try document summarization, question answering, and metadata extraction through the API. The first step for any Box Platform integration is to create and configure a Box application. 1. Go to Box Developer Console. 2. For this quick start, create an App with the `Client Credentials Grant` application type. 3. Once the app is created, enable the following scopes: * Read all files and folders stored in Box * Write all files and folders stored in Box * Manage AI For more information about creating a new Box application, see Create your first application. This step requires Admin access to your Box Enterprise. If you do not have access in your current environment, contact your Box administrator. Box AI enables you to extract data from documents in several ways: | Type | Description | Use case | | ----------------------------------- | ------------------------------------------------ | ------------------------------------------------------------------------------------------- | | Freeform extraction | Accepts a string prompt. | Provide a natural language prompt. | | Structured extraction with template | Accepts a Box Metadata template key. | Define fields and data types once; simplifies pushing back to Box as metadata. | | Structured extraction with fields | Accepts a JSON array of fields. | Run one-off extractions without creating a template. | | Enhanced Extract Agent | Uses a specialized agent with a reasoning model. | Use for complex documents or nuanced extraction; works with structured templates or fields. | For this quick start, create a Box metadata template to define the fields you want to extract from your documents. See Customizing Metadata Templates for a detailed walkthrough of the steps to create a Box metadata template in the Box Admin Console. 1. Give your template a name, for example, `Box AI extract quick start`. 2. Create the following fields: | Field name | Type | Description | | -------------- | ------ | ---------------------------------------------------------------------------------------- | | Client Name | Text | The name of the client receiving the invoice | | Invoice Amount | Number | The total amount of the invoice after taxes and fees | | Products | Text | The names of the products delivered in the invoice, returned as a comma-delimited string | The field description is used by Box AI to supplement the prompt to the LLM to ensure the right data is extracted. 3. Click **Save** to create your template. Make note of the template key to use in a later step. When you save the template, a list of templates appears. To find the template key, open the template you just created and inspect the URL. The last part of the path is your template key. For example, the URL might look like this: `https://app.box.com/master/metadata/templates/boxAiExtractquick start`. In this case, the template key is `boxAiExtractquick start`. After preparing the template, select a file to test. For this quick start, use this sample invoice document. 1. Download the test document, and then drag and drop it into your Box account. 2. Get the file ID by opening the file in Box and inspecting the URL. The last part of the path is your file ID. For example, the URL might look like this: `https://app.box.com/file/2064123286902` In this case, the file ID is `2064123286902`. Now set up your development environment to run the extraction. For this quick start, use Python and the Box Python SDK version 10. Make sure you have Python 3.11 or higher installed on your machine. 1. Create a new directory for your project and navigate into it. 2. Create a virtual environment: ```bash theme={null} python3 -m venv .venv source .venv/bin/activate ``` 3. Install the Box Python SDK: ```bash theme={null} pip install "boxsdk~=10" ``` 4. Install the `python-dotenv` package to load environment variables from the `.env` file: ```bash theme={null} pip install python-dotenv ``` 5. Create an `.env` file in the root of your project directory and add the following environment variables, replacing the placeholder values with your actual Box app credentials and the IDs from the previous steps: ```bash theme={null} BOX_DEVELOPER_TOKEN=your_box_developer_token BOX_METADATA_TEMPLATE_KEY=your_metadata_template_key BOX_FILE_ID=your_box_file_id ``` To get your developer token, go to the Box Developer Console, open your app, and navigate to the **Configuration** tab. 6. Click **Generate Developer Token** to create a new token. For simplicity, this quick start uses a short-lived developer token. In production, you should authenticate using your app’s configured method (for example, Client Credentials Grant) instead of a developer token. Your development environment is now ready to create the Python script to extract data from the document using Box AI. 1. Create a new file named `extract.py` in the root of your project directory and add the following code: ```python theme={null} import os from dotenv import load_dotenv from box_sdk_gen import ( AiItemBase, BoxClient, BoxDeveloperTokenAuth, CreateAiExtractStructuredMetadataTemplate, CreateAiExtractStructuredMetadataTemplateTypeField, CreateFileMetadataByIdScope ) load_dotenv() developer_token = os.getenv("BOX_DEVELOPER_TOKEN") file_id = os.getenv("BOX_FILE_ID") template_key = os.getenv("BOX_METADATA_TEMPLATE_KEY") def get_box_client(token: str) -> BoxClient: if not developer_token: raise ValueError("BOX_DEVELOPER_TOKEN is not set in environment variables.") auth = BoxDeveloperTokenAuth(token=token) client = BoxClient(auth=auth) return client def main(): client = get_box_client(token=developer_token) me = client.users.get_user_me() print(f"My user ID is {me.id}") if __name__ == "__main__": main() ``` This code loads the environment variables from the `.env` file, initializes the Box SDK client, and prints the current user's ID to validate that the client is working correctly. 2. Run the script using the following command in your terminal: ```bash theme={null} python extract.py ``` If the Box SDK client is set up correctly, the console displays your user ID. For example: ```bash theme={null} My user ID is 123456789 ``` With a working Box SDK client, you can add the code to extract data from the document using Box AI. 1. Between the `get_box_client` function and the `main` function, add the following function: ```python theme={null} def extract_metadata(client: BoxClient, file_id: str, template_key: str) -> dict: metadata = client.ai.create_ai_extract_structured( [AiItemBase(id=file_id)], metadata_template=CreateAiExtractStructuredMetadataTemplate( template_key=template_key, type=CreateAiExtractStructuredMetadataTemplateTypeField.METADATA_TEMPLATE, scope="enterprise", ), ) return metadata.to_dict()['answer'] ``` This function uses the Box AI `create_ai_extract_structured` method to extract metadata from the specified file. Your BoxClient, the file ID, and the metadata template key created earlier are sent to the function, which returns the extracted metadata as a dictionary. 2. Add the function call to extract the metadata in the `main` function. Ensure that the new `main` function contains the following logic: ```python theme={null} def main(): client = get_box_client(token=developer_token) me = client.users.get_user_me() print(f"My user ID is {me.id}") metadata = extract_metadata(client=client, file_id=file_id, template_key=template_key) print(f"Extracted Metadata: {metadata}") ``` The SDK handles the API call to Box AI and returns the extracted metadata as an `AiExtractStructuredResponse` object. In this quick start, the code converts this object to a dictionary and returns the `answer` field that contains the extracted key/value pairs. 3. Print out the extracted metadata to the console to verify that the extraction was successful by running the following command in your terminal: ```bash theme={null} python extract.py ``` If the extraction was successful, the console displays your user ID followed by the extracted metadata from the invoice document. ```bash theme={null} My user ID is 123456789 Extracted Metadata: {'clientName': 'ACME Inc', 'invoiceAmount': 1106.06, 'products': 'Polyol, Diisocyanate, Carbon Dioxide, Laser, Lens, Oleic Acid, Glycerine, Sodium Tallowate, Paint Base, Polypropylene, Rubber, Additive, Pigment, Aluminum Silicate, Magnesium Silicate, Zinc Oxide, Distilled Solvent, Petroleum Distillate, Sulfur Dioxide, Sodium Benzoate, Dust cap, Ferrite cap, Cone and coil assembly, Cleaner, Polypropylene pellets, Polypropylene chips, Polypropylene blocks, Polypropylene slag, Parts Wash Solvent, Jar, Plastic Bottle - 15.2 FL Oz (450 ml), Polymer'} ``` Now that you have extracted metadata from the document, you can use these key/value pairs in your application: push to databases, integrate with CRMs, feed to agents for processing, or trigger automated workflows. This quick start demonstrates pushing the extracted data back to Box as file metadata. Box metadata management enables powerful filtering and search capabilities across your content. For example, you can query all invoices over \$500 from the last 30 days, create dashboards in Box Apps, or surface key document insights directly in the Box web application. 1. Push the extracted metadata back to Box by adding the following function between the `extract_metadata` function and the `main` function: ```python theme={null} def push_metadata(client: BoxClient, file_id: str, metadata: dict, template_key: str) -> dict: attached_metadata = client.file_metadata.create_file_metadata_by_id( file_id, CreateFileMetadataByIdScope.ENTERPRISE, template_key, metadata, ) return attached_metadata.to_dict() ``` This function uses the `create_file_metadata_by_id` method to attach metadata to the specified file, processing the BoxClient, file ID, metadata dictionary, and template key. The API itself returns a `MetadataFull` object. The function converts this object to a dictionary and returns it. 2. Add the function call to push the metadata in the `main` function. Ensure that the updated `main` function contains the following logic: ```python theme={null} def main(): client = get_box_client(token=developer_token) me = client.users.get_user_me() print(f"My user ID is {me.id}") metadata = extract_metadata(client=client, file_id=file_id, template_key=template_key) print(f"Extracted Metadata: {metadata}") attached_metadata = push_metadata(client=client, file_id=file_id, metadata=metadata, template_key=template_key) print(f"Attached Metadata: {attached_metadata}") ``` 3. Run the following command in your terminal: ```bash theme={null} python extract.py ``` If the script is successful, the console displays your user ID, the extracted metadata, and the attached metadata response from Box. For example: ```bash theme={null} My user ID is 123456789 Extracted Metadata: {'clientName': 'ACME Inc', 'invoiceAmount': 1106.06, 'products': 'Polyol, Diisocyanate, Carbon Dioxide, Laser, Lens, Oleic Acid, Glycerine, Sodium Tallowate, Paint Base, Polypropylene, Rubber, Additive, Pigment, Aluminum Silicate, Magnesium Silicate, Zinc Oxide, Distilled Solvent, Petroleum Distillate, Sulfur Dioxide, Sodium Benzoate, Dust cap, Ferrite cap, Cone and coil assembly, Cleaner, Polypropylene pellets, Polypropylene chips, Polypropylene blocks, Polypropylene slag, Parts Wash Solvent, Jar, Plastic Bottle - 15.2 FL Oz (450 ml), Polymer'} Attached Metadata: {'invoiceAmount': 1106.06, 'products': 'Polyol, Diisocyanate, Carbon Dioxide, Laser, Lens, Oleic Acid, Glycerine, Sodium Tallowate, Paint Base, Polypropylene, Rubber, Additive, Pigment, Aluminum Silicate, Magnesium Silicate, Zinc Oxide, Distilled Solvent, Petroleum Distillate, Sulfur Dioxide, Sodium Benzoate, Dust cap, Ferrite cap, Cone and coil assembly, Cleaner, Polypropylene pellets, Polypropylene chips, Polypropylene blocks, Polypropylene slag, Parts Wash Solvent, Jar, Plastic Bottle - 15.2 FL Oz (450 ml), Polymer', 'clientName': 'ACME Inc', '$parent': 'file_1956534287859', '$template': 'boxAiExtractquick start', '$scope': 'enterprise_899905961', '$version': 0, '$canEdit': True, '$id': '4d4f0b55-d45a-4ba4-9ff6-1241182cb76a', '$type': 'boxAiExtractquick start-c4024235-2384-49f4-9286-ada6d68fd6a9', '$typeVersion': 0, 'extra_data': {'invoiceAmount': 1106.06, 'products': 'Polyol, Diisocyanate, Carbon Dioxide, Laser, Lens, Oleic Acid, Glycerine, Sodium Tallowate, Paint Base, Polypropylene, Rubber, Additive, Pigment, Aluminum Silicate, Magnesium Silicate, Zinc Oxide, Distilled Solvent, Petroleum Distillate, Sulfur Dioxide, Sodium Benzoate, Dust cap, Ferrite cap, Cone and coil assembly, Cleaner, Polypropylene pellets, Polypropylene chips, Polypropylene blocks, Polypropylene slag, Parts Wash Solvent, Jar, Plastic Bottle - 15.2 FL Oz (450 ml), Polymer', 'clientName': 'ACME Inc'}} ``` ## Resources * Final code * Extract Structured Metadata API Reference * Create metadata instance on file * Box Python SDK # Structured extraction with the Box AI Enhanced Extract Agent in Python Source: https://developer.box.com/guides/box-ai/quick-start/box-ai-extract-enhanced Learn how to use the Box AI Enhanced Extract Agent to automatically extract data from large, complex documents using the Box Python SDK. Box AI exposes intelligent extraction capabilities that enable developers to automatically extract key-value pairs from documents through a single API call. The Enhanced Extract Agent uses advanced reasoning models to transform complex unstructured document content into actionable metadata without manual data entry, streamlining document processing workflows for invoices, forms, contracts, and other business documents. This quick start demonstrates how to configure the Box Python SDK and use Box AI to extract data from a stock purchase agreement stored in Box. A free developer account gives you access to the Box AI API. Try document summarization, question answering, and metadata extraction through the API. The first step for any Box Platform integration is to create and configure a Box application. 1. Go to Box Developer Console. 2. For this quick start, create an App with the `Client Credentials Grant` application type. 3. Once the app is created, enable the following scopes: * Read all files and folders stored in Box * Write all files and folders stored in Box * Manage AI For more information about creating a new Box application, see Create your first application. After preparing the template, select a file to test. For this quick start, use this sample stock purchase agreement. 1. Download the test document, and then drag and drop it into your Box account. 2. Get the file ID by opening the file in Box and inspecting the URL. The last part of the path is your file ID. For example, the URL might look like this: `https://app.box.com/file/2064123286902` In this case, the file ID is `2064123286902`. Now set up your development environment to run the extraction. For this quick start, use Python and the Box Python SDK version 10. Make sure you have Python 3.11 or higher installed on your machine. 1. Create a new directory for your project and navigate into it. 2. Create a virtual environment: ```bash theme={null} python3 -m venv .venv source .venv/bin/activate ``` 3. Install the Box Python SDK: ```bash theme={null} pip install "boxsdk~=10" ``` 4. Install the `python-dotenv` package to load environment variables from the `.env` file: ```bash theme={null} pip install python-dotenv ``` 5. Create an `.env` file in the root of your project directory and add the following environment variables, replacing the placeholder values with your actual Box app credentials and the IDs from the previous steps: ```bash theme={null} BOX_DEVELOPER_TOKEN=your_box_developer_token BOX_METADATA_TEMPLATE_KEY=your_metadata_template_key BOX_FILE_ID=your_box_file_id ``` To get your developer token, go to the Box Developer Console, open your app, and navigate to the **Configuration** tab. 6. Click **Generate Developer Token** to create a new token. For simplicity, this quick start uses a short-lived developer token. In production, you should authenticate using your app’s configured method (for example, Client Credentials Grant) instead of a developer token. Your development environment is now ready to create the Python script to extract data from the document using Box AI. 1. Create a new file named `enhanced-extract.py` in the root of your project directory and add the following code: ```python theme={null} import os from dotenv import load_dotenv from box_sdk_gen import ( AiAgentReference, AiAgentReferenceTypeField, AiItemBase, BoxClient, BoxDeveloperTokenAuth, CreateAiExtractStructuredFields, CreateAiExtractStructuredFieldsOptionsField ) load_dotenv() developer_token = os.getenv("BOX_DEVELOPER_TOKEN") file_id = os.getenv("BOX_FILE_ID") def get_box_client(token: str) -> BoxClient: if not developer_token: raise ValueError("BOX_DEVELOPER_TOKEN is not set in environment variables.") auth = BoxDeveloperTokenAuth(token=token) client = BoxClient(auth=auth) return client def main(): client = get_box_client(token=developer_token) me = client.users.get_user_me() print(f"My user ID is {me.id}") if __name__ == "__main__": main() ``` This code loads the environment variables from the `.env` file, initializes the Box SDK client, and prints the current user's ID to validate that the client is working correctly. 2. Run the script using the following command in your terminal: ```bash theme={null} python enhanced-extract.py ``` If the Box SDK client is set up correctly, the console displays your user ID. For example: ```bash theme={null} My user ID is 123456789 ``` With a working Box SDK client, you can add the code to extract data from the document using Box AI. 1. Between the `get_box_client` function and the `main` function, add the following function: ```python theme={null} def extract_metadata(client: BoxClient, file_id: str) -> dict: enhanced_extract_config = AiAgentReference( id="enhanced_extract_agent", type=AiAgentReferenceTypeField.AI_AGENT_ID ) fields=[ CreateAiExtractStructuredFields( key="parties", display_name="Parties", description="The named parties involved", prompt="A comma separated list of the named parties involved", type="string", ), CreateAiExtractStructuredFields( key="effectiveDate", display_name="Effective date", description="The effective date of the contract", prompt="The effective date of the contract", type="date", ), CreateAiExtractStructuredFields( key="purchasePrice", display_name="Purchase price", description="The purchase price stated in the contract", prompt="The purchase price stated in the contract", type="float", ), CreateAiExtractStructuredFields( key="summary", display_name="Summary", description="A summary of the contract in 50 words or less", prompt="A summary of the contract in 50 words or less including key obligations", type="string", ), CreateAiExtractStructuredFields( key="recommendation", display_name="Recommendation", description="Should we make this purchase?", prompt="Given the financial details, would you recommend proceeding with the purchase? Answer Yes or No.", type="enum", options=[ CreateAiExtractStructuredFieldsOptionsField(key="Yes"), CreateAiExtractStructuredFieldsOptionsField(key="No"), ], ), ] metadata = client.ai.create_ai_extract_structured( [ AiItemBase(id=file_id) ], fields=fields, ai_agent=enhanced_extract_config, ) return metadata.to_dict()['answer'] ``` This function uses the Box AI `create_ai_extract_structured` method to extract metadata from the specified file. Your BoxClient and the file ID are sent to the function, which returns the extracted metadata as a dictionary. The `fields` parameter defines the specific data points to extract from the document. You can also reference a metadata template key instead to extract fields defined in a Box metadata template. 2. Add the function call to extract the metadata in the `main` function. Ensure that the new `main` function contains the following logic: ```python theme={null} def main(): client = get_box_client(token=developer_token) me = client.users.get_user_me() print(f"My user ID is {me.id}") metadata = extract_metadata(client=client, file_id=file_id) print(f"\n\nExtracted Metadata: {metadata}") ``` The SDK handles the API call to Box AI and returns the extracted metadata as an `AiExtractStructuredResponse` object. In this quick start, the code converts this object to a dictionary and returns the `answer` field that contains the extracted key/value pairs. 3. Print out the extracted metadata to the console to verify that the extraction was successful by running the following command in your terminal: ```bash theme={null} python enhanced-extract.py ``` If the extraction was successful, the console displays your user ID followed by the extracted metadata from the stock purchase agreement. ```bash theme={null} My user ID is 123456789 Extracted Metadata: {'parties': 'Argyle LLP, Suregood Family Trust', 'effectiveDate': '2023-03-31', 'purchasePrice': 231000000, 'summary': 'Argyle LLP agrees to purchase 51% of Erebor Life, Inc. from Suregood Family Trust for $231,000,000. The Seller must operate the business normally until closing, and the Buyer must pay the purchase price. The agreement is effective March 31, 2023.', 'recommendation': 'Yes'} ``` ## Resources * Final code * Extract Structured Metadata API Reference * Box Python SDK # Natural language extraction with Box AI in Python Source: https://developer.box.com/guides/box-ai/quick-start/box-ai-extract-freeform Learn how to use Box AI to automatically extract data from documents with natural language prompts using the Box Python SDK. Box AI exposes intelligent extraction capabilities that enable developers to automatically extract key-value pairs from documents through a single API call. This powerful feature transforms unstructured document content into actionable metadata without manual data entry, streamlining document processing workflows for invoices, forms, contracts, and other business documents. This quick start demonstrates how to configure the Box Python SDK and use Box AI to extract data from a W-2 stored in Box. A free developer account gives you access to the Box AI API. Try document summarization, question answering, and metadata extraction through the API. The first step for any Box Platform integration is to create and configure a Box application. 1. Go to Box Developer Console. 2. For this quick start, create an App with the `Client Credentials Grant` application type. 3. Once the app is created, enable the following scopes: * Read all files and folders stored in Box * Write all files and folders stored in Box * Manage AI For more information about creating a new Box application, see Create your first application. After preparing the template, select a file to test. For this quick start, use this sample W-2. 1. Download the test document, and then drag and drop it into your Box account. 2. Get the file ID by opening the file in Box and inspecting the URL. The last part of the path is your file ID. For example, the URL might look like this: `https://app.box.com/file/2064123286902` In this case, the file ID is `2064123286902`. Now set up your development environment to run the extraction. For this quick start, use Python and the Box Python SDK version 10. Make sure you have Python 3.11 or higher installed on your machine. 1. Create a new directory for your project and navigate into it. 2. Create a virtual environment: ```bash theme={null} python3 -m venv .venv source .venv/bin/activate ``` 3. Install the Box Python SDK: ```bash theme={null} pip install "boxsdk~=10" ``` 4. Install the `python-dotenv` package to load environment variables from the `.env` file: ```bash theme={null} pip install python-dotenv ``` 5. Create an `.env` file in the root of your project directory and add the following environment variables, replacing the placeholder values with your actual Box app credentials and the IDs from the previous steps: ```bash theme={null} BOX_DEVELOPER_TOKEN=your_box_developer_token BOX_METADATA_TEMPLATE_KEY=your_metadata_template_key BOX_FILE_ID=your_box_file_id ``` To get your developer token, go to the Box Developer Console, open your app, and navigate to the **Configuration** tab. 6. Click **Generate Developer Token** to create a new token. For simplicity, this quick start uses a short-lived developer token. In production, you should authenticate using your app’s configured method (for example, Client Credentials Grant) instead of a developer token. Your development environment is now ready to create the Python script to extract data from the document using Box AI. 1. Create a new file named `freeform-extract.py` in the root of your project directory and add the following code: ```python theme={null} import os from dotenv import load_dotenv from box_sdk_gen import ( AiItemBase, BoxClient, BoxDeveloperTokenAuth ) # Set up environment variables load_dotenv() developer_token = os.getenv("BOX_DEVELOPER_TOKEN") file_id = os.getenv("BOX_FILE_ID") def get_box_client(token: str) -> BoxClient: if not developer_token: raise ValueError("BOX_DEVELOPER_TOKEN is not set in environment variables.") auth = BoxDeveloperTokenAuth(token=token) client = BoxClient(auth=auth) return client def main(): client = get_box_client(token=developer_token) # Get the current user and print the ID to validate the client is working me = client.users.get_user_me() print(f"My user ID is {me.id}") if __name__ == "__main__": main() ``` This code loads the environment variables from the `.env` file, initializes the Box SDK client, and prints the current user's ID to validate that the client is working correctly. 2. Run the script using the following command in your terminal: ```bash theme={null} python freeform-extract.py ``` If the Box SDK client is set up correctly, the console displays your user ID. For example: ```bash theme={null} My user ID is 123456789 ``` With a working Box SDK client, you can add the code to extract data from the document using Box AI. 1. Between the `get_box_client` function and the `main` function, add the following function: ```python theme={null} def extract_metadata(client: BoxClient, file_id: str) -> str: prompt = """ firstName, lastName, wages, federalTaxWithheld, socialSecurityWages, socialSecurityTaxWithheld, medicareWagesAndTips, medicareTaxWithheld, stateWages, stateTaxWithheld, localWagesAndTips, localTaxWithheld """ metadata = client.ai.create_ai_extract( prompt, [AiItemBase(id=file_id)] ) return metadata.to_dict()['answer'] ``` This function uses the Box AI `create_ai_extract` method to extract metadata from the specified file. Your BoxClient and the file ID are sent to the function, which returns the extracted metadata as a dictionary. 2. Add the function call to extract the metadata in the `main` function. Ensure that the new `main` function contains the following logic: ```python theme={null} def main(): client = get_box_client(token=developer_token) me = client.users.get_user_me() print(f"My user ID is {me.id}") metadata = extract_metadata(client=client, file_id=file_id) print(f"\n\nExtracted Metadata: {metadata}") ``` The SDK handles the API call to Box AI and returns the extracted metadata as an `AiExtractResponse` object. In this quick start, the code converts this object to a dictionary and returns the `answer` field that contains the extracted key/value pairs. 3. Print out the extracted metadata to the console to verify that the extraction was successful by running the following command in your terminal: ```bash theme={null} python freeform-extract.py ``` If the extraction was successful, the console displays your user ID followed by the extracted metadata from the W-2. ```bash theme={null} My user ID is 123456789 Extracted Metadata: {"firstName": "Wayne", "lastName": "Gatsby", "wages": "355000", "federalTaxWithheld": "125600", "socialSecurityWages": "355000", "socialSecurityTaxWithheld": "12300", "medicareWagesAndTips": "355000", "medicareTaxWithheld": "13200", "stateWages": "355,000", "stateTaxWithheld": "15000", "localWagesAndTips": "355000", "localTaxWithheld": "8000"} ``` ## Resources * Final code * Extract Freeform Metadata API Reference * Box Python SDK # Summarize files with Box AI in Python Source: https://developer.box.com/guides/box-ai/quick-start/box-ai-summarize Learn how to use Box AI to automatically extract structured data from documents and store it as searchable metadata using the Box Python SDK. Box AI exposes AI capabilities that enable developers to interrogate documents through a single API call. This powerful feature transforms unstructured document content into instant insights without the need to build and maintain complex Retrieval Augmented Generation (RAG) pipelines. This quick start demonstrates how to configure the Box Python SDK and use Box AI to summarize files in Box. A free developer account gives you access to the Box AI API. Try document summarization, question answering, and metadata extraction through the API. The first step for any Box Platform integration is to create and configure a Box application. 1. Go to Box Developer Console. 2. For this quick start, create an App with the `Client Credentials Grant` application type. 3. Once the app is created, enable the following scopes: * Read all files and folders stored in Box * Manage AI For more information about creating a new Box application, see Create your first application. To use Box AI to get insights from documents, you need a file in Box. For this quick start, use this document containing federal code. 1. Download the test document, and then drag and drop it into your Box account. 2. Get the file ID by opening the file in Box and inspecting the URL. The last part of the path is your file ID. For example, the URL might look like this: `https://app.box.com/file/2064123286902` In this case, the file ID is `2064123286902`. Now set up your development environment to run this quickstart. This tutorial uses Python and the latest Box Python SDK to run the code. Make sure you have Python 3.11 or higher installed on your machine. 1. Create a new directory for your project and navigate into it. 2. Create a virtual environment: ```bash theme={null} python3 -m venv .venv source .venv/bin/activate ``` 3. Install the Box Python SDK: ```bash theme={null} pip install "boxsdk~=10" ``` 4. Install the `python-dotenv` package to load environment variables from the `.env` file: ```bash theme={null} pip install python-dotenv ``` 5. Create an `.env` file in the root of your project directory and add the following environment variables, replacing the placeholder values with your actual Box app credentials and the IDs from the previous steps: ```bash theme={null} BOX_DEVELOPER_TOKEN=your_box_developer_token BOX_FILE_ID=your_box_file_id ``` To get your developer token, go to the Box Developer Console, open your app, and navigate to the **Configuration** tab. 6. Click **Generate Developer Token** to create a new token. For simplicity, this quick start uses a short-lived developer token. In production, you should authenticate using your app’s configured method (for example, Client Credentials Grant) instead of a developer token. Your development environment is now ready to create the Python script to summarize the document using Box AI. 1. Create a new file named `summarize.py` in the root of your project directory and add the following code: ```python theme={null} import os from dotenv import load_dotenv from box_sdk_gen import ( AiItemAsk, AiItemAskTypeField, BoxClient, BoxDeveloperTokenAuth, CreateAiAskMode ) load_dotenv() developer_token = os.getenv("BOX_DEVELOPER_TOKEN") file_id = os.getenv("BOX_FILE_ID") def get_box_client(token: str) -> BoxClient: if not developer_token: raise ValueError("BOX_DEVELOPER_TOKEN is not set in environment variables.") auth = BoxDeveloperTokenAuth(token=token) client = BoxClient(auth=auth) return client def main(): client = get_box_client(token=developer_token) me = client.users.get_user_me() print(f"My user ID is {me.id}") if __name__ == "__main__": main() ``` This code loads the environment variables from the `.env` file, initializes the Box SDK client, and prints the current user's ID to validate that the client is working correctly. 2. Run the script using the following command in your terminal: ```bash theme={null} python summarize.py ``` If the Box SDK client is set up correctly, the console displays your user ID. For example: ```bash theme={null} My user ID is 123456789 ``` With a working Box SDK client, you can add the code to summarize the document using Box AI. 1. Between the `get_box_client` function and the `main` function, add the following function: ```python theme={null} def summarize_file(client: BoxClient, file_id: str) -> str: prompt = """ Summarize the content of the following file in a few sentences. """ summary = client.ai.create_ai_ask( CreateAiAskMode.SINGLE_ITEM_QA, prompt, [ AiItemAsk( id=file_id, type=AiItemAskTypeField.FILE ) ] ) return summary.to_dict()['answer'] ``` This function uses the Box AI `create_ai_ask` method to interrogate the specified file. Your BoxClient and file ID created earlier are sent to the function, which returns the summary of the file as a string. 2. Add the function call to summarize the file in the `main` function. Ensure that the new `main` function contains the following logic: ```python theme={null} def main(): client = get_box_client(token=developer_token) # Get the current user and print the ID to validate the client is working me = client.users.get_user_me() print(f"My user ID is {me.id}") summary = summarize_file(client=client, file_id=file_id) # Print the extracted metadata print(f"\n\nSummary: {summary}") ``` The SDK handles the API call to Box AI and returns the summary as an `AiResponseFull` object. In this quick start, the code converts this object to a dictionary and returns the `answer` field that contains the summary. 3. Print out the summary to the console to verify that the operation was successful by running the following command in your terminal: ```bash theme={null} python summarize.py ``` If the summarization was successful, the console displays your user ID followed by the summary from the test document. ```bash theme={null} My user ID is 123456789 Summary: **Summary of 28 CFR § 2.20 (Paroling Policy Guidelines)** - The document sets forth the U.S. Parole Commission’s purpose and framework for national parole policy, emphasizing guidelines to promote consistent, equitable parole decisions while preserving individualized review. - It provides a matrix of customary total time-to-release ranges by offense severity categories (1–8) and offender parole prognosis (salient factor scores), noting guidelines apply to inmates with good institutional adjustment and are discretionary. - A comprehensive Offense Behavior Severity Index (Chapters 1–12) assigns categories to specific crimes (homicide, assault, theft, drugs, firearms, national defense, etc.) with detailed rules, exceptions, and examples for grading offenses (including monetary thresholds and drug-quantity bands). - Chapter Thirteen contains general notes, multiple-offense scoring guidance, definitions of key terms, and the Salient Factor Scoring Manual explaining how to compute parole prognosis points (prior convictions, commitments, age, recent commitment-free period, probation/parole status, and older-offender adjustment). - The document also references reparole guidelines and authority to revise guidelines; aggravated crimes and Category Eight cases receive special treatment. ``` ## Resources * Final code * Box AI Ask API Reference * Box Python SDK # Get started with Box Automate Source: https://developer.box.com/guides/box-automate/getting-started-box-automate ## Enable Box Automate Your Box admin must enable Box Automate (and any add-on products you use in flows, such as Box AI Studio) for the enterprise to begin using Automate. If a scope or feature is not available in the Developer Console, contact Box Support or your account team with the user or app context you plan to use. ## Manual Start API You can trigger Manual Start workflows programmatically using the Box API. | Endpoint | Method | Description | | ---------------------------------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------- | | List workflows with Manual Start trigger | GET | Retrieve all Automate workflows with a Manual Start trigger set for a given folder. Returns a workflow list. Folder ID is required. | | Trigger a Manual Start workflow | POST | Trigger a specific workflow with chosen files. | ### Request Parameters: * `files` - provide file IDs in the request body (optional if triggering on a folder; max 20 files per request) * `fields defined at start` - when a workflow requires runtime fields (for example, task assignees, notification recipients), include them in the API call. Missing required fields return an error. Use the Custom HTTP Request outcome to connect your Box Automate workflows to external apps and APIs. The HTTPS request outcome is available for all Enterprise Advanced users with Automate enabled. However, your Admin needs to either add Connectors to the allow-list in settings or enable you to add your own from the builder. Note: If your admin has turned off the option to add your own connectors, you can only select from pre-approved connectors in the dropdown. **To add a Custom HTTP request outcome:** 1. Open Workflow Builder. 2. Add the Custom HTTP request outcome. 3. Fill in the fields: * URL: Choose a connector, or add a new one if allowed. * Method: Select GET, POST, DELETE, PUT, or PATCH. * Query Parameters: Add any key-value pairs you need. * Authentication: Choose an auth type and enter the required info. * Headers: Add optional headers. * Body: Enter the JSON request body. * Description: Briefly say what the request does. **Authentication options:** * OAuth 2.0 Client Credentials: Client ID, Client Secret, Authorization URL, Token URL, Scopes * Basic Auth: Username and password * Bearer Token: Token * API Key: API key * Custom Header: Header name and value **Test Your Connection** 1. After configuring your outcome, click the Test button. 2. Review the test response code to confirm the connection works. 3. The builder automatically captures response properties and creates variables for you. 4. Use the JSON path: [https://jsonpath.com/](https://jsonpath.com/) to verify and see the variables from the test response. # Box Automate Source: https://developer.box.com/guides/box-automate/index Box Automate availability depends on your Box plan and how your organization enables the product. Work with your Box admin or account team before building integrations against production content. Box Automate is a workflow automation platform built natively on the Box content platform. You can use it to design, build, and run automated workflows with a visual builder that supports conditional branching, loops, and a broad set of triggers and actions. This overview summarizes what the platform can do, how developers can integrate with it, and which Box Platform APIs and scopes you are to use alongside workflows. ## Capabilities * **Triggers** — File, folder, task, File Request, Box Sign, metadata triggers, Forms submissions manual, webhook events can start workflows. * **Outcomes** — File and folder outcomes, collaborations, task assignments, Workflows can assign tasks, send notifications, AI outcomes, Integrations, and metadata. * **Logic** — Branching, variables, JSONPath, and structured AI output help route work and pass data between steps. * **AI** — Custom agents can use knowledge sources, citations, and reasoning traces where those features are enabled for your enterprise. * **Third-party APIs** — The **OpenAPI Connector Engine** builds steps from OpenAPI **2**/**3** specs (import by URL or file), with **domain allowlisting** and auth from the spec. **Custom HTTP (phase 1)** covers arbitrary REST calls with **manual** configuration when no spec is used. * **Extensibility** — **Box Functions** ties custom logic to a **developer application** so advanced integrations and scripts can plug into orchestration where the product supports it. ## Use cases Box Automate fits document-centric processes that combine content, people, and policy. Common examples include: * **Approvals and reviews** — Route files for review, capture outcomes, and notify stakeholders. * **Case and project folders** — React to uploads or metadata changes and kick off the next step automatically. * **AI-assisted triage** — Classify or summarize incoming content, then branch on the result. * **Cross-product flows** — Combine uploads (for example, File Request), metadata, Doc Gen, or Sign in one automation. ## Developer integrations Automations run on Box content. Most integrations use a platform application, standard OAuth or JWT auth, and a mix of workflow APIs plus the content and collaboration endpoints. Start with Get started with Box Automate, ## Rate limits Workflow and content API calls are subject to Box Platform rate limits. See the rate limits guide for details. # Triggers, outcomes, and logic in Box Automate Source: https://developer.box.com/guides/box-automate/triggers-and-logic Box Automate runs **workflows**: directed graphs of steps that start from a **trigger** and run **outcomes** until an end state is reached. In the workflow builder, you place **triggers** and **outcomes** on a canvas; outcomes are the automated steps the workflow performs (this guide uses **outcomes** for the same idea when talking about integration). Triggers are content-aware and can be scoped to folders or metadata. Exact trigger and action types available in your tenant depend on product configuration. ## Triggers A trigger defines when a new **run** of a workflow should begin. ### Common trigger types * **File events** — When a file is uploaded, moved, copied, downloaded, or deleted; also preview, lock, unlock, watermark removed, add collaborator, classification applied, or file-with-metadata scenarios. * **Folder events** — When a folder is created, moved, copied, downloaded, or deleted, or when a collaborator is added. * **Tasks** — When a general task or an approval task completes (including accepted or rejected approval outcomes). * **File Request** — When someone completes a File Request form and submits content to the designated Box folder. * **Box Sign** — Sign events such as completed, declined, expired, or cancelled. * **Metadata** — When a specific metadata template is applied or a specific file or folder. * **Manual start** — A user starts the flow from the file or folder in the Box web app. * **Form submissions** — If enabled for your plan (for example Enterprise Advanced+), a workflow starts when a designated Box Form is submitted. * **HTTPS request** — An external system starts a run by sending an HTTP request to a **unique URL** that Box Automate assigns to the workflow. ## Outcomes **Outcomes** are the steps that run after a trigger fires (called **outcomes** in the builder). You can chain multiple outcomes and pass data between steps with variables. **Key outcome capabilities** * **File outcomes** — Move, copy, rename, delete, lock, unlock, add or remove watermark, add or remove collaborators, apply classification, and related file operations. * **Folder outcomes** — Create, move, copy, rename, delete, restore, add or remove collaborators, apply classification, and related folder operations. * **Collaboration** — Add or remove collaborators on files or folders dynamically. * **Task assignments** — Assign approval tasks or general tasks to users or groups, with instructions and due dates. * **Notifications** — Send email to recipients; subject and body can use variables (for example the person who started the workflow). * **AI and advanced** — Box AI for metadata extraction, summarization, or Q\&A; options such as document generation (DocGen) and requesting signatures (Box Sign). Prefer an approval or review step after AI steps when results must be verified. * **Metadata** — Apply, update, or extract metadata (including with AI) for files and folders. Treat agent output as potentially unpredictable and add human review before critical next steps when needed. ## Logic Workflow logic controls branching and data flow between steps. * **Branching** — Route the workflow on conditions (for example, if an approval task is rejected, move content to a different folder than if it were approved). * **Loops** * **For each** — Iterate over a list of users, files, or all files in a folder. * **Loop back (go back)** — Return the flow to a previous step, with a configurable maximum loop count. * **Variables** — Reuse information from earlier steps in later outcomes (for example, a rename step can use a metadata value from a prior AI step or the name of the user who uploaded the file). * **Merging** — After parallel branches, merge back to a single path before a final outcome. When integrating through an HTTPS request, you may also use **conditions** on field values, metadata, or structured AI output; **JSONPath** or similar approaches to read nested payload fields; and **AI outputs** as inputs to conditions or downstream outcomes where supported. # Get started with Box Doc Gen Source: https://developer.box.com/guides/docgen/docgen-getting-started To start generating documents with Box Doc Gen API you will need a platform application and a developer token to authenticate your calls. You also need a Doc Gen template that will serve as an input source for your document. ## Enable Box Doc Gen To use Box Doc Gen, make sure it is enabled by an admin in the Admin Console. If you are a Box Admin, you will find the necessary information in [Enterprise Settings: Content & Sharing Tab][settings] documentation. ## Create and upload a Box Doc Gen template To use Box Doc Gen API to generate documents, a Box Doc Gen template must already exist in Box. You have the following options to create a template: * Install the [Box Doc Gen Template Creator add-in for Microsoft Word][template-addin]. * Create a Box Doc Gen template [using a JSON file][json-template] or manually create [template tags][template-tags]. ## Create a platform application First you need to create a platform application you will use to make calls. To create an application, follow the guide on creating platform apps. ## Generate a developer token You need a developer token to authenticate your app when sending requests. To generate a token: 1. Go to **Developer Console** > **My Platform Apps**. 2. Click the **Options menu** button (…) on the right. 3. Select **Generate Developer Token**. The token will be automatically generated and saved to clipboard. generate token You can also open your app, go to **Configuration** > **Developer Token** and generate the token. A developer token is only valid for one hour. For additional details, see developer token. After you generate the token, you can use it in cURL or other clients, such as Postman, to make calls. ## Use webhooks You can create webhooks to monitor Doc Gen events and automate your business process or workflow. Follow the instructions for adding webhooks. Your content type is your Doc Gen template file or folder. The supported events are: * `DOCGEN_DOCUMENT_GENERATION_STARTED` * `DOCGEN_DOCUMENT_GENERATION_SUCCEEDED` * `DOCGEN_DOCUMENT_GENERATION_FAILED` Doc Gen event triggers Information that is posted in a notification: * Trigger name. * Webhook trigger timestamp. * Template file ID. * Template file version ID. * Template file name. * Destination folder. * Generated file ID (if the document generation process succeeds). * Output type (DOCX or PDF). * Reason (if the document generation process fails). [settings]: https://support.box.com/hc/en-us/articles/4404822772755-Enterprise-Settings-Content-Sharing-Tab#h_01FYQGK5RW42T07GV985MQ9E9A [template-addin]: https://support.box.com/hc/en-us/articles/36587535449747-Installing-Box-Doc-Gen-Add-in [template-tags]: https://support.box.com/hc/en-us/articles/36151895655059-Creating-A-Box-Doc-Gen-Template-Manually [json-template]: https://support.box.com/hc/en-us/articles/36148012877843-Creating-a-Box-Doc-Gen-Template-using-JSON-data # Box Doc Gen jobs Source: https://developer.box.com/guides/docgen/docgen-jobs A Box Doc Gen job runs when you make a request to generate a document. The `document_generation_data` parameter in the `POST` request is an array of entries that represent Box Doc Gen jobs run to generate a document. ```sh cURL theme={null} curl -L 'https://api.box.com/2.0/docgen_batches' \ -H 'box-version: 2025.0' \ -H 'Authorization: Bearer ' \ -D '{ "file": { "id": "12345678", "type": "file" }, "input_source": "api", "destination_folder": { "id": "12345678", "type": "folder" }, "output_type": "docx", "document_generation_data": [ { "generated_file_name": "Image test", "user_input": { "order": { "id": "12305", "date": "18-08-2023", "country": "US", "expiryDate": "18-08-2024", "currency": "$", "amount": 5060.5, "taxRate": 10, "requester": "John", "approver": "Smith", "department": "Procurement", "paymentTerms": "30 days", "deliveryTerms": "30 days", "deliveryDate": "18-09-2023", "vendor": { "company": "Example company", "address": { "street": "Example street", "city": "Example city", "zip": "EX-456" } }, "products": [ { "id": 1, "name": "A4 Papers", "type": "non-fragile", "quantity": 100, "price": 29, "amount": 2900 }, { "id": 2, "name": "Ink Cartridge", "type": "non-fragile", "quantity": 40, "price": 39, "amount": 1560 }, { "id": 3, "name": "Adhesive tape", "type": "non-fragile", "quantity": 20, "price": 30, "amount": 600.5 } ] } } } ]` ``` ```typescript Node/TypeScript v10 theme={null} await client.docgen.createDocgenBatchV2025R0({ file: new FileReferenceV2025R0({ id: uploadedFile.id }), inputSource: 'api', destinationFolder: new DocGenBatchCreateRequestV2025R0DestinationFolderField({ id: folder.id, }), outputType: 'pdf', documentGenerationData: [ { generatedFileName: 'test', userInput: { ['abc']: 'xyz' }, } satisfies DocGenDocumentGenerationDataV2025R0, ], } satisfies DocGenBatchCreateRequestV2025R0); ``` ```python Python v10 theme={null} client.docgen.create_docgen_batch_v2025_r0( FileReferenceV2025R0(id=uploaded_file.id), "api", CreateDocgenBatchV2025R0DestinationFolder(id=folder.id), "pdf", [ DocGenDocumentGenerationDataV2025R0( generated_file_name="test", user_input={"abc": "xyz"} ) ], ) ``` ```cs .NET v10 theme={null} await client.Docgen.CreateDocgenBatchV2025R0Async(requestBody: new DocGenBatchCreateRequestV2025R0(file: new FileReferenceV2025R0(id: uploadedFile.Id), inputSource: "api", destinationFolder: new DocGenBatchCreateRequestV2025R0DestinationFolderField(id: folder.Id), outputType: "pdf", documentGenerationData: Array.AsReadOnly(new [] {new DocGenDocumentGenerationDataV2025R0(generatedFileName: "test", userInput: new Dictionary() { { "abc", "xyz" } })}))); ``` ```swift Swift v10 theme={null} try await client.docgen.createDocgenBatchV2025R0(requestBody: DocGenBatchCreateRequestV2025R0(file: FileReferenceV2025R0(id: uploadedFile.id), inputSource: "api", destinationFolder: DocGenBatchCreateRequestV2025R0DestinationFolderField(id: folder.id), outputType: "pdf", documentGenerationData: [DocGenDocumentGenerationDataV2025R0(generatedFileName: "test", userInput: ["abc": "xyz"])])) ``` ```java Java v10 theme={null} client.getDocgen().createDocgenBatchV2025R0(new DocGenBatchCreateRequestV2025R0(new FileReferenceV2025R0(uploadedFile.getId()), "api", new DocGenBatchCreateRequestV2025R0DestinationFolderField(folder.getId()), "pdf", Arrays.asList(new DocGenDocumentGenerationDataV2025R0("test", mapOf(entryOf("abc", "xyz")))))) ``` Box Doc Gen API allows you to get information about the Box Doc Gen jobs. ## Prerequisites Before you start using Box Doc Gen API, follow the steps listed in the get started with Box Doc Gen guide to create a platform app and a Box Doc Gen template. ## List all Box Doc Gen jobs To get a list of all Box Doc Gen jobs that were run, use the `GET /2.0/docgen_jobs` endpoint. You don't have to provide any additional parameters. ```sh cURL theme={null} curl -i -X GET "https://api.box.com/2.0/docgen_jobs" \ -H 'box-version: 2025.0' \ -H "authorization: Bearer " ``` ```typescript Node/TypeScript v10 theme={null} await client.docgen.getDocgenJobsV2025R0({ limit: 10000, } satisfies GetDocgenJobsV2025R0QueryParams); ``` ```python Python v10 theme={null} client.docgen.get_docgen_jobs_v2025_r0(limit=10000) ``` ```cs .NET v10 theme={null} await client.Docgen.GetDocgenJobsV2025R0Async(queryParams: new GetDocgenJobsV2025R0QueryParams() { Limit = 10000 }); ``` ```swift Swift v10 theme={null} try await client.docgen.getDocgenJobsV2025R0(queryParams: GetDocgenJobsV2025R0QueryParams(limit: Int64(10000))) ``` ```java Java v10 theme={null} client.getDocgen().getDocgenJobsV2025R0(new GetDocgenJobsV2025R0QueryParams.Builder().limit(10000L).build()) ``` ## Get a Box Doc Gen job by ID To get a specific Box Doc Gen job, use the `GET /2.0/docgen_jobs_id` endpoint and provide the `job_id`. ```sh cURL theme={null} curl -i -X GET "https://api.box.com/2.0/docgen_jobs/12345" \ -H 'box-version: 2025.0' \ -H "authorization: Bearer " ``` ```typescript Node/TypeScript v10 theme={null} await client.docgen.getDocgenJobByIdV2025R0(docgenJobItemFromList.id); ``` ```python Python v10 theme={null} client.docgen.get_docgen_job_by_id_v2025_r0(docgen_job_item_from_list.id) ``` ```cs .NET v10 theme={null} await client.Docgen.GetDocgenJobByIdV2025R0Async(jobId: docgenJobItemFromList.Id); ``` ```swift Swift v10 theme={null} try await client.docgen.getDocgenJobByIdV2025R0(jobId: docgenJobItemFromList.id) ``` ```java Java v10 theme={null} client.getDocgen().getDocgenJobByIdV2025R0(docgenJobItemFromList.getId()) ``` ## Get Box Doc Gen jobs in batch with a specific ID A single request can generate several documents. In such a case, a separate generation job is run for each document and all these jobs are included in one "batch" meaning a request. To get all jobs performed within one request, use the `GET /2.0/docgen_batch_jobs_id` endpoint and provide the `batch_id`. ```sh cURL theme={null} curl -i -X GET "https://api.box.com/2.0/docgen_jobs/12345" \ -H 'box-version: 2025.0' \ -H "authorization: Bearer " ``` ```typescript Node/TypeScript v10 theme={null} await client.docgen.getDocgenJobByIdV2025R0(docgenJobItemFromList.id); ``` ```python Python v10 theme={null} client.docgen.get_docgen_job_by_id_v2025_r0(docgen_job_item_from_list.id) ``` ```cs .NET v10 theme={null} await client.Docgen.GetDocgenJobByIdV2025R0Async(jobId: docgenJobItemFromList.Id); ``` ```swift Swift v10 theme={null} try await client.docgen.getDocgenJobByIdV2025R0(jobId: docgenJobItemFromList.id) ``` ```java Java v10 theme={null} client.getDocgen().getDocgenJobByIdV2025R0(docgenJobItemFromList.getId()) ``` # Box Doc Gen templates Source: https://developer.box.com/guides/docgen/docgen-templates Box Doc Gen API allows you to retrieve information related to Box Doc Gen templates. ## Prerequisites Before you start using Box Doc Gen API, follow the steps listed in the get started with Box Doc Gen guide to create a platform app and a Box Doc Gen template. ## List Box Doc Gen templates To get a list of all created Box Doc Gen templates, use the `GET /2.0/docgen_templates` endpoint. You don't have to provide any additional parameters. ```sh cURL theme={null} curl -L 'https://api.box.com/2.0/docgen_templates' \ -H 'box-version: 2025.0' \ -H 'Authorization: Bearer ' ``` ```typescript Node/TypeScript v10 theme={null} await client.docgenTemplate.getDocgenTemplatesV2025R0(); ``` ```python Python v10 theme={null} client.docgen_template.get_docgen_templates_v2025_r0() ``` ```cs .NET v10 theme={null} await client.DocgenTemplate.GetDocgenTemplatesV2025R0Async(); ``` ```swift Swift v10 theme={null} try await client.docgenTemplate.getDocgenTemplatesV2025R0() ``` ```java Java v10 theme={null} client.getDocgenTemplate().getDocgenTemplatesV2025R0() ``` The response will contain an `entries` array listing the already created Box Doc Gen templates. ## Get a Box Doc Gen template by ID To get a specific Box Doc Gen template, use the `GET /2.0/docgen_templates_id` endpoint and provide the `template_id`. ```sh cURL theme={null} curl -L 'https://api.box.com/2.0/docgen_templates/12345678' \ -H 'box-version: 2025.0' \ -H 'Authorization: Bearer ' ``` ```typescript Node/TypeScript v10 theme={null} await client.docgenTemplate.getDocgenTemplateByIdV2025R0( createdDocgenTemplate.file!.id, ); ``` ```python Python v10 theme={null} client.docgen_template.get_docgen_template_by_id_v2025_r0( created_docgen_template.file.id ) ``` ```cs .NET v10 theme={null} await client.DocgenTemplate.GetDocgenTemplateByIdV2025R0Async(templateId: NullableUtils.Unwrap(createdDocgenTemplate.File).Id); ``` ```swift Swift v10 theme={null} try await client.docgenTemplate.getDocgenTemplateByIdV2025R0(templateId: createdDocgenTemplate.file!.id) ``` ```java Java v10 theme={null} client.getDocgenTemplate().getDocgenTemplateByIdV2025R0(createdDocgenTemplate.getFile().getId()) ``` The response will contain details of a file that was used as a Box Doc Gen template. ## List all document generation jobs for a template To get a list of all created Box Doc Gen templates, use the `GET /2.0/docgen_template_jobs_id` endpoint and provide the `template_id`. ```sh cURL theme={null} curl -L 'https://api.box.com/2.0/docgen_template_jobs/12345678' \ -H 'box-version: 2025.0' \ -H 'Authorization: Bearer ' ``` ```typescript Node/TypeScript v10 theme={null} await client.docgenTemplate.getDocgenTemplateJobByIdV2025R0( fetchedDocgenTemplate.file!.id, ); ``` ```python Python v10 theme={null} client.docgen_template.get_docgen_template_job_by_id_v2025_r0( fetched_docgen_template.file.id ) ``` ```cs .NET v10 theme={null} await client.DocgenTemplate.GetDocgenTemplateJobByIdV2025R0Async(templateId: NullableUtils.Unwrap(fetchedDocgenTemplate.File).Id); ``` ```swift Swift v10 theme={null} try await client.docgenTemplate.getDocgenTemplateJobByIdV2025R0(templateId: fetchedDocgenTemplate.file!.id) ``` ```java Java v10 theme={null} client.getDocgenTemplate().getDocgenTemplateJobByIdV2025R0(fetchedDocgenTemplate.getFile().getId()) ``` The response will contain a list of Box Doc Gen jobs that were run to generate documents. # Generate documents Source: https://developer.box.com/guides/docgen/generate-document The `POST /2.0/docgen_batches` endpoint allows you to generate a document using Box Doc Gen template as input. ## Prerequisites Before you start using Box Doc Gen API, follow the steps listed in the get started with Box Doc Gen guide to create a platform app and a Box Doc Gen template. ## Send a request To generate a document or a set of documents, use the `POST /2.0/docgen_batches` endpoint. ### Parameters To make a call, you need to pass the following parameters. Mandatory parameters are in **bold**. | Parameter | Description | Example | | -------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ | | **`file.id`** | ID of the file to be marked as Box Doc Gen template. | `12345678` | | **`file.type`** | The type of provided input. The value is always **`file`**. | `file` | | `file_version` | The file version of a template. | `12345` | | **`input_source`** | The input source for generated document. The value has to be `api` for all the API-based document generation requests. | `api` | | **`output_type`** | The output file type. | `docx`, `pdf` | | **`destination_folder.id`** | The ID of the folder where the generated document will be stored. | `12345678` | | **`destination_folder.type`** | The type of the destination item. Since the generated files are stored in folders, the value is always **`folder`**. | `file` | | **`document_generation_data.generated_file_name`** | The name of the generated file. | `New_Template` | | **`document_generation_data.user_input`** | The JSON data to be used to generate document. | `{"id": 2, "name": "Ink Cartridge", "type": "non-fragile"}` | ## Use case When your Box Doc Gen template and JSON data is ready, you can make a request to Box Doc Gen API to generate documents. A sample call looks as follows: ```sh cURL theme={null} curl -L 'https://api.box.com/2.0/docgen_batches' \ -H 'box-version: 2025.0' \ -H 'Authorization: Bearer ' \ -D '{ "file": { "id": "12345678", "type": "file" }, "input_source": "api", "destination_folder": { "id": "12345678", "type": "folder" }, "output_type": "docx", "document_generation_data": [ { "generated_file_name": "Image test", "user_input": { "order": { "id": "12305", "date": "18-08-2023", "country": "US", "expiryDate": "18-08-2024", "currency": "$", "amount": 5060.5, "taxRate": 10, "requester": "John", "approver": "Smith", "department": "Procurement", "paymentTerms": "30 days", "deliveryTerms": "30 days", "deliveryDate": "18-09-2023", "vendor": { "company": "Example company", "address": { "street": "Example street", "city": "Example city", "zip": "EX-456" } }, "products": [ { "id": 1, "name": "A4 Papers", "type": "non-fragile", "quantity": 100, "price": 29, "amount": 2900 }, { "id": 2, "name": "Ink Cartridge", "type": "non-fragile", "quantity": 40, "price": 39, "amount": 1560 }, { "id": 3, "name": "Adhesive tape", "type": "non-fragile", "quantity": 20, "price": 30, "amount": 600.5 } ] } } } ]` ``` ```typescript Node/TypeScript v10 theme={null} await client.docgen.createDocgenBatchV2025R0({ file: new FileReferenceV2025R0({ id: uploadedFile.id }), inputSource: 'api', destinationFolder: new DocGenBatchCreateRequestV2025R0DestinationFolderField({ id: folder.id, }), outputType: 'pdf', documentGenerationData: [ { generatedFileName: 'test', userInput: { ['abc']: 'xyz' }, } satisfies DocGenDocumentGenerationDataV2025R0, ], } satisfies DocGenBatchCreateRequestV2025R0); ``` ```python Python v10 theme={null} client.docgen.create_docgen_batch_v2025_r0( FileReferenceV2025R0(id=uploaded_file.id), "api", CreateDocgenBatchV2025R0DestinationFolder(id=folder.id), "pdf", [ DocGenDocumentGenerationDataV2025R0( generated_file_name="test", user_input={"abc": "xyz"} ) ], ) ``` ```cs .NET v10 theme={null} await client.Docgen.CreateDocgenBatchV2025R0Async(requestBody: new DocGenBatchCreateRequestV2025R0(file: new FileReferenceV2025R0(id: uploadedFile.Id), inputSource: "api", destinationFolder: new DocGenBatchCreateRequestV2025R0DestinationFolderField(id: folder.Id), outputType: "pdf", documentGenerationData: Array.AsReadOnly(new [] {new DocGenDocumentGenerationDataV2025R0(generatedFileName: "test", userInput: new Dictionary() { { "abc", "xyz" } })}))); ``` ```swift Swift v10 theme={null} try await client.docgen.createDocgenBatchV2025R0(requestBody: DocGenBatchCreateRequestV2025R0(file: FileReferenceV2025R0(id: uploadedFile.id), inputSource: "api", destinationFolder: DocGenBatchCreateRequestV2025R0DestinationFolderField(id: folder.id), outputType: "pdf", documentGenerationData: [DocGenDocumentGenerationDataV2025R0(generatedFileName: "test", userInput: ["abc": "xyz"])])) ``` ```java Java v10 theme={null} client.getDocgen().createDocgenBatchV2025R0(new DocGenBatchCreateRequestV2025R0(new FileReferenceV2025R0(uploadedFile.getId()), "api", new DocGenBatchCreateRequestV2025R0DestinationFolderField(folder.getId()), "pdf", Arrays.asList(new DocGenDocumentGenerationDataV2025R0("test", mapOf(entryOf("abc", "xyz")))))) ``` When the request is being processed, each entry in the `document_generation_data` array is treated as a separate document generation job that Box Doc Gen adds to the document generation queue. Generated documents will be saved in the designated folder. # Box Doc Gen Source: https://developer.box.com/guides/docgen/index Box Doc Gen API is available only for Enterprise Advanced accounts. Box Doc Gen allows you to generate business documents such as offer letters, sales contracts, invoices or agreements. You can generate documents based on Box Doc Gen templates uploaded to Box, with data fields that can be dynamically filled using Box Doc Gen API. Box Doc Gen only supports the ability to leverage English template tags when using Box Doc Gen templates. We recommend that customers test and review that Box Doc Gen supports their desired language requirements. ## Prerequisites To use Box Doc Gen, you must have access to Microsoft Word, as it is required for creating and authoring your document templates. You can utilize the Box Doc Gen Add-in for a code-free experience or apply tagging scripts within Word to prepare your documents. Box Doc Gen is designed to facilitate the dynamic generation of business documents, but it is important to note that Box does not have control over users’ access to Microsoft Word. Users must ensure they have the necessary permissions and access to Microsoft Word to create and author document templates effectively. ## Box Doc Gen API capabilities Box Doc Gen API allows you to: * mark documents as Box Doc Gen templates, * generate documents based on Box Doc Gen templates you store in Box, * examine the details of Box Doc Gen templates and document generation jobs. ## Box Doc Gen API version Box Doc Gen API was released in Box API version `2025.0`. All API requests to Box Doc Gen API endpoints must specify a valid API version by setting the `box-version` header to `2025.0`. For more details, see Box API versioning. ## Box Doc Gen workflow A flow diagram representing Box Doc Gen workflow 1. Author your Doc Gen Template * Use [Doc Gen Add-in for Microsoft Word][template-addin] to create a template without any code. * You can also leverage [Doc Gen's tagging script][tagging-script] to author the template. 2. [Add the template to Box][upload-template] using the Box Doc Gen UI. At this point, you can: * Mark an existing file In Box as Doc Gen template. * Create or Upload a document and mark it as a Box Doc Gen template. 3. Generate the document using Box Doc Gen API. [template-addin]: https://support.box.com/hc/en-us/articles/36587535449747-Installing-Box-Doc-Gen-Add-in [template-tags]: https://support.box.com/hc/en-us/articles/36151895655059-Creating-A-Box-Doc-Gen-Template-Manually [json-template]: https://support.box.com/hc/en-us/articles/36148012877843-Creating-a-Box-Doc-Gen-Template-using-JSON-data [tagging-script]: https://support.box.com/hc/en-us/articles/36149723736723-Template-tags-reference [upload-template]: https://support.box.com/hc/en-us/articles/36587432368275-Managing-Box-Doc-Gen-Templates-in-Relay # Mark file as Box Doc Gen template Source: https://developer.box.com/guides/docgen/mark-template You can mark an existing document as a Box Doc Gen template and use it to generate documents. ## Before you start Before you start using Box Doc Gen API, follow the steps listed in the get started with Box Doc Gen guide to create a platform app and a Box Doc Gen template. ## Send a request To send a request containing your question, use the `POST /2.0/docgen_templates` endpoint and provide the mandatory parameters. ### Parameters To make a call you need to pass the following parameters. Mandatory parameters are in **bold**. | Parameter | Description | Example | | --------------- | ----------------------------------------------------------- | ---------- | | **`file.id`** | ID of the file to be marked as the Box Doc Gen template. | `12345678` | | **`file.type`** | The type of provided input. The value is always **`file`**. | `file` | ## Use cases ### Mark a file as Box Doc Gen template The following sample show you how to mark a file to ensure it is recognized as a Box Doc Gen template. The file must be in `.docx` format. ```sh cURL theme={null} curl -L 'https://api.box.com/2.0/docgen_templates' \ -H 'box-version: 2025.0' \ -H 'Authorization: Bearer ' \ -H 'Content-Type: application/json' \ -D '{ "file": { "id": "12345678", "type": "file" } }' ``` ```typescript Node/TypeScript v10 theme={null} await client.docgenTemplate.createDocgenTemplateV2025R0({ file: new FileReferenceV2025R0({ id: file.id }), } satisfies DocGenTemplateCreateRequestV2025R0); ``` ```python Python v10 theme={null} client.docgen_template.create_docgen_template_v2025_r0(FileReferenceV2025R0(id=file.id)) ``` ```cs .NET v10 theme={null} await client.DocgenTemplate.CreateDocgenTemplateV2025R0Async(requestBody: new DocGenTemplateCreateRequestV2025R0(file: new FileReferenceV2025R0(id: file.Id))); ``` ```swift Swift v10 theme={null} try await client.docgenTemplate.createDocgenTemplateV2025R0(requestBody: DocGenTemplateCreateRequestV2025R0(file: FileReferenceV2025R0(id: file.id))) ``` ```java Java v10 theme={null} client.getDocgenTemplate().createDocgenTemplateV2025R0(new DocGenTemplateCreateRequestV2025R0(new FileReferenceV2025R0(file.getId()))) ``` ### Remove Box Doc Gen template marking from a file To make sure a file is no longer marked as a Box Doc Gen template, use the `DELETE 2.0/docgen_templates/:template_id` request. ```sh cURL theme={null} curl -L -X DELETE 'https://api.box.com/2.0/docgen_templates/12345678' \ -H 'box-version: 2025.0' \ -H 'Authorization: Bearer ' ``` ```typescript Node/TypeScript v10 theme={null} await client.docgenTemplate.deleteDocgenTemplateByIdV2025R0( createdDocgenTemplate.file!.id, ); ``` ```python Python v10 theme={null} client.docgen_template.delete_docgen_template_by_id_v2025_r0( created_docgen_template.file.id ) ``` ```cs .NET v10 theme={null} await client.DocgenTemplate.DeleteDocgenTemplateByIdV2025R0Async(templateId: NullableUtils.Unwrap(createdDocgenTemplate.File).Id); ``` ```swift Swift v10 theme={null} try await client.docgenTemplate.deleteDocgenTemplateByIdV2025R0(templateId: createdDocgenTemplate.file!.id) ``` ```java Java v10 theme={null} client.getDocgenTemplate().deleteDocgenTemplateByIdV2025R0(createdDocgenTemplate.getFile().getId()) ``` # Create your first application Source: https://developer.box.com/guides/getting-started/first-application Once you have your Developer Enterprise set up, you can start creating applications. Click the [Dev Console][console] button once you're logged in to your Developer Enterprise. If this is your first application, you will be prompted to get started. ## Choose application type The first step is to select the application type you want to create. In this guide we use the **Platform App** option, as most of our partners use this type for their integrations. ## Choose the authentication method After you choose the **Platform App**, you need to select an authentication method that your app will use. In this guide we use the **User Authentication (OAuth 2.0)** option, as most of our partners use this type for their integrations. ## Name the app Choose an app name. It can be changed later on and it is not publicly visible until you publish your app. We recommend choosing a name that is recognizable, as the admins and customers will see the name of the app when it's published. Click the **Create App** button to finish creating your app. Next, configure the application settings. ## General settings Begin with the most basic settings. Open the **General Settings** tab and check or fill in below fields: * **App Name** - the name you set up during the app creation, you can change it here if needed; * **Contact Email** - this is set to the developer of the application by default. Keep in mind that once you publish your app, this email is publicly visible to Box users who view your app in the Integrations. We recommend to change it to a support email address, so that users can reach out to support in case of any issues with the integration; * **Collaborators** - add other developers that can work on this integration, so that they can access the developer interface in case they need to adjust any settings. The developers you add here need to be Box users already. If they don't have Box account, you can [create them][add-users] in your Developer Enterprise. ## Advanced settings Go to the **Configuration** tab. Here you can specify the app details, generate a developer token, check your OAuth 2.0 credentials, add and edit OAuth 2.0 redirect URI, choose the application scopes, set app advanced features, and add CORS domains. In the next tabs you can create webhooks, web app integrations, submit app for enablement for access to the Enterprise, submit your app to the Box Integrations, and generate a report to view this application’s activity. ## Test your app You can now make some API calls to test your app and get to know the response format in Box. Use the developer token authenticated to your current developer account. This token is valid for an hour from being generated. Start with the Postman collection to check specific calls and see what responses they return. To see example API calls, browse our API reference documentation. You can also use [Box CLI tool][box-cli] if you prefer to use the terminal. [console]: https://cloud.app.box.com/developers/console [add-users]: https://support.box.com/hc/en-us/articles/360043694594-Add-Users [integrations]: https://cloud.app.box.com/integrations [box-cli]: https://github.com/box/boxcli # Start Here Source: https://developer.box.com/guides/getting-started/index Our documentation is divided into five main sections: * **Learn Box Platform**: A getting started walk through of all things Platform. * **Developer Guides**: In-depth documentation on developer portal, API working, usage of Box functionalities. * **API Reference**: A list of API endpoints and resources, with request and response examples. * **SDK and Tools**: A list of official Box SDKs and tools. * **Sample Code Catalog**: Consolidated list of several code repositories. If you are new to development with the Box API, first familiarize yourself with the content in the Learn Box Platform section. In this section, you will: * learn the Box Platform concepts, * evaluate if your use case is a good fit for Box, * understand the different types of Box users, * select the applicable application type, * check the available authentication methods and choose the best one for your use case, * find out where you can get support, * check the tools needed for developing applications in Box. A free developer account gives you access to the Developer Console and APIs, for everything you need to follow along with these guides. After learning the basics, we recommend you to follow the steps below. 1. Create your first Box application. 2. Configure your application. 3. Explore endpoints and make API calls using common values. 4. Publish your application. If you have any questions, checkout our [forum][forum-link]. [forum-link]: https://forum.box.com # Publish your app Source: https://developer.box.com/guides/getting-started/publish-app When you finish the platform app configuration and testing, you can publish it in the [Box Integrations][integrations]. It allows customers to find your app and add it to their Box accounts. Only apps that use the OAuth 2.0 authentication have a built-in publication option. In case you use a different auth type for your integration, you can still create and publish an OAuth 2.0 platform app that will serve as a marketing listing in the **Integrations** and redirect customers to your website. To publish your platform app: 1. Open the **Dev Console**. 2. Select the platform app you want to publish. 3. Go to the **Publishing** tab. 4. Read through the submission checklist and check the confirmation checkbox if your app meets all the requirements. 5. The next step is the marketing section of the app, where you need to add the following app information: * **General Info** - choose correct categories and platforms for your app to make it easier to find in the Integrations, * **Description** - make sure it contains all information about your app that the customers may find useful, * **Short Description** appears next to your app logo, together with your app name; * **Long Description** is what the users see after they select your app to view its details. You can add clickable links to the long description. * **Screenshots** and **Icon** - provide the screenshots to allow the users see how the app looks like and how it integrates with Box. The icon is needed to represent your app in the list of Integrations. * **Support Resources** - A list of links and supplementary information that will help the users to work with your app. 6. Before submitting your app, preview it to see if you included all the necessary information. 7. Submit your app for approval. Box will review your app and publish it under **Integrations**. If you have any questions or issues, contact the **Partners** team: [`integrate@box.com`][email]. [integrations]: https://cloud.app.box.com/integrations [email]: mailto:integrate@box.com # Sandboxes in Box Platform Source: https://developer.box.com/guides/getting-started/sandbox Developer sandboxes in Box provide a secure, controlled environment where developers can build, test, and collaborate on applications without affecting the actual data of your enterprise. They offer a safe space to experiment with Box APIs, test settings, try new integrations, and work alongside external partners. ## What is a developer sandbox A developer sandbox is an environment isolated from your production (live) enterprise setup that keeps development activities separate from real business data. ## Why use a sandbox Using a sandbox allows you to: * Safely build apps within an enterprise-linked environment instead of a free standalone account. * Collaborate securely with both internal teams and external collaborators. Contractors, partners, and other external users can join the sandbox without accessing live systems and compromising security. * Test apps under realistic testing conditions, as sandboxes inherit your enterprise's plan and add-ons at creation time. If there are any changes to the plan or add-ons, they can be manually synced by an enterprise admin. ## Accessing your sandbox Sandboxes in Box are created by enterprise admins. See this document to learn how to create a sandbox. When you are assigned as a primary admin of a sandbox, you receive a log-in email from Box with your sandbox user ID. To access the Dev Console inside the sandbox environment and set up a password, click the link in the email. You can also access your sandbox by logging in with your sandbox credentials on developer.box.com. The sandbox's primary admin can create individual sandbox accounts, giving developers access to a new Box environment that matches the plan of their parent Box enterprise. ### Accessing multiple sandboxes As a primary admin, you can log into multiple sandboxes. If you want to use this functionality for existing sandboxes, you can remove the unique email address and get a system generated email. [developer-box]: https://developer.box.com [syncing-sandboxes]: https://support.box.com/hc/en-us/articles/360043697274-Managing-developer-sandboxes-for-Box-admins#:~:text=in%20a%20sandbox.-,Synchronizing,-sandbox%20with%20production # Developer Guides Overview Source: https://developer.box.com/guides/guides-list Get started with Box API basics and create your first application Learn about Box Archive capabilities Explore AI-powered features in Box Build and manage AI agents with Box AI Studio Integrate Box with Model Context Protocol Generate documents programmatically Build and manage Box applications Secure your applications with Box authentication Control access and permissions Master API fundamentals and best practices Use Box command line interface Embed Box experiences in your applications Explore tools and SDKs for Box development Implement security best practices Set up single sign-on and app users Enable team collaboration features Organize content with collections Add commenting features to your app Implement file download functionality Monitor and react to Box events Work with files in Box Create and manage file requests Manage folder operations Map users across integrations Manage legal hold requirements Add custom metadata to content Build mobile Box applications Work with file representations Set up content retention policies Implement powerful search functionality Create and manage shared links Automate workflows with Box Relay Add e-signature capabilities Create and manage tasks Handle deleted content Implement file upload functionality Manage Box users Handle real-time events with webhooks Create and manage web links # Create a hub Source: https://developer.box.com/guides/hubs-api/hubs/create-hub To create a new Box Hub, call the `POST /2.0/hubs` endpoint with a `title` (required). You can optionally provide a `description`. The hub is created with default settings. To customize styling and other options, you can later use the API or Box web app. Box Hubs endpoints require the `box-version: 2025.0 header`. If you omit this header, the API returns a 400 error with the message `Missing required box-version header. Supported API versions: [2025.0].` For more information, see [Box API versioning strategy](/guides/api-calls/api-versioning-strategy/). ## Create hub ```sh Box CLI theme={null} box hubs:create "HR Hub" --description "Central hub for HR policies and onboarding materials." ``` ```sh cURL theme={null} curl -i -X POST "https://api.box.com/2.0/hubs" \ -H "Authorization: Bearer " \ -H "box-version: 2025.0" \ -H "Content-Type: application/json" \ -d '{ "title": "HR Hub", "description": "Central hub for HR policies and onboarding materials." }' ``` ```typescript Node/TypeScript v10 theme={null} await client.hubs.createHubV2025R0({ title: hubTitle, description: hubDescription, } satisfies HubCreateRequestV2025R0); ``` ```python Python v10 theme={null} client.hubs.create_hub_v2025_r0("HR Hub", description="Central hub for HR policies and onboarding materials.") ``` ```csharp .NET v10 theme={null} await client.Hubs.CreateHubV2025R0Async(requestBody: new HubCreateRequestV2025R0(title: hubTitle) { Description = hubDescription }); ``` ```swift Swift v10 theme={null} try await client.hubs.createHubV2025R0(requestBody: HubCreateRequestV2025R0(title: hubTitle, description: hubDescription)) ``` ```java Java v10 theme={null} client.getHubs().createHubV2025R0(new HubCreateRequestV2025R0.Builder(hubTitle).description(hubDescription).build()); ``` ## Request body | Field | Type | Required | Description | | ------------- | ------ | -------- | ------------------------------------------------ | | `title` | string | Yes | Title of the hub. Must not exceed 50 characters. | | `description` | string | No | Description of the hub. | A successful response returns the new Hub object. After creating the hub, you can see it in the Box Hubs web interface and manage its items and collaborations through the API. # Box Hubs Source: https://developer.box.com/guides/hubs-api/index Box Hubs provide a centralized way to organize content for specific teams, departments, or projects within your organization. They serve as content portals that bring together files, folders, and web links in a structured, easily accessible manner. Box Hubs are integrated with Box AI, allowing for more accurate responses thanks to a narrowed context window. The Box Hubs API lets you programmatically manage Box Hubs, their content, and collaborations. There are three groups of endpoints: * **Box Hubs:** Create, get, list, update, delete, and copy hubs. * **Box Hub items:** List items in a hub and add or remove files, folders, and web links. * **Box Hub collaborations:** Create, list, get, update, and delete hub collaborations to control who can access a hub and at what level. Box Hubs endpoints require the `box-version: 2025.0 header`. If you omit this header, the API returns a 400 error with the message `Missing required box-version header. Supported API versions: [2025.0].` For more information, see [Box API versioning strategy](/guides/api-calls/api-versioning-strategy/). ## Enable Box Hubs To enable Box Hubs (including the API) for your enterprise, follow the [Configuring Box Hubs](https://support.box.com/hc/en-us/articles/25822332454547-Configuring-Box-Hubs) product guide. ## Prerequisites * A Box account with Box Hubs enabled for your enterprise. * An access token with the appropriate [scopes](/guides/api-calls/permissions-and-errors/scopes) for the operations you need (for example, for listing enterprise hubs, [Global Content Manager (GCM)](https://developer.box.com/guides/api-calls/permissions-and-errors/scopes/#global-content-manager-gcm) for admins or Hub Co-admins). ## Tutorial End-to-end walkthrough: provision a Sales Hub, populate it with approved content, embed it in a CRM, and query it with Box AI. ## Next steps * [Create a hub](/guides/hubs-api/hubs/create-hub) — Create a new Box Hub through the API. * [Get a hub](/guides/hubs-api/hubs/get-hub) — Retrieve a hub by ID. * [List hubs](/guides/hubs-api/hubs/list-hubs) — List hubs for a user or for the enterprise. * [Update a hub](/guides/hubs-api/hubs/update-hub) — Change a hub's title, description, or settings. * [Delete a hub](/guides/hubs-api/hubs/delete-hub) — Delete a single hub. * [Copy a hub](/guides/hubs-api/hubs/copy-hub) — Create a copy of an existing hub. * [Manage hub items](/guides/hubs-api/hubs-items/hub-items) — List, add, and remove items in a hub. * [Manage hub collaborations](/guides/hubs-api/hubs-collaborations/hub-collaborations) — Invite users or groups and manage their access to a hub. # Hubs APIs use cases Source: https://developer.box.com/guides/hubs-api/use-cases Managing content portals at scale can be challenging due to the need for manual curation, complex permission management, and inconsistent user experiences across teams. The Box Hubs API provides the programmatic control for automating the creation, management, and governance of content portals. It handles the complexity—orchestration, security inheritance, and content indexing, so you can build scalable knowledge bases and embed them directly into your applications. The Box Hubs API empowers developers to: * **Scale faster:** Automate Hub creation and management using APIs to replace tedious manual configuration with event-driven workflows. * **Minimize maintenance:** Programmatically inherit Box's enterprise-grade governance, ensuring sensitive data stays protected without building custom security frameworks. * **Reduce complexity:** Seamlessly embed AI-powered content portals into existing internal portals or third-party tools instead of building custom interfaces from scratch. Leverage the Hubs API to build tailored solutions for specific vertical needs. * **Client Portals:** Programmatically generate secure portals for high-net-worth clients to access their specific tax documents, contract updates, and market trend reports. * **Deal Rooms:** Automatically spin up "Deal Hubs" for M\&A activities, populating them with necessary due diligence documents while strictly controlling external access permissions. * **Clinical Trial Portals:** Create standardized hubs for each trial site to centralize protocols, investigator brochures, and patient enrollment forms. * **SOP Guidelines:** Maintain a single source of truth Hub for Standard Operating Procedures that automatically updates when the underlying files in Box are modified. * **Citizen Information Portals:** Build public-facing or inter-agency hubs for grant documentation, policy procurement, and court judgments. * **Case Management:** Automate the creation of hubs for specific legal cases or public records requests, gathering all relevant files into one navigable view for review. * **Store Operations:** Distinct hubs for every franchise location containing the latest merchandising guidelines, campaign assets, and safety policies. * **Franchisee Resources:** Automate the distribution of new season playbooks to thousands of partner portals simultaneously. Streamline knowledge sharing across departments by integrating Hubs into your end users' daily workflows. * **Sales Enablement:** Embed a "Sales Hub" into your CRM that surfaces the latest pitch decks, competitive intelligence, and pricing sheets so reps can close deals faster. * **Request for Proposal (RFP) Libraries:** Create a curated RFP library where teams can use Box AI to instantly find answers to technical questions from past proposals. * **Onboarding Portals:** Automatically generate a personalized "Welcome Hub" for new hires containing their specific benefits info, handbook, and training videos triggered by their start date in the Human Resource Information System (HRIS). * **Employee Resources:** Surface training and benefit resources to employees across the globe in a centralized, easily navigable Hub. * **Brand Asset Libraries:** Create a central, read-only Hub for external agencies to access approved logos and campaign assets without giving them access to the raw working files. * **Campaign Management:** Find, repurpose, and align on campaigns faster with AI-powered insights and a centralized project Hub. * **Contract Repositories:** Build a "Legal Hub" that aggregates approved contract templates and policy libraries, allowing users to ask questions against the content using Box AI. * **Compliance Portals:** Effortlessly manage and organize compliance documentation to ensure teams have access to the latest regulations. * **Standard Operating Procedure (SOP) Libraries:** Streamline and manage content for standardized procedures and documentation, ensuring operational consistency across teams. * **Product Documentation:** Create self-serve product knowledge hubs that reduce the burden on subject matter experts to answer repetitive questions. * **Service Desk Hubs:** Reduce ticket volume by providing a self-service IT documentation and policy hub where users can find their own answers. * **Security Policies:** Distribute up-to-date security and access policies through a governed portal that ensures version control. ## Try it yourself Follow a step-by-step walkthrough that provisions a Sales Hub, populates it with curated content, embeds it in a CRM, and lets reps query past proposals using Box AI. ## Core Benefits of using the Box Hubs API * **Security & Compliance:** All content within a Hub inherits the permissions of the underlying source files. The Hubs API respects Box's enterprise-grade security framework, eliminating the need for developers to build custom authentication or encryption layers. * **AI-Ready Infrastructure:** Hubs are pre-indexed for Box AI. By using the Hubs API, you are tapping into your company's knowledge base, without the complexity of building and maintaining custom RAG systems or storing content in a vector database. * **Model-Neutral Flexibility:** Box AI in Hubs allows you to leverage the latest, most powerful LLMs to query your curated content without being locked into a single AI provider. ## Next steps Get started with the Box Hubs API with the following developer guides: # Build with Box Platform Source: https://developer.box.com/guides/index

Build with Box Platform

All the developer resources to help you get the most from Box products

Onboard to Box Platform in minutes. Dive deeper with technical guides. Connect AI agents to Box, use the Box AI API, and integrate with AI frameworks. Check endpoint details and try API calls. Stay up to date with all latest releases. Create and manage Box Platform Apps.

Get started

Explore tools

Speed up development with Box SDKs and developer tools. Perform actions on Box content seamlessly. Embed Box UI Elements to custom apps.

Tutorials

Build production-ready automations that combine Box AI with other platform capabilities

Watch a folder, extract fields with Box AI, and write metadata back. Accounts payable on autopilot! Build an AI-powered knowledge base with Box Hubs for instant answers grounded in approved sales content.
# Architecture Patterns Source: https://developer.box.com/platform/appendix/architecture-patterns We recommend creating a visual representation for your application before writing any code. The architecture patterns shown below are generic and do not represent an exhaustive list of possibilities. Would you like assistance with application architecture? Contact your account team to purchase Box Consulting services. ## Administrative tasks Admin Tasks Diagram Components: * A server or local machine running a PowerShell script * An identity provider with a user provisioning/deprovisioning service * A [Service Account][sa] owned folder containing a personal folder for each user * A PowerShell script based on a time that monitors the [event stream][events] and creates/collaborates each user on their personal folder ## Vault Portal Vault Portal Diagram Components: * A custom portal allowing users to collaborate in a non-Box branded environment * A load balancer distributing users to a web server with the deployed portal * Users can login using credentials maintained in an identity provider, which are then mapped to [App User][au] information from Box within a data server. * Other site data is stored on the data server [usermodel]: /platform/appendix/user-models [auth]: /guides/authentication [platform-app]: /guides/applications/platform-apps/index [events]: /reference/resources/event [userevents]: /guides/events/user-events/for-user [sa]: /platform/user-types/#service-account [fr]: https://support.box.com/hc/en-us/articles/360045304813-Using-File-Request-to-get-Content-from-Anyone [au]: /platform/user-types/#app-user [metadata]: /reference/post-files-id-metadata-global-boxSkillsCards # Branding Guidelines Source: https://developer.box.com/platform/appendix/branding-guidelines We are glad you are using Box Platform, and we want you to be able to broadcast to the world that you are using Box. However, it is very important that your application not be mistaken for an official Box application. For this reason, we created a guide to using our name and logo. ## Approved logos Approved Box logos can be found in [this Box folder][logos]. ## Things to do ### Inform users Let users know when they’re connecting to Box. Many apps feature a “connect to cloud services” menu, or something similar. In this case, you should feel free to use our name and logo to help people find us. ### Contact us We’re here to help. Many situations can be ambiguous, and we’ll absolutely work with you to make sure that your app works within our guidelines. [Contact us with any questions][contact]. ## Things not to do ### Do not impersonate Box Please don't call your application anything that might be mistaken for an official Box application. This means no use of the word "Box" unless it’s abundantly clear that it’s not official. For example, "Unofficial Box Client" is certainly clear enough, while "Box App for Android" is not. If you include your own brand name (for example, "My Company Box Client"), you’re probably fine. Nonetheless, this is probably the most ambiguous guideline, so please [contact us][contact] if you have any questions, and we’ll get you sorted out right away! In short though, this means: * Don't use our logo or any similar logo or part of our logo as the icon for your application. * Don't use our name or logo in any way inside your application that would make it look like it’s an official Box application. ### Don't alter Box logo Don't alter the 'Box' logo in any way when using it in your application. ### Don't use older names Don't refer to us as `Box.net` or `Boxnet`. Our company is known as "Box" only. [logos]: https://cloud.app.box.com/v/BoxCorporateLogo [contact]: https://support.box.com/hc/en-us/requests/new # Appendix Source: https://developer.box.com/platform/appendix/index In this section, you will find some other getting started related material. It isn't vital to know from the get go, but it can help pinpoint you to a solution if you are having an issue. * [User Models][user_models]: This page goes over how to use the users types discussed earlier in this series. * [Architecture patterns][arch_patterns]: This page goes over some typical infrastructure patterns we see. * [Locating Common Values][common_values]: This page goes over how to find pieces of information like user IDs. * [Branding Guidelines][branding]: This page lists out various things to keep in mind if you plan to use the Box brand for your project [arch_patterns]: /platform/appendix/architecture-patterns [user_models]: /platform/appendix/user-models [common_values]: /platform/appendix/locating-values [branding]: /platform/appendix/branding-guidelines # Locating Common Values Source: https://developer.box.com/platform/appendix/locating-values ## User IDs ### As a developer To locate your own user ID via the Box web app, navigate to your **All Files** page. Click the circle in the top right corner and select **Account Settings** from the dropdown menu. Your user ID is the **Account ID** value listed in the **Account Details** section of the **Account** tab. To locate your user ID via API, navigate to the Developer Console and generate a [Developer Token][devtoken] or obtain an [Access Token][at] for yourself. Use this token with the [get current user endpoint][currentuser], which will return your user ID in the `id` field. ### As an Admin If your account type provides access to the [Content Manager][contentmanager], click on the user in question from user list. The URL will reveal their user ID. For example, `https://.app.box.com/master/content/2267862105/0/0`, the user ID is `2267862105`. To locate user IDs via API, navigate to the Developer Console and generate a [Developer Token][devtoken] or obtain an [Access Token][at] for yourself. Then, make an API call to the [list enterprise users][leu] endpoint. This will provide a list of all users in your enterprise. ## Enterprise ID ### As a developer To find your enterprise ID, select your account icon in the top-right of the Developer Console and click **Copy Enterprise ID**. ### As an Admin From the **Admin Console**, navigate to the **Account & Billing Tab**. The Enterprise ID is located under the **Account Information** section. ## Content IDs ### As a developer To locate a file ID via the Box web app, navigate to the file's preview in your browser and look at the URL. For example, the file ID of `https://app.box.com/file/1234567890` is `1234567890`. To locate a folder ID via the Box web app, navigate into the folder and look at the URL. For example, the folder ID of `https://app.box.com/folder/9876543210` is `9876543210`. To locate content IDs via the API, you may want to start by listing all items at the All Files level by passing `0` as the `folder_id` of the [list items in folder][lif] endpoint. ### As an Admin If you have access to the [Content Manager][contentmanager], click on the user in question from the user list and then navigate to the content. The URL will reveal the folder and/or file id. For example, `https://app.box.com/master/content/1987212562/88560510648/0/532181212706`. The User ID is `1987212562`, the folder ID is `88560510648` and the file ID within that folder is `532181212706`. [contentmanager]: https://support.box.com/hc/en-us/articles/360044197333-Using-the-Content-Manager [currentuser]: /reference/get-users-me [devtoken]: /guides/authentication/tokens/developer-tokens [uo]: /reference/resources/user [uo-full]: /reference/resources/user--full [at]: /guides/authentication/tokens/access-tokens [leu]: /reference/get-users [lif]: /reference/get-folders-id-items # User Models Source: https://developer.box.com/platform/appendix/user-models Once you confirm your [use case][usecase] is a good fit for Box Platform and you have a solid understanding of the [types of users][usertypes] involved, you can select a user model to begin [application architecture][architect]. ## Classic In this model, the application has internal and external users. The external users share or collaborate on content with internal users who use the Box web application. Access Token Components * **Internal User Type**: [Managed Users][mu] * **External User Type**: [App Users][appu] * **Content Owned By**: Application [Service Account][sa] or [Managed Users][mu] * **Examples**: Vault Portals, Document Submissions, Field Worker Applications Benefits of this user model: 1. Removes the need to build additional functionality for internal users 2. Allows App Users to be mapped to your own identity system like `Auth0` 3. Allows reporting on all actions to meet to meet security and compliance requirements ## App User In this model, the application has internal and external users who all leverage the same custom UI. Access Token Components * **Internal User Type**: [App Users][appu] * **External User Type**: [App Users][appu] * **Content Owned By**: [App Users][appu] * **Examples**: Vault Portals, Document Submissions, Field Worker Applications Benefits of this user model: 1. Allows for a custom experience for internal and external users 2. Separates managed user and application content by allowing managed users to have separate App User accounts 3. Allows App Users to be mapped to your own identity system like `Auth0` 4. Allows reporting on all actions to meet to meet security and compliance requirements or tracking in other systems ## Service Account In this model, the application has internal and external users, but the user object already exists. This model also works well when users are transient in nature, but the content must persist. Access Token Components * **Internal User Type**: [Managed Users][mu] * **External User Type**: Managed by your customer’s applications * **Content Owned By**: Application [Service Account][sa] * **Examples**: Wealth Management Portal, Insurance Claim Workflow Benefits of this user model: 1. Useful when the App User model would complicate existing applications 2. Useful when there is not a good 1:1 end user/app user mapping, such as users mapped as groups 3. Permissions are easier to manage, since the Service Account owns all content 4. Ability to implement a token exchange to ensure that broad scoped access to the Service Account does not occur ## System to system In this model, no user content normally needs to be handled. Access Token Components * **External User Type**: N/A * **Internal User Type**: N/A * **Content Owned By**: Application [Service Account][sa] * **Examples**: Back Office Applications, Integrations, User Provisioning, Folder Auto-Creation Benefits of this user model: 1. Useful when user construct isn’t needed (e.g. departmental or company owned content that transcends user ownership) 2. Allows for complete control of permission assignment to backend services since the Service Account can be granted elevated privileges [usecase]: /platform/use-cases [usertypes]: /platform/user-types [architect]: /platform/appendix/architecture-patterns [mu]: /platform/user-types/#managed-users [appu]: /platform/user-types/#app-user [sa]: /platform/user-types/#service-account # Application Types Source: https://developer.box.com/platform/application-types Box offers various application types to cater to different needs and use cases in application development. Each provides different capabilities and authentication method options. ## Platform App Platform Apps are versatile and can accommodate most use cases. They allow developers to present Box functionalities within a custom interface. Box provides customizable UI Elements for tasks like browsing, searching, and previewing content. These apps support OAuth 2.0, JWT, and Client Credentials Grant for authentication. Platform Apps are ideal for applications that need to access both their own and others' files, upload and download files, and potentially be listed in the Box Integrations. ## Web App Integrations Web App Integrations allow third-party applications to integrate seamlessly with the Box user experience. They enable users to edit, share, or modify content stored in Box using a third-party application. Such integrations can add new features to Box users and be added to Recommended Web Integrations in Box Preview, enhancing the user experience by integrating with various content types and file extensions. ## Integrations Publication Box Integrations is a platform for Box users to discover applications that can be used in conjunction with Box. For developers, listing their application in the Integrations is an effective way to reach new users, particularly for applications suited for use by other enterprises. The process for Integrations publication involves ensuring the app is production-ready, leverages OAuth 2.0 authentication, and submitting it for approval through the Developer Console. Once approved, applications can be featured, most popular, or recently added sections in the Integrations, and they can also be unpublished if necessary. Next step [platform_app]: /guides/applications/platform-apps/index [web_app]: /guides/applications/web-app-integrations [integrations]: /guides/applications/integrations/ # Authentication Methods Source: https://developer.box.com/platform/authentication-methods Box offers a variety of authentication methods for application development, each tailored to different use cases and application types. Regardless of the authentication method used, underlying principles still apply. If a user does not have access to content on the front end of the main Box web app, they will not be able to access the content using the API, unless they are impersonating another user. Some API endpoints require admin level privileges - like events. The following authorization methods are available to each Box application type. | Box Application Type | Supports OAuth 2.0? | JWT? | Client Credentials? | | -------------------- | ------------------- | ---- | ------------------- | | Platform App | Yes | Yes | Yes | ## OAuth 2.0 [OAuth 2.0][oauth] is a client-side authentication method, widely used for its simplicity in authorizing users to Box API. It's an open standard that allows users to grant applications access to their data in other applications. Similar to how logging in to a website with Twitter, Facebook, or Google works, Box's client-side authentication involves redirecting a user from an app to the Box web app, where they log in and grant the app access to their data. For example, We use this auth type for users logging into our community forum. **When to use OAuth 2.0?** Client-side authentication is the ideal authentication method for apps that: * Work with users who have existing Box accounts * Use Box for identity management, so users know they are using Box * Store data within each user account vs within an application's Service Account You can find a great Python OAuth 2.0 tutorial on [GitHub][python_oauth]. ## JSON Web Token (JWT) JSON Web Tokens (JWT) is the most common server-side authentication method for the Box API. [JWT][jwt], an open standard, enables robust server-to-server authentication. This method, exclusive to Platform Apps, does not involve end-user interaction. It allows an app, if granted appropriate privileges, to act on behalf of any user in an enterprise, thus facilitating powerful and seamless integrations. Upon approval by an administrator, a JWT application will get assigned a service account to make API calls as by default. **When to use JWT?** Server-side authentication with JWT is the ideal authentication method for apps that: * Work with users without Box accounts * Use their own identity system * Do not want users to know they are using Box * Store data within the application's Service Account and not a user's account * Want to manage public and private key pairs You can find a great Node JWT tutorial on [Medium][node_jwt]. ## Client Credentials Grant (CCG) The [Client Credentials Grant][ccg] approach is used for server authentication, verifying an application's identity using a client ID and secret. It's a secure way of identifying an app when obtaining an Access Token. This method is particularly useful for scenarios requiring server-to-server interactions without user involvement. Depending on the application's configuration, it can authenticate as either the application's Service Account or as a Managed User. Upon approval by an administrator, a CCG application will get assigned a service account to make API calls as by default. **When to use CCG?** Server-side authentication with JWT is the ideal authentication method for apps that: * Work with users without Box accounts * Use their own identity system * Do not want users to know they are using Box * Store data within the application's Service Account and not a user's account * Do not want to manage public and private key pairs You can find a great Python CCG tutorial on [Medium][python_ccg]. ### User permissions and scopes It is important to understand that even if an application has the right scopes to perform an action, the user associated with the Access Token making the call needs to have permission to perform the action as well and vice versa. For example, if your application is set up to read files, the authenticated user does need to have permission to read the file you are trying to access. To learn more about how scopes, token permissions, and user permissions work together, see our [security guide][security]. Next step [oauth]: /guides/authentication/oauth2 [jwt]: /guides/authentication/jwt [ata]: /guides/authentication/app-token [ccg]: /guides/authentication/client-credentials [skill]: /guides/skills/handle/payload/#access-tokens [app_ep]: /guides/authentication/app-token/endpoints [scopes]: /guides/api-calls/permissions-and-errors/scopes [at]: /guides/authentication/tokens [security]: /guides/security [reference]: /reference [python_oauth]: https://github.com/box-community/box-python-oauth-template [python_ccg]: https://medium.com/box-developer-blog/box-python-next-gen-sdk-getting-started-with-ccg-81be0abc82d9 [node_jwt]: https://medium.com/box-developer-blog/authenticate-box-node-js-sdk-with-jwt-47fdd3aeec50 [skill_watson]: https://medium.com/box-developer-blog/box-skills-ibm-watson-speech-to-text-tutorial-b7e3b3c0a8c7 # Box Platform glossary Source: https://developer.box.com/platform/box-glossary This glossary includes terms and definitions used in Box Platform. If you need to find out what a term means, this is your one stop page. | Box Resource Type/Term | Also known as (AKA) | Description | | --------------------------------------- | -------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Admin | Superuser, administrator, supervisor | The main admin on an enterprise account. Admins can manage users and groups, view and edit all of their organization’s files and folders, log in to any user’s account within their organization, edit settings for their organization, and run or access reports. The Box Admin is the principal account administrator. | | [Admin Console][admin-console] | | The dashboard area for administering a particular enterprise. Accessible by the admin, group admins, and co-admins. | | Anonymous User | | A user that is not logged in. | | App user | | Box [app user][app user] is a specific type of user within the Box Platform who is associated with applications or services that integrate with Box. App users are only accessible with the API, meaning they do not have login credentials. They can be created by a service account and are only applicable to applications leveraging server to server authentication. App users are tied to the application used to create them, and the user itself cannot be moved under another application. They can however collaborate on content outside of the application. | | Bookmark / web link | Symbolic link, Symlink, soft link, reference, relationship | A clickable reference that allows you to easily access external websites or specific locations within your content structure. | | Box Integrations | App Store | The first place for Box users to find out about applications that they can use in combination with Box. | | Box Command Line Interface | [Box CLI][CLI] | A user-friendly command line tool that allows both technical and non-technical users to leverage the Box API to perform routine or bulk actions. | | Box Custom Skill | Custom Skill, Box Skill | An application that performs custom processing for files uploaded to Box. Skills are designed to make it possible to use third-party machine learning services to automatically extract information from files uploaded to Box. | | [Box AI][box-ai] | | Built-in AI features that analyze, summarize, extract, and generate content directly from files in Box. | | [Box AI Studio][ai-studio] | | A workspace for configuring and deploying custom AI agents, prompts, and automations on Box content. | | [Box Archive][archives] | | A tool that allows you to create and manage archives – folders dedicated to storing redundant, outdated, or trivial content. | | [Box App item][app-item] | App item | A content object owned by an application that can group files and folders from different paths. That set can be shared through a collaboration. | | [Box Doc Gen][docgen] | | A tool that allows you to generate business documents such as offer letters, contracts, invoices, or agreements from templates stored in Box, with data fields that can be filled dynamically. | | [Box Embed][embed] | | An HTML-based framework that makes it possible to embed the Box Web App experience anywhere in the 3rd party applications. Box Embed provides the ability to upload, search, comment, share, tag, and edit files using Box Edit. | | [Box Hubs][hubs] | | Curated, shared workspaces that organize related content and resources around a team, project, or topic. | | [Box MCP server][box-mcp] | | A secure server that connects AI tools to Box content using permission-aware access through the Model Context Protocol. Box hosts the remote MCP server; a legacy self-hosted option is deprecated. | | [Box Platform][platform] | | An API-driven cloud content management and collaboration platform that provides developers with the tools and infrastructure to build platform applications, integrate workflows, and leverage powerful features for secure document storage, access control, versioning, metadata management, and real-time collaboration. | | [Box Sample Code Catalog][code-catalog] | | Allows developers and admins to search through code repositories of tools, automation scripts, self paced workshops, and demo apps in multiple programming languages. The catalog contains more that eighty open source repositories and guides. | | [Box Shield][shield] | | A security solution offered by Box that helps protect sensitive data, prevent unauthorized access, and detect potential threats through automated classification and proactive monitoring. | | [Box Relay][relay] | | Box Relay allows you to create and configure workflow automations to automate and accelerate business processes centered around content. | | [Box Verified Enterprise][bve] | BVE | Box Verified Enterprise is a certification program that ensures the security and compliance of an organization's content management system. | | [Box UI Elements][ui-elements] | | Pre-built UI components that allow developers to add elements of the main Box web application into their own applications. They can be used to navigate through, upload, preview, and select content stored on Box and are available both as React components and framework-agnostic JavaScript libraries. | | [Cascade policy][cascade-policy] | | Box enables you to add metadata instances to a folder, and automatically cascade them to the folder's contents so you don't need to add the instances individually. Using cascading metadata, you can quickly add metadata to multiple files and sub-folders at one time. | | [Classification][classification] | | An instance of the classification metadata template, containing the classification applied to the file or folder. | | Collaboration | | Working together on a file or folder. | | [Collaborations][collaborations] | Permissions, Role-Based Access Control (RBAC), Access Control List (ACL), permission mapping | Collaborations define access permissions for users and groups to files and folders, similar to access control lists. A collaboration object grants a user or group access to a file or folder with permissions defined by a specific role. | | Collaborator | | Someone who shares access to a file or folder. | | Collaborated folder | Shared folder | A shared folder owned by someone within your enterprise. | | Collaboration roles | Permission levels, access levels | The collaboration roles define the level of permissions a user has for a specific file or folder. The collaboration roles in Box are **Owner**, **Co-owner**, **Editor**, **Viewer Uploader**, **Previewer Uploader**, and **Viewer**. Collaboration levels in Box follow a "waterfall" design in which individuals have access only to the folder they are invited into and any sub-folders beneath it. You can also be invited to individual files. | | Collection | | A collection of items, including files and folders. The contents of a collection can be explored in a similar way to which the contents of a folder is explored. | | [Content Manager][content-manager] | | A feature in the Admin Console that allows you to: search for and download files and folders in your organization, browse by user to see the files and folders they can access, move files between folders, invite collaborators to folders, get shared links and modify access levels, and delete files and folders from any user’s trash. | | [Co-admin][co-admin] | | A user other than the main admin, who has a subset of administrative privileges. Co-admins can perform the same duties as the organization’s admin, but they cannot make changes to the Admin’s permissions or other co-admins' permissions. The default access levels for co-admins include only the ability to manage users and groups, but they can be modified on a per-user basis. | | \[Platform App]\[custom-app] | | A tailored application that extends the functionality of Box by integrating with other tools and systems. It's used to streamline workflows and enhance collaboration. It can be created in the Developer Console and has several authentication methods available. | | Developer | Programmer | A skilled professional who designs, builds, and maintains software applications or systems and has access to the Developer Console. In Box, the developer can have an admin role. | | [Developer Console][dev-console] | | A portal that allows developers to create, debug, test, and monitor their applications by providing real-time insights into code execution and system performance. | | Enterprise | Repository, content store, file cabinet, Docbase, vault | Enterprise in Box is a comprehensive suite of tools and services provided by Box for large organizations, offering secure file storage, collaboration features, access controls, workflow automation, compliance enforcement, and analytics. It enables efficient document management and teamwork while ensuring data security within an enterprise setting. | | [Ethical walls][info-barriers] | Information barriers | A mechanism that prevents exchanges or communication that could lead to conflicts of interest and therefore result in business activities ethically or legally questionable. | | [Event][event] | | Result of an action taken by the user. See [Using the Enterprise Event Stream][event-stream]. | | External collaborator | External user | A collaborator who is not part of an enterprise. | | External collaborated folder | | A folder owned by someone outside your enterprise. | | File | Document, unstructured data | A digital container that stores information or data in a structured format. | | Folder | Directory, container | A directory containing files. | | [Group admin][group-admin] | | Group admins can add existing users to their groups, create new users that will be assigned to their groups, and assign folder access to their groups. They can also run reports for their groups. | | Group | Team | Collaborative workspace where users can share files, collaborate on documents, and communicate with each other. | | Item | Object, Box object, content | Can represent a file, a folder or a web link. | | [Managed user][managed-users] | | A user account that is centrally controlled and administered by an organization's admin. | | Metadata template | Document class, document type, content type, indexes | A predefined structure that captures and organizes important information about a document or file. | | Metadata attribute | Property, field, keyword, index Value | A metadata attribute is a piece of information that provides descriptive details about data, such as its type, format, or source. | | Personal folder | | A folder owned by an individual user. | | [Report][report] | | A file containing a specific data set. You can use the **Admin Console Reports** tab to run a variety of account-wide reports: usage logs, file/user statistics, and security audits. | | Sandbox | Testing environment | Managed, trackable, non-production, testing environment for developers. | | [Service account][service-account] | | A service account provides developers with a programmatic authentication mechanism for server-side integrations with Box. In other words, an application can authenticate to Box as the service, which is represented by a service account user. A service account can then be used to create other application specific users, called app users. | | [Shared link][shared-link] | | A hyperlink to content stored in Box you can share with your coworkers and friends – both inside and outside of the company. Sending someone a shared link to a file or folder is a way to work together with that person around shared content. Customizable permission levels, expiration dates, and optional password-protection make Box shared links a secure, simple way to share important content. | | Software Developer Tool | [SDK][sdk] | A collection of tools, libraries, and documentation that helps developers create software applications for specific platforms or frameworks. | | Task | Action | A specific action or assignment that needs to be completed within the collaborative document creation editor. | | User | Identity, person, authority | An individual who utilizes the collaborative document creation editor to create, edit, and share documents with others. | | Unmanaged user | | A user account that is not centrally managed by an organization and has limited access and control over the content within Box. The unmanaged users may or may not also be external users. | | Version control | | The management and tracking of different versions of a document, ensuring that everyone is working on the most up-to-date version. | | [Webhook][webhook] | | A webhook is a way for an application to provide real-time data or notifications to another application by sending HTTP POST requests. | | Workflow | | Workflows within Box are automated sequences of tasks that help streamline and track the progress of document-centric processes, ensuring efficient collaboration and timely completion. | Next step [app user]: /platform/user-types/#app-user [app-item]: /reference/resources/app-item [ai-studio]: /guides/ai-studio [archives]: /guides/archives [box-ai]: /guides/box-ai [box-mcp]: /guides/box-mcp [CLI]: https://github.com/box/boxcli [docgen]: /guides/docgen [hubs]: /guides/hubs-api [collaborations]: /guides/collaborations [embed]: /guides/embed/box-embed [ui-elements]: /guides/embed/ui-elements [cascade-policy]: https://support.box.com/hc/en-us/articles/360044195873-Cascading-metadata-in-folders [content-manager]: https://support.box.com/hc/en-us/articles/360043698294-Managing-Files-And-Folders-From-The-Admin-Console [co-admin]: https://support.box.com/hc/en-us/articles/360043694174-Understanding-Administrator-and-Co-Administrator-Permissions [info-barriers]: https://support.box.com/hc/en-us/articles/9920431507603-Understanding-Information-Barriers [event]: /reference/resources/event [event-stream]: https://support.box.com/hc/en-us/articles/8391393127955-Using-the-Enterprise-Event-Stream [group-admin]: https://support.box.com/hc/en-us/articles/360043694174-Understanding-Administrator-and-Co-Administrator-Permissions [managed-users]: https://support.box.com/hc/en-us/articles/360044194353-Understanding-User-Management [shared-link]: https://support.box.com/hc/en-us/articles/360043697094-Creating-Shared-Links [sdk]: /sdks-and-tools [code-catalog]: /sample-code [relay]: https://support.box.com/hc/en-us/articles/360044196213 [bve]: https://support.box.com/hc/en-us/articles/4401823156883-Box-Verified-Enterprise [report]: https://support.box.com/hc/en-us/articles/360043696534-Running-Reports [dev-console]: https://cloud.app.box.com/developers/console [admin-console]: https://app.box.com/master [platform]: https://www.box.com/en-gb/platform [shield]: https://www.box.com/en-gb/shield [skills]: /guides/skills [classification]: /guides/metadata/classifications [platform-app]: /guides/applications/platform-apps/index [webhook]: /guides/webhooks [service-account]: /platform/user-types/#service-account # Box Platform 101 Source: https://developer.box.com/platform/box-platform-101 ## What is Box [Box][box] is a cloud-based content management and file sharing platform that enables individuals and businesses to store, access, and collaborate on documents and files from anywhere. It offers features like secure file storage, real-time collaboration, and integrations with various productivity tools, enhancing team efficiency and data accessibility. Known for its focus on security and user-friendly interface, Box is widely used for managing digital assets and fostering collaboration within organizations. ## What is Box Platform [Box Platform][platform] is a set of tools and APIs offered by Box that allows developers to integrate and customize the capabilities of the Box cloud content management system into their own applications and services. It enables businesses and developers to build secure and scalable content-centric applications, leveraging features like file storage, sharing, and collaboration while maintaining control over data and access. With Box Platform, developers can create tailored solutions that enhance productivity and streamline content management workflows. ## How do I make applications In order to use the [Box API][api], you first have to create an application in Box. This application serves as the gateway for any API call made to the platform. You can use two websites to accomplish this task: the Box Developer Site and the Box Developer Console. Let's take a closer look at what those are. ### Box Developer Site The Box Developer Site is this website you are reading right now. It is a comprehensive resource for developers building solutions on top of Box, and should be used alongside the developer console to create applications and make API calls. You can find a multitude of guides, the full OpenAPI spec, quick starts, sample code, etc all within its pages. Box Developer Site The site is updated on a frequent basis with the latest updates posted to the [changelog][change]. Box Developer Changelog ### Box Developer Console The [Box Developer Console][dc] is an interactive interface that provides developers with tools and resources for managing their applications integrated with Box. It allows for the creation, configuration, and monitoring of apps, offering insights and control over how these apps interact with the Box platform. Box Developer Console After you create an application in the console for the first time, you will start seeing a button in the bottom left of the main Box web app. You can use this button to access the console in the future. Box Developer Console button ## Box Platform Concepts In the following learn sections, we will go into more depth on various topics. But at a high level, these are some terms and concepts to be familiar with. ### User Types There are several [user types][ut] to keep in mind when developing on Box Platform. These include users with admin privileges (such as Admin or Co-Admin users) and those without admin privileges (Managed or External Users). Additionally, there are platform-only users, which are categorized as Service Accounts and App Users. Each user type has specific roles and access levels within the Box environment, impacting how they interact with applications and content. At the core, if a user can access a piece of content from the main Box web app, they should be able to access it using the API. ### Application Type You can create a [Platform App][platform-app], a third party integration, and a web app integration in the developer console. ### Authentication Method Depending on the application type selected, there are one of five different authentication methods that can be used to gain an [access token][at]. An access token is the key to get through the gateway that is your application to successfully make an API call to Box. Authentication Types Next step [box]: https://www.box.com [platform]: https://www.box.com/platform [platform-app]: /guides/applications/platform-apps/index [authmethods]: /guides/authentication/select [api]: /reference [change]: /changelog [dc]: https://app.box.com/developers/console [at]: /guides/authentication/tokens [ut]: https://support.box.com/hc/en-us/articles/4636533822483-Box-User-Types # Free Developer Plan Source: https://developer.box.com/platform/free-developer-plan Build and test full-featured Box applications using enterprise-grade APIs, for zero cost. Sign up as a developer to receive: * **1,000 AI units** per month * **10 GB** storage * **250 MB** file upload limit * **1** file version * **Box Sign**, with **5** documents for e-sign per month ## Sign up as a Box Developer 1. Visit the developer signup page. 2. Enter your name, email address, and create a password. 3. Accept the terms and click **Get Started**. Your developer account activates immediately. You have access to the Developer Console, where you can create applications, generate credentials, and start exploring APIs. ## Included APIs With the Free Developer Plan, you can access key endpoints including: * **AI**: Ask questions, extract structured and freeform metadata, and generate text * **Authorization**: Implement OAuth 2.0 (JWT and CCG are not supported on the free plan) * **Content**: Upload, download, preview, version, and manage files and folders * **Metadata**: Read, write, and extend metadata on files and folders * **Webhooks**: Build real-time, event-driven applications * **Search**: Implement powerful content discovery features * **Users & Groups**: Create users, manage group memberships, and control access ## Free Developer Plan vs. Personal and Personal Pro Plans Understanding the difference helps you choose the right starting point. ### Free Developer Plan Best for building, testing, and integrating. Includes: * API access, including Box AI features like extracting metadata, generating text, and asking questions * Developer Console access for app management * OAuth 2.0 authentication * Production-equivalent environment * 1,000 AI units per month * Support through the Box Community forum ### Personal and Personal Pro Plans Best for personal file storage: * Intended for individual file management * Not optimized for application development * No developer-first tooling or workflows If you are building applications that integrate with Box, you need a Developer Plan, regardless of your personal storage needs. The Free Developer Plan is the only free tier that provides API access and the tools necessary for application development. ## Why sign up for the Free Developer Plan? Build applications with enterprise-grade features: * No cost to start * AI integration, including the ability to extract structured and freeform metadata * No gap between the test environment and the real production environment When your project moves from development to production — or when you need more storage, higher limits, or additional features — you can upgrade your Box account. ## Upgrade your Free Developer Plan 1. Log into your Box account and select **Back to My Account**, if not already in Box Drive. 2. From the top of the screen, select **Upgrade Plan**. 3. Choose the plan that aligns with your requirements. 4. Complete checkout and enter payment information to activate your upgraded features immediately. Your existing developer applications, API credentials, and integrations stay the same during the upgrade process. You do not need to reconfigure or redeploy. ## Select the right plan Factors to consider include: * Enterprise plans offer advanced security, compliance, and custom configurations * Higher-tier Enterprise plans include increased AI query limits and advanced capabilities * Business and Enterprise plans support unlimited storage and direct technical support, with support offerings that differ depending on the plan For further guidance on selecting the right plan, contact Box's sales team or visit the Plans and Pricing page. Ready to build? Create your free developer account and start integrating Box's enterprise content management and AI capabilities. # Learn Box Platform Source: https://developer.box.com/platform/index If you are new to Box, **start here**! In the following pages, you'll learn how all the Box Platform concepts and components work together to help you create an application quickly. Learn A free developer account gives you access to the Developer Console, where you can create apps, explore APIs, and start building on Box Platform. ## Learn Sections These pages go into more depth on each topic. Checkout each one and become a Box Platform expert. * [Free Developer Plan][free-dev-plan] * [Box Platform 101][platform101] * [Use Cases][usecases] * [User Types][usertypes] * [Application Types][apptypes] * [Authentication Methods][authtypes] * [Support][support] * [Tools][tools] Get Started [free-dev-plan]: /platform/free-developer-plan [platform101]: /platform/box-platform-101 [usecases]: /platform/use-cases [usertypes]: /platform/user-types [apptypes]: /platform/application-types [authtypes]: /platform/authentication-methods [support]: /platform/support [tools]: /platform/tools # Start Creating Source: https://developer.box.com/platform/start-creating Now that you have learned all about the various parts that makeup Box Platform, you are ready to jump in and start creating. Visit the [Box Developer Console][devconsole] to begin! Start Creating If you are looking for other topics to learn about, be sure to checkout the following: * [Architecture patterns][arch_patterns]: This page goes over some typical infrastructure patterns we see. * [User Models][user_models]: This page goes over how to use the users types discussed earlier in this series. * [Locating Common Values][common_values]: This page goes over how to find pieces of information like user IDs. * [Errors][errors]: This page lists out all the error codes you can receive [devconsole]: https://cloud.app.box.com/developers/console [arch_patterns]: /platform/appendix/architecture-patterns [user_models]: /platform/appendix/user-models [common_values]: /platform/appendix/locating-values [errors]: /guides/api-calls/permissions-and-errors/common-errors # Support Source: https://developer.box.com/platform/support The Box Developer Relations team loves to help developers in any way we can. Outside of interviewing developers regularly, we provide the following options for you to connect with us. ## Developer Forum Recently, we relaunched our developer community. It is now even easier to connect with developers like yourself and ask questions about your development issues. You can also share any successes you have had. [Join Today][forum]! Box Developer Forum ## Box Developer Blog For more updates, tutorials, and announcements check out our Box Developer Blog[blog]. Next step [samples]: /guides/cli/scripts [forum]: https://community.box.com/ [blog]: https://blog.box.com/developer [twitter]: https://twitter.com/BoxPlatform # Tools Source: https://developer.box.com/platform/tools Box offers several [tools][tooling] for you to use to jump start your development. Check them out below. ## Sample Code Catalog The [sample code catalog][sample_code] is the most recent tool we have launched on the Box Developer site. It pulls code sample repositories from multiple places, consolidating them in one place for you to browse. It allows you to filter by language and task. We update the list regularly so the you have access to the most up to date code. Sample Code Catalog ## Box CLI The Box Command Line Interface (CLI) is a tool for making requests to Box APIs from your terminal window or command prompt. It takes less than five minutes to set up and provides you direct access to the API. We also offer a suite of [sample scripts][samples] to jump start any administration automation tasks. ## SDKs Box supports several coding languages with our [SDK libraries][sdk]. It is highly recommended to use SDKs when creating a solution since the libraries automatically handle things like authentication and retry logic for you. In addition, the API reference pages contain samples for all the languages directly in the site; however, each Github repo has a docs section with all that language's samples too. SDK GitHub Libraries ## Postman Collection As an industry standard in software development, Postman helps developers learn APIs quickly, providing real time testing and code samples. You can find our Postman Collection on the [Postman website][postman]. You can also check out the YouTube video below. Next step [samples]: /guides/cli/scripts [sdk]: /sdks-and-tools [file]: /reference/get-files-id [tooling]: /guides/tooling [sample_code]: https://developer.box.com/sample-code/ [postman]: https://www.postman.com/boxdev # Use Cases Source: https://developer.box.com/platform/use-cases Before beginning application development, it is best to assess if your use case is a good fit for the Box Platform. Generally speaking, content centric processes perform best. Some questions to ask when assessing if a use case include: * Is content always involved in the process? * Does the process involve moving content from one place to another? * Can the workflow abide by [waterfall permissions][waterfall]? * Does the process involve administrative tasks that may be automated? If you answered **yes** to the above questions, you most likely have a great use case for Box Platform. Some common customer solutions include: * Marketing asset management * Secure document vaults * Wealth management portals * Automatic folder creation based on user provisioning * Adding relevant metadata using machine learning * Claim reviews with built-in approval/rejection flows * Event monitoring for security and auditing Still not sure if you have a good use case? Reach out to your Box account team. [waterfall]: https://support.box.com/hc/en-us/articles/360043697254-Understanding-Folder-Permissions Next step # User Types Source: https://developer.box.com/platform/user-types The type of user your application authenticates as determines what content it can access and what actions it can take. Which user type you get depends on the application type you create and the authentication method you choose. ## User types at a glance | User type | Has login credentials? | How it's created | Visible in Admin Console? | Best for | | --------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- | ------------------------------------------------------- | | [**Managed User**](#managed-users) | Yes | Provisioned by enterprise | Yes | Employees with licensed Box accounts | | [**External User**](#external-users) | Yes | Has an existing Box account (personal or another enterprise) | Yes, **External Users** tab (**External Users** filter) | Cross-enterprise or free-account collaboration | | [**Unmanaged User**](#unmanaged-users) | Yes | Self-provisioned using a managed domain email | Yes, **External Users** tab (**Unmanaged Users** filter) | Domain users outside enterprise control | | [**Service Account**](#service-account) | No (API only) | Auto-generated when a server-auth app is authorized | Content Manager only | Server-to-server integrations, content owned by the app | | [**App User**](#app-user) | No (API only) | Created by a Service Account using the API | Yes (Users & Groups + Content Manager) | Per-user content isolation without Box accounts | Admin and Co-Admin are roles assigned to Managed Users, not separate user types. See [Admin and Co-Admin roles](#admin-and-co-admin-roles) below. A free developer account gives you access to the Developer Console and API, where you can create and manage Service Accounts, App Users, and more. ## Admin and Co-Admin Roles Admin and Co-Admin are roles that can be assigned to Managed Users, not separate user types. A user must first be a Managed User before they can be given either role. Managed Users with the Admin or Co-Admin role can directly manage the Box enterprise through the Admin Console and can perform actions unavailable to other users, such as managing security policies, running reports, and configuring integrations. Some applications require Admin-level permissions to operate. For example, a security application that monitors enterprise events needs an Admin or a Co-Admin with reporting permissions. ## Managed Users Managed Users belong to your enterprise and consume a standard Box license. Each enterprise has a unique enterprise ID, and all Managed Users share that ID. They typically (but don't always) share the same email domain. ## External Users External Users are collaborators from outside your organization — Box users whose accounts were not created from within your Admin Console and whose email addresses are not associated with your managed domain. They may belong to a different enterprise entirely, or they may have a free personal Box account with no enterprise affiliation at all. While Admins cannot manage External Users' account settings or the content they own, they can manage their collaborations — including granting or revoking access to your enterprise's content at any time. External Users appear in the Admin Console under the **Users & Groups** > **External Users** tab. An Admin can invite them to become Managed Users in your organization, provided they are not already part of another Box enterprise. ## Unmanaged Users Unmanaged Users are Box users who: * Have unlicensed and unpaid personal Box service accounts that are acquired independently of an Admin or Co-admin and that do not belong to your Box organization. * Possess email addresses from your domain or verified domains (domains owned or controlled by your organization). Unmanaged Users are visible in the Admin Console under the **Users & Groups** > **External Users** tab by selecting the **Unmanaged Users** filter. Admins can identify and convert them to Managed Users to bring them under organizational control. ## Service Account A Service Account is a programmatic user that represents your application in the Box enterprise. It authenticates server-to-server without login credentials, making it ideal for backend integrations and automated workflows. Service Account Diagram ### When to use * **Content migration**: Move content between on-premises systems and the cloud * **Event monitoring**: Watch enterprise events for compliance or to trigger workflows * **Content distribution**: Upload and share files with users regardless of their authentication status * **System integrations**: Connect on-premises systems and devices to Box * **Content archiving**: Store infrequently accessed content ### Creation A Service Account is **automatically generated** when an Admin authorizes your JWT or CCG application in the Admin Console. You don't create it manually. Box assigns the Service Account an email address in the format: `AutomationUser_AppServiceID_RandomString@boxdevedition.com` For example: `AutomationUser_123456_6jCo6Pqwo@boxdevedition.com`. The number between the underscores is the **Service ID**, which matches the ID in your app's Developer Console URL (for example, `https://example.app.box.com/developers/console/app/123456`). You can find the Service Account email on the **General** tab of your app in the Developer Console. Service Account Email Address If you attempt API calls with a Service Account token before the app is authorized, you'll receive an `unauthorized_client` error: `"This app is not authorized by the enterprise"`. ### Viewing content Only **Primary Admins** can view a Service Account's content. To do this: 1. Open the Content Manager in the Admin Console. 2. Search for the application name. 3. Right-click the result and select **Log in to user's account**. Service Accounts are **not** visible in the *Users & Groups* tab. They only appear in the Content Manager. Co-Admins can't log in as a Service Account. This mirrors how Co-Admins can't manage each other. ### Permissions and collaboration The API endpoints a Service Account can call are determined by the scopes configured in the Developer Console. With the right scopes, a Service Account can perform Admin-level actions. Because a Service Account can have elevated permissions, JWT and CCG applications require explicit Admin approval before they can be used in an enterprise. A Service Account has its own folder tree, which starts empty. To give it access to existing content: * **By email**: Invite the Service Account using its assigned email address, just as you would invite any other collaborator. * **By API**: Use the create collaboration endpoint with the Service Account's user ID (returned by the get current user endpoint). You can assign a Service Account an email alias to make collaboration invitations easier to remember. By default, Service Accounts receive 10 GB of storage based on the **New User Default Settings** in the Admin Console. To change this, call the update user endpoint with the `space_amount` parameter. ## App User An App User is a programmatic user that your Service Account creates through the API. Like Service Accounts, App Users don't have login credentials and can only interact with Box through your application. Each App User gets their own folder tree, giving you per-user content isolation. App Users are tied to the application that created them and can't be transferred to another application. ### When to use * **Customer portals**: Give clients or patients a place to access and store sensitive documents without needing a Box account. * **Vendor portals**: Distribute content like price lists, contracts, and marketing materials to partners, organized by vendor tier. * **Branded applications**: Build customer-facing features with per-user permissions, auditing, and reporting — especially valuable for regulated industries like financial services and healthcare. * **Identity mapping**: Map users from your own identity provider (like Auth0 or Okta) to individual Box user accounts. ### Creation **Prerequisites**: You need a JWT or CCG application that has been authorized in the Admin Console, which gives you a Service Account. To create an App User, use the Service Account's access token to call the create user endpoint. Set the `is_platform_access_only` body parameter to `true` — otherwise, a Managed User is created instead. Box assigns each App User an email address in the format: `AppUser_AppServiceID_RandomString@boxdevedition.com` For step-by-step instructions and code samples, see Create an App User. ### Viewing content App Users are visible in two places in the Admin Console: 1. **Users & Groups tab**: Use the view options button, then filter by **Role > App Users**. Filter for App Users 2. **Content Manager**: Search for the App User by name or email to browse their folder tree. ### Permissions and collaboration App Users **can't** see the Service Account's folder tree or any other content unless you explicitly add them as a collaborator. Each App User has their own folder tree, which starts empty. To give an App User access to content: * **By email**: Invite the App User using their assigned email address. * **By API**: Use the create collaboration endpoint with the App User's ID and an access token for a user who already has access to the target content. ## Service Account vs. App User: which do you need? Use this decision guide to pick the right approach for your application: | Question | If yes... | | ---------------------------------------------------------------------------------- | ----------------------------------------------- | | Does your app need to own and manage content without tying it to individual users? | Use a **Service Account** as the content owner. | | Do you need per-user content isolation (each user has their own files)? | Create an **App User** for each user. | | Are your users transient, but the content needs to persist? | Use a **Service Account** to own the content. | | Do you want to map users from your own identity provider to Box? | Create an **App User** for each identity. | | Is this a system-to-system integration with no end-user interaction? | Use the **Service Account** directly. | For more advanced architecture decisions, see User Models. ## As-User If you use OAuth 2.0, JWT, or CCG authentication, you can make `as-user` calls to act on behalf of another user. Even though your application originally authenticated as yourself or as a Service Account, subsequent calls can impersonate a different user. This is useful for automating administrative tasks like folder reorganization or employee provisioning. To enable `as-user` calls, turn on the appropriate scope in the Developer Console. As User Next step [scopes]: /guides/api-calls/permissions-and-errors/scopes [collabapi]: /reference/post-collaborations [getuser]: /reference/get-users-me [updateuser]: /reference/put-users-id [createuser]: /reference/post-users [createappuser]: /guides/users/create-app-user [events]: /reference/get-events [apptypes]: /platform/application-types [authmethods]: /platform/authentication-methods [usermodels]: /platform/appendix/user-models [cm]: https://support.box.com/hc/en-us/articles/360044197333-Using-the-Content-Manager [uag-tab]: https://support.box.com/hc/en-us/articles/360043695714-Admin-Console-Guide # Allow domain access Source: https://developer.box.com/guides/api-calls/allowing-domain-access To use the Box APIs it is important that your application and users have access to the following domains, where needed. ## File preview To enable file preview, your application might need to load javascript file from the Box content delivery network (CDN). This file is loaded from the following domains. * `api.box.com` * `boxcdn.net` * `boxcloud.com` * `dl2.boxcloud.com` to `dl20.boxcloud.com` ## File downloads The following API domains are used to download files via the Box API. * `api.box.com` to initially request a file to download * `dl.boxcloud.com` to actually download files for authenticated users * `public.boxcloud.com` to actually download files for unauthenticated users Ensuring access to these domains is only a first step to downloading a file. To download a file the users need to have proper access permissions and need to be fully authenticated where needed. ## File uploads The following API domains are used to upload files via the Box API. * `api.box.com` to start a file upload * `upload.app.box.com` and `upload.box.com` to upload the file to Box # API versioning strategy Source: https://developer.box.com/guides/api-calls/api-versioning-strategy Box provides versioning capabilities for selected API endpoints. The version control system guarantees seamless functioning of existing endpoint versions, even if Box introduces new ones. API versioning empowers Box to continually enhance its platform, while also offering third-party developers a reliable avenue for feature updates and deprecations. To stay informed about the forthcoming API modifications, monitor the Changelog and maintain a current email address in the Developer Console's App Info section. In 2024, Box introduced year-based API versioning. All endpoints available at the end of 2024 were assigned the version `2024.0`. **No action is required for API users to continue using Box APIs.** To make version-aware API calls, include the `box-version` header with the value `2024.0` in your requests. ## How Box API versioning works Box API supports versioning in `header`. To determine which version to use, look at the API reference and included sample requests. ### Versioning in `header` Box API processes the `box-version` header which should contain a valid version name. For example, when a client wants to get a list of all sign requests using version `2025.0`, the request should look like this: ```sh theme={null} curl --location 'https://api.box.com/2.0/sign_requests' \ --header 'box-version: 2025.0' \ --header 'Authorization: Bearer … ``` If the provided version is correct and supported by the endpoint, a response is sent to the client. If the endpoint is available in multiple versions, the response will include the `box-version` header, which indicates the version used to handle the request. Endpoints introduced after 2024 may return a `400` error code if the version is incorrect. More information about versioning errors can be found here. If your request doesn't include a version, the API defaults to the initial Box API version - `2024.0` - the version of endpoints available before year-based versioning was introduced. However, relying on this behavior is not recommended when adopting deprecated changes. To ensure consistency, always specify the API version, with each request. By making your application version-aware, you anchor it to a specific set of features, ensuring consistent behavior throughout the supported timeframe. ## Release schedule and naming convention Box can introduce a new breaking change to certain endpoints **once per year**, which results in a new API version. Introducing a new version of the Sign Request endpoint means that **all paths and HTTP methods** of an endpoint will support it. For example, if Sign Request endpoints receive a new version it will apply to all endpoints listed in the table: | Method | Request URL | Description | | ------ | -------------------------------------------------- | ---------------------------------------- | | GET | `https://api.box.com/2.0/sign_requests/:id` | Retrieves specific sign request details. | | GET | `https://api.box.com/2.0/sign_requests/` | Retrieves all sign requests. | | POST | `https://api.box.com/2.0/sign_requests/` | Creates new sign requests. | | POST | `https://api.box.com/2.0/sign_requests/:id/resend` | Sends a specific sign request again. | | POST | `https://api.box.com/2.0/sign_requests/:id/cancel` | Cancels a specific sign request. | ### Naming convention New API versions are labeled according to the calendar year of their release. **Example**: If a new version of the Sign Requests endpoint is released in 2025, it will be named `2025.0`. Box can issue a new breaking change to API endpoints **once** per year, reserving the right to release an additional breaking change to address security or privacy concerns. In such cases, the new version will be incremented by one in the suffix. **Example**: If security issues need addressing in the previously released version `2025.0` of Sign Requests, the new version will be labeled `2025.1`. Each stable version is supported for a minimum of 12 months. This means that when a new version is released, the previous version becomes deprecated and will be available for use, but no new features will be added. It also means, that a new version cannot be released sooner than every 12 months. We strongly recommend updating your apps to make requests to the latest stable API version. However, if your app uses a stable version that is no longer supported, then you will get a response with an HTTP error code `400 - Bad Request`. For details, see Versioning Errors. ### Endpoint versioning indication To keep you informed about the current API state, and improve the readability of the versioned API reference, the affected endpoints are marked with a pill based on the `x-stability-level` tag or `deprecated` attribute. An example of a beta pill used for API reference endpoints | Schema element | Pill name | Description | | --------------------------------------------------------- | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `x-stability-level: beta` | Beta | Endpoints marked with **beta**, are offered subject to Box’s Main Beta Agreement, meaning the available capabilities may change at any time. When the beta endpoint becomes stable, the **beta** indication is removed. | | `x-stability-level: stable` or no `x-stability-level` tag | Latest version | **Latest version** marks the most recent stable API version of an endpoint. | | `deprecated: true` | Deprecated | An endpoint is deprecated, which means it is still available for use, but no new features are added. Such an endpoint is annotated with the `deprecated` attribute set to `true`. | ## Versioning errors When using versioned API actions such as calling an incorrect API version in header or a deprecated version can lead to errors. For details on possible errors, see versioning errors. ## How Box SDK versioning works The versioning strategy applies only to [generated SDKs](https://developer.box.com/sdks-and-tools/#next-generation-sdks). Box SDKs support the **All Versions In** SDK approach. This means that every release of SDK provides access to all endpoints in any version which is currently live. All generated SDKs use manager's approach - they group all endpoints with the same domain in one manager. For example `FolderManager` contains methods to: `create_folder`, `get_folder_by_id`, `update_folder_by_id`, `delete_folder_by_id`, `get_folder_items` and `copy_folder`. This division is done based on the value of `x-box-tag` field, which is assigned to each method in Public API Service specification. It mostly corresponds to the root of the endpoint URL, but not necessarily. For example: `FolderManager` contains methods with `https://api.box.com/2.0/folders` root URL, but the same base URL is also used in some methods of `SharedLinkFoldersManager`. References to all managers are stored under one Box Client object. See an example of the endpoint's lifecycle: 1. Initial state (only one version is available). ```js theme={null} class FilesManager { async updateFileById( fileId: string, requestBody: UpdateFileByIdRequestBody, queryParams: UpdateFileByIdQueryParams, headers: UpdateFileByIdHeaders ): Promise < FileFull > {} } ``` 2. A new `v2025_0` version of the endpoint is introduced (previous version is deprecated). The SDK introduces a new method for each new version of an endpoint. These methods are stored in the same manager as the old ones, but their names and corresponding classes are suffixed with the version number. The old method is deprecated with a notice indicating the minimal maintenance date – this will be the date when the endpoint will be considered for end-of-life status. ```js theme={null} class FilesManager { /** * @deprecated This endpoint will be EOL'ed after 05-2026. */ async updateFileById( fileId: string, requestBody: UpdateFileByIdRequestBody, queryParams: UpdateFileByIdQueryParams, headers: UpdateFileByIdHeaders ): Promise {} async updateFileById_2025_0( fileId: string, requestBody: UpdateFileByIdRequestBody_2025_0, queryParams: UpdateFileByIdQueryParams_2025_0, headers: UpdateFileByIdHeaders_2025_0 ): Promise {} } ``` 3. The API endpoint is marked as End-of-Life (EOL) The SDK releases a breaking change release with removed end-of-life (EOL) endpoints. Ideally, we should group the end-of-life dates for all endpoints into one date per quarter to avoid releasing numerous new major versions of SDKs. ```js theme={null} class FilesManager { async updateFileById_2025_0( fileId: string, requestBody: UpdateFileByIdRequestBody_2025_0, queryParams: UpdateFileByIdQueryParams_2025_0, headers: UpdateFileByIdHeaders_2025_0 ): Promise < FileFull_2025_0 > {} } ``` ## Breaking vs non-breaking changes Breaking changes in the Box API occur within versioned releases, typically accompanied by a new major API version. Minor adjustments, which do not disrupt existing functionality, can be integrated into an existing API version. The following table lists both breaking and non-breaking changes. | API Change | Breaking change | | ------------------------------------------------------------------------------------------------------------ | --------------- | | New endpoints | No | | New [read-only](https://swagger.io/docs/specification/data-models/data-types/) or optional fields in request | No | | New required fields in request | Yes | | New string constant in request | Yes | | Deprecation | No | | Retired / End-of-Life endpoints | Yes | | Rename/reshape of a field, data type, or string constant | Yes | | More restrictive change to field validations | Yes | | Less restrictive change to field validations | No | | Changing HTTP status code returned by an operation | Yes | | Removing a declared property | Yes | | Removing or renaming APIs or API parameters | Yes | | Adding a required request header | Yes | | Adding more error codes | No | | Removing or modifying error codes | Yes | | Adding a member to an enumeration | Yes | The [oasdiff](https://github.com/Tufin/oasdiff/blob/main/BREAKING-CHANGES-EXAMPLES.md) tool allows detecting most of the possible breaking changes. ## Forward compatibility of API responses Box may add new, optional, or read-only fields to API responses at any time without a version bump. These changes are considered non-breaking and require no advance notification. Client applications must be implemented to tolerate additional JSON fields and ignore fields they do not recognize. Strict response schema validation or deserialization that rejects unknown fields is discouraged, as it may cause integrations to break when Box introduces new fields. To ensure long-term stability: * Integrate only the documented fields your application explicitly requires * Do not assume API responses will exactly match a fixed schema * Configure JSON parsing libraries to ignore unmapped or unexpected properties ## AI agent configuration versioning AI agent versioning gives the developers more control over model version management and ensures consistent responses. For details, see AI agent configuration versioning guide. ## Support policy and deprecation information When new versions of the Box APIs and Box SDKs are released, earlier versions will be retired. Box marks a version as `deprecated` at least 24 months before retiring it. In other words, a deprecated version cannot become end-of-life sooner than after 24 months. Similarly, for individual APIs that are generally available (GA), Box declares an API as `deprecated` at least 24 months in advance of removing it from the GA version. When we increment the major version of the API (for example, from `2025.0` to `2026.0`), we're announcing that the current version (in this example, `2025.0`) is immediately deprecated and we'll no longer support it 24 months after the announcement. We might make exceptions to this policy for service security or health reliability issues. When an API is marked as deprecated, we strongly recommend that you migrate to the latest version as soon as possible. In some cases, we'll announce that new applications will have to start using the new APIs a short time after the original APIs are deprecated. When customer calls deprecated API endpoint, the response will contain a header: ```sh theme={null} Deprecation: date="Fri, 11 Nov 2026 23:59:59 GMT" Box-API-Deprecated-Reason: /reference/deprecated ``` The date tells clients when this version was marked as deprecated. ## Versioning considerations When building your request, consider the following: * Endpoints in version `2024.0` can be called without specifying the version in the `box-version` header. If no version is specified and the `2024.0` version of the called endpoint does not exist, the response will return an HTTP error code `400 - Bad Request`. * If the `box-version` version header is specified but the requested version does not exist, the response will return an HTTP error code `400 - Bad Request`. For details, see versioning errors. When Box deprecates a resource or a property of a resource in the API, the change is communicated in one or more of the following ways: * Calls that include the deprecated behavior return the response header `Box-API-Deprecated-Reason` and a link to get more information: ```sh theme={null} box-version: 2025.0 Deprecation: version="version", date="date" Box-API-Deprecated-Reason: /reference/deprecated ``` * A deprecation announcement is posted in the developer changelog. * The API reference is updated to identify the affected resource and any action you need to take. Affected endpoints are marked with **deprecated** pill. * If there is an imminent backwards-incompatible change that affects your app, then the contact email for your app might be contacted about the deprecation. ## Additional resources * API reference # Ensure consistency with headers Source: https://developer.box.com/guides/api-calls/ensure-consistency Some Box APIs support headers used to ensure consistency between your application and Box. ## `etag`, `if-match`, and `if-none-match` Many of the file system items (files or folders) that can be requested via the API return an `etag` value for the item. For example, a file resource returns an `etag` in the JSON response. ```sh theme={null} curl https://api.box.com/2.0/files/12345 \ -H "authorization: Bearer ACCESS_TOKEN" ``` ```json theme={null} { "id": 12345, "etag": 1, "type": "file", "sequence_id": 3, "name": "Contract.pdf", ... } ``` This `etag` can be used as the value of a `if-match` or `if-none-match` header to either ensure a resource hasn't changed since the `etag` value was received, or to prevent unnecessary downloads for items that haven't changed. For example, to fetch the same file only if it has changed, pass in the `etag` value in a `if-none-match` header. ```sh theme={null} curl https://api.box.com/2.0/files/12345 \ -H "authorization: Bearer ACCESS_TOKEN" \ -H "if-none-match: 1" ``` This API call would result in an empty response if the file had not changed. ## Ensure consistent changes The `if-match` header allows your application to ensure that no changes are made to items when another application or a user has made changes to the item since your application last inspected it. This helps ensure that changes aren't lost when two applications or users are changing items at the same time. The following endpoints support this header. | `if-match` capable endpoints | | | ------------------------------------------------------------------------------ | ------------------------------- | | `POST /files/:id/content` | Upload a new file version | | `PUT /files/:id` | Update a file's information | | `DELETE /files/:id` | Delete a file | | `PUT /folders/:id` | Update a folder's information | | `DELETE /folders/:id` | Delete a folder | | `PUT /web_links/:id` | Update a web link's information | | `DELETE /web_links/:id` | Delete a web link | The response of these APIs calls depends on the existence of the item, and whether the `etag` value matches the most recent version. | Item found? | Etag match? | HTTP status | | ----------- | ----------- | ----------- | | Yes | Yes | 200 | | Yes | No | 412 | | No | Yes | 412 | | No | No | 404 | **Moving items** The `if-match` header can not be used to prevent moving of files, folders, or web links. Instead, Box will always ensure that the latest item is moved to the new location. ## Prevent unnecessary request downloads The `if-none-match` header allows your application to ensure that no information is downloaded for items that have not changed since your application last inspected it. This helps ensure no unnecessary information is downloaded, speeding up your application and saving on bandwidth. | `if-none-match` capable endpoints | | | -------------------------------------------------------------------- | ------------------------------- | | `GET /files/:id` | Get a file's information | | `GET /folders/:id` | Get a folder's information | | `GET /web_links/:id` | Get a web link's information | | `GET /shared_items` | Get a shared item's information | The response of these APIs calls depends on the existence of the item, and whether the `etag` value matches the most recent version. | Item found? | Etag match? | HTTP Status | | ----------- | ----------- | ----------- | | Yes | Yes | 304 | | Yes | No | 200 | | No | Yes | 404 | | No | No | 404 | # API Calls Source: https://developer.box.com/guides/api-calls/index The Box API is a restful API that follow common HTTP standards where possible. The following guides take a look at some of the useful features and common mistakes that a developer can encounter when working with these APIs. ## API calls insights Admins and co-admins can access the Platform Insights dashboard that provides information on the total number of API calls per application. See [Platform Insights][insights] and applications for details. [insights]: https://support.box.com/hc/en-us/articles/20738406915219-Platform-Insights # Language codes Source: https://developer.box.com/guides/api-calls/language-codes The Box API uses a modified version of the **ISO 639-1 Language Code** to specify a user's language. The following is a list of language codes used when creating or updating. | Language | Code | | ----------------------- | ---- | | Bengali | `bn` | | Danish | `da` | | German | `de` | | English (US) | `en` | | English (UK) | `gb` | | English (Canada) | `e2` | | English (Australia) | `e3` | | Spanish (Latin America) | `s2` | | Spanish | `es` | | Finnish | `fi` | | French | `fr` | | French (Canada) | `f2` | | Hindi | `hi` | | Italian | `it` | | Japanese | `ja` | | Korean | `ko` | | Norwegian (Bokmal) | `nb` | | Dutch | `nl` | | Polish | `pl` | | Portuguese | `pt` | | Russian | `ru` | | Swedish | `sv` | | Turkish | `tr` | | Chinese (Simplified) | `zh` | | Chinese (Traditional) | `zt` | # Pagination Source: https://developer.box.com/guides/api-calls/pagination/index The Box API supports two ways to paginate collections. The most common way to paginate is through offset-based pagination which is often used where the list of items is of a fixed, predetermined length. In some cases an API endpoint supports marker-based pagination, either as an alternative to offset-based pagination or as a full replacement. Marker-based pagination is often used in cases where the length of the total set of items is either changing frequently, or where the total length might not be known upfront. # Marker-based Pagination Source: https://developer.box.com/guides/api-calls/pagination/marker-based APIs that use marker-based paging use the `marker` and `limit` query parameters to paginate through items in a collection. Marker-based pagination is often used in cases where the length of the total set of items is either changing frequently, or where the total length might not be known upfront. ## Paging To fetch the first page of entries in a collection the API needs to be called either without the `marker` parameter, or with the `marker` set to `0`. The `limit` parameter is optional. ```sh theme={null} curl https://api.box.com/2.0/folders/0/items?limit=100&usemarker=true&marker= \ -H "authorization: Bearer ACCESS_TOKEN" ``` APIs that support both offset-based pagination and marker-based pagination require the `usemarker` query parameter to be set to `true` to ensure marker-based pagination is used. To fetch the next page of entries the API needs to be called with an `marker` parameter that equals value of the `next_marker` value that was received in the API response. ```sh theme={null} curl https://api.box.com/2.0/folders/0/items?marker=34332423&limit=100&usemarker=true \ -H "authorization: Bearer ACCESS_TOKEN" ``` The final page of items has been requested when the next `next_marker` value is `null` in the response object. At this point there are no more items to fetch. With marker-based paging there is no way to determine the total number of entries in a collection except by fetching them all. Applications should not retain the `next_marker` value long-term as the internal implementation of the markers may change over time. ## Marker & Limit The following query parameters are used to paginate a collection. | Query parameter | Type | Default | | | --------------- | ------- | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `marker` | String | | The first position in the collection to return results from. This should be a value that was returned in a previous request. | | `limit` | Integer | Depends on API | The maximum number of entries to return. If the value exceeds the maximum, then the maximum value will be used. | | `usemarker` | Boolean | | An optional query parameter that can be used with API endpoints that support both types of pagination to select pagination type. Set to `true` to enforce marker-based pagination. | ## Collections When paginating collections, the API returns an object that contains the set of results as an array, as well as some information about the current page of results. | Field | Type | | | ------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `entries` | Array | The page of items for this page. This will be an empty array if there are no results. | | `next_marker` | String | The value that can be used as the `marker` value to fetch the next page of results. If this value is `null` or an empty string there are no more results to fetch. | | `limit` | Integer | The limit used for this page of results. This will be the same as the `limit` query parameter unless it exceeded the maximum value allowed for this API endpoint. | ## Example endpoints Some endpoints that support marker-based pagination are: * List items for a folder * List a file's collaborations * List all webhooks for a user * List all users in an enterprise * List all items in the trash # Offset-based Pagination Source: https://developer.box.com/guides/api-calls/pagination/offset-based APIs that use offset-based paging use the `offset` and `limit` query parameters to paginate through items in a collection. Offset-based pagination is often used where the list of items is of a fixed and predetermined length. ## Paging To fetch the first page of entries in a collection the API needs to be called either without the `offset` parameter, or with the `offset` set to `0`. The `limit` field is optional. ```sh theme={null} curl https://api.box.com/2.0/folders/0/items?offset=0&limit=100 \ -H "authorization: Bearer ACCESS_TOKEN" ``` To fetch the next page of entries the API needs to be called with an `offset` parameter that equals the sum of the previous `offset` value and limit returned in the previous result, `previous_offset + previous_limit`. ```sh theme={null} curl https://api.box.com/2.0/folders/0/items?offset=100&limit=100 \ -H "authorization: Bearer ACCESS_TOKEN" ``` Note that the `offset` should be increased by the previous `limit` and not by the size of the entries in the response array, as this may be less than the limit. Generally we advise using the value of the `limit` in the response object to increase the `offset` value. The final page of items has been requested when the next `offset` value exceeds the `total_count` value in the response object. At this point there are no more items to fetch. ## Offset & Limit The following query parameters are used to paginate a collection. | Query parameter | Type | Default | | | --------------- | ------- | -------------- | -------------------------------------------------------------------------------------------------------------------- | | `offset` | Integer | `0` | The (zero-based) offset of the first item returned in the collection. In a zero-based offset `0` is a correct value. | | `limit` | Integer | Depends on API | The maximum number of entries to return. If the value exceeds the maximum, then the maximum value will be used. | The maximum `offset` for offset-based pagination is `9999`. Marker-based pagination is recommended when a higher offset is needed. ## Collections When paginating collections, the API returns an object that contains the set of results as an array, as well as some information about the current page of results. | Field | Type | | | ------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `entries` | Array | The page of items for this page. This will be an empty array if there are no results. | | `offset` | Integer | The offset used for this page of results | | `limit` | Integer | The limit used for this page of results. This will be the same as the `limit` query parameter unless it exceeded the maximum value allowed for this API endpoint. | | `total_count` | Integer | One greater than the offset of the last item in the entire collection. The total number of items in the collection may be less than `total_count`. | ## Example endpoints Some endpoints that support offset-based pagination are: * List items for a folder * List a file's comments * List all items in the trash # App Diagnostics Report Source: https://developer.box.com/guides/api-calls/permissions-and-errors/app-diagnostics-report The App Diagnostics Report provides a spreadsheet detailing each API call made by a given application during a specified timeframe. The report gives you access to the `API Request ID`, which can be given to Box Support for troubleshooting purposes. This report will not include: * API calls made within the last 48 hours * Authorization and Token API calls We are working on including the above and thereby making the report suitable for real-time troubleshooting in the future. ## 1. Click on the **App Diagnostics** Tab To run the App Diagnostics Report, click the **App Diagnostics** option located along the top of your application's configuration section in the [Developer Console][console]. New Menu Option ## 2. Click **Run App Diagnostics Report** to configure your report Clicking **Run App Diagnostics Report** will display a popup to select report filters and parameters. App Diagnostic Menu ## 3. Select Report Parameters and Click **Run** You can select a date in the last two weeks, starting 48 hours prior to today. A report can be run for up to a total of 24 hours. Click **Run** to generate a report. Report Options ## 4. Access the Box Reports Folder Navigate to [All Files][allfiles] and locate the Box Reports folder. If this is your first time running a report, this folder is automatically generated. If you are an Admin, this is the same folder you access [Admin Console Reports][reports]. Open the folder. Box Report Folder ## 5. Find and Open the latest Platform App Diagnostics Report Folder You will see any reports you have run in the Box Reports folder. Locate and open the most recent Platform App Diagnostics run folder. Box Report Folder Contents ## 6. Check the Status The report will take time to complete. You can see the status in the box at the top of the folder. Status Screen ## 7. Report Completed Upon completion, the status will change, and the `.csv` file will appear in the folder. Diagnostics Report ## 8. Open the Report You can open the file in your web browser or download it to view locally. If you need help from [Box Support][support], you can send in the report with your ticket by attaching a downloaded copy or via shared link. Report Details The report has nine columns. | Column | Description | | | ------------------------- | ---------------------------------------------------- | - | | App Name | The name of the application | | | Client ID | The Client ID of the application | | | HTTP Status Code | The response code returned from Box | | | API Request Duration (ms) | The amount of time from API call to response | | | API Request ID | An unique identifier that can be used by Box Support | | | Resource | The primary resource accessed in the API call | | | Sub Resource | The secondary resource accessed in the API call | | | HTTP Method | The type of HTTP method used in the API call | | | API Request Timestamp | The timestamp of the API call | | [support]: https://support.box.com/hc/en-us/requests/new [console]: https://app.box.com/developers/console [allfiles]: https://app.box.com/folder/0 [reports]: https://support.box.com/hc/en-us/articles/360043696534-Running-Reports # Errors Source: https://developer.box.com/guides/api-calls/permissions-and-errors/common-errors The Box APIs uses [HTTP status codes][status-codes] to communicate if a request has been successfully processed or not. Working through API errors? A free developer account gives you access to the Developer Console, where you can test API calls and debug with your own applications. ## Client error Most client errors in the HTTP 4XX, and some server errors in the HTTP 5XX range returns a standard client error JSON object. ```json theme={null} { "type": "error", "status": 400, "code": "bad_digest", "help_url": "https://developer.box.com/guides/api-calls/permissions-and-errors/common-errors/", "message": "The specified content-md5 did not match what we received", "request_id": "abcdef123456" } ``` See the Client Error resource for more details. ## Common error codes Check our [Developer Troubleshooting Articles][articles] for solution to common errors encountered when working with the Box APIs. ### 400 Bad Request | | | | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Error** | `bad_digest` | | **Message** | The specified `content-md5` did not match what we received. | | **Solution** | While uploading a file, a `content-md5` header with the SHA-1 hash of the file can be supplied to ensure that the file is not corrupted in transit. The SHA-1 hash that was supplied in the request did not match what was received in the upload. Supply a valid SHA-1 hash of the uploaded file. | | | | | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ | | **Error** | `bad_request` | | **Message** | | | **Solution** | Required parameters supplied in the API request are either missing or invalid. Check the extended error message in the response body for more details. | | | | | ------------ | ----------------------------------------------------------------------------------------------------------------------- | | **Error** | `cannot_make_collaborated_subfolder_private` | | **Message** | Cannot move a collaborated subfolder to a private folder unless the new owner is explicitly specified. | | **Solution** | Specify the ID of the user that the content should be transferred to by setting the `owned_by.id` field in the request. | | | | | ------------ | ------------------------------------------------------------------------------------------------------------------- | | **Error** | `collaborations_not_available_on_root_folder` | | **Message** | Root folder cannot be collaborated | | **Solution** | You cannot set collaborators on a user's root folder (folder ID 0). Use a different folder ID than the root folder. | | | | | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Error** | `cyclical_folder_structure` | | **Message** | Folder move creates cyclical folder structure | | **Solution** | The folder ID specified in the folder move would create a cyclical folder structure (for example moving a folder to a subfolder within itself). Change the folder ID for the folder move request. | | | | | ------------ | ------------------------------------------------------------------------ | | **Error** | `folder_not_empty` | | **Message** | Cannot delete – folder not empty | | **Solution** | Delete all content from the folder before attempting to delete it. | | | | | **Error** | `invalid_collaboration_item` | | **Message** | Item type must be specified and set to 'folder' | | **Solution** | The `item.type` field of the collaboration item should be set to folder. | | | | | ------------ | ---------------------------------------------------------------------------------------------------------- | | **Error** | `invalid_client` | | **Message** | The client credentials are invalid. | | **Solution** | Verify the `client_id` and `client_secret` in the token request match the values in the Developer Console. | | | | | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Error** | `invalid_grant` | | **Message** | Verify the authorization code is set correctly in your request, or your application likely needs to get a new authorization code. | | **Solution** | The authorization code supplied in the API request is missing or no longer valid. Possible solutions are to verify that the access token is added correctly in the request. If correctly set, the access token may have expired. Attempt to refresh the access token or fetch a new one. | | | | | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Error** | `invalid_grant` | | **Message** | Current date time must be before the expiration date time listed in the `exp` claim. | | **Solution** | This error occurs when the Unix time on your local machine and the Box server are out of sync. To fix this error, update the Unix time on your machine to match a synchronized time server, then try the request again. | | | | | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Error** | `invalid_grant` | | **Message** | Invalid refresh token. | | **Solution** | The refresh token may be invalid, revoked, or expired. Correct your application's refresh token handling and obtain a new token pair through the OAuth 2.0 authorization flow if needed. | | | | | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Error** | `invalid_grant` | | **Message** | The authorization code has expired. | | **Solution** | Authorization codes expire shortly after they are issued (on the order of tens of seconds). Exchange the code for tokens immediately after the user is redirected back to your application. | | | | | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Error** | `invalid_grant` | | **Message** | Please check the `sub` claim. | | **Solution** | For JWT authentication, set the `sub` (subject) claim to the correct user ID or enterprise ID depending on `box_sub_type`. More information is available on our [support site](https://support.box.com/hc/en-us/articles/360043691734). | | | | | ------------ | -------------------------------------------------------------------------------------------------------------- | | **Error** | `invalid_grant` | | **Message** | Please check the `jti` claim. A unique `jti` value is required. | | **Solution** | Ensure the JWT ID (`jti`) is set to a valid, unique value for each assertion. The same `jti` cannot be reused. | | | | | ------------ | ----------------------------------------------------------------------------------------------------------- | | **Error** | `invalid_grant` | | **Message** | Please check the `iss` claim. | | **Solution** | The issuer (`iss`) claim must match the OAuth client ID for your application when using JWT authentication. | | | | | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | **Error** | `invalid_grant` | | **Message** | Signature verification error. The public key identified by `kid` must correspond to the private key used for signing. | | **Solution** | Use the public/private keypair associated with your app in the Developer Console. If you rotate keys, add the new key, remove the old one, update your configuration file with the new keypair and `kid`, then request a new access token. | | | | | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Error** | `invalid_grant` | | **Message** | `kid` invalid, unable to lookup correct key. | | **Solution** | The key ID (`kid`) in the JWT header must match a public key registered for the application (for example, the `publicKeyID` in your configuration). Confirm you are using the correct configuration file, or generate a new RSA keypair in the Developer Console and update your app to use it. | | | | | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Error** | `invalid_limit` | | **Message** | Limit is not a valid number | | **Solution** | Add a valid numeric value for the supplied limit value. | | | | | **Error** | `invalid_offset` | | **Message** | Offset is not a valid number | | **Solution** | Add a valid numeric value for the supplied offset value. | | | | | **Error** | `invalid_request` | | **Message** | The grant type is unauthorized for this client\_id. | | **Solution** | You may be requesting a token using standard OAuth 2.0 while the app is configured for Server Authentication (JWT), or the other way around. Use the token request type that matches your app's authentication method. See [The grant type is unauthorized for this client\_id](https://support.box.com/hc/en-us/articles/360044193033-API-Authentication-The-grant-type-is-unauthorized-for-this-client-id). | | | | | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Error** | `invalid_request` | | **Message** | Invalid `grant_type` parameter or parameter missing. | | **Solution** | You may be sending token requests to the wrong domain (such as `app.box.com` or `www.box.com`). Send token requests to `https://api.box.com`. Use the `grant_type` and other parameters required for your flow (`authorization_code`, `refresh_token`, [JWT assertion](/reference/post-oauth2-token#body-grant-type), and so on). | | | | | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | **Error** | `invalid_request` | | **Message** | Cannot obtain user token based on the enterprise configuration for your app. | | **Solution** | Your app may be missing a scope or configuration needed to request a user token. See [Cannot Obtain Token Based on Enterprise Configuration for Your App](https://support.box.com/hc/en-us/articles/360044192553). | | | | | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | **Error** | `invalid_request_parameters` | | **Message** | Invalid input parameters in request | | **Solution** | Invalid parameters were sent in the API request. Check the API reference documentation for the correct request parameters that should be supplied for the API operation. | | | | | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Error** | `invalid_status` | | **Message** | You can change the status only if the collaboration is pending | | **Solution** | The status of a collaboration can only be updated to accepted or rejected by the user specified in the `accessible_by` field when the current status is set to pending. | | | | | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------- | | **Error** | `invalid_upload_session_id` | | **Message** | The upload session ID provided in the URL is not of a valid format. | | **Solution** | The session ID supplied when making a chunked upload API request was invalid. Use the same session ID from the session that was created. | | | | | | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | | **Error** | `item_name_invalid` | | | **Message** | Item name invalid | | | **Solution** | Verify that the file's name is valid. Box only supports file or folder names that are 255 characters or less. File names containing non-printable characters, names containing the characters `/`, `\`, `<`, `>`, `:`, \` | `, `?`, `\*`, `-\`, names with leading or trailing spaces, and the special names “.” and “..” are also unsupported. | | | | | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------- | | **Error** | `item_name_too_long` | | **Message** | Item name too long | | **Solution** | Shorten the length of the name that is being supplied for the item. The maximum length of a file or folder name in Box is 255 characters or less. | | | | | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------- | | **Error** | `metadata_after_file_contents` | | **Message** | Metadata is included after file contents in a file upload request. | | **Solution** | Include the file metadata before the file's contents. | | | | | **Error** | `password_reset_required` | | **Message** | User needs to reset password | | **Solution** | The user has not yet completed account [setup steps](https://support.box.com/hc/en-us/articles/360043691614). | | | | | **Error** | `requested_page_out_of_range` | | **Message** | Requested representation page out of range | | **Solution** | The range header supplied does not fit within the size of the specified item. Adjust the bounds to fit within the size of the item and try again. | | | | | ------------ | -------------------------------------------------------------------------------------------------------------------------------- | | **Error** | `requested_preview_unavailable` | | **Message** | Requested preview unavailable | | **Solution** | The thumbnail size requested for the file is not valid. See the reference docs for the API operation for available format sizes. | | | | | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------- | | **Error** | `sync_item_move_failure` | | **Message** | Cannot move a synced item | | **Solution** | The item is set to be synced by the Box sync clients and cannot be moved. A possible solution is to set the `sync_state` of the item to `not_synced`. | | | | | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Error** | `task_assignee_not_allowed` | | **Message** | Assigner does not have sufficient privileges to assign task to assignee | | **Solution** | The user who is attempting to assign the task does not have the appropriate permissions to do so. Adjust the user permissions to allow the assignment of tasks. | | | | | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Error** | `terms_of_service_required` | | **Message** | User must accept custom terms of service before action can be taken | | **Solution** | The admin of your Box account has set custom terms of service and the user has not logged in to accept the terms yet. The user will need to accept the terms of service, or the admin will have to disable them, in order to proceed. More information is available [here](https://support.box.com/hc/en-us/articles/360044192733-Using-Custom-Terms-Of-Service). | | | | | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Error** | `unauthorized_client` | | **Message** | This app is not authorized by the enterprise admin. | | **Solution** | Server authentication applications using JWT or Client Credentials Grant must be authorized by a Box Admin before use. Follow the steps in Platform App Approval. | | | | | ------------ | ------------------------------------------------------------------------------------------------------------------------------- | | **Error** | `user_already_collaborator` | | **Message** | User is already a collaborator | | **Solution** | The user that you are attempting to collaborate in on an item is already collaborated on that item. This request is not needed. | ### 401 Unauthorized | | | | ------------ | --------------------------------------------------------------------------------------------- | | **Error** | `unauthorized` | | **Message** | Unauthorized | | **Solution** | Authorization token is not authorized, check extended error message in body for more details. | | | | | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Error** | `invalid_token` | | **Message** | The access token provided is invalid. | | **Solution** | The access token may be incorrect, corrupted, or expired—for example, because of a typo, using a token from another environment, or revocation or deletion. Obtain a new access token from the token endpoint. For OAuth 2.0 authentication, you can refresh an expired access token; see Refresh a token. | ### 403 Forbidden | | | | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Error** | `access_denied_insufficient_permissions` | | **Message** | Access denied – insufficient permission | | **Solution** | The Access Token does not have the appropriate user permissions or scopes. See [here](https://support.box.com/hc/en-us/articles/360043693434-API-Content-API-403-access-denied-insufficient-permissions-Errors) for solution information. | | | | | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Error** | `insufficient_scope` | | **Message** | The request requires higher privileges than provided by the access token. | | **Solution** | This error is typically produced when scopes that are needed for the API operation are not enabled. Check your configured application scopes and reauthorize your application, if applicable. | | | | | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------- | | **Error** | `access_denied_item_locked` | | **Message** | Access denied – item locked | | **Solution** | You are attempting to access a locked item without appropriate permissions to access it. Unlock the item first, then try to access it again. | | | | | ------------ | -------------------------------------------------------------------------------------------------------------------------------------- | | **Error** | `access_from_location_blocked` | | **Message** | | | **Solution** | You’re attempting to log in to Box from a location that has not been approved by your admin. Talk to your admin to resolve this issue. | | | | | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Error** | `file_size_limit_exceeded` | | **Message** | File size exceeds the folder owner’s file size limit | | **Solution** | See [here](https://support.box.com/hc/en-us/articles/360043697314-Understand-the-Maximum-File-Size-You-Can-Upload-to-Box) for maximum file size limits based on account type. | | | | | **Error** | `forbidden` | | **Message** | | | **Solution** | Client does not have permission to upload to this session. Only the user who initiated the upload session may upload to it. | | | | | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Error** | `forbidden_by_policy` | | **Message** | Access denied – Blocked by Shield Access Policy | | **Solution** | Shield access policies applied on your enterprise have prevented this action. Contact your enterprise admin to adjust the applied Shield access policies. | | | | | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Error** | `forbidden_by_policy` | | **Message** | Access denied – Blocked by Shield Malware Detection Rule | | **Solution** | An active Shield malware detection rule prevents download or local editing of potentially malicious content, but preview and online editing remain available. Contact your enterprise admin to adjust the applied Shield policies. | | | | | ------------ | ---------------------------------------------------------------------------------------- | | **Error** | `incorrect_shared_item_password` | | **Message** | | | **Solution** | A password is required for the shared item, but it was either incorrect or not supplied. | | | | | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | **Error** | `storage_limit_exceeded` | | **Message** | Account storage limit reached | | **Solution** | The storage limit of the account has been reached. Either [upgrade](https://support.box.com/hc/en-us/articles/360043692774-Upgrading-your-Box-Account) your account or permanently delete content to continue. Content that is simply moved to the trash will still count towards the account total until it is permanently deleted. | | | | | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Error** | `user_email_confirmation_required` | | **Message** | User needs to complete email confirmation | | **Solution** | The user has not yet completed [steps](https://support.box.com/hc/en-us/articles/360043691614) for email confirmation. | | | | | **Error** | `cors_origin_not_whitelisted` | | **Message** | Access denied - Did you forget to safelist your origin in the CORS configuration of your app? | | **Solution** | Your application tried to access the Box API from a website. The application needs to explicitly allow Cross Origin Resource Sharing for the domain your site is hosted on. | ### 404 Not Found | | | | ------------ | -------------------------------------------------------------------------------------------------------- | | **Error** | `not_found` | | **Message** | | | **Solution** | The resource could not be found. Check the extended error message in the response body for more details. | | | | | ------------ | ------------------------------------------------------------------------------------------------- | | **Error** | `not_trashed` | | **Message** | Item is not trashed | | **Solution** | The item that is to be permanently deleted is not in the trash. Send the item to the trash first. | | | | | ------------ | ------------------------------------------------------------------------------------------------------------------------------- | | **Error** | `preview_cannot_be_generated` | | **Message** | Preview cannot be generated | | **Solution** | You are not able to generate a preview thumbnail for the specified file. | | | | | **Error** | `trashed` | | **Message** | Item is trashed | | **Solution** | The item that is to be accessed is in the trash and unavailable for modification. Move the item out of the trash and try again. | ### 405 Method Not Allowed | | | | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------ | | **Error** | `method_not_allowed` | | **Message** | Method Not Allowed | | **Solution** | The HTTP method used for the API operation is not allowed. Check the API reference documentation for the HTTP verb needed for the API operation. | ### 409 Conflict | | | | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------- | | **Error** | `conflict` | | **Message** | A resource with this value already exists | | **Solution** | This error may be produced when the resource to be created already exists. Check the extended error message in the response body for more details. | | | | | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------- | | **Error** | `item_name_in_use` | | **Message** | Item with the same name already exists | | **Solution** | This error is produced when a resource with the same name already exists. Ensure that the resource name being added / modified is unique. | | | | | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | **Error** | `name_temporarily_reserved` | | **Message** | The item name is reserved by another processing item. Wait and then retry the request, or wait and check the parent folder to see if the name is in use. | | **Solution** | Two duplicate requests have been submitted at the same time. Box acknowledges the first and reserves the name, but a second duplicate request arrives before the first request has completed. Allow the first request to complete before sending the second. | | | | | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Error** | `operation_blocked_temporary` | | **Message** | The operation is blocked by another ongoing operation | | **Solution** | This error is returned when trying to access a folder that is blocked by another folder operation, such as a move or copy. Try again at a later interval. | | | | | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Error** | `recent_similar_comment` | | **Message** | A similar comment has been made recently | | **Solution** | A similar comment was recently made, and the API has flagged it as a potential duplicate. Verify that the comment was indeed made, or modify the comment content and try again. | | | | | ------------ | ---------------------------------------------------------------------------------------------------------- | | **Error** | `user_login_already_used` | | **Message** | User with the specified login already exists | | **Solution** | A user with the same email already exists. Either refer to the existing user or specify a different email. | ### 410 Gone | | | | ------------ | --------------------------------------------------------------------------------------------------------- | | **Error** | `session_expired` | | **Message** | | | **Solution** | The upload session associated with the given upload session ID has expired and can no longer be accessed. | | | | | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Error** | `upload_failed` | | **Message** | | | **Solution** | The upload session is in an unrecoverable state and cannot continue. This or other requests have resulted in the upload session reaching a bad state (for example parts overlapping). Possible situations where this may arise include when the maximum number of parts has been exceeded or when overlapping parts have been uploaded. | ### 411 Length Required | | | | ------------ | ------------------------------------------------------- | | **Error** | `length_required` | | **Message** | content-length header was required, but not provided. | | **Solution** | Supply a content-length header within your API request. | ### 412 Precondition Failed | | | | ------------ | ----------------------------------------------------------------------- | | **Error** | `precondition_failed` | | **Message** | The resource has been modified. Retrieve the resource again and retry | | **Solution** | Check the extended error message in the response body for more details. | | | | | ------------ | ----------------------------------------------------------------------- | | **Error** | `sync_state_precondition_failed` | | **Message** | The resource has been modified. Retrieve the resource again and retry | | **Solution** | Check the extended error message in the response body for more details. | ### 413 Request Entity Too Large | | | | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------ | | **Error** | `request_entity_too_large` | | **Message** | Request Entity too Large | | **Solution** | This error is produced when the size of the upload is more than the allowed maximum. Check the extended error message in the response body | ### 415 Unsupported Media Type | | | | ------------ | -------------------------------------------------------------------------------------------------------------------------------- | | **Error** | `unsupported_media_type` | | **Message** | Previews for `boxnote` files are not yet supported. | | **Solution** | This error is produced when requested an embed preview of a Box Note. Embedded previews are currently unsupported for Box Notes. | ### 429 Too Many requests | | | | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Error** | `rate_limit_exceeded` | | **Message** | Request rate limit exceeded, try again later. | | **Solution** | The client is performing operations too quickly and has been rate limited. Client is advised to retry their request after the amount of time specified by the `retry-after` header. There are four rate limits to be aware of. | ### 500 Internal Service Error | | | | ------------ | ------------------------------------------------------------------------------------------------------------ | | **Error** | `internal_server_error` | | **Message** | Internal Server Error | | **Solution** | Client should retry using [exponential back-off strategy](https://en.wikipedia.org/wiki/Exponential_backoff) | ### 502 Bad Gateway | | | | ------------ | ------------------------------------------------------------------------------------------------------------ | | **Error** | `bad_gateway` | | **Message** | | | **Solution** | Client should retry using [exponential back-off strategy](https://en.wikipedia.org/wiki/Exponential_backoff) | ### 503 Unavailable | | | | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Error** | `unavailable` | | **Message** | Unavailable | | **Solution** | If a Retry-After header is provided in the response, the client should retry the request according to the header value. In rare situations, a write operation may eventually persist its changes after the 503 response is received by the client, so the client should handle this case upon retry. If the issue persists, check our [Status Site](https://status.box.com/) for any known outage information. | [status-codes]: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html [articles]: https://support.box.com/hc/en-us/sections/360007552913-Troubleshooting-Box-Platform # Token & URL Expiration Source: https://developer.box.com/guides/api-calls/permissions-and-errors/expiration Across the Box API there are a few tokens, codes, and URLs that automatically expire. The following is a quick overview of their respective expiration times. | | | | --------------------- | ------------------------------ | | [Authorization Codes] | Expires after 30 seconds | | [Access Tokens] | expires after 60 minutes | | [Refresh Tokens] | Expires after 60 days or 1 use | | [Download URLs] | Expires after 15 minutes | See each respective guide for more details. [Authorization Codes]: /guides/authentication/oauth2 [Access Tokens]: /guides/authentication/tokens [Refresh Tokens]: /guides/authentication/tokens/refresh [Download URLs]: /guides/downloads # Permissions and errors Source: https://developer.box.com/guides/api-calls/permissions-and-errors/index The following guides provide information on the permissions or errors related to the Box API. It includes pages on Common Errors, Rate Limits, Scopes, Token/URL Expiration, and the App Diagnostic Report. # Rate Limits Source: https://developer.box.com/guides/api-calls/permissions-and-errors/rate-limits There are three common types of API call rate limitations that Box may use at its discretion to best protect network resources and preserve the quality of our customer experience. A free developer account lets you start making API calls and test your integration's rate limit handling with real requests. ## User based These rate limits protect our service from issues that may arise when a single user generates too much traffic. The number of API calls that a user can make in a minute is limited as described below. These limits apply to all Box user accounts and are the most common. Generally, they are initiated when a user exceeds approximately 1000 API calls/minute, but certain API endpoints may have different rate limits. ## Quality of service These rate limits are designed to protect the quality of service of our infrastructure. If there is resource contention in the infrastructure, we introduce automatic rate limits to prevent system degradation and outages. For instance, if an application happens to be accessing the same physical database server, such as the use of a file migration tool accessing related resources that access the same underlying physical resources, Box may impose temporary rate-limits when load spikes and adjust them as the system recovers. ## Licensing based All Box Business Plans come with a licensed number of permitted API calls per enterprise per month. These license based rate limits are designed to prevent excessive overages and misuse of network resources. If Box's infrastructure detects that a tool used by or on behalf of a customer has exceeded that customer's API license allocation or is intending to circumvent network controls, additional selective rate-limiting may be imposed. You can see the default API allocations licensed with a particular account level at our [pricing page][pricing], but note that some customers purchase Platform API Pricing plans that increase their allocation.  ## Per API rate limits There are currently a few distinct rate limits in place within the Box API. * General API calls * 1000 API requests per minute, per user * Uploads * 240 file upload requests per minute, per user * Search * 6 searches per second, per user, to the search endpoint * Two additional limits are applied on top of the basic rate limit * 60 searches per minute, per user * 12 searches per second, per enterprise * Box Sign * Create and resend sign request: 100 requests per minute, per user * Get sign request: 1000 requests per minute, per user ## Rate limit error When an application hits a rate limit, the API will return an API response with a HTTP status code of `429 Too Many Requests`. The response will include the following headers and JSON body. ```yaml theme={null} retry-after: 100 ``` ```json theme={null} { "type": "error", "status": 429, "code": "rate_limit_exceeded", "help_url": "https://developer.box.com/guides/api-calls/permissions-and-errors/common-errors/", "message": "Request rate limit exceeded, please try again later", "request_id": "abcdef123456" } ``` Please see the Client Error resource for more details. The `retry-after` header provides guidance on the number of seconds to wait before the next API call can be retried. In general, we advise using an exponential back-off strategy for retrying API calls. [pricing]: https://www.box.com/pricing # Scopes Source: https://developer.box.com/guides/api-calls/permissions-and-errors/scopes When an application is created in the Developer Console, the user must configure application scopes. Similar to how users have permissions to access files and folders within Box, applications have their own set of permissions to perform certain actions on behalf of a Box user or a Box enterprise. The name for a set of permissions for an application is a "scope". In short, an application's scopes determine which endpoints an application can successfully call and are reflected in the access provided by Access Tokens of the application. ## User permissions and scopes It is important to understand that even if an application has the right scopes to perform an action, the user associated with the Access Token making the call needs to have permission to perform the action as well and vice versa. For example, if your application is set up to read files, the authenticated user does need to have permission to read the file you are trying to access. To learn more about how scopes, token permissions, and user permissions work together, see our security guide. A free developer account gives you access to the Developer Console, where you can configure application scopes and start making API calls. ## Scopes & OAuth 2 authorization When sending a user through a client-side OAuth 2 flow to authorize your application it is possible to append a set of scopes to the authorization URL to further restrict the user's access token. For example, if you application has the `root_readonly` and `root_readwrite` scopes enabled, it is possible to restrict a user's access token to `root_readonly` by specifying this scope when redirecting the user. ```js theme={null} GET https://account.box.com/api/oauth2/authorize?scope=root_readonly&client_id=.... ``` When the scope parameter is omitted the application will use the scopes that were set when the application was created. ## Self-service scopes These scopes are available through the Developer Console when configuring an application. Navigate to the **Application Scopes** section of the **Configuration** tab and select one or more of the following scope. ### Read all files and folders | | | | --------------------- | ---------------------------------------- | | **OAuth Scope** | `root_readonly` | | **Application Scope** | Read all files and folders stored in Box | Gives an application the ability to read all the files/folders for the authenticated user. Although this gives an application the permission to read files and folders, the user making the API call does need to have access to the items being accessed. In the case of a JWT application accessing a Managed User's items, the Service Account's Token will need to either use the `as-user` header or create a User Access Token to directly authenticate as the user who has access to the content. ### Read and write all files and folders | | | | --------------------- | -------------------------------------------------- | | **OAuth Scope** | `root_readwrite` | | **Application Scope** | Read and write all files and folders stored in Box | Gives an application write access for the authenticated user. This allows the application to upload files or new file versions, download content, create new folders, update or delete collaborations, create comments or tasks, and more. Although this gives an application read/write access to items, the user making the API call needs to have access to the content. ### Manage users The manage users scope in the Developer Console maps to two OAuth scopes. | | | | --------------------- | ---------------------- | | **OAuth Scope** | `manage_managed_users` | | **Application Scope** | Manage users | Gives an application permission to manage Managed Users. It allows the app to change the user's primary login, reset their password, and change roles for managed users. Although this allows an application manage users, for client-side applications, the Access Token used must be associated with an Admin or Co-Admin with the correct permissions. Additionally, for JWT applications, the application must be configured with **App Access + Enterprise Access** application access. | | | | --------------------- | ------------------ | | **OAuth Scope** | `manage_app_users` | | **Application Scope** | Manage users | Gives an application permission to manage App Users, which means this scope only applies to server-side authenticated (JWT) applications. ### Manage groups | | | | --------------------- | --------------- | | **OAuth Scope** | `manage_groups` | | **Application Scope** | Manage groups | Gives an application permission to manage an enterprise's groups. It allows the app to create, update, and delete groups, as well as manage group membership. Although this allows an application manage groups, for client-side applications, the Access Token used must be associated with an Admin Co-Admin with the correct permissions. Additionally, for JWT applications, the application must be configured with **App Access + Enterprise Access** application access. ### Manage webhooks | | | | --------------------- | ---------------- | | **OAuth Scope** | `manage_webhook` | | **Application Scope** | Manage webhooks | Gives an application permission to create webhooks for a user. Please review webhook limitations. Most notably, there is a limit of 1000 webhooks per application, per user. ### Manage enterprise properties | | | | --------------------- | ------------------------------ | | **OAuth Scope** | `manage_enterprise_properties` | | **Application Scope** | Manage enterprise properties | Gives an application permission to view the enterprise event stream, as well as view and edit the enterprise's attributes and reports. It also allows the application to edit and delete device pins. Although this allows an application to enterprise properties, for client-side applications, the Access Token used must must be associated with an Admin Co-Admin with the correct permissions. ### Manage retention policies | | | | --------------------- | -------------------------- | | **OAuth Scope** | `manage_data_retention` | | **Application Scope** | Manage retention policies | | **Depends on** | `enterprise_content`-scope | Gives an application permission to view and create retention policies with Box Governance. This requires the enterprise to have purchased [Box Governance][governance]. This scope also requires the `enterprise_content` scope to function properly. These scopes can be requested by opening a ticket via our support channels. ### Manage signature requests | | | | --------------------- | ------------------------- | | **OAuth Scope** | `sign_requests.readwrite` | | **Application Scope** | Manage signature requests | Gives an application permission to get, create, cancel, and resend sign requests. This scope requires the application to also have read/write scopes, which are automatically selected when enabled. In addition, an enterprise must have Sign enabled. ### Manage Box AI API | | | | --------------------- | -------------- | | **OAuth Scope** | `ai.readwrite` | | **Application Scope** | Manage AI | Gives an application permission to send requests to Box AI API. ### Manage Box Relay | | | | --------------------- | ----------------- | | **OAuth Scope** | `manage_triggers` | | **Application Scope** | Manage Box Relay | Gives an application permission to get workflows and start flows of type `WORKFLOW_MANUAL_START` This scope requires the application to also have read/write scopes. ## Available on request There are some additional scopes that are only available upon request. To do so, please submit a ticket to our [support team](https://developer.box.com/support). They will review these requests on an individual basis and only provide approval if the use case requires the scope. It is not possible to request extra scopes if your account is a free trial account. Before filing a support request for activation of the following scopes, log in to your paid enterprise account or [upgrade your free developer account][pricing] to an enterprise account tier. ### Manage Legal Holds | | | | --------------- | -------------------------- | | **OAuth Scope** | `manage_legal_holds` | | **Depends on** | `enterprise_content`-scope | Gives an application permission to view and create retention policies with Box Governance. This requires the enterprise to have purchased Box Governance. This scope depends on the `enterprise_content` scope to function properly. This scope can be requested by opening a ticket via our support channels. ### Suppress email notifications | | | | --------------------- | ----------------------------------------------- | | **Application Scope** | Can suppress email notifications from API calls | Allows some types of email notifications to be suppressed when API calls are made. ### Global Content Manager (GCM) | | | | --------------------- | ---------------------- | | **OAuth Scope** | `enterprise_content` | | **Application Scope** | Global Content Manager | Allows Admins, [Co-Admins][ca], and Service Accounts to retrieve any content they do not own or are not collaborators on within their enterprise, based on their enterprise settings. This scope is required to manage the retention policies and legal holds. **Side effects** Enabling this scope on an application changes the behavior of some API calls, and most notably, makes it impossible to write content without explicitly authenticating as a user using the `as-user` header. Additionally, enabling this scope disables accessing content that is owned by users in another enterprise. For this reason, this scope will not be provisioned unless absolutely necessary. ## Scopes for downscoping In some cases an Access Token needs to be downscoped to a more strict permission level, especially when a token needs to be exposed to a client-side, public environment like a browser. The primary example for this is when using [Box UI Elements][ui-elements], which require an Access Token in the user's browser. The following is a list of **additional** scopes that can be used with the `POST /oauth2/token` endpoint to downscope an existing access token. | OAuth Scope | UI Element affected | Description | | ---------------------- | ------------------- | ----------------------------------------------------------------------------------- | | `annotation_edit` | Preview | Allow user to edit & delete annotations | | `annotation_view_all` | Preview | Allows user to view annotations by all users | | `annotation_view_self` | Preview | Allows user to view their own annotations only | | `base_explorer` | Explorer | Allows access to content in the folder tree based on user/file/token permissions | | `base_picker` | Picker | Allows access to content in the folder tree based on user/file/token permissions | | `base_preview` | Preview | Allows the user to preview the file, nothing else | | `base_sidebar` | Sidebar | Allows the user to get basic file info needed for the sidebar UI element | | `base_upload` | Uploader | Allows upload into the folder specified under `resource` when downscoping the token | | `item_delete` | Explorer | Allows files and folders to be deleted | | `item_download` | Explorer, Preview | Allows files or a folder's content to be downloaded | | `item_preview` | Explorer | Enables preview of a file | | `item_rename` | Explorer | Allows files and folders to be renamed | | `item_share` | Explorer, Picker | Allows the item specified under `resource` of the token exchange to be shared | | `item_upload` | Picker | Allows upload in the content picker | The standard OAuth scopes are also supported when downscoping. | OAuth Scope | Description | | ------------------------------ | ---------------------------- | | `ai.readwrite` | Manage AI API | | `manage_managed_users` | Manage managed users | | `manage_app_users` | Manage app users | | `manage_data_retention` | Manage retention policies | | `manage_enterprise_properties` | Manage enterprise properties | | `manage_groups` | Manage groups | | `manage_webhook` | Manage webhooks | | `sign_requests.readwrite` | Manage sign requests | [console]: https://app.box.com/developers/console [ui-elements]: https://github.com/box/box-ui-elements [pricing]: https://www.box.com/pricing/platform [governance]: https://www.box.com/security/governance-and-compliance [ca]: https://support.box.com/hc/en-us/articles/1500005433721-Users-Groups-Settings#h_01GSE1DYJKTY9EXEWJEDKFHCNV # Versioning errors Source: https://developer.box.com/guides/api-calls/permissions-and-errors/versioning-errors Box provides versioning capabilities for selected API endpoints. The version control system guarantees seamless functioning of existing endpoint versions, even if Box introduces new ones. API versioning empowers Box to continually enhance its platform, while also offering third-party developers a reliable avenue for feature updates and deprecations. To stay informed about the API modifications, monitor the [Changelog](https://developer.box.com/changelog) and maintain a current email address in the **App Info** section of the Developer Console. ## Error examples When using versioned API calls, you can encounter versioning-related errors. This reference lists the most common cases when errors appear and provides you with examples of such errors. ## Calling with incorrect `box-version` header If you call an API using an incorrect `box-version` header, the API will respond with an `HTTP error code 400 - Bad Request` error and provide the supported versions in the response message. The response will include one of the following status messages in `message` field: | Details | Message | | ------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | | `box-version` value is an unsupported API version or was sent malformed. | `Invalid API version specified in 'box-version' header.` | | The request headers did not include `box-version` header when versioned only endpoint was called. | `Missing required box-version header.` | | `box-version` is empty. | `Invalid (empty) API version specified in 'box-version' header.` | | `box-version` contained multiple version. It requires **only one** version per request. | `The 'box-version' header supports only one header value per request, do not use comas.` | | An unsupported API version is used for an existing endpoint. | `Unsupported API version specified in 'box-version' header.` | An example of a response with an incorrect `box-version` header: ```json theme={null} { "type": "error", "status": 400, "code": "invalid_api_version", "help_url": "/reference/error-codes/invalid-api-version", "message": "Invalid API version specified in 'box-version' header. Supported API versions: [2024.0].", "request_id": "abcdef123456" } ``` ## Calling an incorrect API version in the URL Box documentation specifies API URLs. For instance, the Sign Requests endpoints are accessed via: `https://api.box.com/2.0/sign_requests/`. If you mistakenly make a call to an incorrect version, such as `https://api.box.com/3.0/sign_requests/`, the response returns an `HTTP error code 404 - Not Found` error. ## Calling a deprecated API When you use an API version that Box has marked as deprecated, the API will respond as usual. Additionally, it will append a `Deprecation` header, stating the deprecation date. For example: ```sh theme={null} Deprecation: date="Fri, 11 Nov 2026 23:59:59 GMT" Box-API-Deprecated-Reason: /reference/deprecated ``` You should monitor API responses to verify if the `Deprecation` header is present to accordingly plan the transition to a new API version. ## Calling a non-existent version If you attempt to use an outdated API version, such as `2025.0` which has reached its end-of-life, the response will return an `HTTP error code 404 - Not Found`. See [Calling an incorrect API version in the URL](#calling-an-incorrect-api-version-in-the-url) for more information. # Request extra fields Source: https://developer.box.com/guides/api-calls/request-extra-fields The number of fields returned for a resource depends on the API endpoint used to request the resource. ## Use the `fields` query parameter To request a specific field for a resource that is not returned by default in the standard response, append the `fields` query parameter to your request. The value of this parameter is a comma separated list of field names. ```sh theme={null} curl https://api.box.com/2.0/files/12345?fields=is_package,lock \ -H "authorization: Bearer ACCESS_TOKEN" ``` ```json theme={null} { "etag": "1", "id": "12345", "is_package": false, "lock": null, "type": "file" } ``` It is important to note that when a specific field is requested no other fields are returned except for those requested and the **base** set of fields. For a file, this base set is comprised of the `etag`, `id`, and `type` values. ## Resource variants The following resource variants are available in the Box API. ### Standard The default set of fields returned in an API response. The standard variant is returned when requesting a resource through the main APIs available for that resource. For example, when requesting the `GET /files/:id` endpoint the API will return the standard variation of a file. ```sh theme={null} curl https://api.box.com/2.0/files/12345 \ -H "authorization: Bearer ACCESS_TOKEN" ``` ```json theme={null} { "content_created_at": "2019-06-20T06:04:41-07:00", "content_modified_at": "2019-06-20T06:04:41-07:00", "created_at": "2019-06-20T07:28:42-07:00", "created_by": { "id": "191919191", "login": "joe@example.com", "name": "Joe Box", "type": "user" }, "description": "", "etag": "1", "file_version": { "id": "56663434454334", "sha1": "585afa5209bbd586c79499b7336601341ad06cce", "type": "file_version" }, "id": "12345", ... "size": 65000647, "trashed_at": null, "type": "file" } ``` ### Mini Where a resource is returned as a nested part of another response it is often reduced in size, only returning some of the more essential fields. This variant is commonly known as the mini resource variant. For example, when requesting the `GET /folders/:id/items` endpoint the API will return a mini variation of files and folders nested within the `item_collection`. ```sh theme={null} curl https://api.box.com/2.0/files/12345 \ -H "authorization: Bearer ACCESS_TOKEN" ``` ```json theme={null} { "id": "0", "type": "folder", "item_collection": { "entries": [ { "etag": "1", "file_version": { "id": "56663434454334", "sha1": "585afa5209bbd586c79499b7336601341ad06cce", "type": "file_version" }, "id": "12345", "name": "Video.mp4", "sequence_id": "1", "sha1": "585afa5209bbd586c79499b7336601341ad06cce", "type": "file" } ... ] ... } ... } ``` To request more information for a nested resource we recommend calling the API for that resource to request it by ID, and optionally pass along the `field` query parameter. For example, to get the owner of a file returned when listing the items in a folder, request that file by ID with the query parameter `field=owned_by`. ### Full The total set of fields that can be returned in an API response. The full variant is returned when requesting a resource through the main APIs available for that resource and by appending the `fields` query parameter. For example, when requesting the `GET /files/:id` endpoint with the `fields=is_package,lock` parameter the API will return the fields specified plus the basic fields for the file. ```sh theme={null} curl https://api.box.com/2.0/files/12345?fields=is_package,lock \ -H "authorization: Bearer ACCESS_TOKEN" ``` ```json theme={null} { "etag": "1", "id": "12345", "is_package": false, "lock": null, "type": "file" } ``` # Sorting responses Source: https://developer.box.com/guides/api-calls/sorting Where an API returns a collection of items it often supports sorting of API responses. Use the `sort` and `direction` query parameters to sort the collection either in ascending or descending order. ```sh theme={null} curl https://api.box.com/2.0/folders/0/items?sort=size&direction=DESC \ -H "authorization: Bearer ACCESS_TOKEN" ``` Not all API endpoints that return collections have support for sorting. Especially endpoints that use marker-based pagination often lack support for sorting the results. ## Sorting criteria The field to sort on is defined by the `sort` query parameter. Check the API endpoint's documentation for the possible options for this value. In some APIs the `sort` field is the second criteria by which the items are sorted. For example for the `GET /folders/:id/items` endpoint the results are always sorted by their type first before any other criteria. ## Sorting direction The sorting direction supports two values, either `ASC` for ascending order, or `DESC` for the reverse. # Status codes Source: https://developer.box.com/guides/api-calls/status-codes The following rules can be applied to interpret the HTTP status codes received when using the Box API. | HTTP Status | | | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `200-299` | Box received, understood, and accepted the API request. The request has either completed or is in the process of being completed. | | `300-399` | Box received, understood, and accepted the API request, yet the client must take further action in order to complete the request. Often this includes redirect to other URLs. | | `400-499` | An client error occurred when handling the request, often because the client either did not provide the right parameters, did not have access to the resources, or tried to perform an action that is otherwise not possible. | | `500-599` | Box received and accepted the request, but an error occurred within Box while handling it. These errors signify a problem with Box, not a problem with the client's request | # Suppress notifications Source: https://developer.box.com/guides/api-calls/suppress-notifications For some API calls, you can block email and webhook notifications by including a `box-notifications: off` header with the API call. ```sh cURL theme={null} curl -X POST https://api.box.com/2.0/folders \ -H "box-notifications: off" \ -H "authorization: Bearer ACCESS_TOKEN" \ -d '{ "name": "New Folder", "parent": { "id": "0" } }' ``` As an example, this can be used for a virus-scanning tool to download copies every user's files in an enterprise without every collaborator on the file receiving an email informing them of the download. All actions will still appear in users updates feed and the audit-logs. **Scope requirement** Notification suppression is available for approved applications only. Contact support to request the required scopes to be enabled for your application. The following settings need to be configured for your application for this feature to properly work. * **Can suppress email notifications from API calls** - available on request via support * **Manage Enterprise Properties** - available via the developer console * Co-admin permissions of **Edit settings for your company**. Some notifications can not be suppressed, most notable the creation is users, comments, collaborations, task assignments, and when changing a user's login. # Types and formats Source: https://developer.box.com/guides/api-calls/types-and-formats The following sections explain some basic concepts about the types and formats that can be encountered within the Box APIs. ## Requests The Box APIs use JSON in the requests bodies. There are a few notable exceptions to this rule: * The `POST /oauth2/token` is used to request access tokens and as per the OAuth 2.0 specification it accepts the body to be sent with a content type of `application/x-www-form-urlencoded`. * Most of the APIs that are used to upload binary data, like the `POST /files/content` endpoint, expect data to be sent as form data with a content type of `multipart/form-data`. Although not required, we highly recommend passing a header with each API request to define the content type of the data sent, for example `content-type: application/json`. ### Headers As per the HTTP specification, all request header names in the Box API are case-insensitive and can be provided in lowercase, uppercase, or any mixed case form. In other words, the content type header can be set as `CONTENT-TYPE: application/json`, `content-type: application/json`, `content-type: application/json` or even the slightly absurd `cOnTeNt-TyPe: application/json`. Header values **are** mostly case sensitive unless stated otherwise. ### GZip compression By default data sent from Box is not compressed. To improve bandwidth and response times it's possible to compress the API responses by including a `Accept-Encoding: gzip, deflate` request header. ### Date and times The Box APIs support [RFC 3339][rfc3339] timestamps. The preferred way to format a date in a request is to convert the time to UTC, for example `2013-04-17T09:12:36-00:00`. In those cases where timestamps are rounded to a given day, the time component can be omitted. In this case, `2013-04-17T13:35:01+00:00` would become `2013-04-17`. In those cases where timestamps support millisecond precision the expected request format should be as followed `2013-04-17T09:12:36.123-00:00`. The timezone can differ between different files and folders because an enterprise's timezone can change over time. A common example is daylight saving time. Items created during standard time would have a different timezone than items created during daylight saving time. For this reason it's important to use a `RFC3339`-compliant date-time parser to handle dates returned by the API. Timestamps are restricted to dates after the start of the Unix epoch, `00:00:00 UTC` on January 1, 1970. ## Responses The Box APIs generally returns JSON in the response body. There are a few notable exceptions to this rule as well. * APIs that delete items return an empty body with a `204 No Content` HTTP status code. * APIs used to request binary data either return a `200 OK` status code with the binary data attached, or a `202 Accepted`, or `302 Found` status code with no body and a `location` header pointing to the actual binary file. The `content-type` response header can be used to understand the type of content returned in the API. Additionally, every API endpoint has it's response type documented in our API reference documentation. ### Headers As per the HTTP specification, all response header names in the Box API are case-insensitive and could change over time. This means that the API might return responses with a content type header of `CONTENT-TYPE: application/json`, `content-type: application/json` or `content-type: application/json`. Ideally your application should convert header names to a standard case upon request and then use that standardized set of headers to look up values of the headers. Header values **are** always case sensitive unless stated otherwise. ### Resources Most standard API responses where only one resource is returned follow the following format. ```json theme={null} { "id": "12345", "type": "folder", ... } ``` Every one of these resources will always return an ID and the type of the resource. ### Collections Where an API response returns multiple items a collection is returned. Although the exact format of these collections can change from endpoint to endpoint they generally are formatted as follows. ```json theme={null} { "total_count": 5000, "limit": 1000, "offset": 2000, "order": [ { "by": "type", "direction": "ASC" } ], "entries": [ { "id": 12345, "etag": 1, "type": "file", "sequence_id": 3, "name": "Contract.pdf" } ] } ``` | Field | Always present? | | | ------------- | --------------- | ------------------------------------------------------------------------------------------------------------------------ | | `entries` | Yes | A list of entries in the collection | | `total_count` | No | The total numbers in the collection that can be requested. This can be larger than this page of results | | `limit` | No | For endpoints that support offset-based pagination, this specifies the limit to the number of results returned | | `offset` | No | For endpoints that support offset-based pagination, this specifies the offset of results returned | | `order` | No | For endpoints that support sorting, this specifies the order the results are returned in | | `next_marker` | No | For endpoints that support marker-based pagination, this specifies the marker for the next page that can be returned | | `prev_marker` | No | For endpoints that support marker-based pagination, this specifies the marker for the previous page that can be returned | ### Request IDs When your API call returns in an error, our API will return an error object with a `request_id` field. ```json theme={null} { "type": "error", "status": 400, "code": "item_name_invalid", "help_url": "https://developer.box.com/guides/api-calls/permissions-and-errors/common-errors/", "message": "Method Not Allowed", "request_id": "abcdef123456" } ``` When reaching out to support about specific error, please provide the full API response including the `request_id` to help our support team to quickly find your request. Most API calls also return a `box-request-id` response header. The value of this header should not be confused with the `request_id` value in the body of an error response. ### Large numbers In some cases the API can return extremely large numbers for a field. For example, a folder's size might have grown to many terabytes of data and as a result the `size` field of the folder might have grown to a very large number. In these cases these numbers are returned in [IEEE754][numbers] format for example `1.2318237429383e+31`. [numbers]: https://en.wikipedia.org/wiki/IEEE_754 [rfc3339]: https://www.ietf.org/rfc/rfc3339.txt # Applications Source: https://developer.box.com/guides/applications/index Box Developer Console allows you to create applications you can then use to integrate with Box. **My Platform Apps** view displays a list of already created applications and gives you quick access to their configuration details. This way, you don't need to open the app each time you want to generate a Developer Token, copy the Client ID, or generate a report. ## Features **My Platform Apps** page allows you to: * Search through the list of already created apps. * Filter the apps by **Enablement Status** and **Authentication Type**. * Create a new app. * Copy the app's Client ID. * Rename the app and access its details with one click. * Check application enablement and authorization status. Apps published to Integrations display status from Integrations. The **Options menu** available for every entry allows you to: * Access the configuration details of your application. * Generate a Developer Token. * Add collaborators to your application. * Run the Platform App Diagnostics Report. ## Platform App Insights Admins and co-admins can access the Platform Insights dashboard that provides a comprehensive view of the organization’s platform usage. This includes app-related data, such as: * The total number of API calls per application. * A list of top applications within the enterprise. * A list of pending application approvals. * A list of applications awaiting enablement. See [Platform Insights][insights] for details. You need the following permissions to access and view Platform Insights: * View settings and apps for your company * Edit settings and apps for your company * Run new reports and access existing reports [insights]: https://support.box.com/hc/en-us/articles/20738406915219-Platform-Insights # Integrations Source: https://developer.box.com/guides/applications/integrations/index [Box Integrations][app-center] is the first place for Box users to find out about applications they can use in combination with Box. If your application can be used by other enterprises, listing your service in under **Integrations** can be a great way to find new users. Integrations group apps into sections so that you can quickly find featured, most popular, or recently added apps. Integrations ## Developing a platform app or becoming a Box Partner If you need more information on developing a platform app for the Box Integrations or becoming a Box Partner, visit our [Box Partner Resources][bp] guides on our community site. ## Publishing a platform app Use the following steps to publish a platform app in Box Integrations. ### Prerequisites Your application must meet the following requirements: * The platform app is in a finished state and ready for production usage. * The platform app leverages OAuth 2.0 authentication, as Integrations do not support any other authentication methods. * You are a developer with access to the platform app in the **Developer Console**. ### Steps 1. Navigate to the Developer Console > **My Platform Apps** and select the app you want to publish. 2. Select the **Publishing** tab from the top menu. Publishing tab for an application 3. Read through the submission checklist and check the confirmation checkbox if your app meets all the requirements. 4. Fill in the form by providing: * the categories your app falls under * a short and a long description * screenshots and an app icon * supplementary information that will be used to support the users 5. Use the **Preview** button in the top right corner to see how your application will look when listed. 6. Finally, submit the application for approval by clicking the **Submit for Approval** button. Once a request for approval is received, the Box Partner team will be notified and review your request as soon as possible. For any questions, email [`integrate@box.com`][email]. ## Unpublishing a platform app Once approved and published, a platform app can be unpublished from the same control panel: 1. Navigate to the **Developer Console** and select your platform app. 2. Select the **Publishing** tab. 3. You can now unpublish the app. [app-center]: https://app.box.com/services [email]: mailto:integrate@box.com [bp]: https://support.box.com/hc/en-us/sections/21356597387539-Box-Partner-Programs # Create a Platform App Source: https://developer.box.com/guides/applications/platform-apps/create A Platform App allows for interaction with our 150+ endpoints. For example, downloading/uploading, searching, applying metadata and more. ## Prerequisites Access to the [Developer Console][dev-console]. ## Create a Platform App 1. Navigate to the [Developer Console][dev-console]. 2. Select **Create Platform App**. 3. Provide a name for your app. 4. Select the authentication method you want to use. 5. Click **Create App**. ## Configure application settings After you create a Platform App, the settings screen is displayed. ### General settings * **App Name** - the name you set up during the app creation, you can change it here if needed. * **App Description** - provide a description for your app (optional). * **Contact Email** - this is set to the developer of the application by default. Keep in mind that once you publish your app, this email is publicly visible to Box users who view your app in the Integrations. We recommend to change it to a support email address, so that users can reach out to support in case of any issues with the integration. ### Configuration * **Purpose** - select the purpose of your app from the drop-down list. Depending on the option you choose, you might need to specify further details. | Purpose | Details | | --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | | **Automation**, **Custom Portal** | Specify if the app is built by a customer or partner. | | **Integration** | Specify the integration category, external system name if you're integrating with one, and if the app is built by a customer or partner. | | *Other* | Specify the app purpose and if it is built by a customer or partner. | * **Authentication Method** - choose how your app will authenticate to the Box APIs. Depending on the authentication method you choose, you need to specify further details. | Authentication Method | Details | | ---------------------------- | ------------------------------------------------------------------------------------ | | **OAuth 2.0** | Specify the client ID and client secret. | | **JWT** | Add a public key or generate a public/private key pair. Choose the app access level. | | **Client Credentials Grant** | Specify the client ID and client secret. Choose the app access level. | * **Developer Token** - a developer token is created automatically when you create a Platform App. * **Application Scopes** - choose the scopes you want to grant to your app. See the scopes guide for detailed information on each option. * **Advanced Features** - enable the advanced features your application requires. * **CORS Domains** - add the domains you want to allow requests from. [dev-console]: https://app.box.com/developers/console # Platform App Source: https://developer.box.com/guides/applications/platform-apps/index Platform App typically presents Box functionality to a user through a custom interface. Box offers pre-built, customizable user interface components, known as UI Elements, for functionalities like browsing, searching, and previewing content. ## Authentication methods Platform Apps support OAuth 2.0, JWT, and Client Credentials Grant authentication methods. ## When to use Use a Platform App when you want to: * Use OAuth 2.0, JWT or Client Credentials Grant for authentication. * Upload and download files * Access both your own files and files owned by managed or external users. * List the application in the Box Integrations * Provide integration into the Box Web App ## Use cases Example use cases include: * A file vault in an application that allows an end user to access files that have been shared with them, while also providing access for employees to the same files through the Box Web app. An example of this is financial advisor sharing statements and investment prospectuses with investors that can be viewed and commented on within a platform application. * A file upload feature in an application that allows an end user to submit and upload files from within a custom-built application to Box. These uploads then initiate a business process with the Box Web app. An example of this is a candidate submitting a PDF of a resume to a recruiting portal then can then be routed to an appropriate employee for review. A free developer account gives you access to the Developer Console, where you can create Platform Apps using your preferred authentication method. ## Approval Platform Apps may require approval before use. # Create Web App Integration Source: https://developer.box.com/guides/applications/web-app-integrations/configure This guide explains how to set up a Web App Integration with a Platform App. Server-side integration is no longer supported. This means the applications using server-side actions will still be working, but you won't be able to modify the server-side configuration options such as Preliminary Callback URL or Basic Authentication. You will be able to deactivate them and change the implementation to a new one. ## Create an OAuth 2.0 Application Navigate to the [Developer Console][devconsole] and create a Platform App that leverages OAuth 2.0 authentication. ## Create a New Integration Then, navigate to the **Integrations** tab and click **Create a Web App Integration**. Integration Tab ## Configure Integration To configure the integration, follow the guidance below for each value. ### App Info | Field | Description | | --------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Integration name | The name of your integration, which users see in the Box Web App when they select the **More Options** > **Integrations** menu on a file or folder. | | Description | The description of the integration displayed in the Box Integrations. | | Supported file extensions | The integration will only appear as an option in the **More Options** > **Integrations** menu for the selected file extensions. | | Permissions requirement | Determines what permissions level users need to see the integration. **Download permissions are required** allows users to download the file - they will not be able to update it. **Full permissions are required** allows users to download and update the file. | | Integration scopes | Specifies the scope of your integration - either the file/folder from which integration is invoked, or its parent folder. | | Display on shared pages toggle | Determines if an integration can be shown to external users on a shared page. If enabled, users who are not collaborating on the content will see the integration in the context-menu when accessing the items through a shared link. | | Lock to only allow the current user to overwrite the file using your integration toggle | Determines if different web app integrations can edit the file at the same time. | | Integration type | Select desired integration type. Available options are: **Files**, **Folders**, **Both**. | ### Callback Configuration | Field | Description | | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Client Callback URL | Handles additional callback requests from Box after the primary request with Popup Integrations. If the application specifies a file parameter in the REST method, the preliminary callback URL cannot originate from the client. As a result, a second request must be made from the client to your server so the server can send the necessary interface to the user. | | Prompt Message | Specifies the message that users see when they initiate the integration. Use this field to provide context about what happens next. The message is limited to 500 characters. | | User Experience | Informs that the integration will open in a new window. | | New Window Settings | Determines if the application opens in a new tab. | ### Callback Parameters The **Callback Parameters** section configures the parameters that Box sends to the callback URL when a user accepts a confirmation prompt. If this setting is not configured, Box does not send any parameters to the callback URL. To add a parameter, select the **Method** (GET or POST), specify the **Parameter name** and add a **Parameter value**. The **File** method is no longer supported. If you already used this method, you cannot edit its values. You can change the **File** method to **GET** or **POST**, but you can't undo this action. For example: **GET - `userid` - `#user_id#`**. The following parameter values are available. | Parameter | Method | Description | | --------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `user_id` | GET, POST | The Box user ID. This information is used in Popup Integrations in which user authentication is required to complete an action. You can store the Box ID in your application to enable subsequent authentication requests from the integration. | | `user_name` | POST | The full name or email address of the Box user. Not all Box users specify their names at all times. | | `file_id` | GET, POST | The Box file ID. You can use this ID to make Box API calls that affect the file. | | `file_name` | POST | The name of the file. | | `file_extension` | GET, POST | The extension of the file. | | `auth_code` | GET, POST | The OAuth 2.0 authorization code, which is generated by Box upon successful authentication. Your application must then supply this authorization code to Box in exchange for an OAuth 2.0 Access Token. An authorization header containing a valid Access Token must be included in every Box API request. | | `redirect_to_box_url` | GET, POST | In Popup Integrations, the URL to which requests are sent by the confirmation prompt. Use this URL to redirect users to the All Files page. This parameter closes the popup panel and refreshes the All Files page to reflect any changes performed by the integration. If you do not want to add this parameter to your application, you can specify the entire URL. **Success**: `#redirect_to_box_url#&status=success&message=Your%20action%20was%20successful%2E`. **Failure**: `#redirect_to_box_url#&status=failure&message=Your%20action%20was%20unsuccessful%2E` | ### Integration Status * **Development**: The integration is visible and available only to application collaborators listed under the **General Settings** tab. This option is best used when the application is still in development and undergoing testing. * **Online**: The integration is visible and available to all Box users. This option is best used when development is complete and the application is ready to publish in the Integrations. * **Maintenance**: The integration is visible and available only to application collaborators listed under the **General Settings** tab. This option is best used after the integration is published in the Integrations, but needs to perform maintenance updates or troubleshoot issues. Use this option to temporarily take the integration offline for everyone except the application's collaborators. ## Example Use Cases of Box Integrations When a user chooses a Popup Integration, Box sends a callback request to the primary callback URL. It sends the callback parameters have been configured to the server. In some cases, Box may make a second request if the client cannot get all the data it needs from the first request. The following example does not require a client callback URL: * The Popup Integration performs a REST call using a `download_file_url` callback parameter. * The user clicks **OK** in the confirmation prompt to accept the popup. * Box sends a request to the following URL (the primary callback URL plus the callback parameter): `http://www.doceditor.com/service?apikey=abc&file=&redirect=`. * The response from the callback URL displays a user interface to the user who made the request. The popup has all the information needed to continue the action and an additional client callback is not needed. The following example requires a client callback URL: * The Popup Integration performs a REST call using a file-callback parameter. * The user clicks **OK** in the confirmation prompt to accept the popup. * The popup displays a page where Box sends a POST request with the contents of a file, along with the callback parameters to the remote server. * Box receives the response from the remote server and directs the client to POST the response to the client callback URL. The server identified by the URL interprets the response and redirects the user with the correct session ID. ## Client-callback URL Request Format The POST request that Box sends to the client callback URL takes the response from the primary callback URL and forwards it to the same URL along with the same data as the original callback. | Client Callback URL | Example | | --------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- | | Two GET parameters and one POST parameter: `http://your-client-callback-url.com/?get_param1=value1&get_param2=value2` | `POST data: post_param1=value1initial_callback_response` | The response to the client-callback request is an HTTP status 302, redirecting the user to the correct URL or to the HTML for a UI. Most often the URL points to a separate API or custom script developed for Web App Integrations, which parses the result of the primary callback URL. If you want to publish your Box platform app for all Box customers to use, make sure that the URL is publicly accessible on the internet. ## Making Integration Publicly Available To make a Box integration publicly available it needs to be listed in the App Center. Follow the Integrations guide for more details. [devconsole]: https://app.box.com/developers/console [devaccount]: https://account.box.com/signup/n/developer # Web App Integration Source: https://developer.box.com/guides/applications/web-app-integrations/index Web App Integrations allow third-party applications to become part of the Box user experience by allowing users to use such third-party applications when editing or sharing files. ## Features * **File interaction**. Users can modify, share, or edit content stored in Box using a third-party application. * **Recommended Apps support**. Integrations can appear in the Box Preview interface under **Recommended Apps**. For details, see [Recommended Web Integrations][recommended-web-integrations]. Integration example * **Scoped availability**. Integrations can be restricted to certain content types and file extensions. ## Visibility in Recommended Apps Your web application integration appears in **Recommended Apps** only if it is published in Integrations. [integrations]: /guides/applications/integrations [custom-app]: /guides/authentication/oauth2/oauth2-setup [oauth2]: /guides/authentication/oauth2 [devconsole]: https://app.box.com/developers/console [recommended-web-integrations]: https://support.box.com/hc/en-us/articles/360044195533-Installing-Recommended-Apps-in-your-Enterprise # Integrations Types Source: https://developer.box.com/guides/applications/web-app-integrations/types Currently, Box provides the Popup integration type. ## Popup Integrations In a popup integration, Box opens a panel and loads the application's callback URL configured for the integration. The application can display its own user interface for the integration in the popup. The integration receives a short-lived authorization code with this request, which can be used to connect to the Box APIs, exchange the code for an Access Token, and then use that to make API calls to Box. Popup panels use HTML ` ``` For details on working with Box Embed, see this guide. Box Embed uses the Cloud Game widget to prevent clickjacking. In this case, when the user wants to sign a document, they will have to interact with the widget and drag a cloud to the correct location before proceeding to document signing. # Box Sign Source: https://developer.box.com/guides/box-sign/index Programmatically harness the full functionality of the Box Sign web app experience by leveraging Box Sign’s API endpoints to create, list, resend, and cancel sign requests. ## Enablement The following account types support requests through the Box Sign API: Business, Business Plus, Enterprise, Enterprise Suites, Enterprise Plus, and Enterprise Advanced. To locate your account type, navigate to **Account Settings** and scroll down to the **Account Details** section of the **Account** tab. For Admin details on restricting access, please see our [support article][restrict]. ## Required scopes The following scopes must be enabled for an application before use of Box Sign's endpoints. * Read all files and folders stored in Box * Write all files and folders stored in Box * Manage signature requests Depending on the selected authentication method and enterprise's settings, your application may require Admin authorization or re-authorization before successful use of any newly selected scopes. ## Events Please see our events guide for more information. ## Webhooks Please see our webhooks guide for more information. ## Rate Limits Please see our rate limit guide for more information. ## Testing Due to the feature parity, it may be useful to familiarize yourself with [Box Sign functionality using the Box web app][webapp] before leveraging the API. As with all API endpoints, we recommend testing via [developer sandbox environment][sandbox] to eliminate the risk of impacting production content. [restrict]: https://support.box.com/hc/en-us/articles/4404076971155-Enabling-Box-Sign [webapp]: https://support.box.com/hc/en-us/articles/4404105810195-Sending-a-document-for-signature [sandbox]: https://support.box.com/hc/en-us/articles/360043697274-Managing-developer-sandboxes-for-Box-admins # List Box Sign Requests Source: https://developer.box.com/guides/box-sign/list-sign-requests ## All The get sign requests endpoint can be used to view a list of all Box Sign requests created by the user associated with the passed Access Token. ```sh cURL theme={null} curl -i -X GET "https://api.box.com/2.0/sign_requests" \ -H "authorization: Bearer " ``` ```typescript Node/TypeScript v10 theme={null} await client.signRequests.getSignRequests(); ``` ```python Python v10 theme={null} client.sign_requests.get_sign_requests() ``` ```cs .NET v10 theme={null} await client.SignRequests.GetSignRequestsAsync(); ``` ```swift Swift v10 theme={null} try await client.signRequests.getSignRequests() ``` ```java Java v10 theme={null} client.getSignRequests().getSignRequests() ``` ```java Java v5 theme={null} Iterable signRequests = BoxSignRequest.getAll(api); for (BoxSignRequest.Info signRequestInfo : signRequests) { // Do something with each `signRequestInfo`. } ``` ```python Python v4 theme={null} sign_requests = client.get_sign_requests() for sign_request in sign_requests: print(f'(Sign Request ID: {sign_request.id})') ``` ```cs .NET v6 theme={null} BoxCollectionMarkerBased signRequests = await client.SignRequestsManager.GetSignRequestsAsync(); ``` ```javascript Node v4 theme={null} const result = await client.signRequests.getAll(); console.log(`There are ${result.count} sign requests`); ``` ## By ID The get sign requests by ID endpoint can be used to view information about a specific Box Sign request. This endpoint requires the sign request's ID, which can be obtained by using the get all Box Sign requests endpoint or in the response when creating a Box Sign request. ```sh cURL theme={null} curl -i -X GET "https://api.box.com/2.0/sign_requests/" \ -H "authorization: Bearer " ``` ```typescript Node/TypeScript v10 theme={null} await client.signRequests.getSignRequestById(createdSignRequest.id!); ``` ```python Python v10 theme={null} client.sign_requests.get_sign_request_by_id(created_sign_request.id) ``` ```cs .NET v10 theme={null} await client.SignRequests.GetSignRequestByIdAsync(signRequestId: NullableUtils.Unwrap(createdSignRequest.Id)); ``` ```swift Swift v10 theme={null} try await client.signRequests.getSignRequestById(signRequestId: createdSignRequest.id!) ``` ```java Java v10 theme={null} client.getSignRequests().getSignRequestById(createdSignRequest.getId()) ``` ```java Java v5 theme={null} BoxSignRequest signRequest = new BoxSignRequest(api, id); BoxSignRequest.Info signRequestInfo = signRequest.getInfo(); //using `fields` parameter BoxSignRequest.Info signRequestInfoWithFields = signRequest.getInfo("status") ``` ```python Python v4 theme={null} sign_request = client.sign_request(sign_request_id='12345').get() print(f'Sign Request ID is {sign_request.id}') ``` ```cs .NET v6 theme={null} BoxSignRequest signRequest = await client.SignRequestsManager.GetSignRequestByIdAsync("12345"); ``` ```javascript Node v4 theme={null} const sr = await client.signRequests.getById({ sign_request_id: 12345, }); console.log( `Sign request id ${sr.id} contains ${sr.source_files.length} files` ); ``` # Resend Box Sign Request Source: https://developer.box.com/guides/box-sign/resend-sign-request The resend a Box sign request endpoint can be used to resend request emails to any remaining signers. A Box Sign request cannot be resent if the status is: `signed`, `cancelled`, `declined`, `expired`, `error_sending`, or `error_converting`. If a Box Sign request was recently sent, you will need to wait 10 minutes before resending. If you try before this time has passed you will receive a 400 error. Reminder emails can be enabled when creating a Box Sign request to avoid the need to resend the request. ```sh cURL theme={null} curl -i -X POST "https://api.box.com/2.0/sign_requests//resend" \ -H "authorization: Bearer " ``` ```java Java v5 theme={null} BoxSignRequest signRequest = new BoxSignRequest(api, id); BoxSignRequest.Info signRequestInfo = signRequest.getInfo(); signRequestInfo.resend(); ``` ```python Python v4 theme={null} sign_request = client.sign_request(sign_request_id='12345') sign_request.resend() ``` ```cs .NET v6 theme={null} await client.SignRequestsManager.ResendSignRequestAsync("12345"); ``` ```javascript Node v4 theme={null} const id = 12345; await client.signRequests.resendById({ sign_request_id: id }); console.log(`Sign request id ${sr.id} resent`); ``` # Create Sign Request with Sign Template Source: https://developer.box.com/guides/box-sign/sign-templates The Sign Request API allows you to use a predefined Box Sign template when creating a sign request. The template includes placeholders that are automatically populated with data when creating the request. ## Create Template Start with creating a Box Sign template that includes `text`, `date`, and `signature` fields you will need for you request. See the [template guides][docuprep] guide for detailed instructions. ## Get the Template ID To send a sign request, you need to pass the ID of the template you want to use. List the templates to find the `template_id`. ```json theme={null} "entries": [ { "id": "6ae28666-03c4-4ac1-80db-06a90d3b1361", "name": "Contract.pdf", "parent_folder": { "id": "157064745449", "etag": "0", "type": "folder", "sequence_id": "0", "name": "My Sign Requests" }, "source_files": [ { "id": "1216382236853", "etag": "0", "type": "file", "sequence_id": "0", "sha1": "ca9c75cda0d5e3c3c9b0a1e6d42cb5e29a211ab6", "file_version": { "id": "1327286673653", "type": "file_version", "sha1": "ca9c75cda0d5e3c3c9b0a1e6d42cb5e29a211ab6" } } ], "signers": [ { "email": "", "label": "reader", "public_id": "4Z8QZZV4", "role": "final_copy_reader", "is_in_person": false, "order": 1, "inputs": [...] }, { "email": "", "label": "signer1", "public_id": "4Z8QZZV4", "role": "signer", "is_in_person": false, "order": 1, "inputs": [...] }, { "email": "", "label": "signer2", "public_id": "13VK8794", "role": "signer", "is_in_person": false, "order": 1, "inputs": [ { "document_tag_id": "signer2_full_name", "id": "da431975-55c5-4629-86ae-3fb12dda1386", "type": "text", "text_value": null, "is_required": true, "content_type": "full_name", ... }, { "document_tag_id": null, "id": "b5a76a22-8d48-456e-a012-22a12fc91eb7", "type": "signature", ... }, { "document_tag_id": null, "id": "7e0cc4ee-b878-4739-afde-acbf69b117b2", "type": "date", "date_value": null, ... } ], } ] ... } ] ``` The response is similar to the following one (abbreviated for guide purposes). For the full response example, see Box Sign template API. You can also learn more about the specific parameters in the Create Sign Request guide. ```json theme={null} "entries": [ { "id": "6ae28666-03c4-4ac1-80db-06a90d3b1361", "name": "Contract.pdf", "parent_folder": { "id": "157064745449", "etag": "0", "type": "folder", "sequence_id": "0", "name": "My Sign Requests" }, "source_files": [ { "id": "1216382236853", "etag": "0", "type": "file", "sequence_id": "0", "sha1": "ca9c75cda0d5e3c3c9b0a1e6d42cb5e29a211ab6", "file_version": { "id": "1327286673653", "type": "file_version", "sha1": "ca9c75cda0d5e3c3c9b0a1e6d42cb5e29a211ab6" } } ], "signers": [ { "email": "", "label": "reader", "public_id": "4Z8QZZV4", "role": "final_copy_reader", "is_in_person": false, "order": 1, "inputs": [...] }, { "email": "", "label": "signer1", "public_id": "4Z8QZZV4", "role": "signer", "is_in_person": false, "order": 1, "inputs": [...] }, { "email": "", "label": "signer2", "public_id": "13VK8794", "role": "signer", "is_in_person": false, "order": 1, "inputs": [ { "document_tag_id": "signer2_full_name", "id": "da431975-55c5-4629-86ae-3fb12dda1386", "type": "text", "text_value": null, "is_required": true, "content_type": "full_name", ... }, { "document_tag_id": null, "id": "b5a76a22-8d48-456e-a012-22a12fc91eb7", "type": "signature", ... }, { "document_tag_id": null, "id": "7e0cc4ee-b878-4739-afde-acbf69b117b2", "type": "date", "date_value": null, ... } ], } ] ... } ] ``` ## Create the sign request Follow these steps to create sign request using a template: 1. In the request body, provide the `template_id`: ```json theme={null} { "template_id": "6ae28666-03c4-4ac1-80db-06a90d3b1361", "parent_folder": { "id": "123456789", "etag": "0", "type": "folder", "sequence_id": "0", "name": "My Sign Requests" }, ... } ``` 2. Add the signer email addresses and roles: ```json theme={null} { "template_id": "6ae28666-03c4-4ac1-80db-06a90d3b1361", "parent_folder": { "id": "157064745449", "etag": "0", "type": "folder", "sequence_id": "0", "name": "My Sign Requests" }, "signers": [ { "email": "signer1@sample.com", "role": "signer" }, { "email": "signer2@sample.com", "role": "signer" } ] } ``` 3. Add the `prefill_tags` to populate the fields. Make sure the signer order is the same as the one displayed on the template. If the template had `signer1` first and then `signer2`, the `POST` request must reflect the same order to assign the proper signers. ```json theme={null} { "template_id": "6ae28666-03c4-4ac1-80db-06a90d3b1361", "parent_folder": { "id": "123456789000", "etag": "0", "type": "folder", "sequence_id": "0", "name": "My Sign Requests" }, "signers": [ { "email": "signer1@sample.com", "role": "signer" }, { "email": "signer2@sample.com", "role": "signer" } ], "prefill_tags": [ { "document_tag_id": "signer1_full_name", "text_value": "Aaron Levie" }, { "document_tag_id": "signer2_full_name", "text_value": "Albert Einstein" } ] } ``` 4. Send the `POST` request. The response will be similar to the following: ```json theme={null} { "is_document_preparation_needed": false, ... "signers": [ { "email": "reader@sample.com", "role": "final_copy_reader", }, { "email": "signer1@sample.com", "role": "signer", }, { "email": "signer2@sample.com", "role": "signer", } ], "id": "d02fefd2-15fa-431f-a127-2b4525616ae6", "prefill_tags": [ { "document_tag_id": "signer1_full_name", "text_value": "Aaron Levie", }, { "document_tag_id": "signer2_full_name", "text_value": "Albert Einstein", } ], "source_files": [], "parent_folder": { "id": "123456789000", "type": "folder", "name": "My Sign Requests" }, "name": "Contract.pdf", "type": "sign-request", "status": "created", "sign_files": { "files": [ { "id": "123456789", "type": "file", "name": "Contract.pdf", } ], "is_ready_for_download": true }, "template_id": "6ae28666-03c4-4ac1-80db-06a90d3b1361" } ``` [docuprep]: https://support.box.com/hc/en-us/articles/4404094944915-Creating-templates [parentfolder]: /guides/box-sign/create-sign-request#parent-folder [signers]: /guides/box-sign/create-sign-request#signers # Suppress default Box Sign notifications Source: https://developer.box.com/guides/box-sign/suppress-sign-notifications Box Sign API allows you to suppress the default Box email notifications sent during the Sign workflow. ​​This feature facilitates the ownership of Box Sign notifications with the following options: * You can use a fully-customized email notification template to send emails from your domain. * Apart from emails, you can send push notifications or text messages.​ When you choose to suppress Box email notifications, your organization assumes responsibility for ensuring the delivery to Signers of all notifications at the appropriate time in the signing process and with the appropriate content, in compliance with all applicable laws and regulations, including with respect to obtaining Signer consent to the delivery methods used, if applicable. ## Using Box Sign API to suppress default notifications To suppress Box Sign email notifications, you must set the following parameters: 1. Set the `suppress_notifications` parameter in the `signers` object to `true` to turn the notifications off. 2. Set the `embed_url_external_user_id` parameter to specify the user who will not receive notifications. This configuration turns off the automatic Box Sign email notifications for a given user. As a result, you can configure and send your own notifications. ```sh theme={null} curl -i -X POST "https://api.box.com/2.0/sign_requests" \ -H "authorization: Bearer " \ -d '{ "signers": [ { "role": "signer", "email": "example_email@box.com" "suppress_notifications": true "embed_url_external_user_id": "1234" } ], "source_files": [ { "type": "file", "id": "123456789" } ], "parent_folder": { "type": "folder", "id": "0987654321" } }' ``` ## Signing Log entries When Box Sign default notifications are suppressed, the Signing Log will indicate that the sender has suppressed all Box Sign notifications. The log will also provide information on the system used for purposes of notification delivery and the user ID of the signer on your organization’s system, as provided to Box Sign through your API integration. # Manage hub collaborations Source: https://developer.box.com/guides/hubs-api/hubs-collaborations/hub-collaborations Box Hub collaborations control who can access a hub and at what role. You can invite users or groups by user ID, group ID, or email (for users). Roles are `editor`, `viewer`, and `co-owner`. You can only invite users who have a Box account (any plan) to collaborate on a hub. Box Hubs endpoints require the `box-version: 2025.0 header`. If you omit this header, the API returns a 400 error with the message `Missing required box-version header. Supported API versions: [2025.0].` For more information, see [Box API versioning strategy](/guides/api-calls/api-versioning-strategy/). ## Create a hub collaboration To add a user or group to a hub, call the `POST /2.0/hub_collaborations` endpoint and provide: * The hub reference (`HUB_ID`) * The collaborator's ID and type in the `accessible_by` field * The level of access granted to a hub in the `role` field ### Create by user ID ```sh Box CLI theme={null} box hubs:collaborations:create HUB_ID --role viewer --user-id USER_ID ``` ```sh cURL theme={null} curl -i -X POST "https://api.box.com/2.0/hub_collaborations" \ -H "Authorization: Bearer " \ -H "box-version: 2025.0" \ -H "Content-Type: application/json" \ -d '{ "hub": { "type": "hubs", "id": "HUB_ID" }, "accessible_by": { "type": "user", "id": "USER_ID" }, "role": "viewer" }' ``` ```typescript Node/TypeScript v10 theme={null} await client.hubCollaborations.createHubCollaborationV2025R0({ hub: new HubCollaborationCreateRequestV2025R0HubField({ id: hub.id }), accessibleBy: { type: 'user', id: user.id, } satisfies HubCollaborationCreateRequestV2025R0AccessibleByField, role: 'viewer', } satisfies HubCollaborationCreateRequestV2025R0); ``` ```python Python v10 theme={null} client.hub_collaborations.create_hub_collaboration_v2025_r0( CreateHubCollaborationV2025R0Hub(id=hub.id), CreateHubCollaborationV2025R0AccessibleBy(type="user", id=user.id), "viewer", ) ``` ```csharp .NET v10 theme={null} await client.HubCollaborations.CreateHubCollaborationV2025R0Async(requestBody: new HubCollaborationCreateRequestV2025R0(hub: new HubCollaborationCreateRequestV2025R0HubField(id: hub.Id), accessibleBy: new HubCollaborationCreateRequestV2025R0AccessibleByField(type: "user") { Id = user.Id }, role: "viewer")); ``` ```swift Swift v10 theme={null} try await client.hubCollaborations.createHubCollaborationV2025R0(requestBody: HubCollaborationCreateRequestV2025R0(hub: HubCollaborationCreateRequestV2025R0HubField(id: hub.id), accessibleBy: HubCollaborationCreateRequestV2025R0AccessibleByField(type: "user", id: user.id), role: "viewer")) ``` ```java Java v10 theme={null} client.getHubCollaborations().createHubCollaborationV2025R0(new HubCollaborationCreateRequestV2025R0(new HubCollaborationCreateRequestV2025R0HubField(hub.getId()), new HubCollaborationCreateRequestV2025R0AccessibleByField.Builder("user").id(user.getId()).build(), "viewer")); ``` ### Create by user email (login) ```sh Box CLI theme={null} box hubs:collaborations:create HUB_ID --role editor --login john@example.com ``` ```sh cURL theme={null} curl -i -X POST "https://api.box.com/2.0/hub_collaborations" \ -H "Authorization: Bearer " \ -H "box-version: 2025.0" \ -H "Content-Type: application/json" \ -d '{ "hub": { "type": "hubs", "id": "HUB_ID" }, "accessible_by": { "type": "user", "login": "john@example.com" }, "role": "editor" }' ``` ```python Python v10 theme={null} client.hub_collaborations.create_hub_collaboration_v2025_r0( CreateHubCollaborationV2025R0Hub(id=hub.id), CreateHubCollaborationV2025R0AccessibleBy(type="user", login="john@example.com"), "editor", ) ``` Replace `HUB_ID`, `USER_ID`, and the email with real values. Valid `role` values are `editor`, `viewer`, and `co-owner`. A successful response returns the new Hub collaboration object. ## List hub collaborations To list all collaborations for a hub, call the `GET /2.0/hub_collaborations` endpoint with the hub ID. ```sh Box CLI theme={null} box hubs:collaborations HUB_ID ``` ```sh cURL theme={null} curl -i -X GET "https://api.box.com/2.0/hub_collaborations?hub_id=HUB_ID" \ -H "Authorization: Bearer " \ -H "box-version: 2025.0" ``` ```typescript Node/TypeScript v10 theme={null} await client.hubCollaborations.getHubCollaborationsV2025R0({ hubId: hub.id, } satisfies GetHubCollaborationsV2025R0QueryParams); ``` ```python Python v10 theme={null} client.hub_collaborations.get_hub_collaborations_v2025_r0(hub.id) ``` ```csharp .NET v10 theme={null} await client.HubCollaborations.GetHubCollaborationsV2025R0Async(queryParams: new GetHubCollaborationsV2025R0QueryParams(hubId: hub.Id)); ``` ```swift Swift v10 theme={null} try await client.hubCollaborations.getHubCollaborationsV2025R0(queryParams: GetHubCollaborationsV2025R0QueryParams(hubId: hub.id)) ``` ```java Java v10 theme={null} client.getHubCollaborations().getHubCollaborationsV2025R0(new GetHubCollaborationsV2025R0QueryParams(hub.getId())); ``` Optional query parameters: `marker` and `limit`. For details, see [Marker-based pagination](/guides/api-calls/pagination/marker-based). ## Get a hub collaboration by ID To retrieve a single hub collaboration, call the `GET /2.0/hub_collaborations/{hub_collaboration_id}` endpoint with the collaboration ID. ```sh Box CLI theme={null} box hubs:collaborations:get HUB_COLLABORATION_ID ``` ```sh cURL theme={null} curl -i -X GET "https://api.box.com/2.0/hub_collaborations/HUB_COLLABORATION_ID" \ -H "Authorization: Bearer " \ -H "box-version: 2025.0" ``` ```typescript Node/TypeScript v10 theme={null} await client.hubCollaborations.getHubCollaborationByIdV2025R0(hubCollaborationId); ``` ```python Python v10 theme={null} client.hub_collaborations.get_hub_collaboration_by_id_v2025_r0(hub_collaboration_id) ``` ```csharp .NET v10 theme={null} await client.HubCollaborations.GetHubCollaborationByIdV2025R0Async(hubCollaborationId: hubCollaborationId); ``` ```java Java v10 theme={null} client.getHubCollaborations().getHubCollaborationByIdV2025R0(hubCollaborationId); ``` ## Update a hub collaboration To change a collaborator's role, call the `PUT /2.0/hub_collaborations/{hub_collaboration_id}` endpoint with the hub collaboration ID and the new `role`. ```sh Box CLI theme={null} box hubs:collaborations:update HUB_COLLABORATION_ID --role editor ``` ```sh cURL theme={null} curl -i -X PUT "https://api.box.com/2.0/hub_collaborations/HUB_COLLABORATION_ID" \ -H "Authorization: Bearer " \ -H "box-version: 2025.0" \ -H "Content-Type: application/json" \ -d '{ "role": "editor" }' ``` ```typescript Node/TypeScript v10 theme={null} await client.hubCollaborations.updateHubCollaborationByIdV2025R0(hubCollaborationId, { role: 'editor', } satisfies HubCollaborationUpdateRequestV2025R0); ``` ```python Python v10 theme={null} client.hub_collaborations.update_hub_collaboration_by_id_v2025_r0(hub_collaboration_id, role="editor") ``` ```csharp .NET v10 theme={null} await client.HubCollaborations.UpdateHubCollaborationByIdV2025R0Async(hubCollaborationId: hubCollaborationId, requestBody: new HubCollaborationUpdateRequestV2025R0() { Role = "editor" }); ``` ```java Java v10 theme={null} client.getHubCollaborations().updateHubCollaborationByIdV2025R0(hubCollaborationId, new HubCollaborationUpdateRequestV2025R0.Builder().role("editor").build()); ``` ## Delete a hub collaboration To remove a collaborator from a hub, call the `DELETE /2.0/hub_collaborations/{hub_collaboration_id}` endpoint with the hub collaboration ID. ```sh Box CLI theme={null} box hubs:collaborations:delete HUB_COLLABORATION_ID ``` ```sh cURL theme={null} curl -i -X DELETE "https://api.box.com/2.0/hub_collaborations/HUB_COLLABORATION_ID" \ -H "Authorization: Bearer " \ -H "box-version: 2025.0" ``` ```typescript Node/TypeScript v10 theme={null} await client.hubCollaborations.deleteHubCollaborationByIdV2025R0(hubCollaborationId); ``` ```python Python v10 theme={null} client.hub_collaborations.delete_hub_collaboration_by_id_v2025_r0(hub_collaboration_id) ``` ```csharp .NET v10 theme={null} await client.HubCollaborations.DeleteHubCollaborationByIdV2025R0Async(hubCollaborationId: hubCollaborationId); ``` ```java Java v10 theme={null} client.getHubCollaborations().deleteHubCollaborationByIdV2025R0(hubCollaborationId); ``` A successful delete returns no body (HTTP 204). ## Use cases * **Onboarding automation:** When a new hire is added to your HRIS, create a "Welcome Hub" and add them as a collaborator with the appropriate role. * **Group-based access:** Use the Box Groups API to find the right group, then add the group as a collaborator so all members get access. # Manage hub items Source: https://developer.box.com/guides/hubs-api/hubs-items/hub-items The Box Hub items API allows you to: * [List all items in a hub](#list-hub-items). * [Add or remove files, folders, and web links from a hub](#add-or-remove-hub-items). At this stage, the API supports managing files, folders, and web links only. Elements such as callouts, dividers, paragraphs, or sections must be added in the Box Hubs web interface. Content added through the API is placed in the first content block. Box Hubs endpoints require the `box-version: 2025.0 header`. If you omit this header, the API returns a 400 error with the message `Missing required box-version header. Supported API versions: [2025.0].` For more information, see [Box API versioning strategy](/guides/api-calls/api-versioning-strategy/). The `GET /2.0/hub_items` returns HTTP `207` (Multi-Status). The response body includes the status of each operation (add or remove). Follow the API reference for full response and error handling. ## List hub items To retrieve all items in a Box Hub, call the `GET /2.0/hub_items` endpoint with the hub ID. ```sh Box CLI theme={null} box hubs:items 12345 ``` ```sh cURL theme={null} curl -i -X GET "https://api.box.com/2.0/hub_items?hub_id=HUB_ID" \ -H "Authorization: Bearer " \ -H "box-version: 2025.0" ``` ```typescript Node/TypeScript v10 theme={null} await client.hubItems.getHubItemsV2025R0({ hubId: createdHub.id, } satisfies GetHubItemsV2025R0QueryParams); ``` ```python Python v10 theme={null} client.hub_items.get_hub_items_v2025_r0(created_hub.id) ``` ```csharp .NET v10 theme={null} await client.HubItems.GetHubItemsV2025R0Async(queryParams: new GetHubItemsV2025R0QueryParams(hubId: createdHub.Id)); ``` ```swift Swift v10 theme={null} try await client.hubItems.getHubItemsV2025R0(queryParams: GetHubItemsV2025R0QueryParams(hubId: createdHub.id)) ``` ```java Java v10 theme={null} client.getHubItems().getHubItemsV2025R0(new GetHubItemsV2025R0QueryParams(createdHub.getId())); ``` Replace `HUB_ID` with your hub ID. You can use optional query parameters `marker` and `limit` for pagination. The response includes an `entries` array of hub items (each with `id`, `type`, `name`). ## Add or remove hub items To add or remove items in a hub, call the `POST /2.0/hubs/{hub_id}/manage_items` endpoint with the hub ID and a list of operations. Each operation has an `action` (`add` or `remove`) and an `item` reference (`type` and `id`). ### Add a file to a hub ```sh Box CLI theme={null} box hubs:items:manage 12345 --add id=11111,type=file ``` ```sh cURL theme={null} curl -i -X POST "https://api.box.com/2.0/hubs/HUB_ID/manage_items" \ -H "Authorization: Bearer " \ -H "box-version: 2025.0" \ -H "Content-Type: application/json" \ -d '{ "operations": [ { "action": "add", "item": { "type": "file", "id": "FILE_ID" } } ] }' ``` ```typescript Node/TypeScript v10 theme={null} await client.hubItems.manageHubItemsV2025R0(createdHub.id, { operations: [ { action: 'add' as HubItemOperationV2025R0ActionField, item: new FileReferenceV2025R0({ id: file.id }), } satisfies HubItemOperationV2025R0, ], } satisfies HubItemsManageRequestV2025R0); ``` ```python Python v10 theme={null} client.hub_items.manage_hub_items_v2025_r0( created_hub.id, operations=[ HubItemOperationV2025R0( action=HubItemOperationV2025R0ActionField.ADD, item=FileReferenceV2025R0(id=file.id), ) ], ) ``` ```csharp .NET v10 theme={null} await client.HubItems.ManageHubItemsV2025R0Async(hubId: createdHub.Id, requestBody: new HubItemsManageRequestV2025R0() { Operations = Array.AsReadOnly(new [] { new HubItemOperationV2025R0(action: HubItemOperationV2025R0ActionField.Add, item: new FileReferenceV2025R0(id: file.Id)) }) }); ``` ```java Java v10 theme={null} client.getHubItems().manageHubItemsV2025R0(createdHub.getId(), new HubItemsManageRequestV2025R0.Builder().operations(Arrays.asList(new HubItemOperationV2025R0(HubItemOperationV2025R0ActionField.ADD, new FileReferenceV2025R0(file.getId())))).build()); ``` ### Add a folder to a hub ```sh Box CLI theme={null} box hubs:items:manage 12345 --add id=67890,type=folder ``` ```sh cURL theme={null} curl -i -X POST "https://api.box.com/2.0/hubs/HUB_ID/manage_items" \ -H "Authorization: Bearer " \ -H "box-version: 2025.0" \ -H "Content-Type: application/json" \ -d '{ "operations": [ { "action": "add", "item": { "type": "folder", "id": "FOLDER_ID" } } ] }' ``` ```python Python v10 theme={null} client.hub_items.manage_hub_items_v2025_r0( created_hub.id, operations=[ HubItemOperationV2025R0( action=HubItemOperationV2025R0ActionField.ADD, item=FolderReferenceV2025R0(id=folder.id), ) ], ) ``` ### Remove an item from a hub ```sh Box CLI theme={null} box hubs:items:manage 12345 --remove id=11111,type=file ``` ```sh cURL theme={null} curl -i -X POST "https://api.box.com/2.0/hubs/HUB_ID/manage_items" \ -H "Authorization: Bearer " \ -H "box-version: 2025.0" \ -H "Content-Type: application/json" \ -d '{ "operations": [ { "action": "remove", "item": { "type": "file", "id": "FILE_ID" } } ] }' ``` ```python Python v10 theme={null} client.hub_items.manage_hub_items_v2025_r0( created_hub.id, operations=[ HubItemOperationV2025R0( action=HubItemOperationV2025R0ActionField.REMOVE, item=FileReferenceV2025R0(id=file.id), ) ], ) ``` Replace `HUB_ID`, `FILE_ID`, and `FOLDER_ID` with actual IDs. For web links, use `"type": "web_link"` and the web link ID. You can combine multiple add and remove operations in a single request. ## Use cases * **Automate hub creation:** Use the Box Search API or metadata queries to find content matching criteria, then add the filtered results to a hub with the manage hub items endpoint. * **Event-driven updates:** Use webhooks to react to events (for example, a new file in a folder) and add that content to a hub automatically. # Copy a hub Source: https://developer.box.com/guides/hubs-api/hubs/copy-hub To create a copy of an existing Box Hub, call the `POST /2.0/hubs/{hub_id}/copy` endpoint with the source hub ID and optional new title and description. The original hub is not modified. Box Hubs endpoints require the `box-version: 2025.0 header`. If you omit this header, the API returns a 400 error with the message `Missing required box-version header. Supported API versions: [2025.0].` For more information, see [Box API versioning strategy](/guides/api-calls/api-versioning-strategy/). ## Copy hub ```sh Box CLI theme={null} box hubs:copy 12345 --title "HR Hub (Copy)" --description "Copy of the HR hub for a new region." ``` ```sh cURL theme={null} curl -i -X POST "https://api.box.com/2.0/hubs/HUB_ID/copy" \ -H "Authorization: Bearer " \ -H "box-version: 2025.0" \ -H "Content-Type: application/json" \ -d '{ "title": "HR Hub (Copy)", "description": "Copy of the HR hub for a new region." }' ``` ```typescript Node/TypeScript v10 theme={null} await client.hubs.copyHubV2025R0(createdHub.id, { title: copiedHubTitle, description: copiedHubDescription, } satisfies HubCopyRequestV2025R0); ``` ```python Python v10 theme={null} client.hubs.copy_hub_v2025_r0(created_hub.id, title=copied_hub_title, description=copied_hub_description) ``` ```csharp .NET v10 theme={null} await client.Hubs.CopyHubV2025R0Async(hubId: createdHub.Id, requestBody: new HubCopyRequestV2025R0() { Title = copiedHubTitle, Description = copiedHubDescription }); ``` ```swift Swift v10 theme={null} try await client.hubs.copyHubV2025R0(hubId: createdHub.id, requestBody: HubCopyRequestV2025R0(title: copiedHubTitle, description: copiedHubDescription)) ``` ```java Java v10 theme={null} client.getHubs().copyHubV2025R0(createdHub.getId(), new HubCopyRequestV2025R0.Builder().title(copiedHubTitle).description(copiedHubDescription).build()); ``` Replace `HUB_ID` with the source hub ID. Request body fields are optional. If you omit the `title` parameter, the API uses a default one. A successful response returns the new Hub object. ## Request body fields | Field | Type | Required | Description | | ------------- | ------ | -------- | ------------------------------------------------------- | | `title` | string | No | Title for the new hub. Maximum length is 50 characters. | | `description` | string | No | Description for the new hub. | # Delete a hub Source: https://developer.box.com/guides/hubs-api/hubs/delete-hub To delete a Box Hub, call the `DELETE /2.0/hubs/{hub_id}` endpoint with the hub ID. The hub and its association with content are removed. The underlying files and folders in Box are not deleted. Box Hubs endpoints require the `box-version: 2025.0 header`. If you omit this header, the API returns a 400 error with the message `Missing required box-version header. Supported API versions: [2025.0].` For more information, see [Box API versioning strategy](/guides/api-calls/api-versioning-strategy/). ## Delete hub ```sh Box CLI theme={null} box hubs:delete 12345 ``` ```sh cURL theme={null} curl -i -X DELETE "https://api.box.com/2.0/hubs/HUB_ID" \ -H "Authorization: Bearer " \ -H "box-version: 2025.0" ``` ```typescript Node/TypeScript v10 theme={null} await client.hubs.deleteHubByIdV2025R0(hubId); ``` ```python Python v10 theme={null} client.hubs.delete_hub_by_id_v2025_r0(hub_id) ``` ```csharp .NET v10 theme={null} await client.Hubs.DeleteHubByIdV2025R0Async(hubId: hubId); ``` ```swift Swift v10 theme={null} try await client.hubs.deleteHubByIdV2025R0(hubId: hubId) ``` ```java Java v10 theme={null} client.getHubs().deleteHubByIdV2025R0(hubId); ``` Replace `HUB_ID` with the actual hub ID. A successful response has no response body (HTTP 204). The caller must have permission to delete the hub. # Get a hub Source: https://developer.box.com/guides/hubs-api/hubs/get-hub To retrieve details for a single Box Hub, call the `GET /2.0/hubs/{hub_id}` endpoint with the hub's ID. You can find the hub ID in the Box Hubs web interface URL (for example, `https://*.app.box.com/hubs/12345` has hub ID `12345`). Box Hubs endpoints require the `box-version: 2025.0 header`. If you omit this header, the API returns a 400 error with the message `Missing required box-version header. Supported API versions: [2025.0].` For more information, see [Box API versioning strategy](/guides/api-calls/api-versioning-strategy/). ## Get hub by ID ```sh Box CLI theme={null} box hubs:get 12345 ``` ```sh cURL theme={null} curl -i -X GET "https://api.box.com/2.0/hubs/HUB_ID" \ -H "Authorization: Bearer " \ -H "box-version: 2025.0" ``` ```typescript Node/TypeScript v10 theme={null} await client.hubs.getHubByIdV2025R0(hubId); ``` ```python Python v10 theme={null} client.hubs.get_hub_by_id_v2025_r0(hub_id) ``` ```csharp .NET v10 theme={null} await client.Hubs.GetHubByIdV2025R0Async(hubId: hubId); ``` ```swift Swift v10 theme={null} try await client.hubs.getHubByIdV2025R0(hubId: hubId) ``` ```java Java v10 theme={null} client.getHubs().getHubByIdV2025R0(hubId); ``` Replace `HUB_ID` (or `hubId` / `hub_id`) with the actual hub ID. A successful response returns the Hub object. # List hubs Source: https://developer.box.com/guides/hubs-api/hubs/list-hubs You can list Box Hubs in two ways: * [All hubs for the requesting user](#list-hubs-for-the-requesting-user) * [All hubs for the enterprise](#list-hubs-for-the-enterprise) Use query parameters to search, filter by scope, and sort results. Box Hubs endpoints require the `box-version: 2025.0 header`. If you omit this header, the API returns a 400 error with the message `Missing required box-version header. Supported API versions: [2025.0].` For more information, see [Box API versioning strategy](/guides/api-calls/api-versioning-strategy/). ## List hubs for the requesting user To retrieve all Box Hubs accessible to the authenticated user, call the `GET /2.0/hubs` endpoint. ```sh Box CLI theme={null} box hubs --scope all --sort name --direction ASC ``` ```sh cURL theme={null} curl -i -X GET "https://api.box.com/2.0/hubs?scope=all&sort=name&direction=ASC" \ -H "Authorization: Bearer " \ -H "box-version: 2025.0" ``` ```typescript Node/TypeScript v10 theme={null} await client.hubs.getHubsV2025R0({ scope: 'all', sort: 'name', direction: 'ASC' as GetHubsV2025R0QueryParamsDirectionField, } satisfies GetHubsV2025R0QueryParams); ``` ```python Python v10 theme={null} client.hubs.get_hubs_v2025_r0(scope="all", sort="name", direction=GetHubsV2025R0Direction.ASC) ``` ```csharp .NET v10 theme={null} await client.Hubs.GetHubsV2025R0Async(queryParams: new GetHubsV2025R0QueryParams() { Scope = "all", Sort = "name", Direction = GetHubsV2025R0QueryParamsDirectionField.Asc }); ``` ```swift Swift v10 theme={null} try await client.hubs.getHubsV2025R0(queryParams: GetHubsV2025R0QueryParams(scope: "all", sort: "name", direction: GetHubsV2025R0QueryParamsDirectionField.asc)) ``` ```java Java v10 theme={null} client.getHubs().getHubsV2025R0(new GetHubsV2025R0QueryParams.Builder().scope("all").sort("name").direction(GetHubsV2025R0QueryParamsDirectionField.ASC).build()); ``` ### Query parameters (list hubs for user) | Parameter | Type | Required | Description | | ----------- | ------- | -------- | ------------------------------------------------------------------------------------------------------- | | `query` | string | No | Search string for Box Hubs. | | `scope` | string | No | `editable`, `view_only`, or `all`. Default is `all`. | | `sort` | string | No | Sort by `name`, `updated_at`, `last_accessed_at`, `view_count`, or `relevance`. Default is `relevance`. | | `direction` | string | No | `ASC` or `DESC`. | | `marker` | string | No | Marker for marker-based pagination. | | `limit` | integer | No | Maximum items per page (must not exceed 1000). | ## List hubs for the enterprise Admins or Hub Co-admins of an enterprise with Global Content Manager (GCM) scope can list all Box Hubs for the enterprise using the `GET /2.0/enterprise_hubs` endpoint. ```sh Box CLI theme={null} box hubs:enterprise --sort name --direction ASC ``` ```sh cURL theme={null} curl -i -X GET "https://api.box.com/2.0/enterprise_hubs?scope=all&sort=name&direction=ASC" \ -H "Authorization: Bearer " \ -H "box-version: 2025.0" ``` ```typescript Node/TypeScript v10 theme={null} await client.hubs.getEnterpriseHubsV2025R0({ scope: 'all', sort: 'name', direction: 'ASC' as GetEnterpriseHubsV2025R0QueryParamsDirectionField, } satisfies GetEnterpriseHubsV2025R0QueryParams); ``` ```python Python v10 theme={null} client.hubs.get_enterprise_hubs_v2025_r0(scope="all", sort="name", direction=GetEnterpriseHubsV2025R0Direction.ASC) ``` ```csharp .NET v10 theme={null} await client.Hubs.GetEnterpriseHubsV2025R0Async(queryParams: new GetEnterpriseHubsV2025R0QueryParams() { Scope = "all", Sort = "name", Direction = GetEnterpriseHubsV2025R0QueryParamsDirectionField.Asc }); ``` ```swift Swift v10 theme={null} try await client.hubs.getEnterpriseHubsV2025R0(queryParams: GetEnterpriseHubsV2025R0QueryParams(scope: "all", sort: "name", direction: GetEnterpriseHubsV2025R0QueryParamsDirectionField.asc)) ``` ```java Java v10 theme={null} client.getHubs().getEnterpriseHubsV2025R0(new GetEnterpriseHubsV2025R0QueryParams.Builder().scope("all").sort("name").direction(GetEnterpriseHubsV2025R0QueryParamsDirectionField.ASC).build()); ``` Both endpoints return a list of hubs with pagination fields (`limit`, `next_marker`). Use the API reference for full parameter descriptions and limitations. # Update a hub Source: https://developer.box.com/guides/hubs-api/hubs/update-hub To update an existing Box Hub, call the `PUT /2.0/hubs/{hub_id}` endpoint with the hub ID and the fields you want to change. You can update the title, description, AI settings, and collaboration restrictions. Box Hubs endpoints require the `box-version: 2025.0 header`. If you omit this header, the API returns a 400 error with the message `Missing required box-version header. Supported API versions: [2025.0].` For more information, see [Box API versioning strategy](/guides/api-calls/api-versioning-strategy/). ## Update hub ```sh Box CLI theme={null} box hubs:update 12345 --title "HR Hub" --description "Updated description for HR policies and onboarding." --ai-enabled ``` ```sh cURL theme={null} curl -i -X PUT "https://api.box.com/2.0/hubs/HUB_ID" \ -H "Authorization: Bearer " \ -H "box-version: 2025.0" \ -H "Content-Type: application/json" \ -d '{ "title": "HR Hub", "description": "Updated description for HR policies and onboarding.", "is_ai_enabled": true }' ``` ```typescript Node/TypeScript v10 theme={null} await client.hubs.updateHubByIdV2025R0(hubId, { title: newHubTitle, description: newHubDescription, } satisfies HubUpdateRequestV2025R0); ``` ```python Python v10 theme={null} client.hubs.update_hub_by_id_v2025_r0(hub_id, title=new_hub_title, description=new_hub_description) ``` ```csharp .NET v10 theme={null} await client.Hubs.UpdateHubByIdV2025R0Async(hubId: hubId, requestBody: new HubUpdateRequestV2025R0() { Title = newHubTitle, Description = newHubDescription }); ``` ```swift Swift v10 theme={null} try await client.hubs.updateHubByIdV2025R0(hubId: hubId, requestBody: HubUpdateRequestV2025R0(title: newHubTitle, description: newHubDescription)) ``` ```java Java v10 theme={null} client.getHubs().updateHubByIdV2025R0(hubId, new HubUpdateRequestV2025R0.Builder().title(newHubTitle).description(newHubDescription).build()); ``` Replace `HUB_ID` with the actual hub ID. Request body fields are optional. Include only the fields you want to update. ## Request body fields | Field | Type | Required | Description | | ------------------------------------------- | ------- | -------- | ------------------------------------------------------ | | `title` | string | No | Title of the Box Hub. Maximum length is 50 characters. | | `description` | string | No | Description of the Box Hub. | | `is_ai_enabled` | boolean | No | Whether AI features are enabled for the hub. | | `is_collaboration_restricted_to_enterprise` | boolean | No | Whether collaboration is restricted to the enterprise. | A successful response returns the updated Hub object. # Working with Box Sign Source: https://developer.box.com/sign/index Working with box sign image This learning page provides developers with practical insights into working with [Box Sign][sign], aiming to facilitate the integration of the Box Platform Sign engine into their applications. ## Quick start Use the [Quick start][quick-start] to go straight into the creation of a signature request. ## Technical use cases In the [Technical use cases][technical-use-cases], you will learn how to handle the different types of documents that can be used in a signature request: from unstructured documents that require a preparation step, through templates, to generated ready to sign documents. ## Request Options In the [Request options][request-options], you will find a detailed exploration of the available customization and configuration options when sending signing requests through the Box Sign API. Learn how to tailor the signing experience to match your application's user interface, workflow, and specific requirements. Let's get started! [sign]: https://www.box.com/esignature [quick-start]: /sign/quick-start [request-options]: /sign/request-options [technical-use-cases]: /sign/technical-use-cases # API Basics Source: https://developer.box.com/sign/quick-start/api-basics ## Sign API The Sign request endpoint is used to create and manage signature requests. You can create, resend, and cancel signature requests. You can also list all signature requests and get details of a specific signature request. The endpoint is `https://{api.box.com}/2.0/sign_requests`. The following table lists the operations that you can perform on this endpoint. | Operation | Endpoint | Description | | --------- | --------------------------- | -------------------------------------------- | | GET | `/sign_requests` | List all signature requests. | | GET | `/sign_requests/:id` | Get details of a specific signature request. | | POST | `/sign_requests` | Create a signature request. | | POST | `/sign_requests/:id/resend` | Resend a signature request. | | POST | `/sign_requests/:id/cancel` | Cancel a signature request. | For full details on the request and response parameters, see the [Sign request API reference][sign-api-reference]. ## Sign templates API The Sign templates endpoint is used to list and get details of a template. You can not create, edit, or delete templates using the API. These templates are exclusively managed in the Box web application. The endpoint is `https://{api.box.com}/2.0/sign_templates`. The following table lists the operations that you can perform on this endpoint. | Operation | Endpoint | Description | | --------- | --------------------- | ----------------------------------- | | GET | `/sign_templates` | List all templates. | | GET | `/sign_templates/:id` | Get details of a specific template. | For a full details on the request and response parameters, see the [Sign template request API reference][sign-api-template-ref]. [sign-api-reference]: /reference/resources/sign-request [sign-api-template-ref]: /reference/resources/sign-template # Quick start Source: https://developer.box.com/sign/quick-start/index Get a sense of how the [Box Sign API][api-basics] is structured and how to create your first signature request. The Sign API does not follow the traditional CRUD model. You can create, resend, and cancel signature requests. You can also list all signature requests and get details of a specific signature request. Sign Templates API is read-only. You can list all templates and get details of a specific template. Once you get a sense of the API, you can create [your first signature request][quick-start]. [api-basics]: /sign/quick-start/api-basics [quick-start]: /sign/quick-start/your-first-request # Your first request Source: https://developer.box.com/sign/quick-start/your-first-request Imagine that you have a document stored in Box and you want to send it to a customer for signature. At a minimum your app needs to know what document to sign, where to store the signed document, and the signer email. ## Creating a signature request You can use the Box Sign API or one of the available SDKs to create a signature request. See the example: ```sh cURL theme={null} curl --location 'https://api.box.com/2.0/sign_requests' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer ' \ --data-raw '{ "is_document_preparation_needed": true, "parent_folder": { "id": "234102987614", "type": "folder" }, "source_files": [ { "id": "1355143830404", "type": "file" } ], "signers": [ { "email": "signer@example.com", "role": "signer" } ] }' ``` ```python Python Gen SDK theme={null} def sign_doc_single( client: Client, document_id: str, destination_folder_id: str, signer_email: str, prep_needed: bool = False, ) -> SignRequest: # Sign request params source_file = FileBase(id=document_id, type=FileBaseTypeField.FILE) destination_folder = FolderMini( id=destination_folder_id, type=FolderBaseTypeField.FOLDER ) signer = SignRequestCreateSigner(signer_email) # sign document sign_request = client.sign_requests.create_sign_request( signers=[signer], parent_folder=destination_folder, source_files=[source_file], is_document_preparation_needed=prep_needed, ) return sign_request def main(): conf = ConfigOAuth() client = get_client_oauth(conf) # Simple sign a pdf request with preparation sign_pdf_prep = sign_doc_single( client, SIMPLE_PDF, SIGN_DOCS_FOLDER, SIGNER_A, True ) if sign_pdf_prep.prepare_url is not None: open_browser(sign_pdf_prep.prepare_url) ``` This will result in a signature request with a prepare document URL (simplified): ```json cURL theme={null} { "is_document_preparation_needed": true, "signers": [ { "email": "requester@example.com", "role": "final_copy_reader", }, { "email": "signer@example.com", "role": "signer", } ], "id": "348decab-48a8-4f2c-9436-8967afebf7bb", "prepare_url": "https://app.box.com/sign/document/xyz-abc-123/.../prepare_doc/", "source_files": [ { "id": "1355143830404", "type": "file", } ], "parent_folder": { "id": "234102987614", "type": "folder", }, "name": "Simple-PDF.pdf", "type": "sign-request", "status": "converting", "sign_files": { "files": [ { "id": "1381301154812", "type": "file", } ], "is_ready_for_download": true }, "template_id": null } ``` ```YAML Python Gen SDK theme={null} Simple sign request with prep: xyz-abc-123 Status: converting Signers: signer@example.com Prepare url: https://app.box.com/sign/document/xyz-abc-123/.../prepare_doc/ ``` ## Check the status of the signature request Creating the signature request is an asynchronous process, and can generate errors. Your application should check the status of the request before proceeding, and handle any errors. A signature request can have the following statuses: Signature flow * `converting`: The file is converted to a `.pdf` for the signing process once the sign request is sent. * `error_converting`: An issue occurred while converting the file to a `.pdf`. * `created`: When the `document_preparation_is_needed` is set to `true`, but the `prepare_url` has not yet been visited. * `sent`: The request was successfully sent, but no signer has interacted with it. * `error_sending`: An issue occurred while sending the request. * `viewed`: The first, or only, signer clicked on **Review document** in the signing email or visited the signing URL. * `downloaded`: The document was downloaded by the signer. * `signed`: All signers completed the request. * `signed and downloaded`: The document was signed and downloaded by the signer. * `declined`: If any signer declines the request. * `cancelled`: If the request is cancelled via UI or API. * `expired`: The date of expiration has passed with outstanding, incomplete signatures. * `finalizing`: All signers have signed the request, but the final document with signatures and the signing log have not been generated yet. * `error_finalizing`: The `finalizing` phase did not complete successfully. ## Preparing the document Depending on your technical use case you may need to prepare the document. In this specific example, we are signing a PDF, and the Box Sign engine has no idea where to place the signature pad field or any other inputs. This is why we used the `is_document_preparation_needed` flag. If a prepare URL is present, then your application should open the prepare URL in a browser, where the requester can add the signature pad field and any other inputs needed for the signer to complete the document. Once the document is prepared, the requester can send the signature request to the signer. This preparation step is not always necessary. Take a look at the [technical use cases][technical-use-cases] for more information. ## Completing the signature request The signer then receives an email from Box with a link to the signature request. The signer can click the link and sign the document. When the process is completed, both a signature log containing metadata and the signed document are stored in the destination folder. Congratulations! You have successfully created your first signature request. This represents the basic use case for Box Sign. The `create` method has many options that you can use to customize your signature request. Be sure to check the [request options][request-options], and the [technical use cases][technical-use-cases] sections for more information. [request-options]: /sign/request-options [technical-use-cases]: /sign/technical-use-cases # Custom email and notifications Source: https://developer.box.com/sign/request-options/custom-email ## Email subject and body By default, the email sent to the signers contains a link to the document, a generic subject, and a generic message. If you are using templates managed within Box, the subject and message body can be set in the template itself. However, if you are not using templates, you can still customize the email messages sent to the signers by passing the `email_subject` and the `email_message` parameters. Both parameters accept strings, but the `email_message` parameter also accepts HTML with some limitations. Only some HTML tags are allowed. Links included in the message are also converted to hyperlinks in the email. The message parameter may contain the following HTML tags: * `a`, `abbr`, `acronym`, `b`, `blockquote`, `code`, `em`, `i`, `ul`, `li`, `ol`, `strong` Custom styles on these tags are not allowed. Be aware that when the text to HTML ratio is too high, the email may end up in spam filters or clipped. For example: ```sh cURL theme={null} curl --location 'https://api.box.com/2.0/sign_requests' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer ej...3t' \ --data-raw '{ "email_subject": "All we need is your signature to get started", "parent_folder": { "id": "234102987614", "type": "folder" }, "source_files": [ { "id": "1358047520478", "type": "file" } ], "signers": [ { "email": "signer@example.com", "role": "signer" } ] }' ``` ```python Python Gen SDK theme={null} def sign_doc_single_more_options( client: Client, ... email_subject: str = None, email_message: str = None, ) -> SignRequest: ... # sign document sign_request = client.sign_requests.create_sign_request( ... email_subject=email_subject, email_message=email_message, ) return sign_request def main(): ... # Sign with custom email subject sign_custom_email_subject = sign_doc_single_more_options( client, SIMPLE_PDF, SIGN_DOCS_FOLDER, SIGNER_A, prep_needed=False, email_subject="All we need is your signature to get started", ) ``` ## Manual notification By now, you've noticed that the signature request sends an email notification to the signers by default. This email is sent from a `box.com` domain and email system. You can take over the notification process by setting the `embed_url_external_user_id` parameter to an identifier of your choice for a specific signer. By setting this parameter, the signer will not receive an email notification, and within the signature request, you get back both an `embed_url` and an `iframeable_embed_url`. The `embed_url` can be opened directly, so it is suitable for your app to send it in an email, or by any other notifications system for the signer to open. The `iframeable_embed_url` is suited to be used with the [Box Embedded Sign Client][embed], which allows you to embed the Box Sign client on an iframe within your web app. For example see this request: ```bash theme={null} --header 'Content-Type: application/json' \ --header 'Authorization: Bearer fN...dD' \ --data-raw '{ "is_document_preparation_needed": false, "parent_folder": { "id": "234102987614", "type": "folder" }, "source_files": [ { "id": "1355143830404", "type": "file" } ], "signers": [ { "email": "signer@example.com", "embed_url_external_user_id": "1234", "role": "signer" } ] }' ``` ```python Python Gen SDK theme={null} def sign_doc_embed_url( client: Client, document_id: str, destination_folder_id: str, signer_email: str, signer_embed_url_id: str, ) -> SignRequest: # Sign request params source_file = FileBase(id=document_id, type=FileBaseTypeField.FILE) destination_folder = FolderMini( id=destination_folder_id, type=FolderBaseTypeField.FOLDER ) signer = SignRequestCreateSigner( email=signer_email, embed_url_external_user_id=signer_embed_url_id, ) # sign document sign_request = client.sign_requests.create_sign_request( signers=[signer], parent_folder=destination_folder, source_files=[source_file], ) return sign_request def main(): """Simple script to demonstrate how to use the Box SDK""" conf = ConfigOAuth() client = get_client_oauth(conf) # Sign with phone verification sign_with_embed_url = sign_doc_embed_url( client, SIMPLE_PDF, SIGN_DOCS_FOLDER, SIGNER_A, SIGNER_A_EXTERNAL_ID, ) check_sign_request(sign_with_embed_url) ``` Returns (simplified): ```json theme={null} { "is_document_preparation_needed": false, "signers": [ { "email": "sender@example.com", "role": "final_copy_reader", }, { "email": "signer@example.com", "role": "signer", "embed_url_external_user_id": "1234", "embed_url": "https://app.box.com/sign/document/22a990ce-4e24-463b-b2f4-124820fe161a/9331fe9ac85650d61645d4b0fd30fe3e0ebee7921720ab6ecca587654d3cd875/", "iframeable_embed_url": "https://app.box.com/embed/sign/document/22a990ce-4e24-463b-b2f4-124820fe161a/9331fe9ac85650d61645d4b0fd30fe3e0ebee7921720ab6ecca587654d3cd875/" } ], "id": "22a990ce-4e24-463b-b2f4-124820fe161a", } ``` ```yaml theme={null} Simple sign request: 22a990ce-4e24-463b-b2f4-124820fe161a-defddc79c946 Status: created Signers: 2 final_copy_reader: sender@example.com signer: signer@example.com embed_url: https://app.box.com/sign/document/... iframeable_embed_url: https://app.box.com/embed/sign/document/... Prepare url: None ``` You can now take the embedded URLs and use your own notification process or embed the signature client within your own app. [embed]: /guides/box-sign/embedded-sign-client # Redirect URLs Source: https://developer.box.com/sign/request-options/custom-urls Often after signing a document your company might want to redirect the user to a specific web page like a thank you or an onboarding page. There are two features to support these requirements. When the signer completes the signature process, they can be redirected to a web page. The same can happen when the signer declines the signature request. We can customize these pages by passing the `redirect_url` and `decline_redirect_url` parameters. Custom redirect pages For example: ```sh cURL theme={null} curl --location 'https://api.box.com/2.0/sign_requests' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer ej...3t' \ --data-raw '{ "is_document_preparation_needed": true, "redirect_url": "https://community.box.com/", "declined_redirect_url": "https://developer.box.com/", "parent_folder": { "id": "234102987614", "type": "folder" }, "source_files": [ { "id": "1358047520478", "type": "file" } ], "signers": [ { "email": "signer@example.com", "role": "signer" } ] }' ``` ```python Python Gen SDK theme={null} def sign_doc_single_more_options( ... redirect_url: str = None, declined_redirect_url: str = None, ) -> SignRequest: ... # sign document sign_request = client.sign_requests.create_sign_request( ... redirect_url=redirect_url, declined_redirect_url=declined_redirect_url, ) return sign_request def main(): ... # Sign with redirects sign_with_redirects = sign_doc_single_more_options( client, SIMPLE_PDF, SIGN_DOCS_FOLDER, SIGNER_A, prep_needed=False, redirect_url="https://community.box.com/", declined_redirect_url="https://developer.box.com/", ) check_sign_request(sign_with_redirects) ``` If you sign you’ll be redirected to our forum page. If you decline you’ll be redirected to our developer page. # Extra security (2FA) Source: https://developer.box.com/sign/request-options/extra-security Box Sign enables senders to provide an [additional layer of security][2FA] for their signature requests and reusable templates. You can require signers to verify their identity through CAC/PIV smart card authentication, SMS multifactor authentication, or Box account login. A password can be added alongside any of these verification methods for an extra layer of protection. 2FA Signature request You can add the additional layer of security in a template or when you create a signature request. ## Verification method (recommended) The `verification_method` property on the `signer` object provides a unified way to configure signer verification when you create a sign request. This approach is recommended for new integrations because it uses a consistent structure across all verification types. Set the `type` field to specify which method to use. Supported types: | Type | Description | | --------- | ----------------------------------------------------------------------------------- | | `cac_piv` | Requires the signer to verify with a CAC/PIV smart card. | | `phone` | Requires the signer to complete SMS verification. Include the `phone_number` field. | | `login` | Requires the signer to log in to their Box account before signing. | When you query a sign request or sign template, the `verification_method` property on each signer shows which verification method is set. A `null` value means the signer doesn't need to complete verification. If you set both `verification_method` and a legacy verification property (such as `login_required` or `verification_phone_number`) on the same signer, `verification_method` takes precedence. The API ignores the legacy property. ### CAC/PIV smart card verification To require a signer to verify their identity with a CAC/PIV smart card, set `verification_method` on the signer to `{ "type": "cac_piv" }`. Your enterprise must have CAC/PIV permissions enabled to use smart card authentication. If the enterprise does not have the required permissions, the API returns a `403 Forbidden` error. Please contact your account team to learn more about the CAC/PIV smart card authentication. If the sign request has multiple signers, you must provide a signing order when using `cac_piv` as the verification method. For a single signer, signing order is not required. ```sh cURL theme={null} curl --location 'https://api.box.com/2.0/sign_requests' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer ej...3t' \ --data-raw '{ "parent_folder": { "id": "234102987614", "type": "folder" }, "source_files": [ { "id": "1358047520478", "type": "file" } ], "signers": [ { "email": "signer@example.com", "role": "signer", "verification_method": { "type": "cac_piv" } } ] }' ``` ### SMS verification To require SMS verification, set `verification_method` on the signer to `{ "type": "phone", "phone_number": "" }`. The phone number must include a country code, prefixed with either `+` or `00` (for example, `+15551232190` or `0015551232190`). ```sh cURL theme={null} curl --location 'https://api.box.com/2.0/sign_requests' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer ej...3t' \ --data-raw '{ "parent_folder": { "id": "234102987614", "type": "folder" }, "source_files": [ { "id": "1358047520478", "type": "file" } ], "signers": [ { "email": "signer@example.com", "role": "signer", "verification_method": { "type": "phone", "phone_number": "+15551232190" } } ] }' ``` ### Login verification To require the signer to log in to their Box account before signing, set `verification_method` on the signer to `{ "type": "login" }`. This is the recommended alternative to the `login_required` parameter. ```sh cURL theme={null} curl --location 'https://api.box.com/2.0/sign_requests' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer ej...3t' \ --data-raw '{ "parent_folder": { "id": "234102987614", "type": "folder" }, "source_files": [ { "id": "1358047520478", "type": "file" } ], "signers": [ { "email": "signer@example.com", "role": "signer", "verification_method": { "type": "login" } } ] }' ``` ## Password verification You can require the signer to use a password to open the signature request by passing the `password` parameter in the `signer` object. For example: ```sh cURL theme={null} curl --location 'https://api.box.com/2.0/sign_requests' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer ej...3t' \ --data-raw '{ "is_document_preparation_needed": true, "parent_folder": { "id": "234102987614", "type": "folder" }, "source_files": [ { "id": "1358047520478", "type": "file" } ], "signers": [ { "email": "verify@example.com", "role": "signer", "password": "1234" } ] }' ``` ```python Python Gen SDK theme={null} def sign_doc_verify_password( client: Client, document_id: str, destination_folder_id: str, signer_email: str, signer_password: str, ) -> SignRequest: # Sign request params source_file = FileBase(id=document_id, type=FileBaseTypeField.FILE) destination_folder = FolderMini( id=destination_folder_id, type=FolderBaseTypeField.FOLDER ) # signer signer = SignRequestCreateSigner( email=signer_email, password=signer_password, ) # sign document sign_request = client.sign_requests.create_sign_request( signers=[signer], parent_folder=destination_folder, source_files=[source_file], ) return sign_request def main(): ... # Sign with phone verification sign_with_password_verification = sign_doc_verify_password( client, SIMPLE_PDF, SIGN_DOCS_FOLDER, SIGNER_A, "1234", ) ``` Once the signer opens the signature request they should see something like this: Password verification pop-up As the password verification is done on the first step, it prevents the signer from accessing the document until the correct password is provided. ## SMS verification (legacy) You can also configure SMS verification using the `verification_phone_number` parameter on the signer object. This approach is fully supported, but for new integrations we recommend using `verification_method` instead for a consistent experience across all verification types. To require the signer to complete SMS verification, pass the `verification_phone_number` parameter along with their phone number. For example: ```sh cURL theme={null} curl --location 'https://api.box.com/2.0/sign_requests' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer ej...3t' \ --data-raw '{ "is_document_preparation_needed": true, "is_phone_verification_required_to_view": true, "parent_folder": { "id": "234102987614", "type": "folder" }, "source_files": [ { "id": "1358047520478", "type": "file" } ], "signers": [ { "email": "verify@example.com", "role": "signer", "verification_phone_number": "+15551232190" } ] }' ``` ```python Python Gen SDK theme={null} def sign_doc_verify_phone( client: Client, document_id: str, destination_folder_id: str, signer_email: str, signer_phone: str, ) -> SignRequest: # Sign request params source_file = FileBase(id=document_id, type=FileBaseTypeField.FILE) destination_folder = FolderMini( id=destination_folder_id, type=FolderBaseTypeField.FOLDER ) signer = SignRequestCreateSigner( email=signer_email, verification_phone_number=signer_phone, ) # sign document sign_request = client.sign_requests.create_sign_request( signers=[signer], parent_folder=destination_folder, source_files=[source_file], is_phone_verification_required_to_view=True, ) return sign_request def main(): ... # Sign with phone verification sign_with_phone_verification = sign_doc_verify_phone( client, SIMPLE_PDF, SIGN_DOCS_FOLDER, SIGNER_A, SIGNER_A_PHONE, ) check_sign_request(sign_with_phone_verification) ``` When the signer tries to access the signature request an SMS verification dialog pops up: Phone verification Then the signer is prompted to enter the code sent in an SMS: Entering the SMS code By default, SMS verification is required at the signing step, which means the signer can view the document before completing the verification. To require SMS verification before the signer can view the document, set the `is_phone_verification_required_to_view` parameter to `true` when creating the sign request. [2FA]: https://support.box.com/hc/en-us/articles/4406861109907-Additional-Signer-Authentication # In person signatures Source: https://developer.box.com/sign/request-options/in-person Imagine your application is used by a salesperson when they are face to face with a customer and an immediate signature is required, for example, to subscribe to a service or to confirm a purchase. In this case, the salesperson can use your application to create a signature request and then hand over the device to the customer to sign the document, immediately closing the deal. Doing this using the Box web application, for example from a template, is very straightforward. You set the signer or signers email so they can receive a copy of the signed document, flag them as in person, and as soon as you send the request, the Sign interface opens requesting the signature for the first signer, then for the second signer, and so on. In order to use this within your application, you need to create a signature request with the `is_in_person` flag set to `true` for each signer. However because your application needs to show the Sign interface to the signer, you also need to use the `embed_url_external_user_id`so that you get back the embedded URLs, and then either open a browser window or use an iframe to display the signature interface. In person signing loops through signers ## Create an in person signature request Let's use a template with a single signer as an example: ```sh cURL theme={null} curl --location 'https://api.box.com/2.0/sign_requests' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer Le...Cb' \ --data-raw '{ "template_id": "ee9a689e-96b6-4076-92a0-b9b765eb09ca", "parent_folder": { "id": "234102987614", "type": "folder" }, "signers": [ { "email": "signer@example.com", "role": "signer", "is_in_person": true, "embed_url_external_user_id": "1234" } ] }' ``` ```python Python Gen SDK theme={null} def sign_doc_in_person( client: Client, document_id: str, destination_folder_id: str, signer_email: str, signer_embed_url_id: str, ) -> SignRequest: # Sign request params source_file = FileBase(id=document_id, type=FileBaseTypeField.FILE) destination_folder = FolderMini( id=destination_folder_id, type=FolderBaseTypeField.FOLDER ) signer = SignRequestCreateSigner( email=signer_email, embed_url_external_user_id=signer_embed_url_id, is_in_person=True, ) # sign document sign_request = client.sign_requests.create_sign_request( signers=[signer], parent_folder=destination_folder, source_files=[source_file], ) return sign_request def main(): """Simple script to demonstrate how to use the Box SDK""" conf = ConfigOAuth() client = get_client_oauth(conf) # Sign with phone verification sign_with_embed_url = sign_doc_embed_url( client, SIMPLE_PDF, SIGN_DOCS_FOLDER, SIGNER_A, SIGNER_A_EXTERNAL_ID, ) check_sign_request(sign_with_embed_url) ``` Resulting in (simplified): ```json theme={null} { "signers": [ { "email": "sender@example.com", "role": "final_copy_reader", "is_in_person": false, }, { "email": "signer@example.com", "role": "signer", "is_in_person": true, "embed_url_external_user_id": "1234", "embed_url": "https://app.box.com/sign/document/...", "iframeable_embed_url": "https://app.box.com/embed/sign/document/..." } ], "id": "a9159d31-d2fb-4e88-9306-02c00de013d1", "parent_folder": { "id": "234102987614", "type": "folder", "name": "signed docs" }, "name": "Simple-PDF (1).pdf", "type": "sign-request", "status": "created", "template_id": "ee9a689e-96b6-4076-92a0-b9b765eb09ca" } ``` ```yaml theme={null} Simple sign request: a9159d31-d2fb-4e88-9306-02c00de013d1 Status: created Signers: 2 final_copy_reader: sender@example.com signer: signer@example.com embed_url: https://app.box.com/sign/document/... iframeable_embed_url: https://app.box.com/embed/sign/document/... Prepare url: None ``` Notice the `embed_url` and `iframeable_embed_url` in the response. Now when we browse to the embed URL, you see the signature interface: In person signing Once finished the signer will receive a copy of the signed document via their email. ## Multiple in person signers As long as the signer is flagged as `is_in_person`, the signing interface cycles through all the signers in the request. For example, if you add a second signer to the request: ```sh cURL theme={null} curl --location 'https://api.box.com/2.0/sign_requests' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer Le...Cb' \ --data-raw '{ "template_id": "ee9a689e-96b6-4076-92a0-b9b765eb09ca", "parent_folder": { "id": "234102987614", "type": "folder" }, "signers": [ { "email": "signer_a@example.com", "role": "signer", "is_in_person": true, "embed_url_external_user_id": "1234" }, { "email": "signer_b@example.com", "role": "signer", "is_in_person": true } ] }' ``` ```python Python Gen SDK theme={null} def sign_doc_in_person_multiple( client: Client, document_id: str, destination_folder_id: str, signer_a_email: str, signer_a_embed_url_id: str, signer_b_email: str, ) -> SignRequest: # Sign request params source_file = FileBase(id=document_id, type=FileBaseTypeField.FILE) destination_folder = FolderMini( id=destination_folder_id, type=FolderBaseTypeField.FOLDER ) signer_a = SignRequestCreateSigner( email=signer_email, embed_url_external_user_id=signer_embed_url_id, is_in_person=True, ) signer_b = SignRequestCreateSigner( email=signer_email, is_in_person=True, ) # sign document sign_request = client.sign_requests.create_sign_request( signers=[signer_a, signer_b], parent_folder=destination_folder, source_files=[source_file], ) return sign_request def main(): """Simple script to demonstrate how to use the Box SDK""" conf = ConfigOAuth() client = get_client_oauth(conf) # Sign with phone verification sign_with_embed_url = sign_doc_embed_url( client, SIMPLE_PDF, SIGN_DOCS_FOLDER, SIGNER_A, SIGNER_A_EXTERNAL_ID, SIGNER_B ) check_sign_request(sign_with_embed_url) ``` Results in (simplified): ```json theme={null} { "signers": [ { "email": "sender@example.com", "role": "final_copy_reader", "is_in_person": false, }, { "email": "signer_a@example.com", "role": "signer", "is_in_person": true, "embed_url": "https://app.box.com/sign/document/...", "iframeable_embed_url": "https://app.box.com/embed/sign/document/..." }, { "email": "signer_b@example.com", "role": "signer", "is_in_person": true, "embed_url": null, "iframeable_embed_url": null } ], "id": "d066575f-f22b-42fc-b9e2-701468776475", "parent_folder": { "id": "234102987614", "type": "folder", "name": "signed docs" }, "name": "Simple-PDF (3).pdf", "type": "sign-request", "status": "created", "template_id": "ee9a689e-96b6-4076-92a0-b9b765eb09ca" } ``` ```yaml theme={null} Simple sign request: d066575f-f22b-42fc-b9e2-701468776475 Status: created Signers: 3 final_copy_reader: sender@example.com signer: signer_a@example.com embed_url: https://app.box.com/sign/document/... iframeable_embed_url: https://app.box.com/embed/sign/document/... signer: signer_b@example.com Prepare url: None ``` Browsing to the embedded URL shows the signature interface for the first signer: First in person signer Once the first signer has signed, the signature interface automatically switches to the second signer: Alt text # Request options Source: https://developer.box.com/sign/request-options/index The Box Sign API offers a wide range of customization and configuration options when sending signature requests. These options allow developers to tailor the user experience and workflow to match their application's specific requirements. # Multiple signers and roles Source: https://developer.box.com/sign/request-options/multiple-signers ## Multiple signers What if you have a document that needs to be signed by multiple people? This is typical for contracts between two or more entities. Having multiple signers introduces another dimension to the Box Sign process, the order in which the signers need to sign the document. If you do not specify the order, the request is sent to everyone at the same time, and when all parties have signed the document, they each receive a copy with all signatures. If you specify the signing order, the signature request is sent to the first signer. Only when the first signer signs the document, the request is sent to the second signer, and so on. Let’s see this working with an example scholarship contract between a university and a student. In this case the institution/teacher must sign the document first. Creating a method specific for this: ```sh cURL theme={null} curl --location 'https://api.box.com/2.0/sign_requests' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer ej...3t' \ --data-raw '{ "is_document_preparation_needed": true, "parent_folder": { "id": "234102987614", "type": "folder" }, "source_files": [ { "id": "1358047520478", "type": "file" } ], "signers": [ { "email": "institution@example.com", "role": "signer", "order": 1 }, { "email": "student@example.com", "role": "signer", "order": 2 }, ] }' ``` ```python Python Gen SDK theme={null} def sign_contract( client: Client, document_id: str, destination_folder_id: str, institution_email: str, student_email: str, prep_needed: bool = False, ) -> SignRequest: """Sign contract""" # Sign request params source_file = FileBase(id=document_id, type=FileBaseTypeField.FILE) destination_folder = FolderMini( id=destination_folder_id, type=FolderBaseTypeField.FOLDER ) # signers institution = SignRequestCreateSigner( email=institution_email, role=SignRequestCreateSignerRoleField.SIGNER, order=1, ) student = SignRequestCreateSigner( email=student_email, role=SignRequestCreateSignerRoleField.SIGNER, order=2, ) # create sign request sign_request = client.sign_requests.create_sign_request( signers=[institution, student], parent_folder=destination_folder, source_files=[source_file], is_document_preparation_needed=prep_needed, ) return sign_request def main(): ... # Multiple signers sign_contract_multi = sign_contract( client, CONTRACT, SIGN_DOCS_FOLDER, institution_email=SIGNER_A, student_email=SIGNER_B, prep_needed=True, ) if sign_contract_multi.prepare_url is not None: open_browser(sign_contract_multi.prepare_url) ``` In this particular example the document needs to be prepared, so the browser to the prepare URL opens. Drag the signature pad, the full name and the date to the appropriate places in the document, and click Send Request: Preparing the contract Notice you now have two signers, with the order already specified. The `color` is also important to identify which signer is which (in this case the institution is blue and the student is green), determining which signature pad, name and date belongs to which signer. If you look at the signature request details, you should see something like this: Signature request details showing the document and signers Indicating that the first request was sent, but the second is waiting for the first to be completed. Go ahead and complete the signature process for both signers. Notice that when you get the second request it is already signed by the first signer. ## Roles So far we have been working with the `signer` role. However there are [other roles][roles] that you can use to customize the signature process. The available roles are, `signer`, `approver`, and `final copy reader` From a developer perspective, this means: * **Signer**: Any person who is allowed to add data to the document. This includes adding a signature, initials, date, but also filling out text fields, check boxes, and radio buttons, even if it does not include a signature. * **Approver**: This role will be asked if they approve the signature request. This approval happens before the preparation step, if enabled, and before the request is sent to any of the signers. This role is useful if you need to get approval from someone before sending the document to the signers. * **Final copy reader**: This role does not interact with the signature process, but will receive a copy of the signed document. Let's use roles to be a bit more creative in the scholarship example. Imagine that the scholarship needs to be approved by the dean, and the legal department receives a final copy of the contract. The flow starts with the signature request, flowed by the dean approval, the institution signature, the student signature, and finally the legal department receives a copy of the signed document: Multiple signers and roles Let's create a method for this: ```sh cURL theme={null} curl --location 'https://api.box.com/2.0/sign_requests' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer ej...3t' \ --data-raw '{ "is_document_preparation_needed": true, "parent_folder": { "id": "234102987614", "type": "folder" }, "source_files": [ { "id": "1358047520478", "type": "file" } ], "signers": [ { "email": "institution@example.com", "role": "signer", "order": 1 }, { "email": "student@example.com", "role": "signer", "order": 2 }, { "email": "dean@example.com", "role": "approver" }, { "email": "legal@example.com", "role": "final_copy_reader" } ] }' ``` ```python Python Gen SDK theme={null} def sign_contract_step( client: Client, document_id: str, destination_folder_id: str, institution_email: str, student_email: str, dean_email: str, legal_email: str, ) -> SignRequest: """Sign contract""" # Sign request params source_file = FileBase(id=document_id, type=FileBaseTypeField.FILE) destination_folder = FolderMini( id=destination_folder_id, type=FolderBaseTypeField.FOLDER ) # signers institution = SignRequestCreateSigner( email=institution_email, role=SignRequestCreateSignerRoleField.SIGNER, order=1, ) student = SignRequestCreateSigner( email=student_email, role=SignRequestCreateSignerRoleField.SIGNER, order=2, ) dean = SignRequestCreateSigner( email=dean_email, role=SignRequestCreateSignerRoleField.APPROVER, ) legal = SignRequestCreateSigner( email=legal_email, role=SignRequestCreateSignerRoleField.FINAL_COPY_READER, ) # create sign request sign_request = client.sign_requests.create_sign_request( signers=[institution, student, dean, legal], parent_folder=destination_folder, source_files=[source_file], is_document_preparation_needed=True, ) return sign_request def main(): ... # Multiple signers and steps sign_contract_multi_step = sign_contract_step( client, CONTRACT, SIGN_DOCS_FOLDER, institution_email=SIGNER_A, student_email=SIGNER_B, dean_email=APPROVER, legal_email=FINAL_COPY, ) if sign_contract_multi_step.prepare_url is not None: open_browser(sign_contract_multi_step.prepare_url) ``` Like before you need to prepare the document, so open the prepare URL in your browser. Notice in the example the institution is represented by blue on the left, and the student by green on the right, and both are signers. Neither the `approver` nor the `final copy reader` can have inputs associated with them. If you do this, their roles will be adjusted to `signer`: Multiple role preparation Continuing the signature process: * The dean approves the scholarship * The institution signs the scholarship * The student signs the scholarship * The legal department receives a copy of the signed document. [roles]: https://support.box.com/hc/en-us/articles/4404105660947-Roles-for-signers # Request expiration Source: https://developer.box.com/sign/request-options/request-expiration There are situations where you might need to [set an expiration date][exp-date] for the signature request. For example, imagine a quote for a service that is valid for 30 days. This proposal has to be signed by a certain date, and if not, the signature request for the quote is no longer valid. All you need to do is pass the `days_valid` parameter. For example: ```sh cURL theme={null} curl --location 'https://api.box.com/2.0/sign_requests' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer ej...3t' \ --data-raw '{ "days_valid": 30, "parent_folder": { "id": "234102987614", "type": "folder" }, "source_files": [ { "id": "1358047520478", "type": "file" } ], "signers": [ { "email": "signer@example.com", "role": "signer" } ] }' ``` ```python Python Gen SDK theme={null} def sign_doc_single_more_options( ... days_valid: int = None, ) -> SignRequest: ... # sign document sign_request = client.sign_requests.create_sign_request( ... days_valid=days_valid, ) return sign_request ``` [exp-date]: https://support.box.com/hc/en-us/articles/4404105810195-Sending-a-document-for-signature#:~:text=Step%205%3A%20Setting%20an%20expiration # Resend requests Source: https://developer.box.com/sign/request-options/resend-requests What if the signer did not receive the email, the email was lost, or the signer deleted the email by mistake? You can resend the signature request email to the `signer` , either manually or you can turn on the automatic resend option. ## Manual resend To manually resend the signature request email to the signer, call the `resend_sign_request` method on the `sign_requests` object. You can only do it once every 10 minutes. Here is an example: ```sh cURL theme={null} curl --location --request POST 'https://api.box.com/2.0/sign_requests/ 52f6f86c-c0b3-401e-a4ec-1709f277c469/resend' \ --header 'Authorization: Bearer ej...3t' ``` ```python Python Gen SDK theme={null} def sign_send_reminder(client: Client, sign_request_id: str): """Send reminder to signers""" sign_request = client.sign_requests.resend_sign_request(sign_request_id) return sign_request ``` ## Automatic resend The automatic resend option sends a reminder email to signers that have not signed the document yet, after 3, 8, 13, and 18 days. To enable automatic resend set the `are_reminders_enabled` parameter to `true`. For example: ```sh cURL theme={null} curl --location 'https://api.box.com/2.0/sign_requests' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer ' \ --data-raw '{ "are_reminders_enabled": true, "parent_folder": { "id": "234102987614", "type": "folder" }, "source_files": [ { "id": "1355143830404", "type": "file" } ], "signers": [ { "email": "signer@example.com", "role": "signer" } ] }' ``` ```python Python Gen SDK theme={null} def sign_doc_single_more_options( client: Client, document_id: str, destination_folder_id: str, signer_email: str, prep_needed: bool = False, auto_reminder: bool = False, ) -> SignRequest: """Single doc sign by single signer""" # Sign request params source_file = FileBase(id=document_id, type=FileBaseTypeField.FILE) destination_folder = FolderMini( id=destination_folder_id, type=FolderBaseTypeField.FOLDER ) # signer signer = SignRequestCreateSigner(signer_email) # sign document sign_request = client.sign_requests.create_sign_request( signers=[signer], parent_folder=destination_folder, source_files=[source_file], is_document_preparation_needed=prep_needed, are_reminders_enabled=auto_reminder, ) return sign_request def main(): ... # Sign with redirects sign_with_auto_reminder = sign_doc_single_more_options( client, SIMPLE_PDF, SIGN_DOCS_FOLDER, SIGNER_A, prep_needed=False, auto_reminder = True, ) ``` # Set signer language Source: https://developer.box.com/sign/request-options/signer-language Use the `language` parameter to set the language for individual signers in your signature requests. This ensures that each recipient receives emails and signing pages in the designated language, regardless of their Box account settings or browser configuration. ## Overview By default, Box Sign determines the language for each signer based on: * The signer's Box account language setting (if they're logged in at time of signing) * English (if they're not logged in) In some workflows, especially legal or compliance scenarios, you may need to explicitly enforce display in a particular language. With the `language` parameter, you can explicitly set the language for a signer, ensuring compliance with legal and regulatory requirements. This language applies to: * All email notifications sent to the signer * The signing experience page ## Set the language To set the language for a signer, add the `language` field to the `signer` object in your API request. ```sh cURL theme={null} curl -i -X POST "https://api.box.com/2.0/sign_requests" \ -H "authorization: Bearer " \ -d '{ "signers": [ { "role": "signer", "email": "signer@example.com", "language": "nl" } ], "source_files": [ { "type": "file", "id": "123456789" } ], "parent_folder": { "type": "folder", "id": "0987654321" } }' ``` ### Supported language codes Box Sign supports the language codes defined in the Box API language codes specification. For the complete list of supported languages and their codes, see Language codes. Common language codes include: * en — English * nl — Dutch * fr — French * de — German * es — Spanish * ja — Japanese ### Error handling If you specify an unsupported language code, the API returns a **400 Bad Request** error. Example error response: ```json theme={null} { "type": "error", "status": 400, "code": "invalid_request_parameters", "help_url": "https://developer.box.com/guides/api-calls/permissions-and-errors/common-errors/", "message": "invalid_request_parameters", "request_id": "abcdef123456" } ``` To fix this error, check that your language code matches one of the supported Language codes. # Technical use cases Source: https://developer.box.com/sign/technical-use-cases/index In your application you will be signing different documents from many sources. How can your application process such documents in order for them to be recognized by the Box Sign service? A signature request can have multiple requirements, or inputs, beyond the traditional signature, such as name, date, and initials. These inputs are called signature properties. The Box Sign service needs to know where to place these inputs in the document, and how to recognize them. The first step is to consider if the document has the necessary information for the Box Sign service to recognize the signature properties. If not, then the [document is unstructured][unstructured-docs], and should be prepared before sending the signature request. This is called document preparation, and is an extra step automatically created by the Box Sign service. There are two other types of documents that already have the necessary information for the Box Sign service to recognize the signature properties. The [sign templates][sign-templates], managed in the Box application, and the [structured documents][sign-structured-docs], which are dynamically generated documents, containing specific tags representing the signature properties. Signing unstructured docs [unstructured-docs]: /sign/technical-use-cases/sign-unstructured-docs [sign-templates]: /sign/technical-use-cases/sign-template [sign-structured-docs]: /sign/technical-use-cases/sign-structured-docs # Signing structured docs Source: https://developer.box.com/sign/technical-use-cases/sign-structured-docs A structured document in the context of Box Sign is a document that includes specific tags that can be recognized by the Box Sign API. These tags are used to place the signature properties associated with a specific signer in the document, such as name, date, and signature. This allows your app to handle a dynamic generated document that is ready to be signed, which has a couple of advantages: * The document can be dynamically generated, and the signature properties can be added to the document before creating the signature request, effectively bypassing the document preparation step. * The document format can be handled outside of Box Sign templates, allowing higher flexibility and integration with external document management systems. ## Anatomy of a structured document Here is an example of a structured document, showing the formatting used to place tags in a Microsoft Word document: Using tags in a Microsoft Word document In the sample above `[[c|1]]` means a checkbox assigned to signer 1, and `[[s| 1]]` means a signature pad assigned to signer 1. Notice how the signature pad is using font size 48 to reserve space vertically for the signature. The `[[t|1|id:tag_full_name|n:enter your complete name]]` means a name tag assigned to signer 1, with the label `enter your complete name`, and using an id of `tag_full_name`. Check out this [document][support-tags] for a complete description of all the tags available. Setting the tags to the same `color` as the background will make them invisible, but they will still be there. The number in the tags refer to the signer number, not the signing order, so `[[c|1]]` is the checkbox for signer 1, `[[c|2]]` is the checkbox for signer 2, and so on. Tag 0 is reserved for the sender, and always exists. So even if the sender does not need to input any data into the document, the other signers must start with 1. ## Create a signature request from a structured document This is the same as creating a signature request from an unstructured document. At minimum, you will need to specify the document, the receiving folder and the email of the `signer`. Since the structured document already contains the signature properties details and location, you can bypass the document preparation. This is how the flow would look like, from the generated document, create the signature request and finally sign the document: Signing a structured document Consider this method: ```sh cURL theme={null} curl --location 'https://api.box.com/2.0/sign_requests' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer nQ...xY' \ --data-raw '{ "source_files": [ { "type": "file", "id": "1363379762284" } ], "parent_folder": { "id": "234102987614", "type": "folder" }, "signers": [ { "email": "signer@example.com", "role": "signer" } ] }' ``` ```python Python Gen SDK theme={null} def create_sign_request_structured( client: Client, file_id: str, signer_email: str ) -> SignRequest: """Create a sign request with structured data""" # Sign request params source_file = FileBase(id=file_id, type=FileBaseTypeField.FILE) parent_folder = FolderMini( id=SIGN_DOCS_FOLDER, type=FolderBaseTypeField.FOLDER ) signer = SignRequestCreateSigner(signer_email) # Create a sign request sign_request = client.sign_requests.create_sign_request( signers=[signer], parent_folder=parent_folder, source_files=[source_file], ) return sign_request def main(): ... # Create a sign request with structured data sign_request = create_sign_request_structured( client, STRUCTURED_DOC, SIGNER_A ) check_sign_request(sign_request) ``` Resulting in (simplified): ```json cURL theme={null} { "is_document_preparation_needed": false, "signers": [ { "email": "sender@example.com", "role": "final_copy_reader", }, { "email": "signer@example.com", "role": "signer", } ], "id": "28199d6c-4662-471e-8426-4cbba9affcf1", "source_files": [ { "id": "1363379762284", "type": "file", "name": "Box-Dive-Waiver.docx", } ], "parent_folder": { "id": "234102987614", "type": "folder", "name": "signed docs" }, "name": "Box-Dive-Waiver.pdf", "type": "sign-request", "status": "converting", "sign_files": { "files": [ { "id": "1393138856442", "type": "file", "name": "Box-Dive-Waiver.pdf", } ], }, } ``` ```yaml Python Gen SDK theme={null} Simple sign request: 6878e048-e9bd-4fb1-88c6-8e502783e8d0 Status: converting Signers: 2 final_copy_reader: sender@example.com signer: signer@example.com Prepare url: None ``` If you go to the **signer** email inbox, open the email from Box Sign, click the **Review Document** button, you'll see the document with the signature properties in place: Document with the properties in place After completing the process the signed document looks like this: Signed document ## Pre-populate the signature attributes If you have an external id in the document tags you can use it to pre-populate their values. For example, you can use the `tag_full_name` to pre-populate the name of the signer. See this method: ```sh cURL theme={null} curl --location 'https://api.box.com/2.0/sign_requests' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer nQ...xY' \ --data-raw '{ "prefill_tags": [ { "document_tag_id": "tag_full_name", "text_value": "Signer A" } ], "source_files": [ { "type": "file", "id": "1363379762284" } ], "parent_folder": { "id": "234102987614", "type": "folder" }, "signers": [ { "email": "signer@example.com", "role": "signer" } ] }' ``` ```python Python Gen SDK theme={null} def create_sign_request_structured_with_prefill( client: Client, file_id: str, signer_name, signer_email: str ) -> SignRequest: """Create a sign request with structured data""" # Sign request params source_file = FileBase(id=file_id, type=FileBaseTypeField.FILE) parent_folder = FolderMini( id=SIGN_DOCS_FOLDER, type=FolderBaseTypeField.FOLDER ) signer = SignRequestCreateSigner(signer_email) # tags tag_full_name = SignRequestPrefillTag( document_tag_id="tag_full_name", text_value=signer_name, ) # Create a sign request sign_request = client.sign_requests.create_sign_request( signers=[signer], parent_folder=parent_folder, source_files=[source_file], prefill_tags=[tag_full_name], ) return sign_request def main(): ... # Create a sign request with name pre populate sign_request_pre_pop = create_sign_request_structured_with_prefill( client, STRUCTURED_DOC, "Signer A", SIGNER_A ) check_sign_request(sign_request_pre_pop) ``` Resulting in (simplified): ```json cURL theme={null} { "is_document_preparation_needed": false, "redirect_url": null, "declined_redirect_url": null, "are_text_signatures_enabled": true, "signature_color": null, "is_phone_verification_required_to_view": false, "email_subject": null, "email_message": null, "are_reminders_enabled": false, "signers": [ { "email": "sender@example.com", "role": "final_copy_reader", }, { "email": "signer@example.com", "role": "signer", } ], "id": "11ecebc0-a2b2-4c14-a892-3f56333cc4fa", "prefill_tags": [ { "document_tag_id": "tag_full_name", "text_value": "Signer A", } ], "source_files": [ { "id": "1363379762284", "type": "file", "name": "Box-Dive-Waiver.docx", } ], "parent_folder": { "id": "234102987614", "type": "folder", "name": "signed docs" }, "name": "Box-Dive-Waiver (1).pdf", "type": "sign-request", "status": "converting", "sign_files": { "files": [ { "id": "1393142670032", "type": "file", "name": "Box-Dive-Waiver (1).pdf", } ], }, } ``` ```yaml Python Gen SDK theme={null} Simple sign request: 7b86e46c-72ba-4568-a6ff-787077cca007 Status: converting Signers: 2 final_copy_reader: sender@example.com signer: signer@example.com Prepare url: None ``` The document now has the name pre-populated: Document ready for sign with the name pre-populated ## Extract information from a signed document Let's say you want to extract the name of the signer and the other properties from the signed document. This is useful if you need to tie the information from the signature request back into your systems. Let's create a method to extract the information from the signed request: ```sh cURL theme={null} curl --location 'https://api.box.com/2.0/sign_requests/ 11ecebc0-a2b2-4c14-a892-3f56333cc4fa' \ --header 'Authorization: Bearer nQ...xY' ``` ```python Python Gen SDK theme={null} def check_sign_request_by_id(client: Client, sign_request_id: str): """Check sign request by id""" sign_request = client.sign_requests.get_sign_request_by_id(sign_request_id) print(f"\nSimple sign request: {sign_request.id}") print(f" Status: {sign_request.status.value}") print(f" Signers: {len(sign_request.signers)}") for signer in sign_request.signers: print(f" {signer.role.value}: {signer.email}") for input in signer.inputs: content_type = input.content_type value = None if content_type == SignRequestSignerInputTypeField.CHECKBOX: value = input.checkbox_value elif content_type == SignRequestSignerInputTypeField.TEXT: value = input.text_value elif content_type == SignRequestSignerInputTypeField.DATE: value = input.date_value print( f" {input.type.value}: {value if value is not None else ''}" ) print(f" Prepare url: {sign_request.prepare_url}") def main(): ... # Latest sign request LATEST_SIGN_REQUEST = "7b86e46c-72ba-4568-a6ff-787077cca007" check_sign_request_by_id(client, LATEST_SIGN_REQUEST) ``` Resulting in (simplified): ```json cURL theme={null} { "signers": [ { "email": "sender@example.com", "role": "final_copy_reader", }, { "email": "signer@example.com", "role": "signer", "signer_decision": { "type": "signed", "finalized_at": "2023-12-19T14:53:10.547Z", }, "inputs": [ { "document_tag_id": null, "checkbox_value": true, "type": "checkbox", "content_type": "checkbox", }, { "document_tag_id": "tag_full_name", "text_value": "Signer A", "type": "text", "content_type": "text", }, { "document_tag_id": null, "text_value": "Dec 19, 2023", "date_value": "2023-12-19", "type": "date", "content_type": "date", }, { "document_tag_id": null, "type": "signature", "content_type": "signature", } ], } ], "id": "11ecebc0-a2b2-4c14-a892-3f56333cc4fa", "prefill_tags": [ { "document_tag_id": "tag_full_name", "text_value": "Signer A", } ], "source_files": [ { "id": "1363379762284", "type": "file", "name": "Box-Dive-Waiver.docx", } ], "parent_folder": { "id": "234102987614", "type": "folder", "name": "signed docs" }, "name": "Box-Dive-Waiver (1).pdf", "type": "sign-request", "signing_log": { "id": "1393140642252", "type": "file", "name": "Box-Dive-Waiver (1) Signing Log.pdf", }, "status": "signed", "sign_files": { "files": [ { "id": "1393142670032", "type": "file", "name": "Box-Dive-Waiver (1).pdf", } ], }, } ``` ```yaml Python Gen SDK theme={null} Simple sign request: 7b86e46c-72ba-4568-a6ff-787077cca007 Status: signed Signers: 2 final_copy_reader: sender@example.com signer: signer@example.com checkbox: True text: Rui Barbosa date: 2023-11-15 signature: Prepare url: None ``` ## Summary Structured documents are a great way to integrate with external document management systems, creating dynamic documents that are ready for signature. If your document signature requirements have a lot of options, you can pre-populate these from another data source and save the user's time, but remember that the user who owns these properties can always change them. After the document is signed you can extract the information from the signature request, which is useful if you need to tie it back into your systems. [support-tags]: https://support.box.com/hc/en-us/articles/4404085855251-Creating-templates-using-tags # Signing using templates Source: https://developer.box.com/sign/technical-use-cases/sign-template A [Box Sign template][template] is a specific type of document that not only contains the text, but also the signature requirements and placement. It is prepared for signing in advance, and as such can be sent directly to the signer or signers. Required fields include, for example, the signature pad field, the full name, and the date. These fields have an owner, meaning they are populated by a specific signer and cannot be shared between them. They can be `mandatory` or `optional` , and be pre-populated by your application. However even if pre-populated, they can always be changed by the `signer`. Within the Box web app, the template not only sets the signature fields, but also the number of signers, the order in which they sign, other roles and recipients such as `approver`, and `final_copy_recipient`, email notification settings, and a few more options. For a complete set of options of the signature request please refer to the [request options][request-options] section. These templates are exclusively created and managed in the Box Sign web app, and can be used to create signature requests using the API or the web app. Let's start by creating a template. ## Creating a template From the Box app navigate to the sign menu on the left, then select templates. Navigating to templates under Box Sign Then, click on the New Template button, and choose or upload the document from Box. Selecting a document when creating a template For example, drag and drop a date, a name and a signature pad to the template, like so: Adding the signature, name, and date to the template You can add an [extra layer of security][additional-sec] for a recipient. It works for both a defined recipient with a pre-defined email address, and a placeholder recipient, where the template user has to provide their email address. Save the template. ## Identify the template In order to work with templates in the Box Sign API we are going to need the `template_id` . Consider this method to list all the templates available to the user: ```sh cURL theme={null} curl --location 'https://api.box.com/2.0/sign_templates' \ --header 'Authorization: Bearer E9...Q0' ``` ```python Python Gen SDK theme={null} def sign_templates_list(client: Client): """List all sign templates""" sign_templates = client.sign_templates.get_sign_templates() print(f"\nSign templates: {len(sign_templates.entries)}") for sign_template in sign_templates.entries: print(f" {sign_template.id} - {sign_template.name}") def main(): """Simple script to demonstrate how to use the Box SDK""" conf = ConfigOAuth() client = get_client_oauth(conf) user = client.users.get_user_me() print(f"\nHello, I'm {user.name} ({user.login}) [{user.id}]") sign_templates_list(client) ``` Returns something similar to (simplified): ```json cURL theme={null} { "limit": 10, "next_marker": null, "prev_marker": null, "entries": [ { "type": "sign-template", "id": "f2ec720d-47a6-4052-8210-9bfa8d6c349c", "name": "Simple-DOC.pdf", "parent_folder": { "id": "157064745449", "type": "folder", "name": "My Sign Requests" }, "source_files": [ { "id": "1393013714313", "type": "file", } ], "signers": [ { "email": "", "label": "", "role": "final_copy_reader", "inputs": [] }, { "email": "", "label": "Signer", "role": "signer", "inputs": [ { "document_tag_id": null, "id": "d02c8e16-5050-475e-b74b-9a952193e4f8", "type": "date", "date_value": null, "content_type": "date", }, { "document_tag_id": null, "id": "bdcc966e-2ebf-4b3b-aaee-99d4e1161a9e", "type": "text", "text_value": null, "is_required": true, "content_type": "full_name", }, { "document_tag_id": null, "id": "1a8f4cb1-5c09-46bd-96f5-0ab449f19640", "type": "signature", "text_value": null, "is_required": true, "content_type": "signature", } ] } ], } ] } ``` ```yaml Python Gen SDK theme={null} Hello, I'm Rui Barbosa [18622116055] Sign templates: 1 94e3815b-f7f5-4c2c-8a26-e9ba5c486031 - Simple-PDF.pdf ``` ## Creating a signature request from a template The big advantage of using templates is that we do not need to worry about document preparation. Most of the signature options can be set in the template itself. This is how the flow would look like: Signing using a template Using a signature template, create the signature request, and finally sign the document. See this example: ```sh cURL theme={null} curl --location 'https://api.box.com/2.0/sign_requests' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer E9...Q0' \ --data-raw '{ "template_id": "f2ec720d-47a6-4052-8210-9bfa8d6c349c", "parent_folder": { "id": "234102987614", "type": "folder" }, "signers": [ { "email": "signer@example.com", "role": "signer" } ] }' ``` ```python Python Gen SDK theme={null} def create_sign_request(client: Client, template_id: str, signer_email: str): """Create sign request from template""" parent_folder = FolderMini( id=SIGN_DOCS_FOLDER, type=FolderBaseTypeField.FOLDER ) signer = SignRequestCreateSigner( email=signer_email, ) sign_request = client.sign_requests.create_sign_request( signers=[signer], parent_folder=parent_folder, template_id=template_id, ) return sign_request def main(): ... # Create sign request from template sign_request = create_sign_request(client, TEMPLATE_SIMPLE, SIGNER_A) check_sign_request(sign_request) ``` Resulting in (simplified): ```json theme={null} { "signers": [ { "email": "sender@example.com", "role": "final_copy_reader", }, { "email": "signer@example.com", "role": "signer", } ], "id": "71e86670-5850-44cc-8b4d-9f5eab6c04de", "parent_folder": { "id": "234102987614", "type": "folder", "name": "signed docs" }, "name": "Simple-DOC (1).pdf", "type": "sign-request", "status": "created", "sign_files": { "files": [ { "id": "1393030489686", "type": "file", "name": "Simple-DOC (1).pdf", } ], }, "template_id": "f2ec720d-47a6-4052-8210-9bfa8d6c349c" } ``` ```yaml theme={null} Simple sign request: b25674a2-540b-4201-ae18-a78f05ef1a9a Status: created Signers: 2 final_copy_reader: sender@example.com signer: signer@example.com Prepare url: None ``` The signer receives an email from Box.com with a link to the document, and can sign it. Since the template already had the signature requirements, document preparation was not needed. Notice the date was automatically populated with the current date. ## Pre-populate the signature attributes From a usability perspective, it is a good idea to pre-populate the inputs you require from your users. Some inputs may be intentionally left unpopulated. For example, when your legal department specifies that the “Yes, I agree” field must be explicitly set by the signer. Using the Box app sign template editor, you can assign an `external_id` to each of the inputs, and have the app populate them from any data source. Let’s implement this for the name. Go back to the template design and add an id to the name field: Assigning a tag id to a signature property input Save the template. Let’s create a new method to pre-populate the name: ```sh cURL theme={null} curl --location 'https://api.box.com/2.0/sign_requests' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer E9..Q0' \ --data-raw '{ "template_id": "f2ec720d-47a6-4052-8210-9bfa8d6c349c", "parent_folder": { "id": "234102987614", "type": "folder" }, "signers": [ { "email": "signer@example.com", "role": "signer" } ], "prefill_tags": [ { "document_tag_id": "signer_full_name", "text_value": "Signer A" } ] }' ``` ```python Python Gen SDK theme={null} def create_sign_request_name_default( client: Client, template_id: str, signer_name, signer_email: str ): """Create sign request from template""" parent_folder = FolderMini( id=SIGN_DOCS_FOLDER, type=FolderBaseTypeField.FOLDER ) signer = SignRequestCreateSigner( email=signer_email, ) # tags tag_full_name = SignRequestPrefillTag( document_tag_id="signer_full_name", text_value=signer_name, ) sign_request = client.sign_requests.create_sign_request( signers=[signer], parent_folder=parent_folder, prefill_tags=[tag_full_name], template_id=template_id, ) return sign_request def main(): ... # Create sign request from template with name sign_request_name = create_sign_request_name_default( client, TEMPLATE_SIMPLE, "Signer A", SIGNER_A ) check_sign_request(sign_request_name) ``` Resulting in (simplified): ```json theme={null} { "signers": [ { "email": "sender@example.com", "role": "final_copy_reader", }, { "email": "signer@example.com", "role": "signer", "is_in_person": false, } ], "id": "6f42a041-7ed8-4e08-9958-78a97259f80d", "prefill_tags": [ { "document_tag_id": "signer_full_name", "text_value": "Signer A", } ], "parent_folder": { "id": "234102987614", "type": "folder", "name": "signed docs" }, "name": "Simple-DOC (2).pdf", "type": "sign-request", "status": "created", "sign_files": { "files": [ { "id": "1393047116817", "type": "file", "name": "Simple-DOC (2).pdf", } ], }, "template_id": "f2ec720d-47a6-4052-8210-9bfa8d6c349c" } ``` ```yaml theme={null} Simple sign request: adab1740-eeba-4392-a3f5-defddc79c946 Status: created Signers: 2 final_copy_reader: sender@example.com signer: signer@example.com Prepare url: None ``` Open the signer inbox and complete the sign request. Signing the document When the signer views the document, the `signer` can still change it. ## Get more information about a template You've seen that you can list the templates available to a user. But you can also get more information about a specific template. Let’s create a method that returns basic information of a template, but details all the signature requirements: ```sh cURL theme={null} curl --location 'https://api.box.com/2.0/sign_templates/ f2ec720d-47a6-4052-8210-9bfa8d6c349c' \ --header 'Authorization: Bearer OL..BQ' ``` ```python Python Gen SDK theme={null} def sign_template_print_info(client: Client, template_id: str): sign_template = client.sign_templates.get_sign_template_by_id(template_id) print(f"\nSign template: {sign_template.id} - {sign_template.name}") print(f" Signers: {len(sign_template.signers)}") for signer in sign_template.signers: print(f" {signer.role.value}") if len(signer.inputs) > 0: print(" Tag ID\t Type\t Required") for input in signer.inputs: print( f" {input.document_tag_id} {input.type.value} {input.is_required}" ) def main(): ... # Print sign template details sign_template_print_info(client, TEMPLATE_SIMPLE) ``` Resulting in (simplified): ```json theme={null} { "type": "sign-template", "id": "f2ec720d-47a6-4052-8210-9bfa8d6c349c", "name": "Simple-DOC.pdf", "parent_folder": { "id": "234102987614", "type": "folder", "name": "signed docs" }, "source_files": [ { "id": "1393013714313", "type": "file", } ], "signers": [ { "email": "", "label": "", "role": "final_copy_reader", }, { "email": "", "label": "Signer", "role": "signer", "inputs": [ { "document_tag_id": null, "id": "d02c8e16-5050-475e-b74b-9a952193e4f8", "type": "date", "is_required": true, "date_value": null, "content_type": "date", }, { "document_tag_id": "signer_full_name", "id": "bdcc966e-2ebf-4b3b-aaee-99d4e1161a9e", "type": "text", "text_value": null, "is_required": true, "content_type": "full_name", }, { "document_tag_id": null, "id": "1a8f4cb1-5c09-46bd-96f5-0ab449f19640", "type": "signature", "is_required": true, "content_type": "signature", } ] } ], } ``` ```yaml theme={null} Sign template: 94e3815b-f7f5-4c2c-8a26-e9ba5c486031 - Simple-PDF.pdf Signers: 2 final_copy_reader signer Tag ID Type Required None date True signer_full_name text True None signature True ``` Notice that the `signer_full_name` is the `tag_id` we used to pre-populate the name. ## Summary Templates are a form of signing structured documents where the signature requirements are already defined and placed on the document. This not only keeps your contract management team happy, but it also creates a process which is consistent and requires a low level of effort from your users. Finally if your document signature requirements have a lot of options, you can pre-populate these from another data source and save the user some time. Remember that the user who owns these properties can always change them. There is no API entry point to create a template, so you will have to create and manage them manually from the Box app, unless the document already includes signature tags that can be used by the Box Sign engine. Take a look at our [Structured Docs][structured-docs] section for more information. [template]: https://support.box.com/hc/en-us/sections/21356768117651-Templates [request-options]: /sign/request-options [structured-docs]: /sign/technical-use-cases/sign-structured-docs [additional-sec]: /sign/request-options/extra-security # Signing unstructured docs Source: https://developer.box.com/sign/technical-use-cases/sign-unstructured-docs Imagine a document management app, where users can upload a document and ask anyone to sign it. In this case your app will know what document to sign and who needs to sign, but it has no idea where to put the signature or its properties like name, date, initial, and so on. This contrasts with [using templates][sign-templates] or [structured documents][sign-structured-docs] where your app knows what they are, and where the signature properties go. In these cases, and because each document can have a different structure, it is a good idea to always set the `is_document_preparation_needed` flag set to `true`, so that the sender has a chance to select and place the signature properties in the document before the signer gets the request. There are three steps to this flow, creating the signature request, then preparing the document, and finally signing it. This is how the flow looks like: Sign unstructured docs flow Consider this example: ```sh cURL theme={null} curl --location 'https://api.box.com/2.0/sign_requests' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer ' \ --data-raw '{ "is_document_preparation_needed": true, "parent_folder": { "id": "234102987614", "type": "folder" }, "source_files": [ { "id": "1355143830404", "type": "file" } ], "signers": [ { "email": "signer@example.com", "role": "signer" } ] }' ``` ```python Python Gen SDK theme={null} def sign_doc_single( client: Client, document_id: str, destination_folder_id: str, signer_email: str, prep_needed: bool = False, ) -> SignRequest: # Sign request params source_file = FileBase(id=document_id, type=FileBaseTypeField.FILE) destination_folder = FolderMini( id=destination_folder_id, type=FolderBaseTypeField.FOLDER ) signer = SignRequestCreateSigner(signer_email) # sign document sign_request = client.sign_requests.create_sign_request( signers=[signer], parent_folder=destination_folder, source_files=[source_file], is_document_preparation_needed=prep_needed, ) return sign_request def main(): conf = ConfigOAuth() client = get_client_oauth(conf) # Simple sign a pdf request with preparation sign_pdf_prep = sign_doc_single( client, SIMPLE_PDF, SIGN_DOCS_FOLDER, SIGNER_A, True ) if sign_pdf_prep.prepare_url is not None: open_browser(sign_pdf_prep.prepare_url) ``` This results in a signature request with a prepare document URL (simplified): ```json cURL theme={null} { "is_document_preparation_needed": true, "signers": [ { "email": "requester@example.com", "role": "final_copy_reader", }, { "email": "signer@example.com", "role": "signer", } ], "id": "348decab-48a8-4f2c-9436-8967afebf7bb", "prepare_url": "https://app.box.com/sign/document/xyz-abc-123/.../prepare_doc/", "source_files": [ { "id": "1355143830404", "type": "file", } ], "parent_folder": { "id": "234102987614", "type": "folder", }, "name": "Simple-PDF.pdf", "type": "sign-request", "status": "converting", "sign_files": { "files": [ { "id": "1381301154812", "type": "file", } ], "is_ready_for_download": true }, "template_id": null } ``` ```yaml Python Gen SDK theme={null} Simple sign request with prep: xyz-abc-123 Status: converting Signers: signer@example.com Prepare url: https://app.box.com/sign/document/xyz-abc-123/.../prepare_doc/ ``` Notice in the above script that, if a prepare document URL was generated by the signature request, then the app opens a browser for it. The requester can then apply the different signature properties, for example: Preparing the document using drag and drop on the template editor Once the document is prepared, the requester can send the signature request to the signer. Back in the Box app you can see the status `In Progress`. Pending signature request The signer then receives an email from Box with a link to the signature request. Signing the document When the process is completed, both a signature log containing metadata and the signed document are stored in the destination folder. Log and signed document [sign-templates]: /sign/technical-use-cases/sign-template [sign-structured-docs]: /sign/technical-use-cases/sign-structured-docs # Sign webhooks Source: https://developer.box.com/sign/webhooks/index Sign webhooks allow you to receive notifications about events that happen with Box Sign signature requests. You can use them to trigger actions in your own application, or to notify your users about events that happen in Box Sign. This is particularly important since the signature requests are asynchronous, and the signers can interact with them at any time, possibly outside of your application. ## Sign-related events There are Box Sign-related events that can trigger the webhooks. Like most of Box events the listeners are set at the folder or document level. The most common use case is to listen to the events at the folder where the signature requests are created. This way you can listen to all the signature requests created in that folder. Some examples of events that can be listened to are: * `SIGN_REQUEST.COMPLETED`, when a signature request is completed. * `SIGN_REQUEST.DECLINED`, when a signature request is declined. * `SIGN_REQUEST.EXPIRED`, when a signature request expires. * `SIGN_REQUEST.SIGNER_EMAIL_BOUNCED`, when a signer's email is bounced. * `SIGN_REQUEST.SIGNER_SIGNED`, when the signature request is signed by a particular signer. * `SIGN_REQUEST.SIGNATURE_REQUESTED`, when the signature is requested from the signer. * `SIGN_REQUEST.ERROR_FINALIZING`, when the signature request could not be processed. # Setup with Client Credentials Grant Source: https://developer.box.com/guides/authentication/client-credentials/client-credentials-setup ## Prerequisites To set up a Platform App using server-side authentication, you need to ensure you have access to the [Developer Console][devconsole] from your Box enterprise account. Alternatively, you may sign up for a [developer account][devaccount]. ## App creation steps ### Navigate to the Developer Console Log into Box and go to the [Developer Console][devconsole]. Select **Platform Apps**, then click **New App**. ### Create a new app On the **Create a New App** screen, enter your app name and select **Client Credentials Grant** from the **App Type** dropdown. Create a New App screen Once you make a selection, you are not able to change to a different authentication method without creating a new application. ## App Authorization Before the application can be used, a Box Admin or Co-Admin needs to authorize it. On the **Configuration** tab in the [Developer Console][devconsole]: * If you are a Box Admin or Co-Admin, click **Authorize** to authorize the app immediately. * If you are not an Admin or Co-Admin, click **Submit** to send an authorization request to your Admin or Co-Admin. You receive an email once the request is approved or denied. More information on this process is available in our authorization guide. ## Basic configuration ### Application Access An application's access level determines which users and content your app may access. By default, an application can only successfully interact with the content of its Service Account and any App Users. To also access existing Managed Users of an enterprise, navigate to the **App Access Level** setting on the **Configuration** tab of the [Developer console][devconsole] and set to **App + Enterprise Access**. App access level To authenticate as a Managed User or Admin, enable **Generate User Access Tokens** in the **Additional Configuration** section of the **Configuration** tab. ### Application Scopes An application's scopes determine which endpoints and resources an application can successfully call. See the scopes guide for detailed information on each option. App scopes ### CORS Domains If your application makes API calls from front-end browser code in Javascript, the domain that these calls are made from needs to be added to an allow-list due to [Cross Origin Resource Sharing][cors], also known as CORS. If all requests are made from server-side code, you may skip this section. To add the full URI(s) to the allow-list, navigate to the **CORS Domain** section at the bottom of the **Configuration** tab in the [Developer console][devconsole]. App CORS config ## Using SDKs and Client Credentials Grant To learn more about Client Credentials Grant for each SDK head over to: * [.Net][.Net] * [Java][Java] * [Python][Python] * [Node][Node] * [IOS][IOS] [.Net]: https://github.com/box/box-windows-sdk-v2/blob/legacy/docs/authentication.md#server-auth-with-ccg [Java]: https://github.com/box/box-java-sdk/blob/legacy/doc/authentication.md#client-credentials-grant [Python]: https://github.com/box/box-python-sdk/blob/legacy/docs/usage/authentication.md#client-credentials-grant [Node]: https://github.com/box/box-node-sdk/blob/legacy/docs/authentication.md#client-credentials-grant-authentication [IOS]: https://github.com/box/box-ios-sdk/blob/legacy/BoxSDK/docs/usage/authentication.md#client-credentials-grant [devconsole]: https://app.box.com/developers/console [devaccount]: https://account.box.com/signup/n/developer [cors]: https://en.wikipedia.org/wiki/Cross-origin_resource_sharing # Client Credentials Grant Source: https://developer.box.com/guides/authentication/client-credentials/index Follow the steps below if you would like to leverage server authentication and verify your application's identity using a client ID and client secret. ## Prerequisites * A Platform Application using Server Authentication (with Client Credentials Grant) authentication in the Box [Developer Console][devconsole]. * [2FA][2fa] enabled on your Box account for viewing and copying the application's client secret from the configuration tab. * The application is authorized for use with your enterprise. A free developer account gives you access to the Developer Console, where you can set up Client Credentials Grant authentication in minutes. Your client secret is confidential and needs to be protected. Because this is how we securely identify an application's identity when obtaining an Access Token, you do not want to freely distribute a client secret. This includes via email, public forums and code repositories, distributed native applications, or client-side code. If you would like to add more security mechanisms, we recommend using our standard JWT application type. ## How to use When making your API call to obtain an Access Token, your request body needs to contain your client ID and client Secret. Set the `grant_type` to `client_credentials`. If you would like to authenticate as the application's Service Account: * Set `box_subject_type` to `enterprise`. * Set `box_subject_id` to the enterprise ID. If you would like to authenticate as an Admin or a Managed User: * Set `box_subject_type` to `user`. * Set `box_subject_id` to the user ID. * Enable **App + Enterprise Access** and **Generate User Access Tokens** in the Box [Developer Console][devconsole]. If you would like to authenticate as any application user: * Set `box_subject_type` to `user`. * Set `box_subject_id` to the user ID. * Enable **Generate User Access Tokens** in the Box [Developer Console][devconsole]. ## Common Errors ### Grant credentials are invalid During authentication, you can encounter the following error: ```sh theme={null} Grant credentials are invalid [400 Bad Request] invalid_grant - Grant credentials are invalid ``` This error indicates either: * The client ID and client secret passed are incorrect or are not for the same application. * The `box_subject_id` cannot be used based on the selected application access. A CCG app with App Access Only can send in the `box_subject_type` of `enterprise` to authenticate as its service account, but it can't authenticate as a Managed User or an Admin. * To use a `box_subject_type` of `user`, your application should be configured to generate user access tokens in the **Advanced Features** section of the **Configuration tab**. Generate access tokens check Once you make changes to the app settings, don't forget to reauthorize the application in the Admin Console. * Your application has not been authorized in the Box Admin Console. [2fa]: https://support.box.com/hc/en-us/articles/360043697154-Two-Factor-Authentication-Set-Up-for-Your-Account [devconsole]: https://app.box.com/developers/console # User Access Token Source: https://developer.box.com/guides/authentication/jwt/user-access-tokens It is possible for a JWT application to create an Access Token for a specific user instead of for the Service Account. ## Preconditions The application must be configured to allow the creation of user Access Tokens. This setting can be found in the **Configuration** tab of the [Developer Console][devconsole]. Advanced Features Additionally, the authenticated user needs to be a user with Admin permissions, meaning either an Admin, Co-Admin, or Service Account. See our guide on User Types for more details. ## User Access Tokens with SDKs To create a Box SDK client that authenticates as a specific user, follow the steps described in the JWT with SDK guide, but create a user client instead of an "Enterprise" client. ```csharp .Net theme={null} var userId = "12345"; var sdk = new BoxJWTAuth(config); var token = sdk.UserToken(appUserID); BoxClient client = sdk.UserClient(userToken, userId); ``` ```java Java theme={null} String userId = "12345"; BoxDeveloperEditionAPIConnection api = new BoxDeveloperEditionAPIConnection.getAppUserConnection(userId, config) ``` ```python Python theme={null} user = client.user(user_id='12345') auth = JWTAuth( client_id='[CLIENT_ID]', client_secret='[CLIENT_SECRET]', user=app_user, jwt_key_id='[JWT_KEY_ID]', rsa_private_key_file_sys_path='[CERT.PEM]', rsa_private_key_passphrase='[PASSPHRASE]' ) auth.authenticate_user() user_client = Client(auth) ``` ```js Node theme={null} var sdk = BoxSDK.getPreconfiguredInstance(config); var client = sdk.getAppAuthClient('user', '12345'); ``` ## User Access Tokens without SDKs To create a user Access Token that authenticates as a specific user, follow the steps as described in the JWT without SDK guide but instead of creating a claim for the enterprise, create one for a specific user ID. ```csharp .Net theme={null} var userId = "12345"; var claims = new List{ new Claim("sub", userid), new Claim("box_sub_type", "user"), new Claim("jti", jti), }; ``` ```java Java theme={null} String userId = "12345"; JwtClaims claims = new JwtClaims(); claims.setIssuer(config.boxAppSettings.clientID); claims.setAudience(authenticationUrl); claims.setSubject(userId); claims.setClaim("box_sub_type", "user"); claims.setGeneratedJwtId(64); claims.setExpirationTimeMinutesInTheFuture(0.75f); ``` ```python Python theme={null} user_id = '12345' claims = { 'iss': config['boxAppSettings']['clientID'], 'sub': user_id, 'box_sub_type': 'user', 'aud': authentication_url, 'jti': secrets.token_hex(64), 'exp': round(time.time()) + 45 } ``` ```js Node theme={null} let user_id = '12345'; let claims = { iss: config.boxAppSettings.clientID, sub: user_id, box_sub_type: "user", aud: authenticationUrl, jti: crypto.randomBytes(64).toString("hex"), exp: Math.floor(Date.now() / 1000) + 45 }; ``` ```ruby Ruby theme={null} user_id = '12345' claims = { iss: config['boxAppSettings']['clientID'], sub: user_id, box_sub_type: 'user', aud: authentication_url, jti: SecureRandom.hex(64), exp: Time.now.to_i + 45 } ``` ```php PHP theme={null} $userId = '12345'; $claims = [ 'iss' => $config->boxAppSettings->clientID, 'sub' => $userId, 'box_sub_type' => 'user', 'aud' => $authenticationUrl, 'jti' => base64_encode(random_bytes(64)), 'exp' => time() + 45, 'kid' => $config->boxAppSettings->appAuth->publicKeyID ]; ``` [devconsole]: https://app.box.com/developers/console # Common Errors Source: https://developer.box.com/guides/authorization/common-errors ## Unable to retrieve service of enterprise app authorization Unable to retreive error This error indicates that the entered client ID entered is invalid. To resolve this issue, please re-copy the Client ID from the Developer Console and ensure you are not including any trailing characters. ## Something went wrong with adding the app authorization This error indicates you are a Box co-admin granted privileges to view, but not edit enterprise settings. You will need to have your Box Admin grant edit privileges in order to successfully authorize an application. Something went wrong error ## Disabled by Administrator This error indicates that not all authorization requirements are satisfied. Please review our authorization guide to confirm the necessary steps for a given application. Admin error # Authorization Source: https://developer.box.com/guides/authorization/index Some applications require explicit Admin authorization before use with an enterprise. The steps an Admin needs to take are dependent on the developer-selected authentication method and enabled enterprise settings. ## Authentication methods The following authentication methods always require explicit Admin authorization: * Server Authentication (with JWT) * Server Authentication (with Client Credentials Grant) These authentication methods automatically generate a Service Account. With the right scopes enabled, a Service Account can perform many Admin actions, thus requiring Admin authorization before use. OAuth 2.0 apps may also require explicit Admin authorization based on enabled enterprise settings. ## Enterprise settings Subsequent steps are required if any of the following enterprise settings are enabled: * Enable Integrations by default — navigate to **Admin Console** > **Integrations** > **Platform Apps Manager** > **Platform Apps Settings** button. * Disable unpublished apps by default - navigate to **Enterprise Settings** > **Platform Apps** Published Platform Apps are any applications that can be found under Integrations. ## Required actions To see what steps an Admin must complete for a given app, review the following scenarios. **Disable published third party apps by default**: | Authentication Method | Enabled | Disabled | | -------------------------------------------------------------------------------------------------------- | ------------------------------------------- | ------------- | | OAuth 2.0 | Set to available in individual app controls | Ready for use | | Server Authentication (with JWT) | N/A | N/A | | Server Authentication (client credentials) | N/A | N/A | **Disable unpublished apps by default**: | Authentication Method | Enabled | Disabled | | -------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | | OAuth 2.0 | Enable in **Integrations** > **Platform Apps Manager** > **User Authentication Apps** > Select Platform App > Use **More** menu to enable the app. | Ready for use | | Server Authentication (with JWT) | Authorize and enable in **Integrations** > **Platform Apps Manager** > **Server Authentication Apps** Select Platform App > Use **More** menu to authorize the app. | Authorize in **Integrations** > **Platform Apps Manager** > **Server Authentication Apps** > Select Platform App > Use **More** menu to authorize the app. | | Server Authentication (client credentials) | Authorize and enable in **Integrations** > **Platform Apps Manager** > **Server Authentication Apps** > Select Platform App > Use **More** menu to authorize the app. | Authorize in **Integrations** > **Platform Apps Manager** > **Server Authentication Apps** > Select Platform App > Use **More** menu to enable the app. | **Require manual Admin authorization for Platform Apps**: | Authentication Method | Enabled | Disabled | | -------------------------------------------------------------------------------------------------------- | ------- | -------- | | OAuth 2.0 | N/A | N/A | | Server Authentication (with JWT) | N/A | N/A | | Server Authentication (client credentials) | N/A | N/A | [setting]: https://support.box.com/hc/en-us/articles/360044196653-Managing-custom-apps [ag]: /guides/applications/integrations # Limited Access App Approval Source: https://developer.box.com/guides/authorization/limited-access-approval Limited Access Integrations are automatically authorized for use in an enterprise upon creation. However, if the enterprise setting to **Require manual Admin authorization for Limited Access Apps** is enabled, an Admin must preform additional steps. ## Approval Notifications A semi-automated process to submit an app approval is available in the Developer Console. Navigate to the **Authorization** tab for your application in the [Developer Console][devconsole]. Add and Manage keys Submitting the application for approval will send an email to your enterprise's Primary Admin to approve the application. More information on this process is available in our [support article on app authorization][app-auth]. ## Manual Approval The following steps provide instructions on how to manually approve the application. ### As a developer 1. Navigate to the **Configuration** tab for your application in the [Developer Console][devconsole]. 2. Scroll down to the OAuth 2.0 Credentials section and copy the **Client ID** value to provide to a Box Admin. Alternatively, hover over the application in the My Platform Apps view to look up the **ClientID** and then copy it using the `copy` button. **Finding a Box Admin** If you don't know your enterprise Admin, go to your Box [Account Settings][settings] page and scroll to the bottom. If an admin contact is set you should see their contact information under **Admin Contact**. ### As an Admin As a Box Admin, navigate to the [Admin Console][adminconsole] and select the **Integrations** > **Platform Apps Manager** > **Add Platform App** Apps tab In the popup that appears, enter the Client ID for the application that the developer collected from the **Configuration** tab of the Developer Console. ## Re-authorization on changes When the application's scopes or access level change the application needs to be re-authorized. Repeat the process above and request a new Access Token for the new changes to take effect. In the same section where the application was initially authorized, an Admin can re-authorize the application by clicking on the ellipses to the right of the application name to **Reauthorize App**. Re-authorize app [devconsole]: https://app.box.com/developers/console [ccg]: /guides/authentication/client-credentials [settings]: https://app.box.com/account [adminconsole]: https://app.box.com/master/settings/custom [jwt]: /guides/authentication/jwt [app-token]: /guides/authentication/app-token [app-auth]: https://support.box.com/hc/en-us/articles/360043697014-Authorizing-Apps-in-the-Box-App-Approval-Process # Platform App Approval Source: https://developer.box.com/guides/authorization/platform-app-approval Server authentication applications using JWT or Client Credentials Grant must be authorized by a Box Admin or Co-Admin before use. Unpublished applications using OAuth 2.0 authentication may require enablement by a Box Admin or Co-Admin if they are inactive by default. A Box Admin or Co-Admin needs an application's Client ID in order to properly authorize or enable it in the Admin Console. Apps created by free developer (Individual) accounts are authorized automatically. You can use My Platform Apps view to quickly look up the authorization and enablement status of your application. ## One-Click Authorization JWT and CCG authentication apps can be authorized directly from the **Configuration** tab in the [Developer Console][devconsole]. This is a convenient alternative to the methods described below. ### As an Admin or Co-Admin If you are a Box Admin or Co-Admin, the Configuration tab displays: **Server authenticated apps must be authorized before use.** Click **Authorize** to authorize the app immediately. ### As a developer If you are not a Box Admin or Co-Admin, the Configuration tab displays: **Submit app for authorization for access to the Enterprise.** Click **Submit** to send the request. Your admin or co-admin receives an email notification, and you are notified by email once the request is approved or denied. ## Approval Notifications ### User authentication apps A semi-automated process to submit an app approval is available in the Developer Console for user authentication applications. Navigate to the **Enablement** tab for your application in the [Developer Console][devconsole]. Enablement tab Submitting the application for approval sends an email to your enterprise's Primary Admin to approve the application. When a Box Admin or Co-Admin approves or declines your request, you receieve an email with the decision. More information on this process is available in our [support article on app authorization][app-auth]. ## Manual Approval The following steps provide instructions on how to manually approve the application. ### As a developer 1. Navigate to the **Configuration** tab for your application in the [Developer Console][devconsole]. 2. Scroll down to the OAuth 2.0 Credentials section and copy the **Client ID** value to provide to a Box Admin or Co-Admin. Alternatively, hover over the application in the My Platform Apps view to look up the **ClientID** and then copy it using the `copy` button. **Finding a Box Admin** If you don't know your enterprise Admin, go to your Box [Account Settings][settings] page and scroll to the bottom. If an admin contact is set you should see their contact information under "Admin Contact". ### As an Admin 1. Navigate to the [Admin Console][adminconsole] and select the **Apps** tab (1) from the left navigation panel. 2. Click the **Platform Apps Manager** tab (2) at the top of your screen. 3. For both Server and User Authentication Apps screens, click the **Add App** (3) button in the top right corner to add a new app. 4. Alternatively, you can use the Platform Apps Manager table menu (4) to authorize and enable apps. #### Server Authentication Apps Server Apps tab #### User Authentication Apps User Apps tab In the popup that appears, enter the client ID for the application that the developer collected from the **Configuration** tab of the [Developer Console][devconsole]. ## Re-authorization on changes When the application's scopes or access level change the application needs to be re-authorized. Repeat the process above and request a new Access Token for the new changes to take effect. In the same section where the application was initially authorized, an Admin can re-authorize the application by clicking on the ellipses to the right of the application name to **Reauthorize App**. Re-authorize app [devconsole]: https://app.box.com/developers/console [settings]: https://app.box.com/account [adminconsole]: https://app.box.com/master/settings/custom [app-token]: /guides/authentication/app-token [app-auth]: https://support.box.com/hc/en-us/articles/360043697014-Authorizing-Apps-in-the-Box-App-Approval-Process # Box CLI with JWT Authentication Source: https://developer.box.com/guides/cli/cli-with-jwt-authentication/jwt-cli Previously, our Box CLI Quick Start Guide, followed the JWT or server authentication application setup flow. Since we released a new OAuth 2.0 version of the Box CLI, we updated it to use the new feature. We migrated the original JWT setup instructions here, in case you would still like to use the server authentication application type. ## Setup a JWT application The first step to using the CLI with server authentication is creating a Box application in the [Developer Console][dc], which the CLI can use behind the scenes to make API calls. If you would like to associate your CLI with an existing JWT application you can skip this step. However, you will want to ensure that, at a minimum, the following scopes are set in the **Configuration** tab of your application: * Read all files and folders stored in Box * Write all files and folders stored in Box 1. From the left-hand navigation panel on your All Files page, open the [Developer Console][dc]. If this is your first time using the Box API and this option is not already available, you can add it to your account by clicking [here][dc]. 2. Click **Create Platform App** > **Platform App** > **Server Authentication (with JWT)** > name the application > **Create App** Server Authentication (with JWT) always requires Admin authorization before use. ## Configure the application This brings you to the application's configuration page where you need to choose its access and permissions. Again, keep in mind that because of the application's authentication type, it requires Admin approval. At a minimum, you need the following scopes: * Read all files and folders stored in Box * Write all files and folders stored in Box You can choose either App Access Only or App + Enterprise Access as the application access. ## Authorize the application All applications leveraging Server Authentication must be authorized in the Admin Console before making successful API calls. This is because all JWT applications have a Service Account, which, based on the applications scopes, may be able to perform Admin actions. Steps for developers and Admins can be found in our authorization guide. If you would like more information on how scopes, application access, tokens, and permissions work together, please see our article on understanding [Box's security mechanisms][blogpost]. If configuration changes are made to this application, it will need to be reauthorized in order for the changes to take effect. You will know when an application is ready for use by visiting its Authorization tab in the [Developer Console][dc]. The state and status must be enabled and authorized. App Authorized ## Download Required Data The CLI needs a configuration file stored locally in order to make API calls. To download the configuration file, visit the **Configuration** tab in the [Developer Console][dc]. Click **Generate a Public/Private Keypair**, which will send you through 2FA verification before automatically downloading the configuration file for your application. For more information see our guide. For security reasons 2FA must be enabled on your Box account to successfully generate a public/private keypair. Locate the downloaded file on your machine which has a default name in the format: `EnterpriseID_publicKeyID_config.json`. You may leave this name or choose to rename it. This guide assumes the file is renamed to `config.json`. It is critical you place the file in a location where it will not be inadvertently deleted or moved. If this occurs you will need to repeat the step 2 to reconfigure the CLI. ## CLI Installation and Configuration The CLI can be installed as a Node package on any platform, including Linux. For this to work you will need to have [Node JS](https://nodejs.org/) installed on your machine. ```bash theme={null} npm install --global @box/cli ``` ## Source Code The source code for the CLI is available via [GitHub][cli]. ## Run configuration command You will now need to configure the CLI to point to to the configuration file downloaded in step 1.
CLI Configuration Diagram
Open your terminal or command line and execute the command: `box configure:environments:add PathToConfigFileHere`, replacing `PathToConfigHere` with the path to your `config.json` file. For example: `box configure:environments:add /Users/ExampleUser/Documents/CLI/config.json` You can drag the csv file from the Finder/File Explorer to the terminal/command line window to auto-populate the path. ## Confirm configuration To confirm successful configuration, use the command `box users:get`. A successful response will provide details about the Service Account user associated with your Access Token: ```json theme={null} Type: user ID: ''0123456789'' Name: Box CLI - Quickstart Example Login: AutomationUser_123456_8jSo6Lqvko@boxdevedition.com Created At: '2020-01-01T09:45:01-07:00' Modified At: '2021-03-01T09:30:05-07:00' Language: en Timezone: America/Los_Angeles Space Amount: 999999999999999 Space Used: 6291500 Max Upload Size: 16106127360 Status: active Job Title: '' Phone: '' Address: example+user@box.com Avatar URL: '' Notification Email: [] ``` By default, JWT applications automatically obtain an Access Token for the Service Account. It is possible to change the default user, but this guide assumes you do not do this. ## Next Steps * You can checkout the [commands][commands] page on GitHub for example code. * You can also go to the second part of the OAuth 2.0 Quick Start for a tutorial on how to use the commands. [cli]: https://github.com/box/boxcli [auth]: /guides/authentication/jwt/without-sdk [dc]: https://account.box.com/developers/console [blogpost]: https://medium.com/box-developer-blog/box-api-understanding-security-9fcad7b1d72e [four]: /guides/cli/quick-start/using-bulk-commands [cache]: https://github.com/box/boxcli/blob/master/docs/configure.md#box-configureenvironmentsupdate-name [ac]: https://github.com/box/boxcli/blob/master/docs/autocomplete.md [commands]: https://github.com/box/boxcli#command-topics # Login for Headless Environments Source: https://developer.box.com/guides/cli/headless-login Authenticate the Box CLI on machines without a browser using manual code entry. Use the `--code` flag to authenticate the Box CLI in headless environments such as remote servers, containers, or CI/CD pipelines where no browser is available. ## Prerequisites * The Box CLI is installed. * You have access to a browser on a separate machine (for example, your laptop) to complete the authorization step. ## How it works The standard `box login` command opens a browser on the same machine and starts a local callback server to receive the authorization response automatically. In headless environments, neither is possible. The `--code` flag changes the login flow: * The CLI prints an authorization URL instead of opening a browser. * No local callback server is started. * After you authorize in a browser on another machine, you manually copy the resulting code and state back into the CLI. ## Authenticate ### Step 1: Start login with the `--code` flag On the headless machine, run: ```bash theme={null} box login --code ``` The CLI prints an authorization URL and waits for input. You can combine `--code` with any other `box login` options. For example, to authenticate with a custom Box platform app, provide your Client ID and Client Secret when prompted. ### Step 2: Authorize in a browser on another machine Copy the authorization URL that the CLI printed, then open it in a browser on a machine that has one. Sign in to Box and select **Grant Access to Box**. ### Step 3: Copy the code and state from the redirect URL After you grant access, the browser redirects to a `localhost` callback URL. Because no callback server is running on the headless machine, the page does not load and the browser displays a connection error. This is expected. Look at the URL in the browser's address bar. It contains the values you need: ``` http://localhost:3000/callback?state=AUTHORIZATION_STATE&code=CODE_VALUE ``` Copy the values of `code` and `state` from this URL. ### Step 4: Enter the codes in the CLI Return to the terminal on the headless machine and paste the `code` and `state` values when the CLI prompts for them. After the CLI confirms successful authentication, you are ready to run commands. ### Step 5: Verify the setup ```bash theme={null} box users:get me ``` If authentication was successful, the CLI returns information about your Box user account. ## Using `--code` on a machine with a browser The `--code` flag is intended for headless environments. If you use it on a machine that has a browser: * The CLI still prints the authorization URL. * After you authorize, the browser redirects to the callback URL. Because `--code` skips starting the local callback server, the redirect page does not load and the browser shows a connection error. * The CLI continues to wait for you to manually enter the `code` and `state` values, just as it would in a headless environment. If a browser is available on the same machine, use `box login` without `--code` for a smoother experience. # CLI Source: https://developer.box.com/guides/cli/index The Box CLI brings Box to your terminal. It works with agentic tools and harnesses, letting you manage content, automate tasks, and integrate Box into scripts, tools, and AI agents. Scopes are limited to files and folders, AI, and Sign when [logging in as a Box user](#log-in-as-box-user). If you need additional scopes, [use a Box platform app](#use-a-box-platform-app) instead. Install the Box CLI and connect to your account in minutes. A free developer account is all you need to get started. ## Quickstart ### Step 1: Install the CLI The CLI can be installed as a Node package on any platform, including Linux, Windows, and macOS. For this to work, you need to have [Node.js](https://nodejs.org/) installed. ```bash theme={null} npm install --global @box/cli ``` ### Step 2: Authenticate the CLI In your terminal, run: ```bash theme={null} box login ``` ##### 1. Log in as a Box user (OAuth) The fastest way to get started. Uses a preconfigured Box application that only supports file and folder operations, AI, and Sign. Select the **Grant Access to Box** button which appears in the browser. After authentication completes successfully, you are ready to run commands. ##### 2. Use a Box platform app This option requires additional setup but allows you to configure scopes and permissions. 1. Go to your [Developer Console][devconsole] and select or create an application. 2. In the application’s **Configuration** section: * Make sure it uses **Standard OAuth 2.0**. * Set the **Redirect URI** to `http://localhost:3000/callback`. * Select your desired scopes. * Copy your **Client ID** and **Client Secret**. 3. At the top of the page, click **Save Changes**. 4. Return to the terminal window and enter the **Client ID** and **Client Secret** when prompted. 5. Select the **Grant Access to Box** button which appears in the browser. After authentication completes successfully, you are ready to run commands. Use `box login --platform-app` to skip the prompt for the Client ID and Client Secret. ##### 3. Headless environment (no browser) If you are on a remote server or any machine without a browser, use the `--code` flag for manual code entry. See Headless Login for step-by-step instructions. ```bash theme={null} box login --code ``` ### Step 3: Run your first command To confirm the configuration was successful, enter: ```bash theme={null} box users:get me ``` If authentication was successful, the CLI returns information about your Box user account. ```json theme={null} Type: user ID: '0123456789' Name: Aaron Levie Login: example@box.com Created At: '2020-01-01T09:45:01-07:00' Modified At: '2021-03-01T09:30:05-07:00' Language: en Timezone: America/Los_Angeles Space Amount: 999999999999999 Space Used: 6291500 Max Upload Size: 16106127360 Status: active Job Title: '' Phone: '' Address: example+user@box.com Avatar URL: '' Notification Email: [] ``` The CLI supports Box Hubs commands. Manage hubs and hub items directly from your terminal. Run `box hubs --help` to see all available operations. ## Getting help Every CLI command begins with `box`. Add `--help` to any command for assistance. Run `box --help` to display all available top-level commands. A full list of commands and usage information is available in the [GitHub repository][github]. Supported callback ports are: `3000`, `3001`, `4000`, `5000`, and `8080`. Change with `--port`. ## Alternative methods to interact with the Box API * To use the server authentication method, check our CLI with JWT guide. * To use the CCG authentication method, check our [Box configure][ccg-page] guide. ## Additional information More information about the Box CLI is available in the following pages: * Review all [commands][commands]. * Review [token cache][cache] settings. * Review [autocomplete][ac] settings. * To perform bulk actions using CLI commands, check our [CLI bulk commands][bulk] guide. [cache]: https://github.com/box/boxcli/blob/master/docs/configure.md#box-configureenvironmentsupdate-name [ac]: https://github.com/box/boxcli/blob/master/docs/autocomplete.md [commands]: https://github.com/box/boxcli#command-topics [github]: https://github.com/box/boxcli#command-topics-1 [devconsole]: https://cloud.app.box.com/developers/console API requests made through Box first-party applications are not chargeable. Requests made by custom applications using the Box API are chargeable. ## Advanced The GitHub page contains additional guides that might be of interest to an advanced CLI user: * [Set up autocomplete][cli-autocomplete] * [Configure another app][cli-add-config] * [Switch accounts][cli-switch] * [Token cache][cache] [cli]: https://github.com/box/boxcli [cli-autocomplete]: https://github.com/box/boxcli/blob/main/docs/autocomplete.md [cli-switch]: https://github.com/box/boxcli/blob/main/docs/configure.md#box-configureenvironmentsswitch-user-userid [cli-add-config]: https://github.com/box/boxcli/blob/main/docs/configure.md#box-configureenvironmentsadd-path [cache]: https://github.com/box/boxcli/blob/main/docs/configure.md#box-configureenvironmentsupdate-name [scripts]: https://github.com/box/boxcli/tree/main/examples [ccg-page]: https://github.com/box/boxcli/tree/main/docs/configure.md#box-configureenvironmentsadd-path [bulk]: https://github.com/box/boxcli/blob/main/docs/Bulk%20actions/README.md # Building Commands and Help Feature Source: https://developer.box.com/guides/cli/quick-start/build-commands-help A full list of CLI commands and usage information can be found in the [GitHub repository][github]. Only Service Accounts and Admins are able to use some commands. If your user is not authorized with the necessary scopes or you configured your CLI to obtain a default token for another user, calls may fail. Add `-v` or `--verbose` to your command for verbose error logging. If you do not see a command for an endpoint you need, you can build a [custom request][custom]. Use repository documentation in conjunction with reference documentation to see information the help command does not provide. This includes restrictions, token permission requirements, fields, etc. ## Using help to create a folder Every CLI command begins with `box`. Append the `--help` flag to any CLI command to display usage information, available actions, and required arguments. For example, executing `box --help` shows you to a list of all possible resource commands, such as `folders`, `files`, and `users`. More information is available in Using Options. Help Then, for example, use the folder object and execute the command `box folders --help`. This provides a list of all eligible actions for this object. Help Discover the required arguments for creating a folder: `box folders:create --help` Help Execute the command `box folders:create 0 "My CLI Folder"` and note the folder ID returned in the response. The root level of the folder tree, the All Files page, is always represented by folder ID 0. Log into **your** Box account and verify that the folder appears. If you set up the Box CLI using JWT authentication, you will not see the folder in your Box account. The folder will live in the service account of the application that was created after application approval. [github]: https://github.com/box/boxcli#command-topics-1 [custom]: https://github.com/box/boxcli/blob/master/docs/request.md [sa]: /platform/user-types/#service-account # Using Bulk Commands Source: https://developer.box.com/guides/cli/quick-start/using-bulk-commands ## Bulk Commands You can use a CSV file to execute commands in bulk. Each row of the spreadsheet is treated as an individual API call. To execute a bulk command, use the option `--bulk-file-path=`, where `` is the local path of a CSV file containing the necessary information. For example, you can create folders using the command `box folders:create --bulk-file-path=path/to/file.csv` Drag the CSV file from your finder window/file explorer to the terminal/command line window to auto-populate the path. To specify the column names for your CSV file, go to the [GitHub repository][github] and look at the argument names, or use the `--help` option. In this case, these are `PARENTID` and `NAME` and are case insensitive. You can also use a CSV [template][csv] for this example bulk create folders command. Executing the command below creates three folders at the root level, 0, of the Service Account's folder tree. ```bash theme={null} box folders:create --bulk-file-path=/Users/ExampleUser/Desktop/bulkcreatefolders.csv ``` ## Set up and use bulk commands 1. Clone the `boxcli` GitHub repository or download the files from [`Bulk actions`][bulkactions] directory. ```bash theme={null} git clone https://github.com/box/boxcli.git ``` 2. Adjust the `.csv` template to your needs. For example, if you want to create several folders, you can use the [`folders-create.csv`][folderstemplate] template as your starting point. 3. Run the command. ```bash theme={null} box folders:create --bulk-file-path /folders-create.csv ``` [console]: https://app.box.com/developers/console [bulkactions]: https://github.com/box/boxcli/tree/main/docs/Bulk%20actions [folderstemplate]: https://github.com/box/boxcli/blob/main/docs/Bulk%20actions/folders/folders-create.csv ## Bulk Commands with Options Any option included in the command is applied to every row in the CSV file. For example, `box folders:collaborations:create --bulk-file-path=path/to/file.csv --role=editor` will create collaborations for each user in the csv as an editor. However, you can also use options in the CSV file. Building on the last example, instead of using the `--role=editor` option in the command itself, it can be a column called `role`. The command becomes: `box folders:collaborations:create --bulk-file-path=pathtocsv` ## CSV templates Predefined CSV templates help you to structure the data you want to manage in bulk. Templates reside in the [`Bulk actions`][bulkactions] directory, grouped into folders. The table below lists the currently available templates. | Templates | Description | | ---------------------- | ------------------------------------------------------------------- | | box collaborations | Create, delete, and update collaborations. | | box files | Download, update, and upload files. | | box folders | Create and update folders, add metadata to folders. | | box groups | Create groups and add memberships. | | box metadata-templates | Create metadata templates and metadata cascade policies on folders. | | box shared-links | Delete shared links. | | box users | Create and update users, move one user's content to another user. | | box webhooks | Delete webhooks. | [github]: https://github.com/box/boxcli#command-topics [csv]: https://github.com/box/boxcli/blob/main/docs/Bulk%20actions/folders/folders-create.csv # Using Options Source: https://developer.box.com/guides/cli/quick-start/using-options ## Options Options, also known as flags, provide additional, optional functionality to use with a CLI command. To see all valid options for a command, run it with `--help` or visit the [GitHub repository][github]. ## Getting help Add `--help` to any command to see its usage, arguments, and available flags. ```bash theme={null} box folders --help ``` ## Controlling output format ### JSON output Use `--json` to return the full API response as structured JSON. This is useful for scripting or when you need to inspect the complete response. ```bash theme={null} box files:get 123456 --json ``` ### CSV output Use `--csv` to return results as a CSV. This pairs well with `--save` to produce reports you can open in a spreadsheet. ```bash theme={null} box folders:items 0 --csv --save ``` ### Filtering fields Use `--fields` to specify only the fields you need in the response. This reduces output noise and can speed up calls that would otherwise return a large number of fields. ```bash theme={null} box folders:items 0 --fields id,name,login ``` ## Saving output ### Save to the default reports folder Use `--save` to write output to the default reports directory. ```bash theme={null} box folders:items 0 --csv --save ``` ### Save to a custom path Use `--save-to-file-path` to override the default location and write output to a specific location. ```bash theme={null} box folders:items 0 --json --save-to-file-path ./exports/users.json ``` ## Scripting and automation ### Skip confirmation prompts Use `--yes` to automatically answer yes to any confirmation prompt. This is useful when running the CLI in scripts or automated pipelines. ```bash theme={null} box folders:delete 123456 --yes ``` ### Disable color Use `--no-color` to strip ANSI color codes from output. This is recommended when capturing output in log files or CI environments where color codes can corrupt output. ```bash theme={null} box folders:items 0 --no-color ``` ## Debugging Use `--verbose` to print detailed output including request and response metadata. Add this flag when troubleshooting unexpected errors. ```bash theme={null} box folders:items 0 --verbose ``` ## Using a specific token Use `--token` to authenticate a single command with a specific access token, overriding the configured default environment. This is useful when testing tokens or running one-off calls without switching environments. ```bash theme={null} box folders:items 0 --token YOUR_ACCESS_TOKEN ``` ## As-User header Use the `--as-user` option to perform an action on behalf of another user. For example, the following command creates a folder called `Example_Folder` at the root level in user ID 123456's account. ```bash theme={null} box folders:create 0 Example_Folder --as-user=123456 ``` Only Service Accounts and Admins are able to use the as-user header. If your application was not authorized with the necessary scopes or you configured your CLI to obtain a default token for another user, this call may fail. Add `-v` or `--verbose` to your command for verbose error logging. [github]: https://github.com/box/boxcli#command-topics [df]: https://github.com/box/boxcli/blob/master/docs/folders.md#box-foldersdelete-id # Deprovision users and archive folders Source: https://developer.box.com/guides/cli/scripts/deprovision-users This script allows you to deprovision and delete a list of users. It performs the following steps: 1. Transfers the user content to the another user's root folder, specified in the `EmployeeArchiveFolderName` parameter. 2. Deletes the user. ## Prerequisites ### Windows Install the latest version of [.NET core](https://dotnet.microsoft.com/download). ### macOS & Linux Install [PowerShell][pwsh]. Run the `pwsh` command to test the installation. ```bash theme={null} pwsh ``` Depending on the directory you are running the command in, the output may differ. For example: ```bash theme={null} PowerShell 7.2.5 Copyright (c) Microsoft Corporation. https://aka.ms/powershell Type 'help' to get help. PS /Users/user/repos/boxcli/examples> ``` If you encounter issues make sure you installed both [dotnet core](https://dotnet.microsoft.com/download) and [PowerShell][pwsh]. ### Box CLI To use the script, you need the Box CLI installed and configured. You can do this by following our quick start guide. The user you use to login with should be the main Box admin or co-admin. ## Configure the script 1. Clone the `boxcli` GitHub repository and cd into this example's folder or download the files from [`examples`][examples] directory. ```bash theme={null} git clone https://github.com/box/boxcli.git boxcli cd boxcli/examples/User\ Deprovisioning/ ``` 2. Create the list of employees for deletion in `.csv`. The header row should look like as follows: ```bash theme={null} name, email ``` where: * `name` is the name of the user in Box. * `email` is the primary email address of the user in Box. For example: | `name` | `email` | | -------------- | ----------------------- | | Managed User 1 | `ManagedUser1@test.com` | | Managed User 2 | `ManagedUser2@test.com` | | Managed User 3 | `ManagedUser3@test.com` | ### List of parameters | `Parameter` | `Description` | `Required` | `Default Value` | | --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- | -------------------------------------------------------------------------------------------------------------------- | | `EmployeeList` | Path to Employee List CSV with employees to be deleted. | Yes | - | | `SkipTransferContent` | Set this flag to skip transfer of user content before deletion when running the script. Otherwise user's content will be transferred. | No | `False` | | `NewFilesOwnerID` | The ID of the user to transfer files to before deleting the user. If not specified, the script will prompt to input in the interactive mode, or use the current authenticated user ID to receive the content. | No | If not specified, the script will prompt to input in the interactive mode, or use the current authenticated user ID. | | `EmployeeArchiveFolderName` | The name of a folder, where users' content will be moved to if `SkipTransferContent` is set to `False`. If a folder with this name already exists in the user's `NewFilesOwnerID` root folder, it will be used. Otherwise, a new one will be created. | Yes | `Employee Archive` | | `DryRun` | A flag that determines the script should be run in a mode, where no delete/create/update calls will be made, only read ones. | No | `False` | ### Define script parameters You can the following options to pass parameters. * Use hardcoded value in script. To use this option, update all required parameters listed in the [script parameters section][parameters] before running. * Run script with parameters. You can specify parameters while providing the command. For example: ```bash theme={null} PS > ./Users_Deprovision.ps1 -EmployeeList ./Employees_to_delete.csv ` -NewFilesOwnerID 123456789 -EmployeeArchiveFolderName "Employee Archive" ``` or ```bash theme={null} PS > ./Users_Deprovision.ps1 -EmployeeList ./Employees_to_delete.csv ` -SkipTransferContent ``` If you don't specify parameters, the script will prompt you to enter it. ```bash theme={null} PS > ./Users_Deprovision.ps1 Please enter the path to the employee list CSV file: ./Employees_to_delete.csv Please specify the user ID of the user who will own the files of the users being deprovisioned. Press Enter if you want to use the current user as the new owner. User ID: 1234567689 Starting User Deprovisioning script... ``` ## Run the script Now all you need to do is run the script. 1. Run the Powershell command. ```bash theme={null} pwsh ``` 2. Run the script: ```bash theme={null} ./Users_Deprovision.ps1 ``` When all parameters are defined, you will see following output to confirm the script started: ```bash theme={null} PS /home/rvb/box-cli/examples/User Deprovisioning> ./Users_Deprovision.ps1 Starting User Deprovisioning script... ``` ## Logging Logs are stored in a `logs` folder located in the main folder. You have access to these log files: * `Users_Deprovision_all.txt` that contains all log entries * `Users_Deprovision_errors.txt` that contains only errors. [scripts]: https://github.com/box/boxcli/tree/main/examples [pwsh]: https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell?view=powershell-7.2 [console]: https://app.box.com/developers/console [auth]: /guides/authentication/oauth2/oauth2-setup [examples]: https://github.com/box/boxcli/tree/main/examples/User%20Deprovisioning [parameters]: https://github.com/box/boxcli/tree/main/examples/User%20Deprovisioning/Users_Deprovision.ps1#L17-L36 [employeelist]: https://github.com/box/boxcli/blob/main/examples/User%20Deprovisioning/Users_Deprovision.ps1#L12 # CLI sample scripts Source: https://developer.box.com/guides/cli/scripts/index Box CLI scripts are designed to help you automate your tasks. Currently, the sample scripts library provides several PowerShell scripts you can use and customize. In order to run them, you need to install and configure the Box CLI. You can follow the quick start guide to get that done. Most of the below scripts require the user you run commands with to have Box [administrative privileges][7]. ## PowerShell scripts * PowerShell script templates * Deprovision users and archive folders * Manage groups and collaborations * Report inactive users * Extract metadata * Update user zones * Manage Slack integration folder mappings [7]: https://support.box.com/hc/en-us/articles/360043694174-Understanding-Administrator-and-Co-Administrator-Permissions # Manage groups and collaborations Source: https://developer.box.com/guides/cli/scripts/manage-groups-collaborations ## Script structure This script uses the Box CLI to create or update groups, add users to them, and create collaborations between groups and folders. The script consists of two parts described in detail in the sections below. You can run them both or use the optional flags to decide which part to run. ### Create or update groups 1. The script uses the `.csv` file you specify for the `UserGroupAdditionPath` parameter. The file lists group names and user emails. When creating the file, you can use the same group name for several users, and assign one user to several groups. For example: | `GroupName` | `UserEmail` | | ----------- | ----------------------- | | Group1 | `ManagedUser1@test.com` | | Group1 | `ManagedUser2@test.com` | | Group2 | `ManagedUser3@test.com` | | Group3 | `ManagedUser1@test.com` | 2. If the group doesn't exist, the script creates it. If it does exist, the script can update the entries based on the provided data. ### Create or update collaborations 1. The script uses the `.csv` file you specify for the `CollaborationsCreationPath` parameter. The file lists group names, folder IDs, and collaboration roles. 2. For each row, the script checks if a group exists and if it's not already added as a collaborator to the corresponding folder. For example: | `GroupName` | `FolderId` | `CollaborationRole` | | ----------- | ---------- | ------------------- | | Group1 | 1111111 | editor | | Group2 | 1111111 | viewer\_uploader | | Group2 | 2222222 | viewer | | Group3 | 1111111 | viewer\_uploader | 3. If both of these conditions are met, the script assigns the group to a folder using the role defined in the `CollaborationRole` column. Also, if a group already exists, but the `CollaborationRole` changed, the script will update it if you pass the `-UpdateExistingCollabs` flag when running the script. ## Prerequisites ### Windows Install the latest version of [.NET core](https://dotnet.microsoft.com/download). ### MacOS & Linux Install [PowerShell][pwsh]. Run the `pwsh` command to test the installation. ```bash theme={null} pwsh ``` Depending on the directory you are running the command in, the output may differ. For example: ```bash theme={null} PowerShell 7.2.5 Copyright (c) Microsoft Corporation. https://aka.ms/powershell Type 'help' to get help. PS /Users/user/repos/boxcli/examples> ``` If you encounter issues make sure you installed both [dotnet core](https://dotnet.microsoft.com/download) and [PowerShell][pwsh]. ### Box CLI To use the script, you need to install and configure the Box CLI. You can do this by following our quick start guide. The user you use to login with should be the main Box admin or co-admin. ## Configure the script 1. Clone the `boxcli` GitHub repository and cd into this example's folder or download the files from the [`examples`][examples] directory. ```bash theme={null} git clone https://github.com/box/boxcli.git boxcli cd boxcli/examples/Mass\ Groups\ \&\ Collaborations\ Update/ ``` 2. Set the path to the `.csv` file with the list of groups and user emails. ```bash theme={null} $UserGroupAdditionPath = "./User_Group_Addition.csv" ``` * `UserEmail` is the primary email address for the user in Box. * `GroupName` is the name of the group. 3. Set your own path to the `.csv` file with the list groups and user emails. ```bash theme={null} $CollaborationsCreationPath = "./Collaborations_Creation.csv" ``` * `GroupName` is name of the group the script will add as a collaborator to the folder. * `FolderId` is the folder ID the collaborator will be added to. * `CollaborationRole` is the name of the role used when creating a collaboration. You can configure the available roles by setting the `AvailableCollaborationRoles` parameter: ```bash theme={null} $AvailableCollaborationRoles = @("editor", "viewer", "previewer", "uploader", "previewer_uploader", "viewer_uploader", "co-owner") ``` ## Run the script 1. Run the Powershell command. ```bash theme={null} pwsh ``` 2. Run the script. ```bash theme={null} ./Mass_Groups_Collabs_Update.ps1 ``` ### Optional flags You can use flags to run or skip specific parts of the script. * If a group is already set as a collaborator for a specific folder but with a role other than defined in the .`csv` file, the script informs you about it. It does not make any changes to an existing collaboration. If you want to update an existing collaboration with a role defined in the `.csv` file, set an additional `-UpdateExistingCollabs` flag when running the script. ```bash theme={null} Mass_Groups_Collabs_Update.ps1 -UpdateExistingCollabs ``` * To update groups without creating collaborations, add the `-SkipCollabsCreation` boolean flag when running the script: ```bash theme={null} Mass_Groups_Collabs_Update.ps1 -SkipCollabsCreation ``` * To create collaborations without any group updates, add the `-SkipGroupsUpdate` boolean flag when running the script: ```bash theme={null} Mass_Groups_Collabs_Update.ps1 -SkipGroupsUpdate ``` ## Logs Logs are stored in the `logs` folder located in the main folder. You have access to these log files: * `Mass_Groups_Collabs_Update_all.txt` that contains all log entries. * `Mass_Groups_Collabs_Update_errors.txt` that contains only errors. [examples]: https://github.com/box/boxcli/tree/main/examples [pwsh]: https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell?view=powershell-7.2 [console]: https://app.box.com/developers/console [auth]: /guides/authentication/oauth2/oauth2-setup # Extract metadata Source: https://developer.box.com/guides/cli/scripts/metadata-extraction This script extracts metadata details for all the files and folders in any Box folder and saves the result in a CSV spreadsheet for each metadata template. ## Prerequisites ### Windows Install the latest version of [.NET core](https://dotnet.microsoft.com/download). ### macOS & Linux Install [PowerShell][pwsh]. Run the `pwsh` command to test the installation. ```bash theme={null} pwsh ``` Depending on the directory you are running the command in, the output may differ. For example: ```bash theme={null} PowerShell 7.2.5 Copyright (c) Microsoft Corporation. https://aka.ms/powershell Type 'help' to get help. PS /Users/user/repos/boxcli/examples> ``` If you encounter issues make sure you installed both [.NET core](https://dotnet.microsoft.com/download) and [PowerShell][pwsh]. ### Box CLI To use the script, you need the Box CLI installed and configured. You can do this by following our quick start guide. ## Configure the script 1. Clone the `boxcli` GitHub repository and cd into this example's folder or download the files from the [`examples`][examples] directory. ```bash theme={null} git clone https://github.com/box/boxcli.git cd boxcli/examples/Metadata\ Extraction/ ``` 2. Specify the `folderID` and `userID` parameters to tell the script which folder to scan, and who is the user running the script. ```bash theme={null} [string]$FolderID = "", [string]$UserID = "", ``` If you don't want to specify the parameters directly in the script, you can either pass them as flags or allow the script to prompt you to enter them. A sample command with flags looks as follows: ```bash theme={null} ./Metadata-extraction.ps1 -folderId 123456789 -userId 123456789 ``` ## Run the script 1. Run the Powershell command. ```bash theme={null} pwsh ``` 2. Run the script. ```bash theme={null} ./Metadata-extraction.ps1 -folderId 123456789 -userId 123456789 ``` When the script finishes, you will see the following output or a similar one. ```bash theme={null} Pulling data from Folder ID: 173961139760 metadata as user ID: 20718545815 Reading Item ID: 1016853559790 Metadata saved to: MetadataTemplate_properties.csv ``` ## Logs Logs are stored in a `logs` folder located in the main folder. You have access to these log files: * `Metadata-extraction_all.txt` that contains all log entries. * `Metadata-extraction_errors.txt` that contains only errors. [scripts]: https://github.com/box/boxcli/tree/main/examples [pwsh]: https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell?view=powershell-7.2 [console]: https://app.box.com/developers/console [auth]: /guides/authentication/oauth2/oauth2-setup [examples]: https://github.com/box/boxcli/tree/main/examples/Metadata%20Extraction # Using PowerShell Scripts with the Box CLI Source: https://developer.box.com/guides/cli/scripts/powershell-script-templates You can automate repetitive administrative workflows by combining the Box CLI with PowerShell scripts. We created an example [scripts][scripts] folder within our CLI GitHub repository to help jump-start your development. To show you how CLI scripts work, we are going to use the provision and create users [script][script-1] template. This script uses the Box CLI to build and create a personal folder structure, create managed users in bulk, and provision new users by adding them to the newly created folder structure as collaborators with viewer or uploader roles. This guide is for service accounts and users with administrative privileges only. Skip this step if you are not a Box administrator or you do not use a service account. ## Use case To automatically create users and folder structure, the script performs the following steps: 1. Uses a `.csv` file to load employee data in bulk. 2. Defines folder structure using a JSON file or uploads the structure from the user's local directory. 3. Creates a predetermined personal folder structure for each new managed user. ## Prerequisites ### Windows Install the latest version of [.NET core](https://dotnet.microsoft.com/download). ### macOS & Linux Install [PowerShell][pwsh]. ### Box CLI To use the script, you need the Box CLI installed and configured. If you haven't done so yet, see our quick start guide. ### Create a personal folder parent folder This script works by creating a folder structure for each user that is created. To do this, create a parent folder for all of the personal folders to live in. By default all folders are created in the root folder of the account used by the CLI. You can name and place the folder wherever you wish, but the user you set up the CLI with must have access to the folder. Here is an example of what the structure looks like after running the script. Finished Folder Structure ## Download the script Clone the script to a directory of your choice and navigate to that directory. ```bash theme={null} git clone https://github.com/box/boxcli.git box-cli cd box-cli/examples/User\ Creation\ \&\ Provisioning/ ``` ## Configure the script settings Adapt the script to run in your own environment. In this example, we use the sample data provided with the script. ### Provide the parameters There are a few parameters you need to supply before running the script: * `EmployeeList`: Path to `Employee List` CSV. * `PersonalFolderParentID`: Destination folder ID for all personal folders to be created in, either when using JSON file as input to create folder structure, or uploading local structure. This folder should be made prior to running the script the first time. It is not advised to make this value `0`, as this creates individual personal folders in the root of the account you set up the CLI with. * `FolderStructureJSONPath`: Your own folder structure JSON path. * `PersonalFolderSlug`: Ending name of the folder created as a parent for personal folders. It's set to `Personal Folder` by default, but you can set it to your needs. The username is linked with this value to create each user's personal folder name. For example - `rsmith2's Personal Folder`. * `LocalUploadPath`: Local directory to upload folder structure directly. Specify **either** a local upload path or a JSON file with the folder structure, but not both. ### Update the user list You can use the following sample files to load users: `Employees_1.csv`, `Employees_5.csv`, and `Employees_10.csv`. Each file creates 1, 5, or 10 new users. Customize these files for a test run. For example, update the `Employees_1.csv` with the following data: ```bash theme={null} firstName,lastName,email,username Isaac,Newton,abc@abc.local,INewton23 ``` With the `EmployeeList` parameter, specify which `.csv` file you would like to load data from. Emails must be unique across all of Box, and usernames must be unique across your specific Box instance. Otherwise, an error will be thrown when running the script. ### Create folder structure You can either create a folder structure from a JSON file or upload it from your local drive. #### Use a JSON file The `Folder_Structure.json` file contains the folder structure you want to create. As an example, you will create a `Market Research` and a `Sales Plays` folder, each with a subfolder `Statistics` and `Big Pharma` respectively. The script will place this folder structure under the `Personal Folder` folder for that user inside the parent folder you designate. With the `FolderStructureJSONPath` parameter, provide the location of the `Folder_Structure.json` file. #### Upload file from local drive You can also upload a folder structure directly from the local file system. With the `LocalUploadPath` parameter, provide the path to your local folder you want to upload. The uploaded folder structure is created in Box using the same naming structure as the JSON method. ### Update the parameters You can provide parameters in three ways: * Use static values in the script Remember to update all required parameters in the script before running. ```bash theme={null} # Set Employee List CSV Path # firstname, lastname, email, username $EmployeeList = "" # Personal Folder Structure: Set either path build off JSON or directly upload # a local folder $FolderStructureJSONPath = "" $LocalUploadPath = "" # Ending slug of folder that will be used in creating personal folders for new # users. Value will get concatenated with username # If username is RSMITH, the personal folder name would be # RSMITH's Personal Folder $PersonalFolderSlug = "" # ID of parent folder for created personal folders to be created in # This folder should be created before running the script the first time. # It is not advised to make this value 0, as this will create individual # Personal folders in root of the account you set up the cli with $PersonalFolderParentID = "" ``` * Run the script with parameters You can specify parameters while running the script, for example: ```bash theme={null} PS > ./Users_Create_Provision.ps1 -EmployeeList ./Employees_1.csv ` -LocalUploadPath ./PersonalLocalUpload ` -PersonalFolderSlug "Personal Folder" ` -PersonalFolderParentID 123456789 Starting User Creation & Provisioning script... ``` * Provide the parameters when prompted If some parameters are still missing at runtime, the script will prompt you to provide them: ```bash theme={null} PS > ./Users_Create_Provision.ps1 Please enter the path to the employee list CSV file: ./Employees_1.csv Please enter the path to the folder structure JSON file or the local upload path: Folder_Structure.json Folder structure JSON path set to: Folder_Structure.json Please enter the ID of the folder where you would like to create the personal folders: 0 Starting User Creation & Provisioning script... ``` ## Run the script 1. Change the directory to the folder containing the script. In this example, it is the `User Creation & Provisioning` folder. ```bash theme={null} pwsh ``` 2. Run the script: ```bash theme={null} PS /home/rvb/box-cli/examples/User Creation & Provisioning> ./Users_Create_Provision.ps1 ``` The response will be similar to the following: ```bash theme={null} Starting User Creation & Provisioning script... firstName lastName email --------- -------- ----- Isaac Newton abc@abc.local Extracting folder structure Found current User ID: 18622116055 Created a user owned Onboarding folder with id: 164734146745 Created subfolder Market Research under Onboarding folder with id: 164735375585 Created subfolder under Statistics folder with id: 164734956242 Created subfolder Sales Plays under Onboarding folder with id: 164735683001 Created subfolder under Big Pharma folder with id: 164736160637 Creating employee Managed User account with first name: Isaac, last name: Newton, email: abc@abc.local, and Created Managed user with id: 19605663027 Type: collaboration ID: '37250833128' Created By: Type: user ID: '18622116055' Name: Rui Barbosa Login: barduinor@gmail.com Created At: '2022-06-07T13:58:05-07:00' Modified At: '2022-06-07T13:58:05-07:00' Expires At: null Status: accepted Accessible By: Type: user ID: '19605663027' Name: Isaac Newton Login: abc@abc.local Invite Email: null Role: viewer uploader Acknowledged At: '2022-06-07T13:58:05-07:00' Item: Type: folder ID: '164734146745' Sequence ID: '0' ETag: '0' Name: Onboarding Collaborated Managed User Isaac Newton to current users Onboarding folder for provisioning ``` ## Running the script again for new users It is common to run this script regularly as your company hires new employees. You can simply edit the `.csv` file, removing the previous rows of users and adding the information for the new users. Then run the script again. ## Summary You explored automation using a PowerShell script with the Box CLI to provision users and create an initial folder structure. Make sure to explore our other sample scripts for more use cases. [scripts]: https://github.com/box/boxcli/tree/main/examples [script-1]: https://github.com/box/boxcli/tree/main/examples/User%20Creation%20&%20Provisioning [jwt-cli]: /guides/cli/cli-with-jwt-authentication/jwt-cli [pwsh]: https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell?view=powershell-7.2 [console]: https://app.box.com/developers/console # Report inactive users Source: https://developer.box.com/guides/cli/scripts/report-inactive-users This script generates a CSV file with a list of users who have been inactive for a number of days. It performs the following steps: 1. Looks for the users who have the role `user`. The script does not consider other roles, such as `AppUser`. 2. Uses Box Events to check if the user performed any actions for a specified number of days. The default list of event types includes: `LOGIN`,`UPLOAD`,`COPY`,`MOVE`,`PREVIEW`,`DOWNLOAD`,`EDIT`,`DELETE`,`UNDELETE`,`LOCK`,`UNLOCK`, `NEW_USER`. You can modify this list in the script settings. 3. Adds users who didn't perform any actions to a `.csv` file with inactive users. You can use this file as input for other scripts, for example to deprovision users. ## Prerequisites ### Windows Install the latest version of [.NET core](https://dotnet.microsoft.com/download). ### macOS & Linux Install [PowerShell][pwsh]. Run the `pwsh` command to test the installation. ```bash theme={null} pwsh ``` Depending on the directory you are running the command in, the output may differ. For example: ```bash theme={null} PowerShell 7.2.5 Copyright (c) Microsoft Corporation. https://aka.ms/powershell Type 'help' to get help. PS /Users/user/repos/boxcli/examples> ``` If you encounter issues make sure you installed both [.NET core](https://dotnet.microsoft.com/download) and [PowerShell][pwsh]. ### Box CLI To use the script, you need the Box CLI installed and configured. You can do this by following our quick start guide. The user you use to login with should be the main Box admin or co-admin. ## Configure the script 1. Clone the `boxcli` GitHub repository and cd into this example's folder or download the files from the [`examples`][examples] directory. ```bash theme={null} git clone https://github.com/box/boxcli.git cd boxcli/examples/Inactive\ Users\ Report/ ``` 2. Set the number of days you want the script to scan for user events. If you don't specify this value or leave the default, the script will prompt you to enter it. ```bash theme={null} $daysInactive = "10" ``` 3. (Optional) To change the report output file name, define the `ReportOutputFile` parameter. ```bash theme={null} $ReportOutputFile = $ReportName + ".csv" ``` 4. (Optional) To change event types, define the list for `eventType` parameter. ```bash theme={null} $eventType = "LOGIN,UPLOAD,COPY,MOVE" ``` ## Run the script Run the Powershell command. ```bash theme={null} pwsh ``` Run the script. ```bash theme={null} ./Inactive_Users_Report.ps1 ``` When the script run is completed, you will see the following output or a similar one. ```bash theme={null} Looking for users inactive for more than 3 days. Found 6 users. Found 7 events in last 3 days Enterprise has: 0 App user, 6 regular users. With 1 admin role, 5 user roles. Need to check 5 users (regular user, with user role) for inactive. Found 5 users inactive for more than 3 days. Report is available at InactiveUsers.csv ``` ## Logging Logs are stored in the `logs` folder located in the main folder. You have access to these log files: * `Inactive_Users_Report_all.txt` - contains all log entries * `Inactive_Users_Report_errors.txt` - contains only errors. [scripts]: https://github.com/box/boxcli/tree/main/examples [pwsh]: https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell?view=powershell-7.2 [console]: https://app.box.com/developers/console [auth]: /guides/authentication/oauth2/oauth2-setup [examples]: https://github.com/box/boxcli/tree/main/examples/Inactive%20Users%20Report # Manage Slack integration folder mappings Source: https://developer.box.com/guides/cli/scripts/slack-integration-mappings This script helps manage the folder mappings between Slack and Box if using Box as the content store for Slack. It creates a list of current Slack channel and Box folder mappings and can create or update mappings based on the input csv. This script maintains all permissions. For more details, see the [Github repo][1]. ## Prerequisites ### Clone script Clone this GitHub repo or download files from the `/examples` directory ```bash theme={null} git clone https://github.com/box/boxcli.git ``` ### Windows Install the latest version of [.NET core](https://dotnet.microsoft.com/download). ### MacOS & Linux Install [PowerShell][pwsh]. Run the `pwsh` command to test the installation. ```bash theme={null} pwsh ``` Depending on the directory you are running the command in, the output may differ. For example: ```bash theme={null} PowerShell 7.2.5 Copyright (c) Microsoft Corporation. https://aka.ms/powershell Type 'help' to get help. PS /Users/user/repos/boxcli/examples> ``` If you encounter issues make sure you installed both [dotnet core](https://dotnet.microsoft.com/download) and [PowerShell][pwsh]. ### Box CLI Install Configure and install the Box CLI using the CLI Quickstart Guide. Make sure the user you use is an admin or co-admin. ### Enterprise configuration * Configure and [install Box for Slack][install-slack] in the relevant Slack workspaces and organizations. * Enable Box as the [content layer for Slack][content-layer]. ## Run the script Change the directory to the folder containing the script. In this example, it is the `Integration Mappings` folder. ```pwsh theme={null} rvb@lab:~/box-cli/examples/Integration Mappings$ pwsh PowerShell 7.2.4 Copyright (c) Microsoft Corporation. https://aka.ms/powershell Type 'help' to get help. PS /home/rvb/box-cli/examples/Integration Mappings> ``` Run the script with EXTRACT to extract current mappings: ```pwsh theme={null} ./integration-mappings.ps1 -Action EXTRACT ``` or Run the script with UPDATE to update current mappings: ```pwsh theme={null} ./integration-mappings.ps1 -Action UPDATE ``` or Run the script with CREATE to create new mappings: ```pwsh theme={null} ./integration-mappings.ps1 -Action CREATE -MappingPath ./mapping_create_example.csv ``` By default, the csv file will save to and load from ./mappings.csv. If you wish to change this location, you can pass in a new path like so: ```pwsh theme={null} ./integration-mappings.ps1 -Action EXTRACT -MappingPath ./mappings_new_location.csv ``` If you don't specify parameters, the script prompts you to enter them. When creating a mapping on a new channel, you must input a Box folder ID, Slack channel ID, and Slack org ID. You can use a Slack workspace ID in place of the org ID. In that case, you need to replace the csv column header `SlackOrgId` with `SlackWorkspaceId`. ```pwsh theme={null} Starting Process Applying new mappings Output [...] All bulk input entries processed successfully. ``` ## Logs Logs are stored in a `logs` folder located in the main folder. You have access to these log files: * `Integration-mappings_all.txt` that contains all log entries. * `Integration-mappings_errors.txt` that contains only errors. ## Disclaimer This project is a collection of open source examples and should not be treated as an officially supported product. Use at your own risk and as a source of examples for how to use the Box CLI. [pwsh]: https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell?view=powershell-7.2 [install-slack]: https://support.box.com/hc/en-us/articles/360044195313-Installing-and-Using-the-Box-for-Slack-Integration [content-layer]: https://support.box.com/hc/en-us/articles/4415585987859-Box-as-the-Content-Layer-for-Slack [1]: https://github.com/box/boxcli/tree/main/examples/Integration%20Mappings # Update user zones Source: https://developer.box.com/guides/cli/scripts/user-zones-mass-update This [script][script] provisions users to a specific data residency zone within a Multizone Box tenant. It performs the following steps: 1. It uses admin or co-admin login email address to find the associated enterprise and the zone policy assigned to this enterprise. An assigned zone policy is inherited by all users unless specified otherwise. It is sometimes called the **default zone**. 2. It performs zone assignment based on an input `.csv` file containing user email addresses and zone mappings. Usually, you use the script once to do the initial provisioning of user zones, but you can also use it for subsequent runs to make zone assignment updates. If you would like to use Admin Console for zone assignment, see [this guide][zonesguide]. For more information about Box Zones, see the [official website][zonespage]. ## Prerequisites ### Windows Install the latest version of [.NET core](https://dotnet.microsoft.com/download). ### MacOS & Linux Install [PowerShell][pwsh]. Run the `pwsh` command to test the installation. ```bash theme={null} pwsh ``` Depending on the directory you are running the command in, the output may differ. For example: ```bash theme={null} PowerShell 7.2.5 Copyright (c) Microsoft Corporation. https://aka.ms/powershell Type 'help' to get help. PS /Users/user/repos/boxcli/examples> ``` If you encounter issues make sure you installed both [.NET core](https://dotnet.microsoft.com/download) and [PowerShell][pwsh]. ### Set up application with JWT authentication To use the script, you need to install and configure the Box CLI with JWT authentication. When creating the app, use the **Configuration** tab to configure the following settings: * In **App Access Level**, select `App + Enterprise Access`. * In **Application Scopes** > **Administrative Actions**, select `Manage Enterprise Properties`, `Manage Users`. * In **Advanced Features**, select `Generate user access tokens`. ### Adjust admin settings Make sure the Box Admin or Co-Admin has at least `Manage Users` privileges. To check this setting: 1. Go to the **Users & Groups** section in the Admin Console. 2. Click the user account you want to verify. 3. Go to the **Edit User Access permissions** section to grant administrative privileges for users and groups. ## Prepare the `.csv` file The `.csv` file must have two columns with the following headers: **Email** and **Region**. * **Email** contains the primary email address of a Box user. * **Region** contains the user-friendly name for the zone to which the script will assign the user. This name is provided by the [ZonesTable][zonestable] that is a hash table used to define zones. The keys are the zone's user-friendly names, and the corresponding value is the global ID of the zone. ```bash theme={null} $ZonesTable = @{ US = "100001" #US GermanyIreland = "100002" #Germany/Ireland with in region uploads/downloads/previews Australia = "100003" #Australia Japan = "100004" #Japan with in region uploads/downloads/previews Canada = "100005" #Canada JapanSingapore = "100007" #Japan/Singapore with in region uploads/downloads/previews UKGermany = "100008" #UK/Germany UK = "100009" #UK with in region uploads/downloads/previews France = "100012" #France } ``` Consult the Box Consulting or Customer Success manager to get the IDs corresponding to the zones enabled in a specific enterprise. A sample input `.csv` file containing emails and zone names is provided with this script. Its content looks as follows: | Email | Region | | ------------------- | -------------- | | `betty@company.com` | US | | `roger@company.com` | France | | `sally@company.com` | JapanSingapore | ## Configure the script Set the `UserZonesUpdatePath` to point to your `.csv` file. ```bash theme={null} $UserZonesUpdatePath = "./your_file_name.csv" ``` Update the `adminEmail` to the admin or `co-admin` login email address of the account the script will use to make zone assignments. If you don't specify this value, the script will prompt you for it. ```bash theme={null} $adminEmail = "john@box.com" ``` ## Run the script Run the Powershell command. ```bash theme={null} pwsh ``` Run the script. ```bash theme={null} ./Mass_Update_User_Zones.ps1 ``` ### Optional flags To run the script in simulation mode, add the `DryRun` boolean flag. Dry run doesn't mean that API calls won't be made, but that any create/update/delete calls are skipped. ```bash theme={null} ./Mass_Update_User_Zones.ps1 -DryRun ``` ## Logging Logs are stored in a `logs` folder located in the main folder. You have access to these log files: * `Mass_Update_User_Zones_all.txt` that contains all log entries. * `Mass_Update_User_Zones_errors.txt` that contains only errors. [zonesguide]: https://support.box.com/hc/en-us/articles/360044193533-Assigning-Zones-through-the-Admin-Console [script]: https://github.com/box/boxcli/tree/main/examples/Mass%20Update%20User%20Zones [zonespage]: https://www.box.com/zones [zonestable]: https://github.com/box/boxcli/blob/main/examples/Mass%20Update%20User%20Zones/Mass_Update_User_Zones.ps1#L23 [scripts]: https://github.com/box/boxcli/tree/main/examples [pwsh]: https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell?view=powershell-7.2 [console]: https://app.box.com/developers/console # Allow a domain for collaboration Source: https://developer.box.com/guides/collaborations/allowed-domains/create An enterprise that normally restricts creating collaborations can add domains, such as `example.com`, to a list for which collaborations may be created within the enterprise. ```sh cURL theme={null} curl -i -X POST "https://api.box.com/2.0/collaboration_whitelist_entries" \ -H "authorization: Bearer " \ -H "content-type: application/json" \ -d '{ "domain": "example.com", "direction": "inboud" }' ``` ```typescript Node/TypeScript v10 theme={null} await client.collaborationAllowlistEntries.createCollaborationWhitelistEntry({ direction: 'inbound' as CreateCollaborationWhitelistEntryRequestBodyDirectionField, domain: domain, } satisfies CreateCollaborationWhitelistEntryRequestBody); ``` ```python Python v10 theme={null} client.collaboration_allowlist_entries.create_collaboration_whitelist_entry( domain, CreateCollaborationWhitelistEntryDirection.INBOUND ) ``` ```cs .NET v10 theme={null} await client.CollaborationAllowlistEntries.CreateCollaborationWhitelistEntryAsync(requestBody: new CreateCollaborationWhitelistEntryRequestBody(direction: CreateCollaborationWhitelistEntryRequestBodyDirectionField.Inbound, domain: domain)); ``` ```swift Swift v10 theme={null} try await client.collaborationAllowlistEntries.createCollaborationWhitelistEntry(requestBody: CreateCollaborationWhitelistEntryRequestBody(direction: CreateCollaborationWhitelistEntryRequestBodyDirectionField.inbound, domain: domain)) ``` ```java Java v10 theme={null} client.getCollaborationAllowlistEntries().createCollaborationWhitelistEntry(new CreateCollaborationWhitelistEntryRequestBody(domain, CreateCollaborationWhitelistEntryRequestBodyDirectionField.INBOUND)) ``` ```cs .NET v6 theme={null} BoxCollaborationWhitelistEntry entry = await client.CollaborationWhitelistManager.AddCollaborationWhitelistEntryAsync( "example.com", "both" ); ``` ```javascript Node v4 theme={null} client.collaborationAllowlist.addDomain('test.com', client.collaborationAllowlist.directions.INBOUND, callback); ``` The endpoint will require the `domain` to allow the collaborations between, and a `direction`, which may be set to: * `inbound`: Whether external users may be collaborated in on content in your enterprise. * `outbound`: Whether your enterprise managed users may be collaborated in on content owned within an external enterprise. * `both`: Both of the above. Supply both parameter to set up the new allowed domain. ```sh cURL theme={null} curl -i -X POST "https://api.box.com/2.0/collaboration_whitelist_entries" \ -H "authorization: Bearer " \ -H "content-type: application/json" \ -d '{ "domain": "example.com", "direction": "inboud" }' ``` ```typescript Node/TypeScript v10 theme={null} await client.collaborationAllowlistEntries.createCollaborationWhitelistEntry({ direction: 'inbound' as CreateCollaborationWhitelistEntryRequestBodyDirectionField, domain: domain, } satisfies CreateCollaborationWhitelistEntryRequestBody); ``` ```python Python v10 theme={null} client.collaboration_allowlist_entries.create_collaboration_whitelist_entry( domain, CreateCollaborationWhitelistEntryDirection.INBOUND ) ``` ```cs .NET v10 theme={null} await client.CollaborationAllowlistEntries.CreateCollaborationWhitelistEntryAsync(requestBody: new CreateCollaborationWhitelistEntryRequestBody(direction: CreateCollaborationWhitelistEntryRequestBodyDirectionField.Inbound, domain: domain)); ``` ```swift Swift v10 theme={null} try await client.collaborationAllowlistEntries.createCollaborationWhitelistEntry(requestBody: CreateCollaborationWhitelistEntryRequestBody(direction: CreateCollaborationWhitelistEntryRequestBodyDirectionField.inbound, domain: domain)) ``` ```java Java v10 theme={null} client.getCollaborationAllowlistEntries().createCollaborationWhitelistEntry(new CreateCollaborationWhitelistEntryRequestBody(domain, CreateCollaborationWhitelistEntryRequestBodyDirectionField.INBOUND)) ``` ```cs .NET v6 theme={null} BoxCollaborationWhitelistEntry entry = await client.CollaborationWhitelistManager.AddCollaborationWhitelistEntryAsync( "example.com", "both" ); ``` ```javascript Node v4 theme={null} client.collaborationAllowlist.addDomain('test.com', client.collaborationAllowlist.directions.INBOUND, callback); ``` # Remove a previously allowed domain for collaboration Source: https://developer.box.com/guides/collaborations/allowed-domains/delete Deleting a domain from the list of allowed collaboration domains will remove the ability for collaborations to be created between your enterprise and users in that domain. To remove a domain from the allowed list, supply the ID of the list entry to the delete request. This ID is returned when allowing a new domain or listing the allowed domains in the enterprise; ```sh cURL theme={null} curl -i -X DELETE "https://api.box.com/2.0/collaboration_whitelist_entries/213123" \ -H "authorization: Bearer " ``` ```typescript Node/TypeScript v10 theme={null} await client.collaborationAllowlistEntries.deleteCollaborationWhitelistEntryById( entry.id!, ); ``` ```python Python v10 theme={null} client.collaboration_allowlist_entries.delete_collaboration_whitelist_entry_by_id( entry.id ) ``` ```cs .NET v10 theme={null} await client.CollaborationAllowlistEntries.DeleteCollaborationWhitelistEntryByIdAsync(collaborationWhitelistEntryId: NullableUtils.Unwrap(entry.Id)); ``` ```swift Swift v10 theme={null} try await client.collaborationAllowlistEntries.deleteCollaborationWhitelistEntryById(collaborationWhitelistEntryId: entry.id!) ``` ```java Java v10 theme={null} client.getCollaborationAllowlistEntries().deleteCollaborationWhitelistEntryById(entry.getId()) ``` ```cs .NET v6 theme={null} string entryID = "11111"; await client.CollaborationWhitelistManager.DeleteCollaborationWhitelistEntryAsync(entryID); ``` ```javascript Node v4 theme={null} client.collaborationAllowlist.removeDomain('12345', callback); ``` # Allowed collaboration domains Source: https://developer.box.com/guides/collaborations/allowed-domains/index Within the content and sharing settings for an enterprise, an admin can specify [collaboration restrictions][collab-restrictions] for the enterprise. These settings include the ability to limit collaborations to only a series of allowed domains. The allowed domain APIs are available to allow applications with appropriate permissions to add, fetch, and delete these allowed domains programmatically for the enterprise. [collab-restrictions]: https://support.box.com/hc/en-us/articles/4404822772755-Enterprise-Settings-Content-Sharing-Tab # List allowed domains for collaboration Source: https://developer.box.com/guides/collaborations/allowed-domains/list Listing the domains that are allowed for collaboration will return all domains that permit collaborations to be created with the current enterprise. There are no required parameters for the request, but `limit` and `market` parameters may optionally be set to limit and page through the full result set. ```sh cURL theme={null} curl -i -X GET "https://api.box.com/2.0/collaboration_whitelist_entries" \ -H "authorization: Bearer " ``` ```typescript Node/TypeScript v10 theme={null} await client.collaborationAllowlistEntries.getCollaborationWhitelistEntries(); ``` ```python Python v10 theme={null} client.collaboration_allowlist_entries.get_collaboration_whitelist_entries() ``` ```cs .NET v10 theme={null} await client.CollaborationAllowlistEntries.GetCollaborationWhitelistEntriesAsync(); ``` ```swift Swift v10 theme={null} try await client.collaborationAllowlistEntries.getCollaborationWhitelistEntries() ``` ```java Java v10 theme={null} client.getCollaborationAllowlistEntries().getCollaborationWhitelistEntries() ``` ```cs .NET v6 theme={null} BoxCollectionMarkerBased whitelistedDomains = await client.CollaborationWhitelistManager .GetAllCollaborationWhitelistEntriesAsync(); ``` ```javascript Node v4 theme={null} client.collaborationAllowlist.getAllAllowlistedDomains(callback); ``` # Configure Box Source: https://developer.box.com/guides/collaborations/connect-slack-to-group-collabs/configure-box We will need to set up a Box application to manage Box groups and add collaborators to files and folders in Box. ## Set up a Box app # Create a new Box app Create and configure a new Box JWT application to use for this integration. # Use an existing approved app Use one of your existing admin-approved Box JWT applications from the Box developer console. # Create a new Box app To create a new Box application that can be used to call the Box APIs, use the following steps. 1. Go to the [Developer Console][devconsole] 2. Select **Create New App** 3. Select **Platform App** as the type of application to create, and click **Next** 4. Select **OAuth 2.0 with JWT** as the authentication method, and click **Next** 5. Give your Box app a unique name and click **Create App** 6. Go to the app's configuration by clicking **View Your App**. 7. Scroll down to **Application Access** and ensure that **Enterprise** is selected. 8. Scroll to the **Application Scopes** section of the same screen and ensure that at least the following scopes are enabled: **Read and write all files and folders stored in Box**, **Manage users**, and **Manage groups**. 9. Under **Advanced Features** ensure that **Perform Actions as Users** is enabled to perform actions on behalf of Box users. 10. At the top of the page click the button to **Save Changes** **App approval** Once the application is created it will still need to be approved by an enterprise admin before you will be able to make calls to the Box APIs. Follow this guide to have the application approved in your enterprise. # Use an Existing JWT Box application If you have an existing JWT based Box application in your [developer console][devconsole] that you would like to use, ensure that the following options are set in the **Configuration** section of your application. * Authentication Method: Should be set to OAuth 2.0 with JWT (Server Authentication). * Application Scopes: Set at least the following scopes. * Read and write all files and folders stored in Box * Manage users * Manage groups * Advanced Features: Both options should be enabled to perform actions as users and generate user access tokens. **App approval** Once the application is updated it will need to be re-approved by an enterprise admin before you will be able to make calls to any of the Box APIs that need any of the new permissions. Follow this guide to have the application approved in your enterprise. ## Download app configuration To begin working with the Box SDKs used in this tutorial, you will need the application configuration file from the **Configuration** page of your application. This will include all information needed to verify your application to start making API requests with the Box SDKs. Within the **Add and Manage Public Keys** section of the **Configuration** page, click to **Generate a Public/Private Keypair**. This will send you through 2FA verification before downloading the configuration file for your application. Store that file as `boxConfig.json` in a location accessible by your application. ## Summary * You created a new, or are using an existing, Box app which is approved by an enterprise admin. * You downloaded your application configuration file and stored it in a location accessible by your application. I downloaded my application configuration file [devconsole]: https://cloud.app.box.com/developers/console # Configure Slack Source: https://developer.box.com/guides/collaborations/connect-slack-to-group-collabs/configure-slack The first step in this guide is to create and configure a Slack application. This Slack application will act as a bot that listens for user events in Slack channels, and responds to **slash commands** by users in those channels - allowing them to share Box files and folders with the group. This section will take you through the following steps. * Create a minimal Slack application within the Slack API dashboard * Configure the Slack application to send notifications to our application whenever a user joins or leaves the channel - allowing our code to update the Box Box group. * Configure a `/boxadd` **slash command** that will allow users to share a Box file or folder with all the users in the channel. ## Create a minimal Slack app Go to the **[Slack apps page][slack-apps]** and click **Create an App**. Add an **App Name**, select your **Development Slack Workspace** from the dropdown list where the bot will be deployed to, then click **Create App**. Create a Slack App Once created, you will be redirected to the basic information section of the application. You may adjust the icon and description of your app within the **Display Information** section at the bottom to customize the application in your workspace. ## Configure the Slack app's event listener Setting up an event listener for our Slack app will allow us to monitor for events within the channel. For this bot, we want to monitor three [Slack events][slack-events] in order to perform actions within Box. * [`bot_added`][slack-event-bot-added]: When the bot is first added to a channel, it will get a list of all users in the channel, then create a Box group for those users. We can then use this group later on to add that group to any content that is shared with the **slash command**. * [`member_joined_channel`][slack-event-member-joined]: When a new user joins a Slack channel they will be added to the Box group. * [`member_left_channel`][slack-event-member-left]: When a user leaves a Slack channel, or the user is removed, they will be removed from the Box group. To set up a notification URL to which these Slack event payloads will be sent, Slack requires a verification step. When you set an event listener URL for your bot application code, Slack will immediately send a challenge to that URL to verify that it's valid. This will be an HTTP POST with a payload that looks something like the following: ```json theme={null} { "token": "Jhj5dZrVaK7ZwHHjRyZWjbDl", "challenge": "3eZbrw1aBm2rZgRNFdxV2595E9CY3gmdALWMmHkvFXO7tYXAYM8P", "type": "url_verification" } ``` To set up the URL for the event listener, that URL that is set needs to respond with a verification payload containing the challenge value back to Slack during this step. The payload will look similar to the following. ```js theme={null} HTTP 200 OK Content-type: application/json {"challenge":"3eZbrw1aBm2rZgRNFdxV2595E9CY3gmdALWMmHkvFXO7tYXAYM8P"} ``` To do this we will deploy a small bit of code to respond to the challenge event. Choose your preferred language / framework below to get started. # Node (Express Framework) # Java (Spring Boot Framework) Within the project directory, run `npm install express --save` to install the Express dependency, then deploy the following code to your public endpoint along with the appropriate Node modules. ```js theme={null} const express = require('express'); const app = express(); const port = process.env.PORT || 3000; app.use(express.urlencoded({ extended: true })); app.use(express.json()); app.post('/event', (req, res) => { if ( req.body && req.body.challenge && req.body.type === 'url_verification' ) { res.send({ challenge: req.body.challenge }); } else { res.status(400).send({ error: "Unrecognized request" }); } }); app.listen(port, function(err) { console.log("Server listening on PORT", port); }); ``` [`Spring Initializr`][spring-initializr] is a useful service for auto-generating a new Spring boot application with all dependencies defined. This may be used instead of creating a blank Java application. * From Eclipse, create a new project. When prompted, select a Gradle project. * Enter a unique name for the project, we used `slack.box` for this guide. * Open your `build.gradle` file and add the following. Ensure that the group matches the group that you used for the application. Once saved, refresh the Gradle project. ```java theme={null} plugins { id 'org.springframework.boot' version '2.3.1.RELEASE' id 'io.spring.dependency-management' version '1.0.9.RELEASE' id 'java' } group = 'com.box' version = '0.0.1-SNAPSHOT' sourceCompatibility = '1.8' repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' testImplementation('org.springframework.boot:spring-boot-starter-test') { exclude group: 'org.junit.vintage', module: 'junit-vintage-engine' } compile 'com.box:box-java-sdk:2.44.1' } test { useJUnitPlatform() } ``` * Within your `src/main/java` path, create a new Java class file named `Application.java`. * Open the file, add the following code, and save. ```java theme={null} package com.box.slack.box; import org.jose4j.json.internal.json_simple.JSONObject; import org.jose4j.json.internal.json_simple.parser.JSONParser; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; @RestController @EnableAutoConfiguration public class Application { @PostMapping("/event") public JSONObject challenge(@RequestBody String data) throws Exception { JSONObject returnJSON = new JSONObject(); Object dataObj = new JSONParser().parse(data); JSONObject inputJSON = (JSONObject) dataObj; String challenge = (String) inputJSON.get("challenge"); String type = (String) inputJSON.get("type"); if (type.equals("url_verification")) { returnJSON.put("challenge", challenge); } else { System.err.println("Invalid input"); } return returnJSON; } public static void main(String[] args) { SpringApplication.run(Application.class, args); } } ``` **Incomplete previous step** Please select a preferred language / framework above to get started. Now that we have the code to respond to the Slack challenge when adding an event URL, we can configure that within the Slack application. From your Slack application **Basic Information** tab, under **Add features and functionality**, click on the button titled **Event Subscriptions** and do the following. * Toggle **Enable Events** to **On**. * Under **Request URL** add in the public URL that you deployed the above code to, and be aware that we are listening at `{YOUR_APP_DOMAIN}/event` (such as `https://myapp.com/event`). Once you add the URL and click outside the field, Slack will immediately send the challenge to the URL that you were hosting the code at above. If the code responds correctly, you will see a green verified note beside the **Request URL** header. Enable Slack Event Subscriptions * Expand the **Subscribe to bot events** section and click on the **Add Bot User Event** button. * Add `member_joined_channel` and `member_left_channel` to the events the bot is subscribed to. These will send events when anyone new is added to the channel. * Click the **Save Changes** button at the bottom of the page. ## Configure the Slack app slash command To provide every user in a Slack channel access to a file or folder in Box, we can use a Slack **"slash commands"**. A slash command will allow any person in the channel to share content they own in Box with the rest of the channel. Through this command, a channel member will be able to type `/boxadd [file / folder] [id]`, for example `boxadd file 1459732312`, into the channel to share the file / folder with every user in the channel. To do this, the file is automatically collaborated with the Box group of users that are in that channel. From the **Basic Information** tab of your application, under **Add features and functionality**, click on the button titled **Slash Commands**. In the page that comes up, click **Create New Command** and input the following: * **Command**: This is the command that a channel user will use to share a Box file / folder ID with the channel. Use `/boxadd` for this quick start. * **Request URL**: The URL that is listening for and responding to slash commands in our Slack bot. In this quick start we use the same event URL that was used for the app event listener section above. * **Short Description**: A description of what the Slash command will do. * **Usage Hint**: Additional parameters that may be passed to the command. In our case, that's the Box file / folder ID and type of content. Create Slack Slash Command Click **Save** to add the command to our Slack app. ## Add Additional Scopes When slash commands or notifications are sent to our application from Slack they will contain a Slack user ID, which relates to the person that took or was affected by the action. To translate that ID to a Box user we need to get the Slack user's email, which we can then use to associate that Slack user to a corresponding Box user. This action requires two extra scopes in the Slack application configuration. From your Slack application configuration, click on **OAuth & Permissions** in the left menu, then do the following. * Scroll down to the **Scopes** section. * Click on the **Add an OAuth Scope** button under **Bot Token Scopes**.. * Search for and add `users:read` and `users:read.email`. ## Deploy Bot to Slack Workspace The last step is to install the application into your Slack workspace. From the **Basic Information** page of the app, expand the **Install your app to your workspace** section. Enable Slack Event Subscriptions Click the button to **Install App to Workspace**. Enable Slack Event Subscriptions Once the **Allow** button is clicked you should see a success message. Your bot is now installed within the workplace. ## Summary * You've created your Slack application. * You've configured user event notifications, slash commands, and additional scoping. * You've deployed your Slack bot to your workspace. I have my local application set up [slack-apps]: https://api.slack.com/apps [slack-events]: https://api.slack.com/events [slack-event-bot-added]: https://api.slack.com/events/bot_added [slack-event-member-joined]: https://api.slack.com/events/member_joined_channel [slack-event-member-left]: https://api.slack.com/events/member_left_channel [step3]: /guides/collaborations/connect-slack-to-group-collabs/scaffold-application-code [spring-initializr]: https://start.spring.io/ # Connect Bot to Box Source: https://developer.box.com/guides/collaborations/connect-slack-to-group-collabs/connect-box-functions We're now handling and processing events coming from Slack, then obtaining all information needed to connect with Box users and groups. We now need to connect that functionality to Box functions. In this step we'll expand several functions from the last step to incorporate new Box features. * Instantiate a Box client. * Add a Box user to a Box group. * Remove a Box user from a Box group. * Fetch a Box group ID from a group name. * Add content that is shared to a group. ## Instantiate a Box Client To make calls to the Box APIs, you'll first need to set up a Box client. Within `process.js`, replace the `// INSTANTIATE BOX CLIENT` comment at the top with the following. ```js theme={null} const boxConfig = require("./boxConfig.json"); const sdk = box.getPreconfiguredInstance(boxConfig); const client = sdk.getAppAuthClient("enterprise"); ``` The `boxConfig` assignment line will use the `boxConfig.json` file you downloaded from your Box app at the end of step 2. The sample above is assuming that you have it stored in the same folder as `process.js`. If that's not the case, change the path to point to where your `boxConfig.json` file is, and what it may be named. The last `client` assignment line is creating a Box client object which may be used to make API calls. At this point it is scoped to the service account of the application, and not a specific user. Within `Application.java`, replace the `// INSTANTIATE BOX CLIENT` comment within the `processEvent` method with the following. ```java theme={null} this.fileReader = new FileReader("boxConfig.json"); this.boxConfig = BoxConfig.readFrom(fileReader); this.boxAPI = BoxDeveloperEditionAPIConnection.getAppEnterpriseConnection(boxConfig); ``` The `boxConfig` assignment line will use the `boxConfig.json` file you downloaded from your Box app at the end of step 2. The sample above is assuming that you have it stored at the root of the Java project. If that's not the case, change the path in the `fileReader` assignment to point to where your `boxConfig.json` file is, and what it may be named. The last `boxAPI` assignment line is creating a Box client object which may be used to make API calls. At this point it is scoped to the service account of the application, and not a specific user. **Incomplete previous step** Please select a preferred language / framework in step 1 to get started. ## Add a Box user to a group Let's add a function that adds a Box user to a group. When a bot is added to a channel and needs to create a Box group with all users of the channel, or when a single user joins the channel after that action, this function will perform that task. Replace the `addGroupUser` function with the following. ```js theme={null} function addGroupUser(groupId, email) { client.enterprise.getUsers({ filter_term: email }).then((users) => { if (users.entries.length > 0) { const userId = users.entries[0].id; const groupRole = client.groups.userRoles.MEMBER; client.groups .addUser(groupId, userId, { role: groupRole }) .then((membership) => { if (membership.id) { console.log(`Member added with membership ID: ${membership.id}`); } else { console.log(`Member not added`); } }) .catch(function (err) { console.log(err.response.body); }); } else { console.log("No Box user found to add to group"); } }); } ``` Replace the `addGroupUser` method with the following. ```java theme={null} public void addGroupUser(String groupId, String userEmail) { Iterable users = BoxUser.getAllEnterpriseUsers(this.boxAPI, userEmail); for (BoxUser.Info user : users) { if (user.getLogin().toUpperCase().equals(userEmail.toUpperCase())) { try { BoxGroup group = new BoxGroup(boxAPI, groupId); BoxUser boxUser = new BoxUser(this.boxAPI, user.getID()); BoxGroupMembership.Info groupMembershipInfo = group.addMembership(boxUser); } catch (Exception ex) { System.err.println("User already present"); } } } } ``` **Incomplete previous step** Please select a preferred language / framework in step 1 to get started. Since we're matching a Slack user to a Box user via their email address, we first find a matching Box user using the Slack profile email. If found, a call is made to add that user to the channel group. The group was created when the bot was first added. The Box Get User endpoint only permits user lookup by user ID. To lookup a user by email address, use the List Enterprise Users endpoint and set the `filter_term` option to the email address you're searching for. ## Remove a Box user to a group When a user leaves or is removed from a Slack channel, we also want to remove them from the Box group so that they can no longer access the shared group content. Replace the `removeGroupUser` function with the following. ```js theme={null} function removeGroupUser(groupId, email) { client.groups.getMemberships(groupId).then(memberships => { for (let i = 0; i < memberships.entries.length; i++) { if (memberships.entries[i].user.login === email) { client.groups .removeMembership(memberships.entries[i].id) .then(() => { console.log('Group user removed') }); break; } } }); } ``` Replace the `removeGroupUser` method with the following. ```java theme={null} public void removeGroupUser(String groupId, String userEmail) { BoxGroup boxGroup = new BoxGroup(this.boxAPI, groupId); Iterable memberships = boxGroup.getAllMemberships(); for (BoxGroupMembership.Info membershipInfo : memberships) { if (membershipInfo.getUser().getLogin().toUpperCase().equals(userEmail.toUpperCase())) { BoxGroupMembership membership = new BoxGroupMembership(this.boxAPI, membershipInfo.getID()); membership.delete(); } } } ``` **Incomplete previous step** Please select a preferred language / framework in step 1 to get started. This code will take the group ID, which will be the Slack channel ID, and get all members of the group. If a matching member is found for the person that left the Slack channel, based on email address, that person is removed from the group using their membership ID. **Improving performance with a data store** While looking up group memberships to obtain a membership ID negates the need to store membership IDs in a local data store (like a database), this code can be made more efficient by having a data store that saves the Box membership ID with the user record. By using a local data store, the membership ID can be retrieved from the data store rather than having to call the Box API repeatedly to search for the membership ID. ## Fetch a Box group ID for a group name The next Box function we need has two main purposes. * Return the Box group ID of an existing group. * If a group doesn't exist, create the Box group and return the ID. Replace the `getGroupId` function with the following. ```js theme={null} function getGroupId(groupName, callback) { client.groups.getAll().then((groups) => { const group = groups.entries.filter((g) => g.name === groupName)[0]; if (!group) { client.groups .create(groupName, { description: "Slack channel collaboration group", invitability_level: "all_managed_users", }) .then((group) => { callback(group.id); }); } else { callback(group.id); } }); } ``` Replace the `getGroupId` method with the following. ```java theme={null} public String getGroupId(String groupName) { String groupId = new String(); Iterable groups = BoxGroup.getAllGroups(this.boxAPI); for (BoxGroup.Info groupInfo : groups) { if (groupInfo.getName().toUpperCase().equals(groupName)) { groupId = groupInfo.getID(); } } if (groupId.isEmpty()) { BoxGroup.Info groupInfo = BoxGroup.createGroup(boxAPI, groupName); groupId = groupInfo.getID(); } return groupId; } ``` **Incomplete previous step** Please select a preferred language / framework in step 1 to get started. The code fetches all the groups in the enterprise, and then tries to match the Slack channel ID to the group name. If any of the groups matches, the group ID is returned. If there are no matches, a new Box group is created and the ID of the group is returned for use. The group will be named after the Slack channel ID since that is a constant that is returned with both slash commands and user events, making it easier to lookup without additional functions. ## Add shared content to a group Finally, the main purpose of our whole application is to allow users to share files and folders from their own Box accounts with everyone else in the group. Building upon all previous functionality, the following function performs that task. Replace the `processContent` function with the following. ```js theme={null} function processContent(user, channel, itemType, itemId) { getGroupId(channel, function (groupId) { const email = user.profile.email; client.enterprise.getUsers({ filter_term: email }).then((users) => { if (users.entries.length > 0) { client.asUser(users.entries[0].id); const collabRole = client.collaborationRoles.VIEWER; const collabOptions = { type: itemType }; client.collaborations .createWithGroupID(groupId, itemId, collabRole, collabOptions) .then((collaboration) => { console.log( `Content added with collaboration ID ${collaboration.id}` ); }) .catch(function (err) { console.log( util.inspect(err.response.body, { showHidden: false, depth: null, }) ); }); } }); }); } ``` Replace the `processContent` method with the following. ```java theme={null} public void processContent(JSONObject userResponse, String channel, String fType, String fId) { String groupId = getGroupId(channel); JSONObject userObj = (JSONObject) userResponse.get("user"); JSONObject userProfile = (JSONObject) userObj.get("profile"); String userEmail = (String) userProfile.get("email"); Iterable users = BoxUser.getAllEnterpriseUsers(this.boxAPI, userEmail); for (BoxUser.Info user : users) { if (user.getLogin().toUpperCase().equals(userEmail.toUpperCase())) { String uid = user.getID(); boxAPI.asUser(uid); BoxCollaborator collabGroup = new BoxGroup(boxAPI, groupId); try { if (fType.equals("file")) { BoxFile file = new BoxFile(boxAPI, fId); file.collaborate(collabGroup, BoxCollaboration.Role.VIEWER, false, false); } else if (fType.equals("folder")) { BoxFolder folder = new BoxFolder(boxAPI, fId); folder.collaborate(collabGroup, BoxCollaboration.Role.VIEWER); } } catch (Exception ex) { System.err.println("Collaboration failed"); } boxAPI.asSelf(); } } } ``` **Incomplete previous step** Please select a preferred language / framework in step 1 to get started. The code starts by capturing the Box group ID for the Slack channel, which is where content will be shared to. Since we want to share files and folders from the Box account of the person who sent the slash command, we next capture their Box user profile based on their email address. Lastly, we make a call to collaborate content with the group via the group ID. ## Summary * You've instantiated a Box client * You've created Box group user add and remove functions. * You've created a function to share content with the group. I've set up my Box functions # Handle Slack Events Source: https://developer.box.com/guides/collaborations/connect-slack-to-group-collabs/handle-slack-events With the application scaffold in place, the next step is to build the handling and processing functionality for user events, as well as the handling of slash commands coming from Slack. Each one of these will eventually be passed to a Box API endpoint to perform group and content collaboration tasks. In this step we'll expand the empty functions we wrote in the last step. These functions will perform the following tasks. * Listen for new events and slash commands from Slack. * Process those events and commands to route to the appropriate function. * Process all Slack users in a channel to be added to a Box group when the bot is first added to a channel. * Fetch profile information for a Slack user to get their email. ## Listen for Slack events When the Slack application was configured, it was instructed to send events to our application code for three events. * When a user joins a channel. * When a user leaves a channel. * When a user enters a `/boxadd` Slash command. Our application needs to have a public route that listens for those messages from Slack. The payloads of these messages will like something like this. ```json "/boxadd"-command theme={null} { "token": "cF1PwB1eIMcRHZWwFHJR1tgs", "team_id": "T932DQSV12P", "team_domain": "slacktest", "channel_id": "C078N43MFHU", "channel_name": "bottest", "user_id": "U016JCDPN56", "user_name": "testuser", "command": "/boxadd", "text": "file 123456", "response_url": "https://hooks.slack.com/commands/T541DQSV12P/3977594927231/ankvsRb42WKnKPRp002FeyTx", "trigger_id": "1189442196855.1183332180295.cca20c3ca1ea193dab432ad8e9e95431" } ``` ```json "member_joined_channel"-event theme={null} { "token": "cF1PwB1eIMcRHZWwFHJR1tgs", "team_id": "T932DQSV12P", "api_app_id": "A321V573PQT", "event": { "type": "member_joined_channel", "user": "U0431JM4RLZ", "channel": "C078N43MFHU", "channel_type": "C", "team": "T932DQSV12P", "inviter": "U016JCDPN56", "event_ts": "1592858788.000700" }, "type": "event_callback", "event_id": "Ev032NRJYASJ", "event_time": 1592858788, "authed_users": [ "U0431JM4RLZ" ] } ``` ```json "member_left_channel"-event theme={null} { "token": "cF1PwB1eIMcRHZWwFHJR1tgs", "team_id": "T932DQSV12P", "api_app_id": "A321V573PQT", "event": { "type": "member_left_channel", "user": "U0431JM4RLZ", "channel": "C078N43MFHU", "channel_type": "C", "team": "T932DQSV12P", "event_ts": "1593033236.000600" }, "type": "event_callback", "event_id": "Ev032NRJYASJ", "event_time": 1593033236, "authed_users": [ "U0431JM4RLZ" ] } ``` To start processing these events, load `process.js` in your preferred editor and replace the `app.post("/event" ...` listener with the following. ```js theme={null} app.post("/event", (req, res) => { if (req.body.token !== slackConfig.verificationToken) { res.send("Slack Verification Failed"); } handler.process(res, req.body); }); ``` When an event comes through, the listener verifies that the message came from Slack, using the verification token from our Slack application. If it's a valid request, the event payload is sent to our event process function. Load `Application.java` in your preferred editor, then replace the `@PostMapping("/event")` block with the following. ```java theme={null} @PostMapping("/event") @ResponseBody public void handleEvent(@RequestBody String data, @RequestHeader("Content-Type") String contentType, HttpServletResponse response) throws Exception { int code = HttpServletResponse.SC_OK; java.io.PrintWriter wr = response.getWriter(); response.setStatus(code); if (contentType.startsWith(MediaType.APPLICATION_JSON_VALUE)) { wr.write("Adding content to group"); } else { wr.print(response); } wr.flush(); wr.close(); if (! contentType.startsWith(MediaType.APPLICATION_JSON_VALUE)) { JSONObject returnJSON = new JSONObject(); String[] inputParts = data.split("&"); for (String part: inputParts) { String[] keyval = part.split("="); try { keyval[1] = java.net.URLDecoder.decode(keyval[1], StandardCharsets.UTF_8.name()); } catch (UnsupportedEncodingException e) { System.err.println(e); } returnJSON.put(keyval[0], keyval[1]); } data = returnJSON.toString(); } processEvent(data); } ``` When an event comes through, the handler will send an immediate 200 response back before code processing. Slash commands will be sent as URL encoded strings, while member join / leave events will be sent as JSON. If a slash command is encountered we respond with a processing message, otherwise we send the `HttpServletResponse` response. In this example we send a `HTTP 200` response before the event is fully processed. This is done because Slack requires a response to an event within 3 seconds from dispatch. When the code execution takes longer than 3 seconds then duplicate event will be dispatched by Slack. To make event processing easier, we want to standardize all event objects as JSON. If a content type isn't JSON it'll be the URL encoded string. If that's encountered the string is converted into a JSON object before being sent to `processEvent`. Replace `processEvent` with the following. ```java theme={null} @Async public void processEvent(String data) throws Exception { Object dataObj = new JSONParser().parse(data); JSONObject inputJSON = (JSONObject) dataObj; String token = (String) inputJSON.get("token"); if (token.equals(slackConfig.verificationToken)) { // INSTANTIATE BOX CLIENT process(inputJSON); } else { System.err.println("Invalid event source"); } } ``` This method will convert the JSON event string to a JSON object, then verify that the event came from Slack by comparing the verification token. If valid, the event is routed to `process`. **Incomplete previous step** Please select a preferred language / framework in step 1 to get started. ## Process Slack events Next, we will want to determine what event was received and pass this on to the right part of our application. Replace the `process` function with the following. ```js theme={null} function process(res, data) { if (data.type && data.type === "event_callback") { const eventType = data.event.type; const channel = data.event.channel; const userId = data.event.user; getSlackUser(userId, function (user) { processUser(user, eventType, channel); }); res.send(); } else if (data.command && data.command === "/boxadd") { const [itemType, itemId] = data.text.split(" "); if (["file", "folder"].includes(itemType) && !isNaN(itemId)) { const userId = data.user_id; getSlackUser(userId, function (user) { processContent(user, data.channel_id, itemType, itemId); }); res.send("Adding content"); } else { res.send("Invalid input. Example usage: /boxadd file 123456"); } } else { res.send("Invalid action"); } } ``` The purpose of this function is to figure out if the payload from Slack is a user event or a Slash command, fetch any needed information, then route to the appropriate function to process the results. If the payload is a user event, denoted by `data.type` being set to `event_callback`, we extract a few pieces of information. * `eventType`: The type of event to determine if a user is leaving (`member_left_channel`) or joining (`member_joined_channel`) the channel. * `channel`: The channel ID, which will be used as the Box group name. * `userId`: The ID of the user, to look up their profile email which will bind to a user profile in Box that uses the same email. The process function then fetches the profile of the user by calling `getSlackUser`, and once obtained that user profile is sent to the `processUser` function to add or remove them from the Box group. If the payload is a slash command, denoted by `data.command` being set to `/boxadd`, the content of the command that represents the Box ID and whether it's a file or folder, such as `file 1234`, is extracted and split to get the individual values. Those values are validated for proper content. Once validated, the profile of the Slack user is obtained to get the email, then the user profile is sent to `processContent` to collaborate the Box content in with the Box group so that everyone has access. The reason for fetching the Slack user's email in this step is because the file or folder is owned by the user, not by the application's service account. When we share content (by creating a collaboration) the action will need to be performed by a user who has sharing permissions on that file or folder. For this reason, we need to match the Slack user's email address against a Box user's email address so that we can create the collaboration on their behalf. Replace the `process` method with the following. ```java theme={null} public void process(JSONObject inputJSON) throws Exception { if (inputJSON.containsKey("event")) { JSONObject event = (JSONObject) inputJSON.get("event"); String eventType = (String) event.get("type"); String eventUserId = (String) event.get("user"); String eventChannel = (String) event.get("channel"); processUser(getSlackUser(eventUserId), eventType, eventChannel); } else if (inputJSON.containsKey("command")) { String eventCommand = (String) inputJSON.get("command"); if (eventCommand.equals("/boxadd")) { String eventChannelId = (String) inputJSON.get("channel_id"); String eventUserId = (String) inputJSON.get("user_id"); String cInput = (String) inputJSON.get("text"); String[] cInputParts = cInput.split(" "); if (cInputParts[0].matches("file|folder")) { processContent(getSlackUser(eventUserId), eventChannelId, cInputParts[0], cInputParts[1]); } } } else { System.err.println("Invalid event action"); } } ``` The purpose of this method is to figure out if the payload from Slack is a user event or a Slash command, fetch any needed information, then route to the appropriate method to process the results. If the payload is a user event, denoted by the event node being present in the JSON payload, we extract a few pieces of information. * `eventType`: The type of event to determine if a user is leaving (`member_left_channel`) or joining (`member_joined_channel`) the channel. * `eventUserId`: The ID of the user, to look up their profile email which will bind to a user profile in Box that uses the same email. * `eventChannel`: The channel ID, which will be used as the Box group name. We then route to `processUser`, passing in the return value from the `getSlackUser` method (a user object), the type of event, and the channel. If the payload is a slash command, denoted by the `command` node being present in the JSON payload, we extract a few pieces of information. * `eventChannelId`: The Slack channel ID, to be used as the Box group name. * `eventUserId`: The ID of the user who issued the command. * `cInputParts`: The type and ID of the command input, from a string such as `file 1234`. We then route to `processContent`, passing in the return value from the `getSlackUser` method (a user object), the channel ID, the content type (file or folder), and the content ID for the file or folder stored in Box. **Incomplete previous step** Please select a preferred language / framework in step 1 to get started. ## Process Slack user Next, we need to define how user events should be processed. There are three events that we need to account for: * The bot was added to the channel. * A regular user joined the channel. * A regular user left the channel. Replace the `processUser` function with the following. ```js theme={null} function processUser(user, event, channel) { getGroupId(channel, function (groupId) { // if bot was added, add all channel users if (user.is_bot) { processSlackChannel(channel, groupId); } else if ( user.profile && user.profile.email && event === "member_joined_channel" ) { addGroupUser(groupId, user.profile.email); } else if ( user.profile && user.profile.email && event === "member_left_channel" ) { removeGroupUser(groupId, user.profile.email); } }); } ``` Replace the `processUser` method with the following. ```java theme={null} public void processUser(JSONObject userResponse, String event, String channel) throws Exception { String groupId = getGroupId(channel); JSONObject userObj = (JSONObject) userResponse.get("user"); Boolean isBot = (Boolean) userObj.get("is_bot"); JSONObject userProfile = (JSONObject) userObj.get("profile"); String userEmail = (String) userProfile.get("email"); if (isBot) { processSlackChannel(channel, groupId); } else if (event.equals("member_joined_channel")) { addGroupUser(groupId, userEmail); } else if (event.equals("member_left_channel")) { removeGroupUser(groupId, userEmail); } } ``` **Incomplete previous step** Please select a preferred language / framework in step 1 to get started. The code starts by fetching the Box group ID for the channel, which will be defining in the next step. Once obtained, it processes users as follows. * If the user is a bot, it needs to initialize the Box group and add all current users of the channel as Box users in the group. This is to account for the bot being added to existing channels, and this is ignored if the bot is being re-added to a channel that they were already present in previously. * If the user joined the channel it needs to add them to the group. * If the user left the channel it needs to remove them from the group. ## Process Slack channel users When a bot is first added to a channel, it needs to list all users currently in the channel and create a Box group with those people in order to create a baseline for the channel. Replace the `processSlackChannel` function with the following. ```js theme={null} function processSlackChannel(channel, groupId) { const limit = 100; const channelUsersPath = `https://slack.com/api/conversations.members?token=${slackConfig.botToken}&channel=${channel}&limit=${limit}`; axios.get(channelUsersPath).then((response) => { response.data.members.forEach((uid) => { getSlackUser(uid, function (user) { if (user.profile.email && !user.is_bot) { addGroupUser(groupId, user.profile.email); } }); }); }); } ``` Replace the `processSlackChannel` method with the following. ```java theme={null} public void processSlackChannel(String channel, String groupId) throws Exception { String limit = "100"; String channelUsersPath = String.format("%s/conversations.members?token=%s&channel=%s&limit=%s", slackConfig.slackApiUrl, slackConfig.botToken, channel, limit); JSONObject channelUserList = sendGETRequest(channelUsersPath); JSONArray channelUserIds = (JSONArray) channelUserList.get("members"); @SuppressWarnings("rawtypes") Iterator i = channelUserIds.iterator(); while(i.hasNext()) { String uid = (String)i.next(); JSONObject userResponse = (JSONObject) getSlackUser(uid.toString()); JSONObject userObj = (JSONObject) userResponse.get("user"); JSONObject userProfile = (JSONObject) userObj.get("profile"); Boolean isBot = (Boolean) userObj.get("is_bot"); String userEmail = new String(); if (!isBot) { userEmail = (String) userProfile.get("email"); } if (!userEmail.isEmpty() && !isBot) { addGroupUser(groupId, userEmail); } } } ``` **Incomplete previous step** Please select a preferred language / framework in step 1 to get started. This code runs a number of actions in sequence. * First, it calls the Slack APIs to fetch all members of the channel. The * `limit` can be adjusted to collect more users in the channel. * For every user that is found, it calls `getSlackUser` to get their profile, allow it to map their email address to a Box user's email address. * Each user is then sent to `addGroupUser` to add them into the group. ## Fetch Slack user profile The last Slack related function is a utility mechanism used by the other functions. It calls the Slack API to fetch the user profile given the user ID provided by either Slack event / command or when fetching a list of channel users. Since we're matching Slack users to Box users via their email address, that is the field that we care about from the user profile lookup. Email addresses in Box are unique and cannot be used for multiple accounts, meaning that they can be used effectively for user account lookup. Replace the `getSlackUser` function with the following. ```js theme={null} function getSlackUser(userId, callback) { const userPath = `https://slack.com/api/users.info?token=${slackConfig.botToken}&user=${userId}`; axios.get(userPath).then((response) => { if (response.data.user && response.data.user.profile) { callback(response.data.user); } else { console.log("No user data found"); } }); } ``` This function makes a call to the Slack user profile endpoint, then sends the user profile information (if valid) to the specified callback. Replace the `getSlackUser` method with the following. ```java theme={null} public JSONObject getSlackUser(String userId) throws Exception { String usersPath = String.format("%s/users.info?token=%s&user=%s", slackConfig.slackApiUrl, slackConfig.botToken, userId); return sendGETRequest(usersPath); } ``` This method sends a request to Slack to capture the user profile, then returns the response from that request, which should be a user profile JSON object. **Incomplete previous step** Please select a preferred language / framework in step 1 to get started. ## Summary * You've verified incoming events and forwarded them to be processed. * You've processed events and routed to the appropriate function. * You've implemented functions for processing all users in a channel and for fetching the Slack profile of a single user. I've set up my Slack functions # Connect Slack to Box Group Collaborations Source: https://developer.box.com/guides/collaborations/connect-slack-to-group-collabs/index Slack is a popular communication and productivity tool, allowing for real-time coordination when working with individuals or groups in and outside of the company. When connected to a custom Box application, the Slack channel structure, along with the [slash command][slack-slash-commands] and [event API][slack-event-api] systems, can be used to provide a logical grouping and collaboration system for Box files and folders. ## Overview This quick start guide will walk you through all the steps needed to group Box users based on the channels they are in within a Slack workspace, and then permit individuals within those Slack channels to share Box files and folders with that group using a Slack slash command. At the end of this tutorial you will have a Slack bot that will be deployed to a channel in your workspace. This bot will create a Box group containing all the people present in the channel, and then listen for a `/boxadd` command in the channel. It will then parse that command and automatically collaborate the Box fie or folder with the entire group of users in the channel. /boxadd command in Slack This guide will take you through the following steps. 1. Setup and configure your Slack app to handle the event notification and Slash command structures. 2. Setup and configure your Box application to connect the web application to Box. 3. Listen for Slack events and commands when users join and leave channels, or share a Box file or folder with the group. 4. Structure Box groups and file / folder collaborations based on the Slack events or slash commands. 5. And finally, deploy the application to your workspace and invite the Slack app bot to your channels to begin listening for events. ## Requirements This quick start guide has two requirements that are worth noting before we proceed. 1. **User emails need to match between Box and Slack**: We are connecting a Slack user account to a Box user account by comparing the Slack user email address. Therefore, a matching Box user account using the same email address must be present in your Box enterprise. 2. **You must have a publicly accessible server**: Slack will need to send event and command notification data to a public URL for your application. This guide assumes that you have a public location where your application code will be hosted, such as `https://mysite.com/`. If you don't have access to any public hosting then application platforms like [Heroku][heroku], serverless options like [AWS lambda][aws-lambda], or exposing localhost with services like [ngrok][ngrok] are all options that you might want to consider. I am ready to get started [slack-slash-commands]: https://api.slack.com/apps/A0155185TT3/slash-commands [slack-event-api]: https://api.slack.com/events-api [step6]: /guides/collaborations/connect-slack-to-group-collabs/test-bot [heroku]: https://heroku.com/ [aws-lambda]: https://aws.amazon.com/lambda/ [ngrok]: https://ngrok.com/ # Scaffold application code Source: https://developer.box.com/guides/collaborations/connect-slack-to-group-collabs/scaffold-application-code With our Slack and Box applications configured, we're ready to write the code for our application which will listen for incoming slash commands and events from Slack. This application will be split up into three parts: * Set up the initial application skeleton and configuration information. * Set up the handlers for Slack events and slash commands. * Connect those handlers to the required functions in Box. ## Add dependencies and scaffold code Let's start by scaffolding the files and minimal code needed to run the application. * Either create a new local directory for your application or load the existing code created for the Slack event URL challenge from step 1. * Create a new `package.json` file, or update the existing one, inside the local directory, open it in your preferred editor, copy / paste the following into it, and save / exit the file. ```json theme={null} { "name": "box-slack", "version": "1.0.0", "description": "Box Slack integration", "main": "process.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "node process.js" }, "author": "Box", "license": "ISC", "dependencies": { "axios": "^0.19.2", "body-parser": "^1.19.0", "box-node-sdk": "^1.33.0", "express": "^4.17.1" } } ``` * Run `npm install` from the terminal / console to install the dependencies. * Create two files, `process.js` and `slackConfig.json` in the local directory. * Open `slackConfig.json` and save the following default configuration. ```json theme={null} { "verificationToken": "TOKEN", "botToken": "TOKEN" } ``` * There are two values above that will need to be replaced with details from your Slack application. Replace the `TOKEN` strings with the appropriate values. * `verificationToken`: Load up your Slack application configuration page. Within the **Basic Information** page, scroll down to the **App Credentials** section. The **Verification Token** string will be available there. * `botToken`: Within your Slack application, go to the **OAuth & Permissions** page. The **Bot User OAuth Access Token** string is available at the top and was auto-populated once the bot was added to your Slack workspace. * Open up the blank `process.js` file, copy and paste the following code, and save the file. ```js theme={null} const box = require("box-node-sdk"); const slackConfig = require("./slackConfig.json"); const boxConfig = require("./boxConfig.json"); const express = require("express"); const app = express(); const axios = require("axios"); const util = require("util"); app.use(express.urlencoded({ extended: true })); app.use(express.json()); // INSTANTIATE BOX CLIENT app.post('/event', (req, res) => { //HANDLE INCOMING EVENTS }); const handler = (() => { function process(res, data) { // PROCESS EVENTS } function processUser(user, event, channel) { // PROCESS USER ADD / REMOVE REQUEST } function addGroupUser(groupId, email) { // ADD USER TO BOX GROUP } function removeGroupUser(groupId, email) { // REMOVE USER FROM BOX GROUP } function processContent(user, channel, type, fid) { // COLLABORATE CONTENT WITH GROUP } function processSlackChannel(channel, gid) { // ADD ALL SLACK CHANNEL USERS TO GROUP } function getSlackUser(userId, _callback) { // GET SLACK USER PROFILE } function getGroupId(groupName, _callback) { // GET AND CREATE BOX GROUP } return { process }; })(); const port = process.env.PORT || 3000; app.listen(port, function(err) { console.log("Server listening on PORT", port); }); ``` This code contains all of the main functions that will be needed to handle and process the communication between Slack and Box. From top to bottom, the functions are: * `/event` handler: Captures all incoming Slack traffic, verifies the content, and routes them to the `process` function. * `process`: Parses the Slack event and routes the event to either Box group processing (user channel events) or to add Box content to the group (slash commands). * `processUser`: Handles user events, either adding or removing a user from a Box group by routing to the appropriate functions. * `addGroupUser`: Adds a user to a Box group. * `removeGroupUser`: Removes a user from a Box group. * `processContent`: Collaborates Box content with the Box group. * `processSlackChannel`: Adds all Slack channel users to a Box group. * `getSlackUser`: Utility function to fetch a Slack user's profile from their Slack user ID. * `getGroupId`: Utility function to fetch a Box group ID from a Box group name. A configuration file needs to be created to house our Slack credentials and URLs. * Within your `src/main/java` path, where your `Application.java` file is located, create a new Java class file named `slackConfig.java`. * Open the file and save the following into it. ```java theme={null} package com.box.slack.box; public class slackConfig { public static String verificationToken = "TOKEN"; public static String botToken = "TOKEN"; public static String slackApiUrl = "https://slack.com/api"; } ``` * There are two values above that will need to be replaced with details from your Slack application. Replace the `TOKEN` strings with the appropriate values. * `verificationToken`: Load up your Slack application configuration page. Within the **Basic Information** page, scroll down to the **App Credentials** section. The **Verification Token** string will be available there. * `botToken`: Within your Slack application, go to the **OAuth & Permissions** page. The **Bot User OAuth Access Token** string is available at the top and was auto-populated once the bot was added to your Slack workspace. * Open up the `Application.java` file that was created for the previous Slack event challenge setup and replace the content of the file with the following. ```java theme={null} package com.box.slack.box; import java.io.BufferedReader; import java.io.FileReader; import java.io.InputStreamReader; import java.io.Reader; import java.io.UnsupportedEncodingException; import java.net.HttpURLConnection; import java.net.URL; import java.nio.charset.StandardCharsets; import java.util.Iterator; import javax.servlet.http.HttpServletResponse; import org.jose4j.json.internal.json_simple.JSONArray; import org.jose4j.json.internal.json_simple.JSONObject; import org.jose4j.json.internal.json_simple.parser.JSONParser; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.http.MediaType; import org.springframework.scheduling.annotation.Async; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import com.box.sdk.BoxAPIConnection; import com.box.sdk.BoxCollaborator; import com.box.sdk.BoxCollaboration; import com.box.sdk.BoxConfig; import com.box.sdk.BoxDeveloperEditionAPIConnection; import com.box.sdk.BoxFile; import com.box.sdk.BoxFolder; import com.box.sdk.BoxGroup; import com.box.sdk.BoxGroupMembership; import com.box.sdk.BoxUser; @RestController @EnableAutoConfiguration public class Application extends slackConfig { private Reader fileReader; private BoxConfig boxConfig; private BoxAPIConnection boxAPI; @PostMapping("/event") @ResponseBody public void handleEvent(@RequestBody String data, @RequestHeader("Content-Type") String contentType, HttpServletResponse response) throws Exception { // HANDLE EVENTS } @Async public void processEvent(String data) throws Exception { // VERIFY EVENTS } public void process(JSONObject inputJSON) throws Exception { // PROCESS EVENTS } public void processUser(JSONObject userResponse, String event, String channel) throws Exception { // PROCESS USER ADD / REMOVE REQUEST } public void addGroupUser(String groupId, String userEmail) { // ADD USER TO BOX GROUP } public void removeGroupUser(String groupId, String userEmail) { // REMOVE USER FROM BOX GROUP } public void processContent(JSONObject userResponse, String channel, String fType, String fId) { // COLLABORATE CONTENT WITH GROUP } public void processSlackChannel(String channel, String groupId) throws Exception { // ADD ALL SLACK CHANNEL USERS TO GROUP } public JSONObject getSlackUser(String userId) throws Exception { // GET SLACK USER PROFILE } public String getGroupId(String groupName) { // GET AND CREATE BOX GROUP } public JSONObject sendGETRequest(String reqURL) throws Exception { StringBuffer response = new StringBuffer(); URL obj = new URL(reqURL); HttpURLConnection httpURLConnection = (HttpURLConnection) obj.openConnection(); httpURLConnection.setRequestMethod("GET"); int responseCode = httpURLConnection.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_OK) { BufferedReader in = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream())); String inputLine; while ((inputLine = in .readLine()) != null) { response.append(inputLine); } in .close(); } else { System.err.println("GET request failed"); } Object dataObj = new JSONParser().parse(response.toString()); JSONObject outputJSON = (JSONObject) dataObj; return outputJSON; } public static void main(String[] args) { SpringApplication.run(Application.class, args); } } ``` This code contains all of the main functions that will be needed to handle and process the communication between Slack and Box. From top to bottom, the functions are: * `handleEvent`: Captures all incoming Slack traffic and responds with an HTTP 200 response to notify Slack that the event was received. Since slash commands will transmit their payload as `application/x-www-form-urlencoded` rather than `application/json`, we convert those payloads to JSON objects to standardize the input. * `processEvent`: Verifies that the event is from Slack, instantiates a Box client, and routes for processing. * `process`: Parses the Slack event and routes to either Box group processing (user channel events) or to add Box content to the group (slash commands). * `processUser`: Handles user event requirements to either add or remove a user to a Box group by routing to the appropriate functions. * `addGroupUser`: Adds a user to a Box group. * `removeGroupUser`: Removes a user from a Box group. * `processContent`: Collaborates Box content with the Box group. * `processSlackChannel`: Adds all Slack channel users to a Box group. * `getSlackUser`: Utility function to fetch a Slack user profile from a Slack user ID. * `getGroupId`: Utility function to fetch a Box group ID from a Box group name. * `sendGETRequest`: Utility function to send an HTTP GET request. **Incomplete previous step** Please select a preferred language / framework in step 1 to get started. ## Summary * You created a minimal application scaffold, and provided the basic configuration details. * You installed all the project dependencies. I have my local application set up # Test the bot Source: https://developer.box.com/guides/collaborations/connect-slack-to-group-collabs/test-bot In this last section we'll test the full range of functionality of the Slack bot. * **Group creation**: When a bot is added to a channel, a new Box group should be created with all of the current channel participants. Only those people in the channel with matching Box accounts (based on email address matching) should be added. * **User event functions**: When a user enters or leaves a channel, they should be added or removed from the channel group. * **Content add functions**: When a user enters a valid `/boxadd` slash command, that content should be shared with the group through a new collaboration. If you haven't done so already, ensure that all the code we've written so far is deployed as an application that is publicly accessible. ## Testing group creation When a bot is first added to a channel, there are a number of expectations. * A new group is created with a name that matches the Slack channel ID. * All people currently in the channel are added to the group, as long as their Slack email address matches an enterprise account with the same email. When the Slack bot was configured in step 1, we installed it within the Slack workspace. To test group creation we need to add it to a channel. From any Slack channel, invite the Slack bot, either through the Slack UI or using a `/invite @bot_app_name` command. Once added, verify that the group is created in Box and members have been added. From a Box enterprise admin account, go to the **[Users and Groups][box-users-groups]** section of the admin console. If successful, you will see a group with an random alpha-numeric string as the group name. This is the Slack channel ID, which is mirrored in the group name. View Box Groups Under the **Members** column, you should also see a number indicating the number of Box users with matching email addresses that were found in the enterprise and added to the group during group creation. If you see your group and members, this step is a success. If you see no members added to the group, and no errors being returned from the bot application, the most likely cause is email mismatch. Ensure that the email addresses used by the accounts in Slack match the emails used by users in your Box enterprise. ## Testing user event functions Keep the **[Users and Groups][box-users-groups]** section of the Box admin console open and take note of the number in the **Members** column beside your Slack group. From the Slack channel with the bot invited, add or remove someone other than the bot from the channel. Refresh the users and groups section of the Box admin console and you should see the members number drop or increase depending on if you added or removed a user. If the number of members changes, this step is a success. ## Testing content add functions To test the functionality of sharing content with the group, you will need access to two users in the channel, one person to share the content from their Box account, and another person in the group to view their list of files to verify that the content was shared. From the Slack channel with the bot invited, type in the slash command to share files or folders with the group, in the format of `/boxadd [file/folder] [ID of file/folder]`, such as `/boxadd folder 324554221`. The file or folder ID specified needs to be content within the Box account of the person sharing it. To find the ID of a file or folder in a Box account, load up the file or folder within [the Box site][box], then look at the URL. The ID will be the last string in the URL, often right after a section which includes either `/file/` or `/folder/`. Get File or Folder ID Once the command is typed in, go to the [the Box site][box] account of another person within the Slack channel and Box group. The content that was shared should now be available to that account. If the shared content is available to others in the group, this step is a success. ## Next Steps With our minima bot deployed we can now think about ways to improve the experience on top of what we've created so far. Next steps in this journey may include any number of different expansion areas. * Add new slash commands for creating shared links for the files and folders shared with the group, allowing you to share the content with others who are not in the group and people outside your enterprise. * Creating retention policies and assigning them to any content shared with the group, allowing you to control the lifespan and governance of shared content. * Adding new slash commands for allowing people in the channel to comment on the files that are shared with the group. [box-users-groups]: https://app.box.com/master/groups [box]: https://box.com # Sharing with Groups Source: https://developer.box.com/guides/collaborations/groups To share a file or folder with a group of users, create a collaboration using the group ID, the ID of the file or folder, and the role or permissions level the group should have when accessing the file or folder. The collaboration roles are `editor`, `viewer`, `previewer`, `uploader`, `previewer uploader`, `viewer uploader`, `co-owner`, or `owner`. For a full description of each role, please refer to our [support documentation]. ## Nested objects When creating a collaboration there are two nested objects within the request body: `accessible_by` and `item`. The `accessible_by` object specifies who the item should be shared with and includes a group `id` and the `type`. The `type` field should always be set to `group`. The `item` object specifies what is being shared. It includes a `type` field which should be set as `file` or `folder`, and an `id` for that file or folder. [support documentation]: https://support.box.com/hc/en-us/articles/360044196413-Understanding-Collaborator-Permission-Levels # Collaborations Source: https://developer.box.com/guides/collaborations/index Collaborations define access permissions for users and groups to files and folders, similar to access control lists. A collaboration object grants a user or group access to a file or folder with permissions defined by a specific role. The collaboration roles are `editor`, `viewer`, `previewer`, `uploader`, `previewer uploader`, `viewer uploader`, `co-owner`, or `owner`. For a full description of each role, please refer to our [support documentation]. [support documentation]: https://support.box.com/hc/en-us/articles/360044196413-Understanding-Collaborator-Permission-Levels # Get Pending Collaborations Source: https://developer.box.com/guides/collaborations/pending To get the pending collaborations for a user, call the `GET /collaborations` API with a `status` of `pending`. ```sh cURL theme={null} curl -i -X GET "https://api.box.com/2.0/collaborations?status=pending" \ -H "authorization: Bearer " ``` ```typescript Node/TypeScript v10 theme={null} await client.listCollaborations.getCollaborations({ status: 'pending' as GetCollaborationsQueryParamsStatusField, } satisfies GetCollaborationsQueryParams); ``` ```python Python v10 theme={null} client.list_collaborations.get_collaborations(GetCollaborationsStatus.PENDING) ``` ```cs .NET v10 theme={null} await client.ListCollaborations.GetCollaborationsAsync(queryParams: new GetCollaborationsQueryParams(status: GetCollaborationsQueryParamsStatusField.Pending)); ``` ```swift Swift v10 theme={null} try await client.listCollaborations.getCollaborations(queryParams: GetCollaborationsQueryParams(status: GetCollaborationsQueryParamsStatusField.pending)) ``` ```java Java v10 theme={null} client.getListCollaborations().getCollaborations(new GetCollaborationsQueryParams(GetCollaborationsQueryParamsStatusField.PENDING)) ``` ```java Java v5 theme={null} Collection pendingCollaborations = BoxCollaboration.getPendingCollaborations(api); ``` ```python Python v4 theme={null} pending_collaborations = client.get_pending_collaborations() for pending_collaboration in pending_collaborations: print(f'Collaboration {pending_collaboration.id} is pending') ``` ```cs .NET v6 theme={null} BoxCollection pendingCollabs = await CollaborationsManager .GetPendingCollaborationAsync(); ``` ```javascript Node v4 theme={null} client.collaborations.getPending() .then(collaborations => { /* collaborations -> { total_count: 1, entries: [ { type: 'collaboration', id: '11111', created_by: { type: 'user', id: '22222', name: 'Example User', login: 'user@example.com' }, created_at: '2011-11-29T12:56:35-08:00', modified_at: '2012-09-11T15:12:32-07:00', expires_at: null, status: 'pending', accessible_by: { type: 'user', id: '33333', name: 'Collaborator User', login: 'collaborator@example.com' }, role: 'editor', acknowledged_at: '2011-11-29T12:59:40-08:00', item: null } ] } */ }); ``` This only returns the current list of pending collaborations for a user. This API does not allow for returning all collaborations for a user. # Share Content with User Source: https://developer.box.com/guides/collaborations/share-content To share content with a user, create a collaboration using the user ID or email address, the ID of the content, and the role or permissions level the user should have when accessing the content. The collaboration roles are `editor`,`viewer`, `previewer`, `uploader`, `previewer uploader`, `viewer uploader`,`co-owner`, or `owner`. For a full description of each role, please refer to our [support documentation]. ```sh cURL theme={null} curl -i -X POST "https://api.box.com/2.0/collaborations" \ -H "authorization: Bearer " \ -H "content-type: application/json" \ -d '{ "item": { "type": "file", "id": "11446498" }, "accessible_by": { "type": "user", "login": "user@example.com" }, "role": "editor" }' ``` ```typescript Node/TypeScript v10 theme={null} await client.userCollaborations.createCollaboration({ item: { type: 'folder' as CreateCollaborationRequestBodyItemTypeField, id: folder.id, } satisfies CreateCollaborationRequestBodyItemField, accessibleBy: { type: 'user' as CreateCollaborationRequestBodyAccessibleByTypeField, id: user.id, } satisfies CreateCollaborationRequestBodyAccessibleByField, role: 'editor' as CreateCollaborationRequestBodyRoleField, } satisfies CreateCollaborationRequestBody); ``` ```python Python v10 theme={null} client.user_collaborations.create_collaboration( CreateCollaborationItem(type=CreateCollaborationItemTypeField.FOLDER, id=folder.id), CreateCollaborationAccessibleBy( type=CreateCollaborationAccessibleByTypeField.USER, id=user.id ), CreateCollaborationRole.EDITOR, ) ``` ```cs .NET v10 theme={null} await client.UserCollaborations.CreateCollaborationAsync(requestBody: new CreateCollaborationRequestBody(item: new CreateCollaborationRequestBodyItemField() { Type = CreateCollaborationRequestBodyItemTypeField.Folder, Id = folder.Id }, accessibleBy: new CreateCollaborationRequestBodyAccessibleByField(type: CreateCollaborationRequestBodyAccessibleByTypeField.User) { Id = user.Id }, role: CreateCollaborationRequestBodyRoleField.Editor)); ``` ```swift Swift v10 theme={null} try await client.userCollaborations.createCollaboration(requestBody: CreateCollaborationRequestBody(item: CreateCollaborationRequestBodyItemField(type: CreateCollaborationRequestBodyItemTypeField.folder, id: folder.id), accessibleBy: CreateCollaborationRequestBodyAccessibleByField(type: CreateCollaborationRequestBodyAccessibleByTypeField.user, id: user.id), role: CreateCollaborationRequestBodyRoleField.editor)) ``` ```java Java v10 theme={null} client.getUserCollaborations().createCollaboration(new CreateCollaborationRequestBody(new CreateCollaborationRequestBodyItemField.Builder().type(CreateCollaborationRequestBodyItemTypeField.FOLDER).id(folder.getId()).build(), new CreateCollaborationRequestBodyAccessibleByField.Builder(CreateCollaborationRequestBodyAccessibleByTypeField.USER).id(user.getId()).build(), CreateCollaborationRequestBodyRoleField.EDITOR)) ``` ```java Java v5 theme={null} BoxCollaborator user = new BoxUser(api, "user-id") BoxFolder folder = new BoxFolder(api, "folder-id"); folder.collaborate(user, BoxCollaboration.Role.EDITOR); ``` ```python Python v4 theme={null} from boxsdk.object.collaboration import CollaborationRole user = client.user(user_id='11111') collaboration = client.folder(folder_id='22222').collaborate(user, CollaborationRole.VIEWER) collaborator = collaboration.accessible_by item = collaboration.item has_accepted = 'has' if collaboration.status == 'accepted' else 'has not' print(f'{collaborator.name} {has_accepted} accepted the collaboration to folder "{item.name}"') ``` ```cs .NET v6 theme={null} // collaborate folder 11111 with user 22222 BoxCollaborationRequest requestParams = new BoxCollaborationRequest() { Item = new BoxRequestEntity() { Type = BoxType.folder, Id = "11111" }, Role = "editor", AccessibleBy = new BoxCollaborationUserRequest() { Type = BoxType.user, Id = "22222" } }; BoxCollaboration collab = await client.CollaborationsManager.AddCollaborationAsync(requestParams); ``` ```javascript Node v4 theme={null} // Invite user 123456 to collaborate on folder 987654 client.collaborations.createWithUserID('123456', '987654', client.collaborationRoles.EDITOR) .then(collaboration => { /* collaboration -> { type: 'collaboration', id: '11111', created_by: { type: 'user', id: '22222', name: 'Inviting User', login: 'inviter@example.com' }, created_at: '2016-11-16T21:33:31-08:00', modified_at: '2016-11-16T21:33:31-08:00', expires_at: null, status: 'accepted', accessible_by: { type: 'user', id: '123456', name: 'Collaborator User', login: 'collaborator@example.com' }, role: 'editor', acknowledged_at: '2016-11-16T21:33:31-08:00', item: { type: 'folder', id: '987654', sequence_id: '0', etag: '0', name: 'Collaborated Folder' } } */ }); ``` ## Nested objects When creating a collaboration there are two nested objects within the request body: `accessible_by` and `item`. The `accessible_by` object specifies who the item should be shared with and includes a group `id` and the `type`. The `type` field should always be set to `user`. The `item` object specifies what is being shared. It includes a `type` field which should be set as `file` and an `id` for that file. [support documentation]: https://support.box.com/hc/en-us/articles/360044196413-Understanding-Collaborator-Permission-Levels # Add Item to Collection Source: https://developer.box.com/guides/collections/add To add an item to a collection, call the `PUT` endpoint for that specific type of item and pass along a list of collection IDs. The only collection that is available via the API is the "Favorites" collection. The ID of this collection is [different for every user](/guides/collections/list). ## Add file to collection To add a file to a collection, call the `PUT /files/:id` API and pass along a list of collection IDs. ## Add folder to collection To add a folder to a collection, call the `PUT /folders/:id` API and pass along a list of collection IDs. ## Add web link to collection To add a web link to a collection, call the `PUT /web_links/:id` API and pass along a list of collection IDs. # Collections Source: https://developer.box.com/guides/collections/index Collections in Box are a way to group files, folders, and web links without putting them all into a folder together. The only collection that is available via the API is the "Favorites" collection. The ID of this collection is [different for every user](/guides/collections/list). # List User's Collections Source: https://developer.box.com/guides/collections/list To list all collections for a user, call the [`GET /collections`](/reference/get-collections) API. ```sh cURL theme={null} curl -i -X GET "https://api.box.com/2.0/collections" \ -H "authorization: Bearer " ``` ```typescript Node/TypeScript v10 theme={null} await client.collections.getCollections(); ``` ```python Python v10 theme={null} client.collections.get_collections() ``` ```cs .NET v10 theme={null} await client.Collections.GetCollectionsAsync(); ``` ```swift Swift v10 theme={null} try await client.collections.getCollections() ``` ```java Java v5 theme={null} Iterable collections = BoxCollection.getAllCollections(api); for (BoxCollection.Info collectionInfo : collections) { // Do something with the collection. } ``` ```python Python v4 theme={null} collections = client.collections() for collection in collections: print(f'Collection "{collection.name}" has ID {collection.id}') ``` ```cs .NET v6 theme={null} BoxCollection collections = await client.CollectionsManager.GetCollectionsAsync(); ``` ```javascript Node v4 theme={null} client.collections.getAll() .then(collections => { /* collections -> { total_count: 1, entries: [ { type: 'collection', id: '11111', name: 'Favorites', collection_type: 'favorites' } ], limit: 100, offset: 0 } */ }); ``` The only collection that is available via the API is the "Favorites" collection. The ID of this collection is different for every user. ## Favorites Collection The only collection that can items can currently be added and removed to via the API is the "Favorites" collection. The ID of the favorites collection is different for every user. To find the user's collection ID for their favorites, list all the user's collections and then find the collection with a `collection_type` of `favorites`. ```json theme={null} { "entries": [ { "collection_type": "favorites", "id": "12345678", "name": "Favorites", "type": "collection" } ], "limit": 100, "offset": 0, "total_count": 1 } ``` # List Items in Collections Source: https://developer.box.com/guides/collections/list-items To list all files, folders and web links in a folder call the [`GET /collections/:id/items`](/reference/get-collections-id-items) API. ```sh cURL theme={null} curl -i -X GET "https://api.box.com/2.0/collections/926489/items" \ -H "authorization: Bearer " ``` ```typescript Node/TypeScript v10 theme={null} await client.collections.getCollectionItems(favouriteCollection.id!); ``` ```python Python v10 theme={null} client.collections.get_collection_items(favourite_collection.id) ``` ```cs .NET v10 theme={null} await client.Collections.GetCollectionItemsAsync(collectionId: NullableUtils.Unwrap(favouriteCollection.Id)); ``` ```swift Swift v10 theme={null} try await client.collections.getCollectionItems(collectionId: favouriteCollection.id!) ``` ```java Java v5 theme={null} BoxFolder folder = new BoxFolder(api, "id"); for (BoxItem.Info itemInfo : folder) { if (itemInfo instanceof BoxFile.Info) { BoxFile.Info fileInfo = (BoxFile.Info) itemInfo; // Do something with the file. } else if (itemInfo instanceof BoxFolder.Info) { BoxFolder.Info folderInfo = (BoxFolder.Info) itemInfo; // Do something with the folder. } } ``` ```python Python v4 theme={null} items = client.collection(collection_id='12345').get_items() for item in items: print(f'{item.type.capitalize()} "{item.name}" is in the collection') ``` ```cs .NET v6 theme={null} BoxCollection items = await client.CollectionsManager.GetCollectionItemsAsync(id: "11111"); ``` ```javascript Node v4 theme={null} client.collections.getItems('81934', {fields: 'name', limit: 2}) .then(items => { /* items -> { total_count: 24, entries: [ { type: 'folder', id: '192429928', sequence_id: '1', etag: '1', name: 'Stephen Curry Three Pointers' }, { type: 'file', id: '818853862', sequence_id: '0', etag: '0', name: 'Warriors.jpg' } ], offset: 0, limit: 2 } */ }); ``` The only collection that is available via the API is the "Favorites" collection. The ID of this collection is [different for every user](/guides/collections/list). # Remove Item from Collection Source: https://developer.box.com/guides/collections/remove To remove an item from a collection, call the `PUT` endpoint for that specific type of item and pass along a list of collection IDs that does not include the ID of the collection that needs to be removed. The only collection that is available via the API is the "Favorites" collection and therefore to remove an item from this collection can be achieved by passing the API an empty array of collections. ## Remove file from collection To remove a file from a collection, call the `PUT /files/:id` API and pass an empty array of collection IDs. ## Remove folder from collection To remove a folder from a collection, call the `PUT /folders/:id` API and pass an empty array of collection IDs. ## Remove web link from collection To remove a web link from a collection, call the `PUT /web_links/:id` API and pass an empty array of collection IDs. # Create Comment Source: https://developer.box.com/guides/comments/create-comment To create a comment, call the `POST /comments` API with the message of the comment, as well as the ID of the file to leave the comment on. ```sh cURL theme={null} curl -i -X POST "https://api.box.com/2.0/comments" \ -H "authorization: Bearer " \ -H "content-type: application/json" \ -d '{ "message": "Review completed!", "item": { "type": "file", "id": 426436 } }' ``` ```typescript Node/TypeScript v10 theme={null} await client.comments.createComment({ message: message, item: { id: fileId, type: 'file' as CreateCommentRequestBodyItemTypeField, } satisfies CreateCommentRequestBodyItemField, } satisfies CreateCommentRequestBody); ``` ```python Python v10 theme={null} client.comments.create_comment( message, CreateCommentItem(id=file_id, type=CreateCommentItemTypeField.FILE) ) ``` ```cs .NET v10 theme={null} await client.Comments.CreateCommentAsync(requestBody: new CreateCommentRequestBody(message: message, item: new CreateCommentRequestBodyItemField(id: fileId, type: CreateCommentRequestBodyItemTypeField.File))); ``` ```swift Swift v10 theme={null} try await client.comments.createComment(requestBody: CreateCommentRequestBody(message: message, item: CreateCommentRequestBodyItemField(id: fileId, type: CreateCommentRequestBodyItemTypeField.file))) ``` ```java Java v10 theme={null} client.getComments().createComment(new CreateCommentRequestBody(message, new CreateCommentRequestBodyItemField(fileId, CreateCommentRequestBodyItemTypeField.FILE))) ``` ```java Java v5 theme={null} BoxFile file = new BoxFile(api, "id"); file.addComment("This file is pretty cool."); ``` ```python Python v4 theme={null} comment = client.file(file_id='11111').add_comment('When should I have this done by?') ``` ```cs .NET v6 theme={null} var requestParams = new BoxCommentRequest() { Item = new BoxRequestEntity() { Type = BoxType.File, Id = "12345" }, Message = "Great work!" }; BoxComment comment = await client.CommentsManager.AddCommentAsync(requestParams); ``` ```javascript Node v4 theme={null} client.comments.create('33333', 'Is this the latest version?') .then(comment => { /* comment -> { type: 'comment', id: '11111', is_reply_comment: false, message: 'Is this the latest version?', created_by: { type: 'user', id: '22222', name: 'Example User', login: 'user@example.com' }, created_at: '2012-12-12T11:25:01-08:00', item: { id: '33333', type: 'file' }, modified_at: '2012-12-12T11:25:01-08:00' } */ }); ``` A comment's message can also mentions users using the `@` sign. To do so, add the string `@[userid:name]` anywhere within the message. The `user_id` is the target user's ID, where the `name` can be any custom phrase. In the Box UI this name will link to the user's profile. Then, pass this string as the `tagged_message` instead of the `message`. # Create Reply Source: https://developer.box.com/guides/comments/create-reply To create a reply to a previous comment, call the `POST /comments` API with the message of the new comment, as well as the ID of the previous comment to leave the reply on. A reply's message can also mentions users using the `@` sign. To do so, add the string `@[userid:name]` anywhere within the message. The `user_id` is the target user's ID, where the `name` can be any custom phrase. In the Box UI this name will link to the user's profile. Then, pass this string as the `tagged_message` instead of the `message`. # Comments Source: https://developer.box.com/guides/comments/index Comments are messages generated by Box users on files, allowing users to collaborate together on a file, discussing any feedback they might have on the content. Each comment is tied to a specific file and user, and comments can be created as independent comments or as replies to previous comments. # Download File Source: https://developer.box.com/guides/downloads/file To download a file, pass the `GET /files/:id/content` the ID of the file to get the content for. ```sh cURL theme={null} curl -i -L -X GET "https://api.box.com/2.0/files/12345/content" \ -H "authorization: Bearer " ``` ```typescript Node/TypeScript v10 theme={null} const fs = require('fs'); const fileContent = await client.downloads.downloadFile('123456789'); const fileWriteStream = fs.createWriteStream('file.pdf'); fileContent.pipe(fileWriteStream); ``` ```python Python v10 theme={null} client.downloads.download_file(uploaded_file.id) ``` ```cs .NET v10 theme={null} await client.Downloads.DownloadFileAsync(fileId: uploadedFile.Id); ``` ```swift Swift v10 theme={null} let downloadsDirectoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! let destinationURL = downloadsDirectoryURL.appendingPathComponent("file.txt") let url = try await client.downloads.downloadFile(fileId: file.id, downloadDestinationURL: destinationURL) if let fileContent = try? String(contentsOf: url, encoding: .utf8) { print("The content of the file: \(fileContent)") } ``` ```java Java v10 theme={null} client.getDownloads().downloadFile(uploadedFile.getId()) ``` ```java Java v5 theme={null} BoxFile file = new BoxFile(api, "id"); BoxFile.Info info = file.getInfo(); FileOutputStream stream = new FileOutputStream(info.getName()); file.download(stream); stream.close(); ``` ```python Python v4 theme={null} file_id = '11111' file_content = client.file(file_id).content() ``` ```cs .NET v6 theme={null} Stream fileContents = await client.FilesManager.DownloadStreamAsync(id: "11111"); ``` ```javascript Node v4 theme={null} var fs = require('fs'); client.files.getReadStream('12345', null, function(error, stream) { if (error) { // handle error } // write the file to disk var output = fs.createWriteStream('/path/to/file'); stream.pipe(output); }); ``` ## Download URL When not using the SDKs, this API call will return a `HTTP 302 Found` status code, with a `location` header containing a link to the download URL, which looks something like this. ```sh theme={null} https://dl.boxcloud.com/d/1/[long-random-string]/download ``` By using the `-L` flag in cURL we are able to automatically follow this redirect. In our SDKs this will result in the binary data to be downloaded. In the API this will result in a download URL being returned via the `location` header. It is possible to get the download URL via the SDKs as well. ## Download URL expiry Although this download URL can be passed to a user's browser to allow them to download the file, the URL does expire and should be requested again for any further downloads. ## File not ready If the file is not ready to be downloaded yet a `retry-after` header will be returned indicating the time in seconds after which the file will be available for the client to download. This response can occur when the file was uploaded immediately before the download request. # Download File Version Source: https://developer.box.com/guides/downloads/file-version To download a specific file version, pass the `GET /files/:id/content` the ID of the file to get the content for, as well as its version ID. ## Download URL When not using the SDKs, this API call will return a `HTTP 302 Found` status code, with a `location` header containing a link to the download URL, which looks something like this. ```sh theme={null} https://dl.boxcloud.com/d/1/[long-random-string]/download ``` By using the `-L` flag in cURL we are able to automatically follow this redirect. In our SDKs this will result in the binary data to be downloaded. In the API this will result in a download URL being returned via the `location` header. It is possible to get the download URL via the SDKs as well. ## Download URL expiry Although this download URL can be passed to a user's browser to allow them to download the file, the URL does expire and should be requested again for any further downloads. ## File not ready If the file is not ready to be downloaded yet a `retry-after` header will be returned indicating the time in seconds after which the file will be available for the client to download. This response can occur when the file was uploaded immediately before the download request. # Download All Files in Folder using SDKs Source: https://developer.box.com/guides/downloads/folder Sometimes an application might want to download all files for a folder. To do so with the SDKs and the CLI requires traversing the folder tree, finding every file and downloading it accordingly. To download a ZIP archive, follow this guide. ```csharp .NET theme={null} using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; using Box.V2.Config; using Box.V2.JWTAuth; namespace BoxDownloadAllFiles { class Program { static void Main (string[] args) { ExecuteMainAsync ().Wait (); } private static async Task ExecuteMainAsync () { using (FileStream fs = new FileStream ($"./config.json", FileMode.Open)) { var session = new BoxJWTAuth (BoxConfig.CreateFromJsonFile (fs)); var client = session.AdminClient (session.AdminToken ()); var folderId = "987654321"; var folder = await client.FoldersManager.GetInformationAsync (folderId); var folderName = folder.Name; var localFolderPath = Path.Combine (Directory.GetCurrentDirectory (), folderName); ResetLocalFolder (localFolderPath); var items = await client.FoldersManager.GetFolderItemsAsync (folderId, 1000, autoPaginate : true); var fileDownloadTasks = new List (); var files = items.Entries.Where (i => i.Type == "file"); foreach (var file in files) { fileDownloadTasks.Add (client.FilesManager.DownloadStreamAsync (file.Id).ContinueWith ((t) => { var localFile = File.Create (Path.Combine (localFolderPath, file.Name)); return t.Result.CopyToAsync (localFile); })); } await Task.WhenAll (fileDownloadTasks); } } private static void ResetLocalFolder (string localFolderPath) { if (!Directory.Exists (localFolderPath)) { Directory.CreateDirectory (localFolderPath); } else { foreach (var file in Directory.EnumerateFiles (localFolderPath)) { File.Delete (Path.Combine (localFolderPath, file)); } Directory.Delete (localFolderPath); Directory.CreateDirectory (localFolderPath); } } } } ``` ```java Java theme={null} package com.box; import com.box.sdk.BoxConfig; import com.box.sdk.BoxDeveloperEditionAPIConnection; import com.box.sdk.BoxFile; import com.box.sdk.BoxFolder; import com.box.sdk.BoxItem; import java.io.BufferedReader; import java.io.FileOutputStream; import java.io.IOException; import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; public class Playground { public static void main(String[] args) throws Exception { Path configPath = Paths.get("config.json"); Path currentDir = Paths.get("").toAbsolutePath(); try (BufferedReader reader = Files.newBufferedReader(configPath, Charset.forName("UTF-8"))) { BoxConfig boxConfig = BoxConfig.readFrom(reader); BoxDeveloperEditionAPIConnection client = BoxDeveloperEditionAPIConnection.getAppEnterpriseConnection(boxConfig); String folderId = "987654321"; BoxFolder folder = new BoxFolder(client, folderId); String folderName = folder.getInfo().getName(); Path localFolderPath = currentDir.resolve(Paths.get(folderName)); if (!Files.exists(localFolderPath)) { localFolderPath = Files.createDirectory(localFolderPath); } else { localFolderPath = resetLocalFolder(localFolderPath); } for (BoxItem.Info itemInfo: folder) { if (itemInfo instanceof BoxFile.Info) { BoxFile.Info fileInfo = (BoxFile.Info) itemInfo; BoxFile file = new BoxFile(client, fileInfo.getID()); String localFilePath = localFolderPath.resolve(Paths.get(fileInfo.getName())).toAbsolutePath().toString(); FileOutputStream stream = new FileOutputStream(localFilePath); file.download(stream); stream.close(); } } } } static Path resetLocalFolder(Path localFolderPath) throws IOException { Files.list(localFolderPath).forEach(file -> { System.out.println(file.getFileName()); try { Files.delete(file.toAbsolutePath()); } catch (IOException e) {} }); Files.delete(localFolderPath); localFolderPath = Files.createDirectory(localFolderPath); return localFolderPath; } } ``` ```js Node theme={null} "use strict"; const box = require("box-node-sdk"); const fs = require("fs"); const util = require("util"); const path = require("path"); let configFile = fs.readFileSync("config.json"); configFile = JSON.parse(configFile); let session = box.getPreconfiguredInstance(configFile); let client = session.getAppAuthClient("enterprise"); client._useIterators = true; let folderId = "987654321"; let folderName; let localFolderPath; client.folders .get(folderId, null) .then(folderInfo => { folderName = folderInfo.name; return client.folders.getItems(folderId, { limit: 1000 }); }) .then(folderItemsIterator => { return autoPage(folderItemsIterator); }) .then(folderItems => { console.log(folderName); console.log(folderItems.length); let files = folderItems.filter(item => { return item.type === "file"; }); console.log(files); localFolderPath = createLocalFolder(folderName); let downloadPromises = []; files.forEach(file => { downloadPromises.push( client.files.getReadStream(file.id, null).then(stream => { let output = fs.createWriteStream( path.join(localFolderPath, file.name) ); stream.pipe(output); }) ); }); return Promise.all(downloadPromises); }) .then(() => { console.log("Downloaded all files..."); console.log(fs.readdirSync(localFolderPath)); }); function createLocalFolder(folderName) { let localFolderName = path.join(__dirname, folderName); try { fs.mkdirSync(localFolderName); } catch (e) { if (e.code === "EEXIST") { resetLocalFolder(localFolderName); fs.mkdirSync(localFolderName); } else { throw e; } } return localFolderName; } function resetLocalFolder(localFolderName) { if (fs.existsSync(localFolderName)) { fs.readdirSync(localFolderName).forEach(localFileName => { console.log(localFileName); fs.unlinkSync(path.join(localFolderName, localFileName)); }); fs.rmdirSync(localFolderName); } } function autoPage(iterator) { let collection = []; let moveToNextItem = () => { return iterator.next().then(item => { if (item.value) { collection.push(item.value); } if (item.done !== true) { return moveToNextItem(); } else { return collection; } }); }; return moveToNextItem(); } ``` It is important to remember that an application needs to have the permissions to access and download the files and folders in question. When the authenticated user does not have access to any of the files or folders, a `HTTP 404 Not Found` error will occur. Lear more about User Types in our guides on authentication. # Get Download URL Source: https://developer.box.com/guides/downloads/get-url The official Box SDKs return the binary data when downloading a file. To get the download URL for the data instead, use the following SDK methods. **Redirects** If you are not using one of our SDKs its important to make sure your HTTP client does not automatically follow HTTP redirects. When redirects are automatically followed, your code will detect the `location` header returned by the API and follow it to get the binary data. ## Download URL expiry Although this download URL can be passed to a user's browser to allow them to download the file, the URL does expire and should be requested again for any further downloads. In most cases the download URL is valid for 15 minutes, after which a new URL needs to be requested. This expiration time may be subject to change without any prior notification. [api]: /reference/get-files-id-content # Download in Browser Source: https://developer.box.com/guides/downloads/in-browser Sometimes an application wants to embed a file into a page as a HTML element. An example would be when working with an audio player. ```html theme={null} ``` In this case, using the regular download URL does not work because the `dl.boxcloud.com` domain does not support Cross Origin Resource Sharing. Instead an application can use the following format. ```sh theme={null} https://api.box.com/2.0/files/[FILE_ID]/content?access_token=[ACCESS_TOKEN] ``` **CORS** For this to work the application needs to have the domain of the web site hosting this file added to the list of allowed domains in the CORS settings. **Downscope Token** Using this method would expose the Access Token to the end user, allowing them to potentially use this token to do more than intended. For this reason we recommend downscoping this token accordingly. # Downloads Source: https://developer.box.com/guides/downloads/index The Box API allows for downloading files to the application's server, or directly by the end user in a browser. ## When not to download Downloading a file is not always the desired solution, especially if the file is only being downloaded for the user to preview, comment, or annotate. In those cases we recommend using one of the ways to embed the Box experience straight into your application. ## Access Errors It is important to realize that the application needs to have access to the file that is to be downloaded. When the application is authenticated through JWT, the user is authenticated as a Service Account. This service account does not have access to files besides their own. If this user does not have access to the file the application will receive a `404 Not Found` error. # Download Shared Link Source: https://developer.box.com/guides/downloads/shared-link To download the file for a Shared Link, first determine the file for the link. You cannot use the shared link to download folders. Create and download the ZIP archive instead. Once the file ID has been determined, the file can be downloaded by passing the `BoxAPI` header to the API. To get the Shared Link for an item the user must have at least viewer-level access to the item. # Download ZIP Archive Source: https://developer.box.com/guides/downloads/zip-archive To download all files in a folder or an entire folder structure, you have to create and download a ZIP archive. ## Create a ZIP Archive First, you need to create a ZIP archive containing the files or the folder structure. You can include up to 10,000 file and folder IDs unless you reach the account’s upload limit. ```sh cURL theme={null} curl -i -X POST "https://api.box.com/2.0/zip_downloads" \ -H "authorization: Bearer " \ -d '{ "download_file_name": "January Financials", "items": [ { "type": "file", "id": "12345" }, { "type": "file", "id": "34325" }, { "type": "folder", "id": "45678" } ] }' ``` ```typescript Node/TypeScript v10 theme={null} await client.zipDownloads.createZipDownload({ items: [ { id: file1.id, type: 'file' as ZipDownloadRequestItemsTypeField, } satisfies ZipDownloadRequestItemsField, { id: file2.id, type: 'file' as ZipDownloadRequestItemsTypeField, } satisfies ZipDownloadRequestItemsField, { id: folder1.id, type: 'folder' as ZipDownloadRequestItemsTypeField, } satisfies ZipDownloadRequestItemsField, ], downloadFileName: 'zip', } satisfies ZipDownloadRequest); ``` ```python Python v10 theme={null} client.zip_downloads.create_zip_download( [ CreateZipDownloadItems(id=file_1.id, type=DownloadZipItemsTypeField.FILE), CreateZipDownloadItems(id=file_2.id, type=DownloadZipItemsTypeField.FILE), CreateZipDownloadItems(id=folder_1.id, type=DownloadZipItemsTypeField.FOLDER), ], download_file_name="zip", ) ``` ```csharp .NET v10 theme={null} await client.ZipDownloads.CreateZipDownloadAsync(requestBody: new ZipDownloadRequest(items: Array.AsReadOnly(new [] {new ZipDownloadRequestItemsField(id: file1.Id, type: ZipDownloadRequestItemsTypeField.File),new ZipDownloadRequestItemsField(id: file2.Id, type: ZipDownloadRequestItemsTypeField.File),new ZipDownloadRequestItemsField(id: folder1.Id, type: ZipDownloadRequestItemsTypeField.Folder)})) { DownloadFileName = "zip" }); ``` ```swift Swift v10 theme={null} try await client.zipDownloads.createZipDownload(requestBody: ZipDownloadRequest(items: [ZipDownloadRequestItemsField(id: file1.id, type: ZipDownloadRequestItemsTypeField.file), ZipDownloadRequestItemsField(id: file2.id, type: ZipDownloadRequestItemsTypeField.file), ZipDownloadRequestItemsField(id: folder1.id, type: ZipDownloadRequestItemsTypeField.folder)], downloadFileName: "zip")) ``` ```java Java v10 theme={null} client.getZipDownloads().createZipDownload(new ZipDownloadRequest.Builder(Arrays.asList(new ZipDownloadRequestItemsField(ZipDownloadRequestItemsTypeField.FILE, file1.getId()), new ZipDownloadRequestItemsField(ZipDownloadRequestItemsTypeField.FILE, file2.getId()), new ZipDownloadRequestItemsField(ZipDownloadRequestItemsTypeField.FOLDER, folder1.getId()))).downloadFileName("zip").build()) ``` ```java Java v5 theme={null} ArrayList items = new ArrayList(); BoxZipItem file = new BoxZipItem("file", "12345"); BoxZipItem folder = new BoxZipItem("folder", "156472"); items.add(file); items.add(folder); BoxZip zip = new BoxZip(api); BoxZipInfo zipInfo = zip.create("Awesome Zip File", items); ``` ```js Node v4 theme={null} var name = 'test', items = [ { type: 'file', id: '466239504569' }, { type: 'folder', id: '466239504580' } ]; client.files.createZip(name, items) .then(zip => { /* zip -> { "download_url": "https://api.box.com/2.0/zip_downloads/124hfiowk3fa8kmrwh/content", "status_url": "https://api.box.com/2.0/zip_downloads/124hfiowk3fa8kmrwh/status", "expires_at": "2018-04-25T11:00:18-07:00", "name_conflicts": [ [ { "id": "100", "type": "file", "original_name": "salary.pdf", "download_name": "aqc823.pdf" }, { "id": "200", "type": "file", "original_name": "salary.pdf", "download_name": "aci23s.pdf" } ], [ { "id": "1000", "type": "folder", "original_name": "employees", "download_name": "3d366a_employees" }, { "id": "2000", "type": "folder", "original_name": "employees", "download_name": "3aa6a7_employees" } ] ] } */ }); ``` The response will look similar to the following: ```json theme={null} { "download_url": "https://dl.boxcloud.com/2.0/zip_downloads/25gvaXcIE4QJlinNiw2oHAQ==ZFs3Q2Xpd7pKBz7OyzXNrUaoW3aJxQRN5znAvyM-KpdEEPdWcQDKU-Dl85Ew/content", "status_url": "https://api.box.com/2.0/zip_downloads/25gvaXcIE4QJlinNiw2oHAQ==ZFs3Q2Xpd7pKBz7OyzXNrUaoW3aJxQRN5znAvyM-KpdEEPdWcQDKU-Dl85Ew/status", "expires_at": "2023-02-28T10:23:54Z", "name_conflicts": [] } ``` ## Extract the ZIP download ID To download the ZIP archive, you need the ZIP download ID. You can find it in the response you got when you created the archive. Go to `status_url` and copy the ID located between`zip_downloads` and `content`: ```json theme={null} 25gvaXcIE4QJlinNiw2oHAQ==ZFs3Q2Xpd7pKBz7OyzXNrUaoW3aJxQRN5znAvyM-KpdEEPdWcQDKU-Dl85Ew ``` Download URL is valid only for a the time specified in `expires_at` parameter. ## Download files Place the download ID in the file location URL as in the sample below to point to the right files. ```sh cURL theme={null} curl -L GET "https://dl.boxcloud.com/2.0/zip_downloads/29l00nfxDyHOt7RphI9zT_w==nDnZEDjY2S8iEWWCHEEiptFxwoWojjlibZjJ6geuE5xnXENDTPxzgbks_yY=/content" \ -H "authorization: Bearer " \ -o sample_curl.zip ``` ```typescript Node/TypeScript v10 theme={null} await client.zipDownloads.getZipDownloadContent(zipDownload.downloadUrl!); ``` ```python Python v10 theme={null} client.zip_downloads.get_zip_download_content(zip_download.download_url) ``` ```csharp .NET v10 theme={null} await client.ZipDownloads.GetZipDownloadContentAsync(downloadUrl: NullableUtils.Unwrap(zipDownload.DownloadUrl)); ``` ```swift Swift v10 theme={null} try await client.zipDownloads.getZipDownloadContent(downloadUrl: zipDownload.downloadUrl!, downloadDestinationUrl: URL(path: destinationPathString)) ``` ```java Java v10 theme={null} client.getZipDownloads().getZipDownloadContent(zipDownload.getDownloadUrl()) ``` ```java Java v5 theme={null} ArrayList items = new ArrayList(); BoxZipItem file = new BoxZipItem("file", "12345"); BoxZipItem folder = new BoxZipItem("folder", "156472"); items.add(file); items.add(folder); BoxZip zip = new BoxZip(api); FileOutputStream stream = new FileOutputStream(); BoxZipDownloadStatus zipDownloadStatus = zip.download("Another Awesome Zip File", items, stream); stream.close(); if (zipDownloadStatus.getState() == BoxZipDownloadStatus.State.SUCCEEDED) { System.out.println("Zip downloaded successfully"); } ``` ```py Python v4 theme={null} name = 'test' file = mock_client.file('466239504569') folder = mock_client.folder('466239504580') items = [file, folder] output_file = open('test.zip', 'wb') status = client.download_zip(name, items, output_file) print(f'The status of the zip download is {status["state"]}') ``` ```csharp .NET v6 theme={null} BoxZipRequest request = new BoxZipRequest(); request.Name = "test"; request.Items = new List(); var file = new BoxZipRequestItem() { Id = "466239504569", Type = BoxZipItemType.file }; var folder = new BoxZipRequestItem() { Id = "466239504580", Type = BoxZipItemType.folder }; request.Items.Add(file); request.Items.Add(folder); Stream fs = new FileStream(@"c:\temp\MyTest.zip"); BoxZipDownloadStatus status = await _filesManager.DownloadZip(request, fs); ``` ```js Node v4 theme={null} var name = 'test', items = [ { type: 'file', id: '466239504569' }, { type: 'folder', id: '466239504580' } ], stream = new Readable(); client.files.downloadZip(name, items, stream) .then(status => { /* status -> { "total_file_count": 20, "downloaded_file_count": 10, "skipped_file_count": 10, "skipped_folder_count": 10, "state": "succeeded" } */ }); ``` For downloads that take longer, you can monitor the download status using the status endpoint. This allows you to inspect the progress of the download as well as the number of items that might have been skipped. ```sh cURL theme={null} curl -i -X GET "https://api.box.com/2.0/zip_downloads/29l00nfxDyHOt7RphI9zT_w==nDnZEDjY2S8iEWWCHEEiptFxwoWojjlibZjJ6geuE5xnXENDTPxzgbks_yY=/status" \ -H "authorization: Bearer " ``` ```typescript Node/TypeScript v10 theme={null} await client.zipDownloads.getZipDownloadStatus(zipDownload.statusUrl!); ``` ```python Python v10 theme={null} client.zip_downloads.get_zip_download_status(zip_download.status_url) ``` ```csharp .NET v10 theme={null} await client.ZipDownloads.GetZipDownloadStatusAsync(statusUrl: NullableUtils.Unwrap(zipDownload.StatusUrl)); ``` ```swift Swift v10 theme={null} try await client.zipDownloads.getZipDownloadStatus(statusUrl: zipDownload.statusUrl!) ``` ```java Java v10 theme={null} client.getZipDownloads().getZipDownloadStatus(zipDownload.getStatusUrl()) ``` If you want to use SDKs to download the contents of the folder, follow this guide. # Box Embed Source: https://developer.box.com/guides/embed/box-embed Box Embed is a HTML-based framework that allows embedding the entire Box Web App experience in a custom-made application. Box Embed provides the ability to upload, search, comment, share, tag, and edit files using Box Edit. You can also embed Box Hubs AI Chat for a focused chatbot experience. ## Before you start To create a widget, you need to: * Set an embeddable element, such as a folder, file, hub, note, or app for sharing. * Have at least **Viewer** [permissions][5]. ## Using web app To fetch the Box Embed widget code from the Box web app, perform the following steps. ### Files and folders 1. Navigate to the chosen file or folder. 2. Click on the ellipsis next to the folder. 3. Go to **More Actions** > **Embed Widget**. ### Hubs 1. Navigate to the chosen hub. 2. Click on the ellipsis menu in the upper-right corner. 3. Click **Embed Hub**. You can also embed only the AI chat interface from a hub. Users can ask questions and get AI-powered answers based on the hub's files, without accessing navigation or file browsing features. For more information, see the Box Hubs AI Chat embedding section. ### Notes 1. Navigate to the chosen note. 2. Click on the ellipsis menu. 3. Click **Embed Box Note**. ### Apps 1. Navigate to the chosen app or Box App View. 2. Click on the ellipsis menu. 3. Click **Embed**. Box Embed In the next step, configure the parameters of an embeddable element. | Element Type | Configuration Options | | ------------ | ----------------------------------------------------------------------------------------------------------- | | Files | Size of the widget. | | Folders | Size of the widget, sorting of the files in a folder, hiding the navigation path and sidebar. | | Hubs | Size of the widget, hiding the parent navigation path and sidebar. | | Hubs AI Chat | Chat mode: button or widget. | | Notes | Size of the widget, skipping cloud game (results in note being in read only mode), hiding notes navigation. | | Apps | Size of the widget. | Box Embed Configuration When you are done customizing the embed widget, copy and paste the embed code into your site or web application. ## Programmatically If you want to customize Box Embed even further, you can do it programmatically. The format for an embed snippet is as follows: ```html theme={null} ``` ### Browser permissions The `allow` attribute enables clipboard operations and local network access for Google Chrome 142 and above and Microsoft Edge 143 and above. While designed for these browser versions, this attribute can be safely included for all browsers. Other browsers will ignore it. Without this attribute, embedded Box content might not work correctly with Box Tools, Device Trust, or the clipboard copy button. The Embed Widget Link Generation modal automatically includes this parameter in the generated code. ### Finding your shared link value The first step to building an embed `iframe` programmatically is to generate or find the value for the shared link. One way to find this value is by using the Box web app. Box Share Another way is to create a shared link with API using the `PUT /files/:file_id` or `PUT /files/:file_id`. Then you can find this shared link value using the `GET /files/:id` or `GET /folders/:id` endpoint and passing in the query parameter `fields=shared_link`. ```curl theme={null} curl https://api.box.com/2.0/folders/12345?fields=shared_link \ -H "authorization: Bearer ACCESS_TOKEN" ``` ```json theme={null} "shared_link": { "url": "https://app.box.com/s/dsbJFzdO7qZxdfOHFzdO7qZxdfOH", "download_url": null, "vanity_url": null, ... } ``` You can also set the page to Root Folder/All Files page. Set the URL to `/folder/0` instead of the share link: `` ### Parameters Next, you will want to choose your view customization options. The following is a list of optional parameters you can configure. | | | | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------- | | `hideHubsGallery` | Hide or show navigation chevron button to go back to Hubs gallery. Can be `true` or `false` (default). | | `hideNavigationControls` | Hide or show navigation controls in Box Notes. | | `showItemFeedActions` | Hide or show file comments or tasks. Can be `true` (default) or `false`. | | `showParentPath` | Hide or show the folder path in the header of the frame. Can be `true` or `false` (default). | | `sortColumn` | The order the files or folders are sorted in. Can be `name`, `date` (default), or `size`. | | `sortDirection` | The sort direction of files or folders. Can be `ASC` (default) or `DESC`. | | `view` | The view type for your files or folders. Can be `list` (default) or `icon`. For logged-in users the view type from user preferences takes precedence. | | `uxLite` | Show the limited content preview (Preview Light), with no cloud game. Works only for shared files and Box Notes. | When you use `uxLite` with Box Notes, navigation controls are not displayed, regardless of the `hideNavigationControls` setting. All custom search parameters from the first-party app URL are passed to the embed widget modal and Content Preview. ### Full screen capabilities To enable full screen capabilities for the Box Embed snippet, include one or more of the following parameters if you want the object to be viewable in full screen within an ` ``` #### Using the close button When embedding the Box AI chat directly with `iframe` (without using the provided script), you can enable a close button within the chat interface that communicates with your parent application through `postMessage`. ##### Enabling the close button To display a close button (✕) in the corner of the iframe, add the `showCloseButton=true` query parameter to your `iframe` URL as follows: `https://app.box.com/ai-chat?hubId=YOUR_HUB_ID&showCloseButton=true` ##### How it works 1. When `showCloseButton=true` is set, an X button appears in the corner of the chat iframe. 2. When a user clicks this button, the iframe sends a `postMessage` event to the parent window. 3. The event contains `event.data.type` set to `"BOX_AI_CHAT_CLOSE"`. 4. Your hosting application listens for this event and handles the closing logic. ##### Implementation example ```javascript theme={null} window.addEventListener('message', (event) => { // Optional: validate origin is from Box for additional security // if (event.origin !== 'https://app.box.com') return; if (event.data && event.data.type === 'BOX_AI_CHAT_CLOSE') { closeChat(); } }); ``` ##### Event reference | Property | Value | Description | | ----------------- | --------------------- | --------------------------------------------------------------- | | `event.data.type` | `"BOX_AI_CHAT_CLOSE"` | Indicates the user clicked the close button in the chat iframe. | ## Expiring embed links For files, another option is to call the `GET /files/:id` and request an `expiring_embed_link` using the `fields` query parameter. ```curl theme={null} curl https://api.box.com/2.0/files/12345?fields=expiring_embed_link \ -H "authorization: Bearer ACCESS_TOKEN" ``` ```json theme={null} { "etag": "1", "expiring_embed_link": { "token": { "access_token": "1!rFppcinUwwwDmB4G60nah7z...", "expires_in": 3646, "restricted_to": [ { "object": { "etag": "1", "file_version": { "id": "34567", "sha1": "1b8cda4e52cb7b58b354d8da0068908ecfa4bd00", "type": "file_version" }, "id": "12345", "name": "Image.png", "sequence_id": "1", "sha1": "1b8cda4e52cb7b58b354d8da0068908ecfa4bd00", "type": "file" }, "scope": "base_preview" }, ... ], "token_type": "bearer" }, "url": "https://cloud.app.box.com/preview/expiring_embed/...." }, "id": "12345", "type": "file" } ``` The `url` attribute can be used in an ` ``` ## Customized Previewer (UI Elements) To leverage advanced preview customization and event handling capabilities, use the Box UI Preview Element. To set up the Preview Element, start by installing the required components. The basic code will resemble the below when adding the JavaScript code to display a new previewer. ```js theme={null} var preview = new Box.Preview(); preview.show("FILE_ID", "ACCESS_TOKEN", { container: ".preview-container", showDownload: true }); ``` Replace the placeholders in the code sample with the following: * `FILE_ID`: The ID of the file uploaded to the application, which can be obtained from the object returned when uploading the file. * `ACCESS_TOKEN`: The primary Access Token set up when configuring the application or a downscoped version of the token. Due to the elevated privileges of the primary access token it's highly recommended that you use a downscoped version of the token in the Javascript code. See best practices for downscoping. # FAQ Source: https://developer.box.com/guides/embed/box-view/faq To get started with the New Box View, follow our guide here. Please follow our guide here to choose the best method for your use case. Supported [file types][file_types] can be found in our support article. * All documents supported on web preview are supported on mobile browsers (Safari for iOS and Chrome). * Full annotations support is available for mobile via the Content Preview UI Element, which leverages Box Annotations. * Mobile SDKs (for iOS and Android) do not support 360 Videos/Images, and 3D. * Mobile SDKs (for iOS and Android) do not support annotations (both read and write). Annotations are markup notes on a file rendering and allow developers to provide collaboration capabilities right from within the embedded Box preview in their application. Box Representations let you get the digital assets created for files stored in Box. You can use these endpoints to get PDF, text, image, and thumbnail representations for a file. Currently, Box View is only compatible with files that are stored in Box. You can delete the files from Box once you no longer need to display them. However, you would need to re-upload them again in order to generate the preview. For this reason, we recommend keeping the files stored in Box for at least as long as you want to be able to display them. To fix the CORS error, add each domain you wish to allow to make CORS requests via the application's configuration page. Wildcards are supported for the subdomain (`https://*.domain.com`). See the CORS guide for more information. See this guide for information on customizing the logo within a Preview UI Element. [file_types]: https://support.box.com/hc/en-us/articles/360043695794-Viewing-Different-File-Types-Supported-in-Box-Content-Preview # Box View Source: https://developer.box.com/guides/embed/box-view/index Box View is an embeddable service that allows developers to upload, convert, and display files in their web and mobile apps via a high-fidelity, interactive file viewer. ## Features ### View any file Embed documents, images, videos, 360-degree videos and images, 3D models, and dozens of other files in any web or mobile app using a standard `