This guide shows the complete pattern for implementing workbook actions that can submit data to external systems.

Blueprint Configuration

First, configure your action in your Blueprint:

// Add this to your workbook configuration
actions: [
  {
    operation: 'submitActionFg',
    mode: 'foreground',
    label: 'Submit data elsewhere',
    type: 'string',
    description: 'Submit this data to a webhook.',
    primary: true,
  },
  // ... other actions
],
settings: {
  trackChanges: true,
}

Listener Implementation

Next, create a listener to handle the job:ready event for your action. For additional webhook patterns and error handling, see the Webhook Examples guide.

listener.on(
  "job:ready",
  { job: "workbook:submitAction" },
  async (event: FlatfileEvent) => {
    const { jobId, workbookId } = event.context;
    const { data: workbook } = await api.workbooks.get(workbookId);
    const { data: workbookSheets } = await api.sheets.list({ workbookId });

    // Collect all sheet data
    const sheets = [];
    for (const [_, element] of workbookSheets.entries()) {
      const { data: records } = await api.records.get(element.id);
      sheets.push({
        ...element,
        ...records,
      });
    }

    try {
      // Acknowledge the job start
      await api.jobs.ack(jobId, {
        info: "Starting job to submit action to webhook",
        progress: 10,
      });

      // Replace with your actual webhook URL
      const webhookReceiver = "https://your-app.com/webhook/flatfile";

      // Submit data to external system
      const response = await fetch(webhookReceiver, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          workbook: {
            ...workbook,
            sheets,
          },
        }),
      });

      if (response.status === 200) {
        const responseData = await response.json();
        const rejections = responseData.rejections;

        // Handle any rejections from the external system
        if (rejections) {
          const outcome = await responseRejectionHandler(rejections);
          await api.jobs.complete(jobId, outcome);
        }
        
        // Mark job as complete
        await api.jobs.complete(jobId, {
          outcome: {
            message: `Data was successfully submitted to ${webhookReceiver}.`,
          },
        });
      } else {
        throw new Error("Failed to submit data to webhook");
      }
    } catch (error) {
      console.error(error);
      await api.jobs.fail(jobId, {
        outcome: {
          message: "This job failed. Check your webhook URL and try again.",
        },
      });
    }
  }
);

Key Points

  • Blueprint Actions: Configure actions with appropriate labels and modes
  • Event Handling: Listen for job:ready events with the specific job filter
  • Data Collection: Gather all workbook and sheet data before submission
  • Job Management: Always acknowledge, complete, or fail jobs appropriately
  • Error Handling: Provide meaningful error messages for troubleshooting