Project Workflow Integration

The Project Workflow Integration API provides an asynchronous flow that uploads a file from an external system, automatically runs the workflow you configured on the project, lets you poll for the processing status, and returns the result as a ZIP.

When a file is uploaded, it is processed automatically while the project's active workflow is running. The caller does not need to send a separate "start execution" request.

All API requests require API key authentication.


Prerequisites

  • An API key must be issued. See the Authentication page.
  • Identify the numeric project ID that will receive the file. Navigate into the project page and use the value from the URL segment projects/{number}.
  • The project's active workflow must be running. If it is stopped, the upload will succeed but analysis will not start, so start it from the project's Workflows menu in advance.
  • The API key user must hold administrator permission on that project. Without it, the upload returns 403.

Authentication

All API requests must include an API key in the HTTP header. The API key follows Bearer token authentication.

Header Value
Authorization Bearer {API_KEY}

Replace {API_KEY} with your actual issued API key in the request.


End-to-end Flow

This API works as a three-step asynchronous flow.

  1. Upload the file — Call POST /projects/{projectId}/documents/upload and receive a documentUuid.
  2. Poll the status — Call GET /external/documents/{uuid}/status periodically to check progress. Stop polling once it reaches a terminal status (succeeded or failed).
  3. Download the result — Once status is succeeded, call GET /external/documents/{uuid}/export to download the result ZIP.

Endpoints

`POST /projects/{projectId}/documents/upload`

Uploads a file to the project. If the project's active workflow is running, the backend automatically triggers that workflow. Use the documentUuid returned in the response for the subsequent status polling and export steps.

Request Examples

cURL

curl -X POST 'https://synapfoundry.ai/api/v1/projects/{PROJECT_ID}/documents/upload' \
  -H 'Authorization: Bearer {API_KEY}' \
  -F 'file=@{FILE_PATH}'

Python

import requests

api_key = "{API_KEY}"
file_path = "/path/to/your/file.ext"
url = "https://synapfoundry.ai/api/v1/projects/{PROJECT_ID}/documents/upload"

headers = { "Authorization": f"Bearer {api_key}" }

with open(file_path, "rb") as file:
    files = { "file": file }
    response = requests.post(url, headers=headers, files=files)

document_uuid = response.json()["documentUuid"]

Node.js

const axios = require('axios');
const fs = require('fs');
const FormData = require('form-data');

const apiKey = "{API_KEY}";
const projectId = "{PROJECT_ID}";
const filePath = "/path/to/your/file.ext";
const url = `https://synapfoundry.ai/api/v1/projects/${projectId}/documents/upload`;

const form = new FormData();
form.append('file', fs.createReadStream(filePath));

const headers = {
  ...form.getHeaders(),
  'Authorization': `Bearer ${apiKey}`,
};

axios.post(url, form, { headers }).then(response => {
  const documentUuid = response.data.documentUuid;
  console.log(documentUuid);
}).catch(error => {
  console.error('Error:', error.response?.data || error.message);
});

Headers

Parameter Type Description
Authorization string Bearer token for API request authentication. Must be provided in the format Bearer {API_KEY}.

Path Parameters

Parameter Type Required Description
projectId number Yes The numeric ID of the project to upload to. Use the value from the project page URL segment projects/{number}.

Body

Parameter Type Required Description
file file Yes The single file to upload. Sent via the file field of multipart/form-data.

Success Responses

Status Code Media Type Description
201 Created application/json Returns the identifiers of the created document on successful upload.

Response Example

{
  "documentId": 1289,
  "documentUuid": "550e8400-e29b-41d4-a716-446655440000"
}

Only documentUuid is used in subsequent steps. (documentId is an internal identifier.)

Error Responses

Status Code Message Description
401 Unauthorized "API Key authentication failed. Please use a valid API Key for your request." Returned when the API key is missing or invalid.
403 Forbidden - Returned when the API key user does not hold administrator permission on the project.
413 Payload Too Large File size exceeds 100MB. Returned when the size of a single uploaded file exceeds the maximum size (100MB) allowed by the server.
415 Unsupported Media Type Unsupported file format. Returned when the format of the uploaded file is not supported by the server. Check Supported Formats.

`GET /external/documents/{uuid}/status`

Returns the workflow processing status of the uploaded document as a simple flag. Stop polling immediately once the status reaches a terminal value.

Status Values

Value Meaning terminal?
pending Waiting to be processed no
processing In progress no
review_pending Awaiting human review (HITL) no
succeeded Completed — result is ready to download yes
failed Failed / aborted / out of credits yes

Clients should treat any unknown value as terminal and stop polling. The backend safely normalizes unknown internal states to failed, but defensive handling is recommended.

  • Interval: Start at 5 seconds with exponential backoff (e.g., 5s → 10s → 20s → up to 60s).
  • Maximum duration: Varies by document size and workflow, but typically within 30 minutes. Contact operations if it exceeds.
  • Retries: Retry 5xx responses with backoff. Do not retry 4xx responses.

Request Examples

cURL

curl -X GET 'https://synapfoundry.ai/api/v1/external/documents/{DOC_UUID}/status' \
  -H 'Authorization: Bearer {API_KEY}'

Python

import requests
import time

