If you aren’t interested in a code-forward approach, we recommend starting with AutoBuild, which uses AI to analyze your template or documentation and then automatically creates and deploys a Blueprint (for schema definition) and a Listener (for validations and transformations) to your Flatfile App.Once you’ve started with AutoBuild, you can always download your Listener code and continue building with code from there!

What We’re Building

In this tutorial, we’ll build a foundational Listener that handles Space configuration - the essential first step for any Flatfile implementation. Our Listener will:
  • Respond to Space creation: When a user creates a new Space, our Listener will automatically configure it
  • Define the Blueprint: Set up a single Workbook with a single Sheet with Field definitions for names and emails that establishes the data schema for the Space
  • Handle the complete Job lifecycle: Acknowledge, update progress, and complete the configuration Job with proper error handling
  • Provide user feedback: Give real-time updates during the configuration process
This forms the foundation that you’ll build upon in the next parts of this series, where we’ll add user Actions and data validation. By the end of this tutorial, you’ll have a working Listener that creates a fully configured workspace ready for data import.

Prerequisites

Before we start coding, you’ll need a Flatfile account and a fresh project directory:
  1. Create a new project directory: Start in a fresh directory for this tutorial (e.g., mkdir my-flatfile-listener && cd my-flatfile-listener)
  2. Sign up for Flatfile: Visit platform.flatfile.com and create your free account
  3. Get your credentials: You’ll need your Secret Key and Environment ID from the Keys & Secrets section later in this tutorial
New to Flatfile? If you’d like to understand the broader data structure and concepts before diving into code, we recommend reading through the Core Concepts section first. This covers the foundational elements like Environments, Apps, and Spaces, as well as our data structure like Workbooks and Sheets, and how they all work together.Each Listener is deployed to a specific Environment, allowing you to set up separate Environments for development, staging, and production to safely test code changes before deploying to production.

Install Dependencies

Choose your preferred language and follow the setup steps:
# Initialize project (skip if you already have package.json)
npm init -y

# Install required Flatfile packages
npm install @flatfile/listener @flatfile/api

# Note: Feel free to use your preferred JavaScript project setup method instead

Authentication Setup

For this step, you’ll need to get your Secret Key and environment ID from your Flatfile Dashboard. Then create a new file called .env and add the following (populated with your own values):
# .env
FLATFILE_API_KEY="your_secret_key"
FLATFILE_ENVIRONMENT_ID="us_env_your_environment_id"

Create Your Listener File

Create a new file called index.js for Javascript or index.ts for TypeScript:
import api from "@flatfile/api";

export default function (listener) {
  // Configure the Space when it's created
  listener.on("job:ready", { job: "space:configure" }, async (event) => {
    const { jobId, spaceId } = event.context;
    try {
      // Acknowledge the job
      await api.jobs.ack(jobId, {
        info: "Setting up your workspace...",
        progress: 10,
      });
      // Create the Workbook with Sheets, creating the Blueprint for the space
      await api.workbooks.create({
        spaceId,
        name: "My Workbook",
        sheets: [
          {
            name: "contacts",
            slug: "contacts",
            fields: [
              { key: "name", type: "string", label: "Full Name" },
              { key: "email", type: "string", label: "Email" },
            ],
          },
        ],
      });
      // Update progress
      await api.jobs.update(jobId, {
        info: "Workbook created successfully",
        progress: 75,
      });
      // Complete the job
      await api.jobs.complete(jobId, {
        outcome: {
          message: "Workspace configured successfully!",
          acknowledge: true,
        },
      });
    } catch (error) {
      console.error("Error configuring Space:", error);
      // Fail the job if something goes wrong
      await api.jobs.fail(jobId, {
        outcome: {
          message: `Failed to configure workspace: ${error.message}`,
          acknowledge: true,
        },
      });
    }
  });
}

Complete Example: The full working code for this tutorial step is available in our Getting Started repository: JavaScript | TypeScript

Project Structure

After creating your Listener file, your project directory should look like this:
my-flatfile-listener/
├── .env      // Environment variables
├── index.js  // Listener code
|
|   /* Node-specific files below */
|
├── package.json
├── package-lock.json
└── node_modules/

Authentication Setup

You’ll need to get your Secret Key and Environment ID from your Flatfile Dashboard to find both values, then add them to a .env file:
# .env
FLATFILE_API_KEY="your_secret_key"
FLATFILE_ENVIRONMENT_ID="us_env_your_environment_id"

Testing Your Listener

Local Development

To test your Listener locally, you can use the flatfile develop command. This will start a local server that implements your custom Listener code, and will also watch for changes to your code and automatically reload the server.
# Run locally with file watching
npx flatfile develop

Step-by-Step Testing

After running your listener locally:

Testing Steps

  1. Create a new space in your Flatfile environment
  2. Observe as the new space is configured with a Workbook and Sheet

What Just Happened?

Your Listener is now ready to respond to Space configuration Events! Here’s how the space configuration works step by step:

1. Exporting your Listener function

This is the base structure of your Listener. At its core, it’s just a function that takes a listener object as an argument, and then uses that listener to respond to Events.
export default function (listener) {
  // . . . code
}

2. Listen for Space Configuration

When a new Space is created, Flatfile automatically triggers a space:configure job that your Listener can handle. This code listens for that job using the job:ready Event, filtered by the job name space:configure.
listener.on("job:ready", { job: "space:configure" }, async (event) => {
  // . . . code
});

3. Acknowledge the Job

The first step is always to acknowledge that you’ve received the job and provide initial feedback to users. From this point on, we’re responsible for the rest of the job lifecycle, and we’ll be doing it all in this Listener. For more information on Jobs, see the Jobs concept.
await api.jobs.ack(jobId, {
  info: "Setting up your workspace...",
  progress: 10,
});

4. Define the Blueprint

Next, we create the workbook with sheets and field definitions. This is your Blueprint definition—establishing the data schema that will govern all data within this Space.
await api.workbooks.create({
  spaceId,
  name: "My Workbook",
  sheets: [
    {
      name: "contacts",
      slug: "contacts", 
      fields: [
        { key: "name", type: "string", label: "Full Name" },
        { key: "email", type: "string", label: "Email" },
      ],
    },
  ],
});

5. Update Progress

Keep users informed about what’s happening during the configuration process.
await api.jobs.update(jobId, {
  info: "Workbook created successfully",
  progress: 75,
});

6. Complete the Job

Finally, mark the job as complete with a success message, or fail it if something went wrong.
// Success case
await api.jobs.complete(jobId, {
  outcome: {
    message: "Workspace configured successfully!",
    acknowledge: true,
  },
});

// Failure case
await api.jobs.fail(jobId, {
  outcome: {
    message: `Failed to configure workspace: ${error.message}`,
    acknowledge: true,
  },
});
This follows the standard Job pattern: acknowledge → update progress → complete (or fail on error). This provides users with real-time feedback and ensures robust error handling throughout the configuration process.

Next Steps

Ready to enhance data quality? Continue to Adding Validation to learn how to validate Fields and provide real-time feedback to users. For more detailed information: