Application Integration

IT EngineersDevelopers

Getting Started

Core Concepts

Run file transfer functions from an application

File-processing work in an application consists of preparing files, requesting a transfer, and then proceeding with the next task based on the processing result.

Application integration connects file transfer functions to application requests so that transfers can run when needed and their results can be used in the application's business logic.

text
Application
     │
     │ Transfer Request
     ▼
File Transfer
     │
     ├── File Processing
     ├── Progress
     └── Result
             │
             ▼
Application Logic

This connects file transfer and result processing to the application's business functions.

Integration Flow

Connect the entire flow from transfer request to result processing

When an application generates a file transfer request, execute the task based on the files to transfer and the destination information.

Use transfer progress and response information in the application, then continue the next business logic according to the final result.

text
File Transfer Request
      │
      ▼
Configure File and Destination Information
      │
      ▼
Execute Transfer Task
      │
      ▼
Receive Status and Response Information
      │
      ▼
Confirm Final Result
      │
      ▼
Process Application Logic

Connecting file transfer and result processing around a single request lets completed tasks flow naturally into the next business operation.

Development Benefits

Apply file transfer functions to an application's business workflow

Application integration connects the execution process and result handling required for file transfer to service functions.

CategoryApplication Integration
Transfer ExecutionStart file transfers based on application requests
Status UsageConnect progress status and response information to screens and business logic
Result ProcessingUse the final result in the next business function
Business ExtensionConnect storage, processing, notifications, and other next steps after transfer completion

This configuration lets you use file transfer from the initial request through result processing in line with the application's business workflow.

IT Engineers

Build and manage application file transfer integration

Integration Setup

Connect the application to the file transfer environment

First, configure the file transfer environment and integration method so the application can use file transfer functions.

Configure request and response paths so application requests are connected to file transfer tasks and execution status and result information can be returned.

text
┌─────────────────┐
│   Application   │
└────────┬────────┘
         │
         │ Request / Response
         ▼
┌─────────────────┐
│ Transfer Layer  │
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│ Transfer Device │
└─────────────────┘

This integration environment connects the application's business functions to actual file transfer tasks.

Request Configuration

Define the files, destination, and execution conditions for the transfer

Configure which request from the integrated application should trigger a file transfer.

A request can include the files to transfer, file paths, destination location, and conditions required for execution.

text
Transfer Request
       │
       ├── Source
       │      └── File / Path
       │
       ├── Target
       │      └── Device / Workspace
       │
       └── Options
              │
              ▼
         Transfer Run

Configuration ItemSetting
SourceFiles or file paths to transfer
TargetDevice or workspace to which files are transferred
RequestRequest information supplied by the application
OptionsExecution conditions applied to file processing
FlowFile transfer task executed for the request

Once the request structure is configured, the required file transfer can run according to the application's business conditions.

Response Handling

Connect transfer status and response results to application logic

When a file transfer runs, status and response information are generated as it starts, progresses, and completes.

Connecting this information to the application's screens and business logic lets you display current progress and configure processing flows for each result.

text
Transfer Run
     │
     ├── Started
     │
     ├── Progress
     │
     └── Result
            │
       ┌────┼────┐
       ▼    ▼    ▼
    Success Retry Error
       │    │    │
       ▼    ▼    ▼
    Next   Retry Result
    Logic  Run   Handling

Transfer InformationApplication Usage
StartedDisplay the transfer start status
ProgressDisplay progress and processing status
SuccessRun the next business logic
RetryRequest the task again according to retry conditions
ErrorConnect the processing flow based on response information

This section manages transfer status and final response results as a single processing structure, consolidating content that was previously repeated under status and event handling and error handling.

Integration Verification

Confirm the final transfer result from the application

After completing the integration configuration, run an actual file transfer request from the application and verify the complete processing result.

Confirm that the requested files were processed at the designated destination, and verify the application response together with the file transfer execution record.

text
Application Request
        │
        ▼
   Transfer Run
        │
        ▼
  File Processing
        │
        ▼
  Result Response
        │
   ┌────┴────┐
   ▼         ▼
Application  Run
 Result      Record
   │         │
   └────┬────┘
        ▼
   Final Check

During integration verification, review the overall flow using the following information.

Review ItemDetails
RequestTransfer request created by the application
ExecutionFile transfer task created for the request
FilesProcessed files, file count, and size
TargetDesignated device or workspace
StatusTransfer progress and final result
ResponseResult information returned to the application

Developers

Run transfers from business applications and connect progress, control, and results to business data

Integration Preparation

Prepare shared request code and status values

import os
import requests

BASE_URL = os.getenv("INNORIX_BASE_URL", "https://app.innorix.com").rstrip("/")
TOKEN = os.environ["INNORIX_ACCESS_TOKEN"]
WORKSPACE_ID = os.getenv("INNORIX_WORKSPACE_ID")   # optional; falls back to the current workspace

STATUS_COMPLETE = 2
TERMINAL = {2, 4, 5, 9, 99}          # complete / error / cancelled / partial / failed
NOT_SUCCEEDED = {4, 5, 9, 99}


def api(method, path, body=None, params=None):
    headers = {
        "Content-Type": "application/json",
        "Authorization": f"Bearer {TOKEN}",
    }

    if WORKSPACE_ID:
        headers["x-workspace-id"] = WORKSPACE_ID

    response = requests.request(
        method, BASE_URL + path,
        headers=headers, json=body, params=params, timeout=30,
    )

    payload = response.json() if response.content else {}

    if not response.ok:
        raise RuntimeError(payload.get("message") or f"HTTP {response.status_code}")

    return payload.get("data")


def is_terminal(detail):
    return detail.get("isTerminal", detail.get("status") in TERMINAL)

Determine the transfer status using the values below. There are five terminal states, and the successful state is Complete (2).

Status ValueMeaningTerminal
2CompleteYes
4ErrorYes
5CancelledYes
9Partially CompleteYes
99FailedYes
1 · 6 · 12 · 13Started · Transferring · Synchronizing · ReceivingNo

Evaluate terminal status and success separately. Partial completion (9) and cancellation (5) are also terminal states, so treating isTerminal alone as success records failures as successful.

Preflight Validation

Validate paths before starting the transfer

A transfer can be created successfully even when a path is invalid. The failure appears only at execution time, after the business data has already been recorded as in progress.

def validate_paths(source_id, target_id, source_paths, target_path):
    # sourceItems reads filePath, not path
    return api("POST", "/api/transfers/validate-path", {
        "sourceId": source_id,
        "targetId": target_id,
        "sourceItems": [{"filePath": p} for p in source_paths],
        "targetPath": target_path,
    }) or {}


result = validate_paths("device-a", "device-b",
                        ["/data/report.pdf"], "/archive")

if result.get("invalidSourcePaths"):
    raise ValueError(f"missing source paths: {result['invalidSourcePaths']}")

if result.get("validTargetPath") is False:
    raise ValueError("target path not found")
Response ItemDetails
validSourcePathsValidated source paths
invalidSourcePathsSource paths that could not be found
validTargetPathWhether the destination path is valid

Pass each path in sourceItems.filePath. If users enter paths directly in the application, apply this validation when the data is saved.

Create the Transfer

Request transfers by specifying devices, paths, and processing criteria

When sending a file list, explicitly set isDir: false in sourceItem. sourcePaths treats every path as a folder, so supplying files can cause the server to scan each file as a folder, resulting in slowdowns or timeouts.

def create_transfer(source_id, target_id, source_paths, target_path,
                    action="numbering"):
    transfer = api("POST", "/api/transfers/manual", {
        "sourceDevice": source_id,
        "targetDevice": target_id,
        "targetPath": target_path,
        "sourceItem": [{"path": p, "isDir": False} for p in source_paths],
        "sendAllFolder": False,
        "transferOptions": {"target-action": action},
    })

    return transfer["monitorId"]

When sending folders, use sourcePaths with sendAllFolder: True.

api("POST", "/api/transfers/manual", {
    "sourceDevice": source_id,
    "targetDevice": target_id,
    "targetPath": target_path,
    "sourcePaths": ["/data/reports"],
    "sendAllFolder": True,
    "transferOptions": {"target-action": "numbering"},
})

Define the handling of same-name files at the destination according to the business purpose.

ValueBehaviorSuitable Use Case
numberingPreserve with a sequence numberWorkflows that retain submissions by run
overwriteOverwriteWorkflows that keep only the latest state
nosendSkip without sending when the file already existsWorkflows that must not retransmit the same file

If settlement data uses overwrite, previous runs are removed, so do not simply use the default; configure the policy for the business requirement.

Files skipped by nosend can cause the transfer to end in a terminal state that is not success. If completion is determined only by status == 2, normal behavior will be counted as a failure, so code using this policy must handle terminal status and success separately.

Connect Business Data

Store monitorId in business data for tracking

The single monitorId returned when a transfer is created is used for subsequent queries, control actions, and retries. Without storing this value in business data, the transfer cannot be traced later.

