<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Box</title>
    <description>The latest articles on DEV Community by Box (box).</description>
    <link>https://dev.to/box</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F1511%2F1a13c590-6288-40d1-accd-66681ac0eacb.png</url>
      <title>DEV Community: Box</title>
      <link>https://dev.to/box</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/box"/>
    <language>en</language>
    <item>
      <title>From upload to routed review with Box Extract and OpenAI Decisions API</title>
      <dc:creator>Olga Stefaniuk</dc:creator>
      <pubDate>Wed, 21 Oct 2026 09:41:31 +0000</pubDate>
      <link>https://dev.to/box/from-upload-to-routed-review-with-box-extract-and-openai-decisions-api-139f</link>
      <guid>https://dev.to/box/from-upload-to-routed-review-with-box-extract-and-openai-decisions-api-139f</guid>
      <description>&lt;p&gt;Imagine a certificate of insurance (COI) arriving in Box as a PDF through a File Request, while the project’s insurance requirements sit in a sibling folder. Box AI extracts key fields from both documents, and the application saves them as metadata on the uploaded COI. It then sends the extracted values and filename to the &lt;a href="https://developers.openai.com/" rel="noopener noreferrer"&gt;OpenAI Decisions API&lt;/a&gt;, which answers a closed-ended question: which of a set of three predefined workflows fits the evidence? The application then uses the selected route and returns a confidence value in its routing rules.&lt;/p&gt;

&lt;p&gt;A Box V2 webhook starts the workflow as soon as the upload reaches the intake folder. The application creates a Box task with the evidence and reason, assigns it to the configured reviewer, and adds the insurance specialist as a file collaborator when needed. Box is where the documents arrive and where people review them. Let’s see how this works under the hood.&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-2110793002528743840-642" src="https://platform.twitter.com/embed/Tweet.html?id=2110793002528743840"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-2110793002528743840-642');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=2110793002528743840&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;h2&gt;
  
  
  Route documents based on intelligent review
&lt;/h2&gt;

&lt;p&gt;Every route creates a Box review task with context for the reviewer. The reviewer is configured by a Box user ID in the application setup. For &lt;code&gt;request_endorsement&lt;/code&gt; and &lt;code&gt;specialist_review&lt;/code&gt;, the insurance specialist is also added as a collaborator on the uploaded file.&lt;/p&gt;

&lt;p&gt;Box AI extracts fields such as the project completion date, required liability limits, named insured, policy expiration, and additional-insured evidence. Then, the application passes these fields and the uploaded filename to Decisions as shared context. The fixed choices let the application create a task that explains why the file needs review.&lt;/p&gt;

&lt;p&gt;The three routes are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Request endorsement.&lt;/strong&gt; Create a review task explaining that a separate additional-insured endorsement appears to be missing; add the specialist as a file collaborator.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Specialist review.&lt;/strong&gt; Create a review task for missing, unclear, or conflicting evidence; add the specialist as a file collaborator.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ready for human review.&lt;/strong&gt; Create a review task for a human to check the evidence.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fu57k8g3ho9ur24kss87i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fu57k8g3ho9ur24kss87i.png" alt="Demo workflow" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If the route is unclear or unsupported, or its confidence falls below the defined application’s threshold, the code sends the case to &lt;code&gt;specialist_review&lt;/code&gt;. The task includes the project requirements and extracted COI values, giving the reviewer a useful starting point.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Box Extract and Decisions work together
&lt;/h2&gt;

&lt;p&gt;These two APIs have separate jobs. Box AI Extract turns each source document into a small set of requested fields. The Decisions API evaluates this context and selects the next workflow route.&lt;/p&gt;

&lt;p&gt;First, the Box SDK calls Box’s structured extraction endpoint. The request identifies a Box file and supplies field definitions with prompts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;extract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;BoxClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;file_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_ai_extract_structured&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;AiItemBase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;file_id&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;
        &lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;plain_dict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;answer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{}))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Data is pulled both from project requirements and an incoming COI document.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;coi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;extract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;file_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;COI_FIELDS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;requirements&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;extract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;requirements_file_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;REQUIREMENT_FIELDS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, the application builds a compact text input containing the uploaded filename and both keyed extraction results. It sends that evidence to the Decisions API with a choice question and the three routes as allowed values:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;decision&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;decisions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Uploaded filename: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;file_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Project requirements extracted from the Box reference document:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;requirements&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;indent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;COI evidence extracted from the Box upload:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;coi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;indent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;questions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;choice&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;route&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;instructions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Choose one administrative workflow route based on the evidence and criteria.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;choices&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ROUTES&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The choices include descriptions explaining when each route applies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;ROUTES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;value&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;request_endorsement&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The COI is readable and the needed coverage details are present, but the separate required additional-insured endorsement is missing. Create a review task so the project team can request the updated document.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;value&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;specialist_review&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;A required date, limit, coverage detail, named party, or document is missing, unreadable, contradictory, or otherwise unclear. Assign a specialist to review.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;value&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ready_for_human_review&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The file appears to contain the requested coverage details and separate endorsement. Create a review task.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The API returns a typed choice instead of a paragraph the application must parse. The app checks that the answer is usable, applies its confidence policy, and only then runs the matching Box actions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trigger the right workflow and give context
