Skip to main content
Get the status and results of a flow execution. Use this endpoint to poll for results after an async execution.

Endpoint

GET https://app.doclo.ai/api/v1/runs/{executionId}

Authentication

Requires an API key with executions:read scope.
Authorization: Bearer dc_live_your_api_key

Path Parameters

ParameterTypeDescription
executionIdstringRequired. The execution identifier (e.g., exec_abc123)

Query Parameters

ParameterTypeDescription
includestringAdditional data to include: artifacts, metrics (comma-separated)

Response

Pending/Running (200 OK)

{
  "id": "exec_abc123def456",
  "flowId": "invoice-extractor",
  "version": "1.2.0",
  "status": "running",
  "progress": {
    "step": "extract",
    "percentage": 65
  },
  "createdAt": "2024-02-20T15:30:00Z",
  "metadata": {
    "customerId": "cust_123"
  }
}

Completed (200 OK)

{
  "id": "exec_abc123def456",
  "flowId": "invoice-extractor",
  "version": "1.2.0",
  "status": "completed",
  "createdAt": "2024-02-20T15:30:00Z",
  "completedAt": "2024-02-20T15:30:12Z",
  "output": {
    "invoiceNumber": "INV-2024-001",
    "date": "2024-02-15",
    "vendor": {
      "name": "Acme Corporation",
      "address": "123 Business St"
    },
    "total": 1627.50
  },
  "metrics": {
    "durationMs": 12340,
    "pageCount": 2,
    "creditsUsed": 4
  },
  "metadata": {
    "customerId": "cust_123"
  }
}

Failed (200 OK)

{
  "id": "exec_abc123def456",
  "flowId": "invoice-extractor",
  "version": "1.2.0",
  "status": "failed",
  "createdAt": "2024-02-20T15:30:00Z",
  "completedAt": "2024-02-20T15:30:05Z",
  "error": {
    "code": "EXTRACTION_FAILED",
    "message": "Unable to extract structured data from document",
    "step": "extract"
  },
  "metadata": {
    "customerId": "cust_123"
  }
}

With Artifacts (200 OK)

When requesting ?include=artifacts:
{
  "id": "exec_abc123def456",
  "flowId": "invoice-extractor",
  "status": "completed",
  "output": { ... },
  "artifacts": {
    "parse": {
      "pageCount": 2,
      "wordCount": 450,
      "documentIR": { ... }
    },
    "extract": {
      "tokensUsed": 1250,
      "model": "gpt-4.1"
    }
  }
}

Response Fields

FieldTypeDescription
idstringExecution identifier
flowIdstringFlow that was executed
versionstringFlow version used
statusstringCurrent status (see below)
progressobjectProgress info (while running)
progress.stepstringCurrent step name
progress.percentagenumberEstimated completion (0-100)
createdAtstringISO 8601 start timestamp
completedAtstringISO 8601 completion timestamp
outputobjectExtracted data (when completed)
errorobjectError details (when failed)
error.codestringError code
error.messagestringError description
error.stepstringStep that failed
metricsobjectExecution metrics
artifactsobjectStep-level artifacts (if requested)
metadataobjectCustom metadata from request

Execution Status Values

StatusDescription
pendingQueued, not yet started
runningCurrently processing
completedSuccessfully finished
failedFailed with error
cancelledCancelled by user

Examples

cURL

curl https://app.doclo.ai/api/v1/runs/exec_abc123def456 \
  -H "Authorization: Bearer dc_live_your_api_key"

With Artifacts

curl "https://app.doclo.ai/api/v1/runs/exec_abc123def456?include=artifacts,metrics" \
  -H "Authorization: Bearer dc_live_your_api_key"

TypeScript Polling

async function pollExecution(executionId: string): Promise<ExecutionResult> {
  const maxAttempts = 60;
  const pollInterval = 2000;

  for (let attempt = 0; attempt < maxAttempts; attempt++) {
    const response = await fetch(
      `https://app.doclo.ai/api/v1/runs/${executionId}`,
      {
        headers: {
          'Authorization': `Bearer ${process.env.DOCLO_API_KEY}`
        }
      }
    );

    const result = await response.json();

    switch (result.status) {
      case 'completed':
        return result;
      case 'failed':
        throw new Error(`Execution failed: ${result.error.message}`);
      case 'cancelled':
        throw new Error('Execution was cancelled');
      case 'pending':
      case 'running':
        // Still processing, wait and retry
        console.log(`Status: ${result.status}, Progress: ${result.progress?.percentage || 0}%`);
        await new Promise(resolve => setTimeout(resolve, pollInterval));
        break;
    }
  }

  throw new Error('Polling timeout exceeded');
}

// Usage
const executionId = 'exec_abc123def456';
const result = await pollExecution(executionId);
console.log('Output:', result.output);

Check Status Only

const response = await fetch(
  `https://app.doclo.ai/api/v1/runs/${executionId}`,
  {
    headers: {
      'Authorization': `Bearer ${apiKey}`
    }
  }
);

const { status, progress } = await response.json();

if (status === 'running') {
  console.log(`Processing: ${progress.step} (${progress.percentage}%)`);
}

Errors

StatusCodeDescription
401UNAUTHORIZEDMissing or invalid API key
403FORBIDDENAPI key missing executions:read scope
404EXECUTION_NOT_FOUNDExecution doesn’t exist
429RATE_LIMITEDRate limit exceeded

Polling Best Practices

  1. Start with longer intervals: Begin with 2-3 second intervals
  2. Use exponential backoff: If still pending after 30s, increase interval
  3. Set a maximum timeout: Don’t poll forever (e.g., max 10 minutes)
  4. Consider webhooks: For production, webhooks are more efficient than polling
// Exponential backoff polling
async function pollWithBackoff(executionId: string) {
  let interval = 2000;
  const maxInterval = 10000;
  const timeout = 600000; // 10 minutes
  const startTime = Date.now();

  while (Date.now() - startTime < timeout) {
    const result = await getExecution(executionId);

    if (result.status === 'completed' || result.status === 'failed') {
      return result;
    }

    await new Promise(resolve => setTimeout(resolve, interval));
    interval = Math.min(interval * 1.5, maxInterval);
  }

  throw new Error('Timeout');
}

Next Steps