api_key = "{API_KEY}"
url = "https://synapfoundry.ai/api/v1/external/documents/{DOC_UUID}/status"
headers = { "Authorization": f"Bearer {api_key}" }

interval = 5
max_seconds = 1800  # 30-minute safety cap
elapsed = 0

while elapsed < max_seconds:
    response = requests.get(url, headers=headers)
    if response.status_code >= 500:
        # 5xx: retry after backoff
        time.sleep(interval)
        elapsed += interval
        interval = min(interval * 2, 60)
        continue
    response.raise_for_status()  # 4xx: raise immediately and stop polling
    status = response.json()["status"]
    if status in ("succeeded", "failed"):
        break
    time.sleep(interval)
    elapsed += interval
    interval = min(interval * 2, 60)
else:
    raise TimeoutError("Polling exceeded 30 minutes.")

Node.js

const axios = require('axios');

const apiKey = "{API_KEY}";
const docUuid = "{DOC_UUID}";
const url = `https://synapfoundry.ai/api/v1/external/documents/${docUuid}/status`;

async function pollStatus() {
  let interval = 5000;
  const maxMs = 30 * 60 * 1000; // 30-minute safety cap
  let elapsed = 0;

  while (elapsed < maxMs) {
    try {
      const { data } = await axios.get(url, {
        headers: { 'Authorization': `Bearer ${apiKey}` }
      });
      if (data.status === 'succeeded' || data.status === 'failed') {
        return data.status;
      }
    } catch (err) {
      const code = err.response?.status;
      if (code && code >= 400 && code < 500) {
        // 4xx: do not retry — stop polling
        throw err;
      }
      // 5xx / network errors: retry after backoff
    }
    await new Promise(r => setTimeout(r, interval));
    elapsed += interval;
    interval = Math.min(interval * 2, 60000);
  }
  throw new Error('Polling exceeded 30 minutes.');
}

Headers

Parameter Type Description
Authorization string Bearer token for API request authentication. Must be provided in the format Bearer {API_KEY}.

Path Parameters

Parameter Type Required Description
uuid string Yes The documentUuid returned from the upload response.

Success Responses

Status Code Media Type Description
200 OK application/json Returns the current processing status.

Response Example

{ "status": "processing" }

Error Responses

Status Code Message Description
401 Unauthorized "API Key authentication failed. Please use a valid API Key for your request." Returned when the API key is missing or invalid.
404 Not Found { "statusCode": 404, "message": "Not Found" } Returned identically when the UUID does not exist, does not belong to the caller, or is malformed (to prevent information disclosure). Stop polling.

`GET /external/documents/{uuid}/export`

Downloads the result of the workflow's final component as a ZIP for a document that completed successfully. Call this right after the polling API returns succeeded.

ZIP Contents by Final Component

The contents of the ZIP differ depending on the workflow's final output component.

Final Component ZIP Contents
Analyze The cached analysis result ZIP as-is
Review The review-completed result ZIP
Transform Analysis Result Conversion result files bundled into a single ZIP
LLM processing A ZIP containing the LLM response text as a single .md or .txt entry

Because the internal layout differs per component, integration clients are recommended to either know the final output component type in advance or process the ZIP entries generically (by iterating entries).

Request Examples

cURL

curl -L 'https://synapfoundry.ai/api/v1/external/documents/{DOC_UUID}/export' \
  -H 'Authorization: Bearer {API_KEY}' \
  -o result.zip

Python

import requests

api_key = "{API_KEY}"
url = "https://synapfoundry.ai/api/v1/external/documents/{DOC_UUID}/export"

response = requests.get(url, headers={ "Authorization": f"Bearer {api_key}" })

with open("result.zip", "wb") as f:
    f.write(response.content)

Node.js

const axios = require('axios');
const fs = require('fs');

const apiKey = "{API_KEY}";
const docUuid = "{DOC_UUID}";
const url = `https://synapfoundry.ai/api/v1/external/documents/${docUuid}/export`;

axios.get(url, {
  headers: { 'Authorization': `Bearer ${apiKey}` },
  responseType: 'stream'
}).then(response => {
  response.data.pipe(fs.createWriteStream('result.zip'));
}).catch(error => {
  console.error('Error:', error.response?.data || error.message);
});

Headers

Parameter Type Description
Authorization string Bearer token for API request authentication. Must be provided in the format Bearer {API_KEY}.

Path Parameters

Parameter Type Required Description
uuid string Yes The documentUuid returned from the upload response.

Success Responses

Status Code Media Type Description
200 OK application/zip Returns the workflow result ZIP. The response also includes Content-Disposition: attachment; filename="<uuid>.zip".

Error Responses

Status Code Message Description
401 Unauthorized "API Key authentication failed. Please use a valid API Key for your request." Returned when the API key is missing or invalid.
404 Not Found { "statusCode": 404, "message": "Not Found" } Returned identically when the UUID does not exist, does not belong to the caller, or is malformed.
409 Conflict { "code": "NOT_EXPORTABLE", "status": "<current status>" } Document is not yet exportable. Go back to the polling API, wait for succeeded, and retry.
500 Internal Server Error Failed to process the request due to an internal server error. A transient internal error. Retry with exponential backoff.