def start_order_transfer(order_id, source_id, target_id, paths, target_path):
    validate_paths(source_id, target_id, paths, target_path)

    monitor_id = create_transfer(source_id, target_id, paths, target_path)

    db.execute(
        "UPDATE orders SET monitor_id = %s, transfer_state = %s WHERE id = %s",
        (monitor_id, "transferring", order_id),
    )

    return monitor_id

Conversely, there are cases where you need to find business data using monitorId, such as when an operator discovers a problem in the transfer list.

sql
CREATE INDEX idx_orders_monitor_id ON orders (monitor_id);

Display Status

Display progress on screen and determine whether the transfer has ended

import time


def describe(monitor_id):
    return api("GET", f"/api/transfers/{monitor_id}")


def wait(monitor_id, timeout=1800, interval=3):
    deadline = time.time() + timeout

    while time.time() < deadline:
        detail = describe(monitor_id)

        if is_terminal(detail):
            return detail

        time.sleep(interval)

    raise TimeoutError(monitor_id)


detail = describe(monitor_id)

print(detail["statusLabel"], detail["percent"], "%")
print(detail["transferSize"], "/", detail["totalSize"])
Response ItemScreen Usage
statusLabelStatus display text
percentProgress percentage
transferSize · totalSizeTransfer volume
fileCount · folderCountTransfer scope
estimateTimeTime remaining
sourceDeviceName · targetDeviceNameSource and destination

Polling too frequently creates excessive requests. For screen display purposes, an interval of about 3 seconds is appropriate.

Transfer Control

Pause, resume, or cancel according to user requests

All three actions are called without a request body. However, even when the call succeeds, the status changes only after the instruction reaches the device, so refreshing the screen immediately may still show the previous status.

PAUSED = 3
RUNNING_STATES = {1, 6, 12, 13}
CANCELLED = 5


def control(monitor_id, action, tries=10):
    api("POST", f"/api/transfers/{monitor_id}/{action}", {})

    expected = {
        "pause": {PAUSED},
        "resume": RUNNING_STATES,
        "cancel": {CANCELLED},
    }[action]

    for _ in range(tries):
        time.sleep(1)
        detail = describe(monitor_id)

        if detail.get("status") in expected:
            return detail

    return describe(monitor_id)

On the screen, it is natural to disable the button immediately and show that processing is underway, then update the status once the change is confirmed.

When multiple transfers need to be stopped at once, use bulk cancellation.

result = api("POST", "/api/transfers/bulk-cancel", {"monitorIds": monitor_ids})

print(result.get("cancelled"), result.get("failed"))

A transfer that has already ended has nothing left to cancel, so cancellation fails and is included in the response's failed field. This is a normal response, not an error.

Confirm the Result

Finalize transfer results in business data and retransmit failed files

def finalize(order_id, monitor_id):
    detail = describe(monitor_id)

    if not is_terminal(detail):
        return None

    status = detail["status"]
    succeeded = status == STATUS_COMPLETE

    db.execute(
        "UPDATE orders SET transfer_state = %s, transfer_status = %s WHERE id = %s",
        ("done" if succeeded else "failed", status, order_id),
    )

    return succeeded

Store the status value as well so failure types can be distinguished later. Cancellation (5) and failure (99) require different follow-up actions.

When only some files fail, retransmit only those files.

def failed_files(monitor_id):
    result = api("GET", f"/api/transfers/{monitor_id}/files", params={
        "state": "any", "size": 500,
    }) or {}

    return [r for r in (result.get("children") or [])
            if r.get("status") in NOT_SUCCEEDED]


def retry_failed(monitor_id):
    rows = failed_files(monitor_id)

    if not rows:
        return 0

    api("POST", f"/api/transfers/{monitor_id}/retry", {
        "filesRetry": [
            {"filePath": r["sourceFilePath"], "isDir": bool(r.get("isFolder"))}
            for r in rows
        ]
    })

    return len(rows)

Each item contains sourceFilePath, statusName, and errorCode, allowing you to show exactly which file failed and why. Retransmission can be called only after the transfer has ended.

If the entire transfer must be run again, retrieve the previous execution information and rerun it.

config = api("GET", f"/api/transfers/{monitor_id}/replay-data")
api("POST", f"/api/transfers/{monitor_id}/replay", {"action": "replay"})
Review ItemDetails
RequestValidated source and destination
ExecutionGenerated monitorId
StatusProgress and terminal status
ResultSuccess status and status value
FilesFailed files and error codes
Follow-upRetransmission or rerun result