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

# Cancel Execution

> POST /api/v1/runs/{executionId}/cancel

Cancel a running or pending flow execution. Useful for aborting long-running jobs or stopping mistakenly triggered executions.

## Endpoint

```
POST https://app.doclo.ai/api/v1/runs/{executionId}/cancel
```

## Authentication

Requires an API key with `executions:cancel` scope.

```bash theme={null}
Authorization: Bearer dc_live_your_api_key
```

## Path Parameters

| Parameter     | Type   | Description                                      |
| ------------- | ------ | ------------------------------------------------ |
| `executionId` | string | **Required.** The execution identifier to cancel |

## Request Body

No request body required. Send an empty POST request.

## Response

### Success (200 OK)

```json theme={null}
{
  "id": "exec_abc123def456",
  "flowId": "invoice-extractor",
  "version": "1.2.0",
  "status": "cancelled",
  "createdAt": "2024-02-20T15:30:00Z",
  "cancelledAt": "2024-02-20T15:30:45Z",
  "metadata": {
    "customerId": "cust_123"
  }
}
```

### Response Fields

| Field         | Type   | Description                           |
| ------------- | ------ | ------------------------------------- |
| `id`          | string | Execution identifier                  |
| `flowId`      | string | Flow that was being executed          |
| `version`     | string | Flow version                          |
| `status`      | string | Always `cancelled` on success         |
| `createdAt`   | string | ISO 8601 start timestamp              |
| `cancelledAt` | string | ISO 8601 cancellation timestamp       |
| `metadata`    | object | Custom metadata from original request |

## Examples

### cURL

```bash theme={null}
curl -X POST https://app.doclo.ai/api/v1/runs/exec_abc123def456/cancel \
  -H "Authorization: Bearer dc_live_your_api_key"
```

### TypeScript

```typescript theme={null}
async function cancelExecution(executionId: string) {
  const response = await fetch(
    `https://app.doclo.ai/api/v1/runs/${executionId}/cancel`,
    {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${process.env.DOCLO_API_KEY}`
      }
    }
  );

  if (!response.ok) {
    const { error } = await response.json();
    throw new Error(`Cancel failed: ${error.message}`);
  }

  const result = await response.json();
  console.log(`Execution ${result.id} cancelled at ${result.cancelledAt}`);
  return result;
}
```

### With Timeout Handling

```typescript theme={null}
async function processWithTimeout(flowId: string, document: string, timeoutMs: number) {
  // Start execution
  const startResponse = await fetch(
    `https://app.doclo.ai/api/v1/flows/${flowId}/run`,
    {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${apiKey}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        input: { document: { base64: document } }
      })
    }
  );

  const { id: executionId } = await startResponse.json();

  // Set up timeout
  const timeoutPromise = new Promise((_, reject) => {
    setTimeout(async () => {
      // Cancel execution on timeout
      await fetch(
        `https://app.doclo.ai/api/v1/runs/${executionId}/cancel`,
        {
          method: 'POST',
          headers: { 'Authorization': `Bearer ${apiKey}` }
        }
      );
      reject(new Error('Execution timed out and was cancelled'));
    }, timeoutMs);
  });

  // Poll for results
  const pollPromise = pollExecution(executionId);

  return Promise.race([pollPromise, timeoutPromise]);
}
```

## Errors

| Status | Code                  | Description                               |
| ------ | --------------------- | ----------------------------------------- |
| 401    | `UNAUTHORIZED`        | Missing or invalid API key                |
| 403    | `FORBIDDEN`           | API key missing `executions:cancel` scope |
| 404    | `EXECUTION_NOT_FOUND` | Execution doesn't exist                   |
| 409    | `ALREADY_CANCELLED`   | Execution was already cancelled           |
| 409    | `NOT_CANCELLABLE`     | Execution already completed or failed     |
| 429    | `RATE_LIMITED`        | Rate limit exceeded                       |

### Error Examples

**Already Cancelled:**

```json theme={null}
{
  "error": {
    "code": "ALREADY_CANCELLED",
    "message": "Execution exec_abc123 was already cancelled"
  }
}
```

**Not Cancellable (completed):**

```json theme={null}
{
  "error": {
    "code": "NOT_CANCELLABLE",
    "message": "Cannot cancel execution with status: completed"
  }
}
```

## Cancellation Behavior

| Original Status | Can Cancel | Result                                                  |
| --------------- | ---------- | ------------------------------------------------------- |
| `pending`       | Yes        | Immediately cancelled, no credits used                  |
| `running`       | Yes        | Cancelled at next checkpoint, partial credits may apply |
| `completed`     | No         | Returns 409 error                                       |
| `failed`        | No         | Returns 409 error                                       |
| `cancelled`     | No         | Returns 409 error                                       |

<Note>
  Cancelling a running execution may not be immediate. The execution will be cancelled at the next processing checkpoint. Some credits may be charged for work already completed.
</Note>

## Use Cases

### User-Initiated Cancellation

Allow users to cancel their own uploads:

```typescript theme={null}
// In your API route
app.post('/api/cancel-extraction/:executionId', async (req, res) => {
  const { executionId } = req.params;
  const userId = req.user.id;

  // Verify user owns this execution
  const execution = await db.executions.findOne({
    executionId,
    userId
  });

  if (!execution) {
    return res.status(404).json({ error: 'Execution not found' });
  }

  // Cancel via Doclo API
  const response = await fetch(
    `https://app.doclo.ai/api/v1/runs/${executionId}/cancel`,
    {
      method: 'POST',
      headers: { 'Authorization': `Bearer ${process.env.DOCLO_API_KEY}` }
    }
  );

  if (response.ok) {
    await db.executions.update(executionId, { status: 'cancelled' });
    return res.json({ success: true });
  }

  const { error } = await response.json();
  return res.status(response.status).json({ error: error.message });
});
```

### Cleanup on Shutdown

Cancel pending executions during graceful shutdown:

```typescript theme={null}
const pendingExecutions = new Set<string>();

// Track started executions
async function startExecution(flowId: string, input: any) {
  const result = await runFlow(flowId, input);
  pendingExecutions.add(result.id);
  return result;
}

// Cleanup on shutdown
process.on('SIGTERM', async () => {
  console.log('Shutting down, cancelling pending executions...');

  await Promise.all(
    Array.from(pendingExecutions).map(async (executionId) => {
      try {
        await cancelExecution(executionId);
        console.log(`Cancelled ${executionId}`);
      } catch (error) {
        // May already be completed, ignore errors
      }
    })
  );

  process.exit(0);
});
```

## Next Steps

<CardGroup cols={2}>
  <Card title="Get Execution" icon="magnifying-glass" href="/api-reference/runs/get">
    Check execution status
  </Card>

  <Card title="Run Flow" icon="play" href="/api-reference/flows/run">
    Start a new execution
  </Card>
</CardGroup>