&lt;/h2&gt;

&lt;p&gt;After the application checks the Decisions API result, it maps the final route to Box actions. Every route creates a review task; &lt;code&gt;request_endorsement&lt;/code&gt; and &lt;code&gt;specialist_review&lt;/code&gt; paths also add the predefined insurance specialist as a file collaborator. The task message gives the reviewer useful context when they open the source document. The application also writes the extracted values and decision confidence to the uploaded file using the enterprise metadata template.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fuxces1n6z9q4ukk2fdc8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fuxces1n6z9q4ukk2fdc8.png" alt="Document uploaded to Box with agentic review task created" width="800" height="493"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Run the workflow
&lt;/h2&gt;

&lt;p&gt;The demo project includes fictional PDFs for the project requirements, an incomplete COI, an unclear-expiration COI, a separate endorsement example, and a complete submission packet.&lt;/p&gt;

&lt;p&gt;To run this sample app you’ll need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;a href="https://app.box.com/upgrade?source=signup" rel="noopener noreferrer"&gt;free Box developer account&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;A Server Authenticated app created in the Developer Console.&lt;/li&gt;
&lt;li&gt;The Manage webhooks scope enabled in your app.&lt;/li&gt;
&lt;li&gt;A generated developer token from the Developer Console.&lt;/li&gt;
&lt;li&gt;Box user IDs for the reviewer and specialist copied from the Box Admin Console (&lt;a href="https://developer.box.com/" rel="noopener noreferrer"&gt;learn how to find user IDs&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;An OpenAI API key. The Decisions API model defaults to &lt;code&gt;gpt-6-luna&lt;/code&gt;; check the &lt;a href="https://developers.openai.com/" rel="noopener noreferrer"&gt;current OpenAI API guide&lt;/a&gt; for model availability and beta status when setting up the demo.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Follow these steps to set up this project:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Clone &lt;a href="https://github.com/" rel="noopener noreferrer"&gt;the repository&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Copy the &lt;code&gt;.env.example&lt;/code&gt; file and fill it with values:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   # Box Developer Token from the Box Developer Console (demo token expires periodically).
   BOX_DEVELOPER_TOKEN=

   # OpenAI API key.
   OPENAI_API_KEY=
   OPENAI_DECISIONS_MODEL=gpt-6-luna

   BOX_REVIEWER_USER_ID=
   BOX_SPECIALIST_USER_ID=
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Webhook handling for this project is optional. The script can be triggered manually or with the webhook handler. When running the webhook receiver locally, expose your port through a public HTTPS tunnel, for example with ngrok. Set &lt;code&gt;BOX_WEBHOOK_ADDRESS&lt;/code&gt; to &lt;code&gt;https://&amp;lt;your-host&amp;gt;/box-webhook&lt;/code&gt;. The tunnel forwards that public callback to the local receiver.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   # Used by seed.py to create/update the intake upload webhook.
   # Set to the public HTTPS tunnel URL ending in /box-webhook
   BOX_WEBHOOK_ADDRESS=
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Create a Box File Request template in the Box web application. It gives users a simple upload page and places submitted content directly in the intake folder. This is the only manual configuration step, as the Box API requires an existing template to create a new one programmatically. See the &lt;a href="https://support.box.com/" rel="noopener noreferrer"&gt;File Request instructions&lt;/a&gt;. Add an email address field if you want the request to collect the submitter’s contact address.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Save the project and copy its link from the File Request builder URL. Put that value in the &lt;code&gt;.env&lt;/code&gt; file as &lt;code&gt;BOX_FILE_REQUEST_TEMPLATE_ID&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   # ID from the File Request builder URL (/filerequest/&amp;lt;id&amp;gt;), not the public upload URL (/f/&amp;lt;token&amp;gt;).
   BOX_FILE_REQUEST_TEMPLATE_ID=
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7sanp523e6sadupz5m2n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7sanp523e6sadupz5m2n.png" alt="Box File request form" width="800" height="798"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In your terminal, launch the virtual environment and install the required packages.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;python seed.py&lt;/code&gt;, which:

&lt;ol&gt;
&lt;li&gt;Creates folders and uploads the demo project’s insurance requirements.&lt;/li&gt;
&lt;li&gt;Creates a new webhook.&lt;/li&gt;
&lt;li&gt;Creates a metadata template.&lt;/li&gt;
&lt;li&gt;Creates a new File Request and returns a link in the terminal.&lt;/li&gt;
&lt;li&gt;Checks collaboration for the defined users in the &lt;code&gt;.env&lt;/code&gt; file.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Start the HTTPS tunnel in a separate terminal and leave it running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ngrok http 8000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the project terminal, run the seed after setting &lt;code&gt;BOX_WEBHOOK_ADDRESS&lt;/code&gt; to the tunnel’s HTTPS URL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python seed.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you created the File Request after the first seed, set its builder ID and run the seed again. Start the receiver with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python demo.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Upload one of the sample COIs through the File Request link. Box sends the upload event; the receiver queues the file and runs extraction, decision, metadata, and review actions.&lt;/p&gt;

&lt;p&gt;To exercise the same processing path before webhook delivery is configured, use the manual trigger with an uploaded Box file ID:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python manual_trigger.py &amp;lt;BOX_FILE_ID&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Watch the terminal for the extraction fields and decision logs. In Box, open the uploaded file to inspect its COI Intake Review metadata, Activity panel, review task, and specialist collaboration. The sample PDFs are fictional; the COI layout is inspired by familiar certificate fields and the &lt;a href="https://www.tdi.texas.gov/" rel="noopener noreferrer"&gt;Texas Department of Insurance sample&lt;/a&gt;, but these artifacts are not official forms or evidence of actual insurance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Expand the workflow
&lt;/h2&gt;

&lt;p&gt;This demo focuses on the intake-to-review path and can serve as a boilerplate for various use cases. It is not production workflow software. Before deploying a real workflow, move event and processing state to durable storage, make retries safe, and add monitoring so failed or delayed submissions are visible.&lt;/p&gt;

&lt;p&gt;From here, the project could grow in a few practical directions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Find existing project evidence.&lt;/strong&gt; Use the &lt;a href="https://developer.box.com/" rel="noopener noreferrer"&gt;Box Search API&lt;/a&gt; to look for current certificates, endorsements, or project documents. Add only relevant matches to the review context and flag possible duplicates before creating another follow-up task.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Handle a multi-file submission.&lt;/strong&gt; Associate a COI and its separate endorsement with the same project and submitter, then evaluate them together instead of treating each upload as a separate case.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use extraction confidence as another review signal.&lt;/strong&gt; Box can return optional confidence for extracted fields. Capture it separately from the Decisions API route confidence, and send a submission for review when a critical date or limit was extracted with low confidence.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Learn from completed reviews.&lt;/strong&gt; Record whether the reviewer confirmed the route or changed it, then use those labeled outcomes to refine the field prompts, route descriptions, and any confidence threshold.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Notify the submitter about missing information.&lt;/strong&gt; Connect &lt;code&gt;request_endorsement&lt;/code&gt; to an email service and send a reviewed message to the address collected by the File Request, with instructions for submitting the missing document.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have any questions or run into setup difficulties, &lt;a href="https://developer.box.com/" rel="noopener noreferrer"&gt;contact Box&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developers.openai.com/" rel="noopener noreferrer"&gt;OpenAI Decisions API guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/box/box-python-sdk" rel="noopener noreferrer"&gt;Box Python SDK&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.box.com/" rel="noopener noreferrer"&gt;Box AI structured extraction API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.box.com/" rel="noopener noreferrer"&gt;Box optional metadata extraction confidence&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.box.com/" rel="noopener noreferrer"&gt;Box File Requests&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.box.com/" rel="noopener noreferrer"&gt;Box V2 webhooks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.box.com/" rel="noopener noreferrer"&gt;Box webhook signatures&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.box.com/" rel="noopener noreferrer"&gt;Create a Box metadata template&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.box.com/" rel="noopener noreferrer"&gt;Apply metadata to a Box item&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.box.com/" rel="noopener noreferrer"&gt;Box Collaborations API&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>openai</category>
      <category>box</category>
      <category>agents</category>
    </item>
  </channel>
</rss>
