Skip to main content
In modern document workflows, two of the most challenging parts are generating consistently formatted documents and managing e-signature execution at scale. This tutorial demonstrates how to address both challenges by integrating the Box Doc Gen API and the Box Sign API into a single, automated pipeline. In this scenario, you build an automated pipeline that submits candidate data and gets a signed PDF back with no manual steps in between. Once you pass the candidate and offer details, the solution calls the Box Doc Gen API to merge that data into an offer letter template. When the PDF is ready, a Box webhook notifies the app which PDF file has been generated. This initiates a Box Sign request for that generated offer letter, which routes it through HR approval and candidate signature. The code is minimal by design. The goal is to show the application pattern clearly so you can extend it into a larger platform workflow, swap in your own templates, or add more signers and approval steps. When your HR system sends candidate and offer details, the service:
  1. Calls Box Doc Gen to merge the data into an offer letter template.
  2. Listens for a Doc Gen completion webhook and records the generated PDF.
  3. Creates a Box Sign request so an HR approver reviews the letter before the candidate signs.

Clone the working sample

Prefer to start from running code? The complete app built in this tutorial is on GitHub. Clone it, add your Box credentials, and run.

What you are building

By the end of this tutorial, you have a working Node.js service that:
  • Accepts offer data from an applicant tracking system (ATS) or HR webhook.
  • Validates the payload and calls Box Doc Gen to merge data into an offer letter template.
  • Listens for a Doc Gen completion webhook and records the generated PDF file ID.
  • Creates a Box Sign request with an HR approver and the candidate as signers.
  • Exposes endpoints to trigger generation, send for signature, and check offer letter status.
This sample is designed to be triggered by an ATS such as Greenhouse, but the same pattern applies to Workday Recruiting, SAP SuccessFactors, or any HR system that can send a webhook and expose offer data through an API.

Prerequisites

Before you start, make sure you have the following:
  • Node.js 18 or higher.
  • A Box Enterprise Advanced account with entitlement and enabled in the Admin Console. Box Doc Gen is not available on free developer accounts.
  • A Box application configured with Client Credentials Grant authentication, authorized in the Admin Console. See for setup details.
  • The Box enterprise ID for your account (BOX_ENTERPRISE_ID). The Client Credentials Grant app authenticates as the enterprise service account. Find it in the Developer Console under your app’s General Settings, or in the Admin Console.

Step-by-step process

This solution uses three Box Platform capabilities:
1

Enable Box Doc Gen and Box Sign

Go to the Admin Console and navigate to the Enterprise Settings tab. Enable Box Doc Gen in the Content & Sharing tab and Box Sign in the Box Sign tab for selected users or all enterprise users.
2

Create Box folders

Create three folders in Box:
  1. Offer Letter Template
  2. Generated Offer Letters
  3. Signed Offer Letters
