Skip to main content

Python API

Import the version 1 Python API from infrahub_sync.api.v1 to run an Infrahub Sync configuration in-process. The API uses the same execution and saved-plan contracts as the product and does not invoke the CLI.

The base infrahub-sync installation includes this API. Prefect and an external control plane are not required. The source and destination declared by the selected configuration remain the runtime integrations for operations that contact adapters.

The examples below use the repository's custom-example project. Its source is a local JSON fixture, and its destination requires the bundled schema at examples/prefect_remote_run/schemas/infra_device.yml in Infrahub. Run the examples from the repository root so the configuration's relative paths resolve correctly. The Prefect remote run walkthrough links the complete destination setup.

Optional durable product projection

Every request accepts an optional product_cache_location. Set it to an absolute local path to publish the same ProductRun and immutable plan-review artifact contract used by managed execution. If it is omitted, the established run-directory and saved-plan behavior is unchanged.

Use the same location for plan, verify, and apply. Reviewed apply advances the planning record under its original run ID; it does not allocate another product record. A confirmed sync similarly keeps one product identity across its plan, verification, and apply stages. The local projection uses SQLite and the filesystem and imports no Prefect or managed runtime module.

Create a plan

plan loads and validates the named configuration, reads both adapters, saves the proposed operations, and returns their counts and artifact locations.

from infrahub_sync.api.v1 import PlanRequest, plan

result = plan(
PlanRequest(
sync_name="custom-example",
config_directory="examples",
branch="main",
product_cache_location="/var/lib/infrahub-sync/product-cache",
)
)

print(result.run_id)
print(result.counts.create)
print(result.domain_summary)

A plan does not write to the destination. Store the returned run_id, then review the manifest and operations under the returned artifact references before applying it.

The plan artifact is committed before the API reads it back to build RunResult. If the API cannot read it back, plan raises RunExecutionError and marks the run failed, but it does not rewrite the immutable plan. Use the error's run_id to inspect or verify the committed artifact before deciding whether to apply it or create a fresh plan.

Verify a saved plan

verify is independent and read-only. It reads the stored plan and checks its format, run binding, checksum, source snapshots, and configuration version. It does not construct an adapter, change run state, or write to the destination.

from infrahub_sync.api.v1 import VerifyRequest, verify

verified = verify(
VerifyRequest(
sync_name="custom-example",
config_directory="examples",
run_id=result.run_id,
product_cache_location="/var/lib/infrahub-sync/product-cache",
)
)

assert verified.outcome == "verified"

Verification against the live destination remains part of apply. Independent verification cannot prove that an endpoint or branch still matches without constructing the destination adapter.

Apply a reviewed plan

Pass the checksum from the reviewed plan manifest. A preliminary read checks that checksum before constructing the destination. The apply seam then reads the artifact once and uses those same bytes for its required verification and writes. It applies the stored operations without extracting the source or recomputing the plan.

import json
from pathlib import Path

from infrahub_sync.api.v1 import ApplyRequest, apply

manifest_path = next(artifact.path for artifact in result.artifacts if artifact.kind == "plan-manifest")
reviewed_checksum = json.loads(Path(manifest_path).read_text())["plan_checksum"]

applied = apply(
ApplyRequest(
sync_name="custom-example",
config_directory="examples",
run_id=result.run_id,
expected_checksum=reviewed_checksum,
branch="main",
product_cache_location="/var/lib/infrahub-sync/product-cache",
)
)

assert applied.outcome in {"applied", "no-change"}

Recorded delete operations remain visible in counts.delete but are not sent to the destination. A destination mismatch, stale configuration, changed source snapshot, or checksum mismatch refuses before the first write.

Run a confirmed sync

sync composes the same plan, independent verification, and apply operations. Set confirm_writes=True; omission or False refuses before configuration loading or adapter construction.

from infrahub_sync.api.v1 import SyncRequest, sync

synced = sync(
SyncRequest(
sync_name="custom-example",
config_directory="examples",
branch="main",
confirm_writes=True,
product_cache_location="/var/lib/infrahub-sync/product-cache",
)
)

The API applies only the operations materialized in the saved plan. An inherited engine limitation means a difference that exists solely in nested child elements can be detected without producing a saved operation row; in that case API sync reports no-change and does not write that nested-only difference.

Result contract

All four functions return RunResult on success.

FieldTypeMeaning
api_version"1"Public result schema version.
run_idstrStable Sync run identifier.
operation"plan", "sync", "verify", or "apply"Requested product operation.
phasestrCurrent product phase. Readers preserve values added by later versions.
outcomestrProduct outcome, such as planned, verified, applied, or no-change. Readers preserve values added by later versions.
countsActionCountsZero-filled create, update, and delete saved-operation counts.
domain_summarydict[str, int]Saved-operation counts grouped by destination kind.
artifactstuple[ArtifactReference, ...]Absolute local references for the run directory, plan manifest, and plan operations.

Artifact references are local paths on the process host. The API does not upload or retain them outside the configured cache.

Errors and redaction

Catch RunValidationError for request, configuration, and saved-plan safety refusals. Catch RunExecutionError for adapter and engine failures after validation. Both inherit from RunError and provide api_version, run_id, operation, stage, outcome, and a secret-safe message.

from infrahub_sync.api.v1 import RunError, SyncRequest, sync

request = SyncRequest(
sync_name="from-netbox",
config_directory="examples",
confirm_writes=True,
)

try:
synced = sync(request)
except RunError as exc:
error_data = exc.model_dump()

Result serialization and public error messages redact collected credential-bearing values. The sanitized exception cause chain prevents those values from reappearing in a rendered stack trace. Credentials remain process configuration; do not put them in request fields.

Write-capable operations use one bounded lock per synchronization. A confirmed sync that cannot acquire the lock within 60 seconds raises RunExecutionError with stage="lock". Any run identifier mentioned in that message comes from the latest sidecar still marked running; it is diagnostic context and may be stale, not proof that the named run owns the lock.

Lifecycle logs

Each operation emits standard-library logging records at lifecycle boundaries. Records carry api_version, run_id, operation, stage, and outcome as structured attributes. Use LifecycleEvent.model_validate(record.__dict__) to read them. Its stage and outcome fields accept values introduced by future versions.