> ## Documentation Index
> Fetch the complete documentation index at: https://developers.pleo.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Detect & Start Export Jobs

export const RememberCallout = ({title, children, icon = "🪢"}) => <div style={{
  backgroundColor: 'var(--recommended-bg)',
  borderLeft: '4px solid #f63b92',
  borderRadius: '10px',
  padding: '18px 22px',
  marginBottom: '20px',
  boxShadow: '1px 1px 3px rgba(0,0,0,0.06)'
}}>
    <div style={{
  display: 'flex',
  alignItems: 'flex-start',
  gap: '14px'
}}>
      <span style={{
  fontSize: '22px',
  lineHeight: '1',
  flexShrink: 0
}}>
        {icon}
      </span>
      <div>
        {title && <div style={{
  fontSize: '16px',
  fontWeight: 600,
  color: 'var(--recommended-title)',
  marginBottom: '6px'
}}>
            {title}
          </div>}
        <div style={{
  fontSize: '14px',
  lineHeight: 1.65
}}>
          {children}
        </div>
      </div>
    </div>
  </div>;

This page describes how integrations must:

1. **Detect Export Jobs** that are ready for processing
2. **Start a single Export Job** to begin processing

This is the **first step** in the Export Integration Workflow.

## Implementation

See the corresponding how-to article for API usage and step-by-step instructions:

* [How to Detect and Start Export Jobs for Processing](/docs/current/how-tos/accounting-integrations/how-to-detect-and-start-export-jobs-for-as-erp-processing)

## Conceptual Model

Export processing begins in two distinct phases:

| Phase     | Responsibility                                |
| --------- | --------------------------------------------- |
| Detection | Identify Export Jobs available for processing |
| Starting  | Take ownership of a single Export Job         |

These phases must remain **logically separate**:

* Detection **must not modify state**
* Starting **is the first state-changing action**

## Detect Export Jobs

### Purpose

Detection identifies Export Jobs that are ready to be processed.

It must:

* Detect newly created Export Jobs
* Identify jobs eligible for processing
* Avoid modifying job state

### Detection Mechanisms

Integrations may use one of the following:

#### Webhooks (preferred)

* Subscribe to `export-job.created`
* Trigger detection when event is received

#### Polling (fallback)

* Periodically call `GET /v3/export-jobs`
* Use controlled intervals (e.g. every few minutes)

#### Ad Hoc Trigger (optional)

* Exposes a user-initiated action (e.g. a button in the integration UI) that immediately runs the same polling flow as schedule polling
* Used **in combination with** scheduled polling, not as a standalone mechanism
* Useful when a user wants to check for pending jobs without waiting for the next scheduled interval

### Eligible Job States

The statuses to include depend on context:

| Context                 | Statuses                    | Reason                                            |
| ----------------------- | --------------------------- | ------------------------------------------------- |
| Normal operation        | `pending`                   | Job has not yet been started by any integration   |
| Recovery / reconnection | `pending` and `in_progress` | Integration may have an interrupted job to resume |

In normal operation, only `pending` jobs should be fetched. An `in_progress` job found during recovery indicates a previously interrupted workflow: the integration should resume it without sending a `started` event again.

### Sequential Processing Requirement

When multiple jobs exist:

* Always select the **oldest job**
* Process jobs **one at a time**
* Do **not** process jobs in parallel

This prevents:

* race conditions
* duplicate exports
* inconsistent accounting state

<RememberCallout title="Remember">
  Export Jobs only exist after expenses have been [queued](/docs/current/how-tos/accounting-integrations/how-to-queue-export-items-in-ui) in Pleo’s Web App.
</RememberCallout>

## Start Export Job

### Purpose

Starting an Export Job:

* Signals that the integration is starting processing
* Prevents multiple workers processing the same job
* Establishes ownership and traceability

### When to Start

An Export Job must only be started after:

* The job has been discovered
* Pre-processing checks (e.g. validation readiness) have completed

Starting too early can lead to:

* failed exports
* stuck jobs
* inconsistent state

### How Starting Works

Starting only applies to `pending` jobs. If the job is already `in_progress` (recovery scenario), skip the `started` event and resume from pre-export validation.

To start a `pending` job:

1. Select the **oldest eligible job**
2. Send a `started` event via:

```json theme={null}
{
  "event": "started",
  "jobId": "<jobId>"
}
```

## Result of Starting

After a successful start:

* Job status transitions to `in_progress`
* The integration becomes responsible for processing
* Export Items can now be fetched

## Concurrency & Conflict Handling

Integrations are designed to run a single export worker, but infrastructure doesn't always guarantee this. Rolling deployments, double-firing scheduled jobs, or a restarting worker can briefly produce two instances that both attempt to start the same job. This is an edge case, not an intended design pattern.

The `started` event acts as an atomic lock: only one instance can successfully start a given job. If starting fails due to a status conflict:

* Treat this as expected behaviour
* Do not retry aggressively
* Restart detection and select the next eligible job

## Key Rules

* Detection must be read-only
* Only one job may be processed at a time. Integrations should run a single export worker; the `started` event enforces this at the API level as a safety net for edge cases such as rolling deployments or double-firing schedulers
* Always process the oldest eligible job
* In normal operation, only `pending` jobs are eligible for detection
* Starting is the first state-changing action and only applies to `pending` jobs
* Starting must be done using the `started` event
* In recovery, an `in_progress` job must be resumed without re-sending the `started` event

## Processing Order

```mermaid theme={null}
%%{init: {"themeVariables": {"fontSize": "12px"}}}%%
flowchart TD
    A[Detect Export Jobs] --> B[Filter eligible jobs]
    B --> C[Select oldest job]
    C --> D[Start job #40;started event#41;]
    D --> E[Begin processing]

   style A white-space:normal
   style B white-space:normal
   style C white-space:normal
   style D white-space:normal
   style E white-space:normal
```

## Upstream Dependencies

* Export Items queued in Pleo Web App
* Integration authentication configured
* Webhooks, scheduled polling, or ad hoc trigger implemented

## Downstream Dependencies

* Pre-export validation
* Export Item retrieval
* AS/ERP processing workflow

***

## What Comes Next?

* [Perform Pre-Export Validation](/docs/current/integration-design/exports/integration-design-exports-pre-export-validation)

***

## Related Reading

* [How to Detect and Start Export Jobs for Processing](/docs/current/how-tos/accounting-integrations/how-to-detect-and-start-export-jobs-for-as-erp-processing)
* [Export Integration Workflow Guide](/docs/current/guides/export-integration-workflow-guide)
* [AS/ERP Processing Workflow Guide](/docs/current/guides/accounting-system-processing-workflow-guide)

***