Copy each folder ID from the Box web app URL (for example, https://app.box.com/folder/123456789123456789). You need these values for the project variables BOX_DOCGEN_DESTINATION_FOLDER_ID and BOX_SIGN_PARENT_FOLDER_ID.Collaborate the app’s service account into the template, generated-offer, and signed-offer folders with Editor access. Service accounts do not automatically have access to user-owned content. You can find the service account address (AutomationUser_...@boxdevedition.com) in the Developer Console under your app’s General Settings.
3

Create an offer letter template

Use a preexisting Box Doc Gen template in the Box web app:
  1. Open the Automate tab in Box.
  2. Navigate to the Doc Gen tab.
  3. Select the Employee Offer Letter template.
  4. Select a destination folder for the template and generated documents.
  5. Select Generate Document, then save the template file ID from the page or from the URL.
To match the sample template, the ATS payload must include the fields the validateOffer function checks in a later step: id, country, contractDate, deliveryTerms, companyName, baseSalary, salaryDetails, salaryModel, employee.address, employee.dob, employee.email, employee.name, company.address, company.designatedSigner, company.name, company.designation, company.department, position, department, and startDate.
4

Create and configure your Box application

Create a Custom App with Server Authentication (Client Credentials Grant) in the .
  1. Enable the Read all files and folders, Write all files and folders, Manage Doc Gen, Manage signature requests, and Manage webhooks scopes.
  2. Save your changes and authorize the app in the Developer Console in App Details section under Status.
5

Set up the development environment

Build the project from scratch so you understand what each file does. The rest of this tutorial walks through every file.
  1. Open your terminal and create a new project directory:
  1. Initialize package.json and enable ES modules. The service uses import/export syntax, so Node needs "type": "module" to run the files:
  1. Install the required packages:
  1. Create a .env file to store your credentials, then add the following content. Replace the placeholder values with your credentials and folder IDs from the Box Developer Console:
For local development, expose your server with a tunnel (for example, ngrok) and set PUBLIC_BASE_URL to the tunnel URL. In production, verify webhook signatures. See .
6

Create configuration and storage helpers

In your project, create a config.js file and add the following code. It loads environment variables used throughout the service:
Create store.js with a simple in-memory store for the demo. Replace this with a database before you deploy to production.
Create box-client.js and add a function that creates a Box client authenticated with Client Credentials Grant:
The app calls Box APIs with the permissions of the service account.
7

Validate offer data

Create offer-letter-data.js with functions that validate incoming offer payloads before you call Doc Gen. The buildOfferLetterData function is a pass-through hook you can extend to map or transform fields before Doc Gen merges them into the template.
8

Generate offer letters with Box Doc Gen

Create box-docgen.js with functions that start document generation and parse webhook payloads:
See for additional API options.
9

Send offer letters for signature with Box Sign

Create box-sign.js with functions that collaborate the HR approver on the generated file and create a Box Sign request. In this example, the HR team member acts as an approver and reviews the documents, so they can double-check the offer details. Once this is approved in Box, the candidate receives the offer letter in their mailbox, with a custom email message valid for 14 days:
Box Sign also supports phone verification, password protection, and other advanced security options. See for the full parameter list.
10

Build the Express server

Create server.js to orchestrate the workflow. The server loads the Box configuration from environment variables, and creates a Box SDK client. It then exposes the REST endpoints:
Protect key routes with the shared secret in production, and verify webhook signatures before you process Doc Gen events. The in-memory store.js module is for demos only — replace it with a database for production before you deploy.
At this point, your project directory should contain the following files:
11

Configure the Doc Gen webhook

Register the webhook on the template file, not the destination folder. The DOCGEN_DOCUMENT_GENERATION_SUCCEEDED trigger is file-only; registering it on a folder returns a 400 invalid_parameter error. For more options, see .Configure a V2 Box webhook for your app:
  1. Define the URL where webhook payloads are sent.
  2. Select the Box Doc Gen template document as the trigger.
  3. Enable the Document Generation Succeeded trigger (DOCGEN_DOCUMENT_GENERATION_SUCCEEDED).
See for the full walkthrough.Or register the webhook with the Box CLI. Replace $BOX_ACCESS_TOKEN with a valid access token from your CCG-authenticated client:
12

Test the application

Start the server:
Confirm the server is running:
Send a test offer payload. Update the shared secret and port to match your .env file, then run:
Example response:
Open the Generated Offer Letters folder in Box. After Doc Gen finishes, the PDF appears there and Box sends the webhook to your app.Simulate the webhook locally if you do not have a public URL:
List in-memory offers:
Send the offer for signature:
Check Box Sign status:
Common Box Sign statuses include created, sent, viewed, signed, declined, and expired.Check the result:
  • GET /offer-letters lists all in-memory offer records and their statuses.
  • GET /offer-letters/:id/sign-request returns the latest Box Sign status for an offer.
  • The HR approver receives the document first. After approval, the candidate receives the offer letter by email.

Troubleshooting

Confirm BOX_CLIENT_ID, BOX_CLIENT_SECRET, and BOX_ENTERPRISE_ID are correct in your .env file. Verify the app uses Client Credentials Grant and is authorized in the Admin Console. See .
The service account does not have access to the template file or destination folder. Confirm the service account is collaborated into the template and folders with Editor access, and that the template file ID and folder IDs are correct.
The Doc Gen webhook has not arrived yet. Confirm your webhook is registered on the template file with the DOCGEN_DOCUMENT_GENERATION_SUCCEEDED trigger, and that your server is reachable at the configured URL.
The offer payload is missing required fields for the Doc Gen template. Compare your payload against the required array in validateOffer and make sure nested fields such as employee.email are present.
Confirm the app uses Client Credentials Grant, the app has read/write, Doc Gen, and Sign scopes, and the service account can access the template file, write to the generated-offers folder, and write to the signed-offers folder. Confirm Doc Gen and Box Sign are enabled for the account in the Admin Console.
Check employee.email in the offer payload. This value is used as the Box Sign recipient.
Confirm .env includes BOX_CLIENT_ID, BOX_CLIENT_SECRET, BOX_ENTERPRISE_ID, BOX_DOCGEN_TEMPLATE_FILE_ID, BOX_DOCGEN_DESTINATION_FOLDER_ID, and BOX_SIGN_PARENT_FOLDER_ID.

Other use cases

The same Box Doc Gen and Box Sign pattern applies to other workflows that need both document generation and approval or signature:

Scaling to production

The demo store.js module loses data on restart. Persist offer records in a database so you can correlate Doc Gen batch IDs, generated file IDs, and Box Sign request IDs across restarts and retries.
In production, validate that Doc Gen webhook payloads originate from Box before you update offer records. See .
If you change scopes or the access level on the CCG app, an administrator must reauthorize the app in the Admin Console under Integrations > Platform Apps before API calls succeed again.
Add multiple approvers, in-person signing, password protection, or phone verification by extending the signers array and other Box Sign request parameters. See .
Make webhook handling idempotent because delivery can produce duplicates. Add retries for Box API calls, protect routes with stronger auth than a shared secret, and avoid logging access tokens, employee personal data, compensation details, or signed-document links.

Next steps

Generate documents with Box Doc Gen

Learn how to generate documents with Box Doc Gen.

Create Box Sign request

Explore advanced Sign request options, including multi-signer flows and security settings.
Last modified on August 14, 2026