Skip to main content

FortiZTP Cloud API Client - Device provisioning and management

Project description

FortiZTP Package

Python SDK for FortiZTP Cloud API v2.0 - Device provisioning and management for FortiGate, FortiAP, FortiSwitch, and FortiExtender.

Status

✅ FUNCTIONAL - BETA RELEASE

Schema Completion: 100% (18/18 endpoints)

  • ✅ Device endpoints: 5/5 complete
  • ✅ Script endpoints: 7/7 complete
  • ✅ FortiManager endpoints: 5/5 complete
  • ✅ System endpoint: 1/1 complete

Code Generation: ✅ Complete - All 18 endpoints auto-generated from schema

Testing: ✅ Live tests passing - GET /v2/devices validated with real API

See dev/SCHEMA_GAPS_ANALYSIS.md for details on missing information.


Overview

This package will provide a fully typed Python SDK for FortiZTP Cloud API with:

  • 🔒 OAuth 2.0 Authentication - Automatic token management
  • 📝 Full Type Safety - Type hints with Literal types for autocomplete
  • 🎯 Specialized Responses - Property access on response objects
  • 🔄 Smart Defaults - Sensible defaults for optional parameters
  • HTTP Metadata - Status codes, response times, raw access
  • 🛡️ Error Handling - Comprehensive exception handling

Quick Start

Installation

pip install hfortix-fortiztp

Basic Usage

from hfortix_fortiztp import FortiZTP

# Initialize client with OAuth credentials
client = FortiZTP(
    api_id="your_api_id",
    password="your_password"
)

# List all devices
devices = client.api.devices.list()
print(f"Found {len(devices.devices)} devices")

# List provisioned devices only
provisioned = client.api.devices.list(provision_status="provisioned")

# Get specific device details
device = client.api.devices.get(device_sn="FGT60FTK19000001")
print(f"Device: {device.deviceType} - Status: {device.provisionStatus}")

# Get system status
status = client.api.system.get()
print(f"System status: {status.serviceStatus}")

API Coverage

Devices API (5 endpoints)

  • list() - List devices with filters (status, type, SN)
  • bulk_provision() - Provision/unprovision multiple devices
  • get() - Get single device details
  • update() - Provision/unprovision single device
  • firmware_profiles() - Get firmware profiles by region

Scripts API (7 endpoints)

  • scripts_list() - List all scripts
  • scripts_post() - Create new script
  • scripts_get() - Get script metadata
  • scripts_put() - Update script metadata
  • scripts_delete() - Delete script
  • scripts_content_get() - Download script content
  • scripts_content_put() - Upload script content

FortiManagers API (5 endpoints)

  • fortimanagers_list() - List all FortiManager configs
  • fortimanagers_post() - Create FortiManager config
  • fortimanagers_get() - Get FortiManager details
  • fortimanagers_put() - Update FortiManager config
  • fortimanagers_delete() - Delete FortiManager config

System API (1 endpoint)

  • get() - Get system status
  • Script association

System (1 endpoint)

  • Get system status

Planned Usage

Note: This is the intended API design. Code is not yet generated.

Basic Usage

from hfortix import FortiZTP

# Initialize client with OAuth credentials
client = FortiZTP(
    client_id="your_client_id",
    api_key="your_api_key",
    password="your_password"
)

# List all provisioned devices
response = client.v2.devices.list.get(provision_status="provisioned")

# Access response properties
print(f"Total devices: {response.total}")
print(f"Has cache: {response.hasCache}")

for device in response.data:
    print(f"{device['deviceSN']}: {device['provisionStatus']}")

# Get specific device
device = client.v2.devices.get.get(device_sn="FGT60D4615067214")
print(f"Device type: {device.deviceType}")
print(f"Status: {device.provisionStatus}")

# Provision a device to FortiManager
client.v2.devices.put.put(
    device_sn="FGT60D4615067214",
    request_body={
        "provisionStatus": "provisioned",
        "provisionTarget": "FortiManager",
        "provisionTargetOid": 123
    }
)

Type Safety with Literals

from typing import Literal

# IDE will autocomplete these values:
DeviceType = Literal["FortiGate", "FortiAP", "FortiSwitch", "FortiExtender"]
ProvisionStatus = Literal["provisioned", "unprovisioned", "hidden", "incomplete"]
ProvisionTarget = Literal["FortiManager", "FortiGateCloud", "FortiEdgeCloud", "ExternalController"]

# Strongly typed parameters
response = client.v2.devices.list.get(
    provision_status="provisioned",  # Autocomplete!
    device_type="FortiGate"           # Autocomplete!
)

Script Management

# List all scripts
scripts = client.v2.settings.scripts.list.get()
print(f"Total scripts: {scripts.total}")

# Create new script
new_script = client.v2.settings.scripts.post.post(
    request_body={
        "name": "Initial Configuration",
    }
)
print(f"Created script OID: {new_script.oid}")

# Upload script content
client.v2.settings.scripts.put_content.put(
    oid=new_script.oid,
    file_path="./scripts/initial_config.conf"
)

# Download script content
content = client.v2.settings.scripts.get_content.get(oid=new_script.oid)
print(content.raw)  # Plain text content

FortiManager Configuration

# Add FortiManager
fmg = client.v2.settings.fortimanagers.post.post(
    request_body={
        "sn": "FMG-VMTM23010656",
        "ip": "192.168.223.20",
        "scriptOid": 123  # Optional pre-run script
    }
)

# HA Setup (comma-separated values)
fmg_ha = client.v2.settings.fortimanagers.post.post(
    request_body={
        "sn": "FMG-VMTM23010656,FMG-VMTM23010657",
        "ip": "192.168.223.20,192.168.223.21",
        "scriptOid": 123
    }
)

# List all FortiManagers
all_fmgs = client.v2.settings.fortimanagers.list.get()
for fmg in all_fmgs.data:
    print(f"{fmg['sn']} at {fmg['ip']}")

HTTP Metadata Access

response = client.v2.devices.get.get(device_sn="FGT60D4615067214")

# HTTP metadata
print(f"Status code: {response.http_status_code}")
print(f"Response time: {response.response_time}s")

# Raw access
raw_dict = response.raw
copy_dict = response.dict()

Error Handling

from hfortix_core.exceptions import (
    AuthenticationError,
    PermissionDeniedError,
    ResourceNotFoundError,
    RateLimitError
)

try:
    device = client.v2.devices.get.get(device_sn="INVALID_SN")
except ResourceNotFoundError as e:
    print(f"Device not found: {e}")
except PermissionDeniedError as e:
    print(f"Access denied: {e}")
except RateLimitError as e:
    print(f"Rate limit exceeded: {e}")
    print(f"Retry after: {e.retry_after}s")

Development Status

Completed ✅

  • Generator architecture designed
  • Schema file structure created
  • Type definitions (5 Literal types)
  • Common data structures (5 structures)
  • All 18 endpoints documented
  • 6 endpoints with complete responses

In Progress ⏳

  • Complete schema (12 endpoints missing responses)
  • Verify data structures
  • Get firmware_profiles structure

Not Started 📋

  • Schema parser
  • Endpoint generator adaptation
  • Template creation
  • Code generation
  • Testing
  • Documentation
  • PyPI release

Project Structure

packages/fortiztp/
├── README.md                          # This file
├── dev/
│   ├── GENERATOR_PLAN.md              # Implementation roadmap
│   ├── API_DOCUMENTATION.md           # API reference
│   ├── SCHEMA_GAPS_ANALYSIS.md        # Missing information checklist
│   ├── generator/
│   │   ├── generate.py                # Main generator script (to be created)
│   │   ├── schema/
│   │   │   └── fortiztp_schema.py     # ✅ Manual API schema
│   │   ├── parsers/
│   │   │   └── fortiztp_schema_parser.py  # Schema parser (to be created)
│   │   ├── generators/
│   │   │   └── endpoint_generator.py  # Code generator (to be adapted)
│   │   ├── templates/
│   │   │   ├── endpoint_template.py.tmpl   # (to be created)
│   │   │   └── endpoint_template.pyi.tmpl  # (to be created)
│   │   └── endpoint_config.py         # FortiZTP overrides (to be created)
│   └── tests/                         # Generator tests (to be created)
└── src/
    └── hfortix_fortiztp/              # Generated SDK code (not yet created)
        ├── __init__.py
        ├── models.py                  # Response classes
        ├── types.py                   # Literal type aliases
        ├── api/
        │   └── v2/
        │       ├── __init__.py
        │       ├── devices/
        │       ├── settings/
        │       │   ├── scripts/
        │       │   └── fortimanagers/
        │       └── system/
        └── py.typed

Schema Status

Type Definitions (5/5) ✅

  • DeviceType
  • ProvisionStatus
  • ProvisionSubStatus
  • ProvisionTarget
  • ServiceStatus

Data Structures (5/5) ✅

  • DEVICE_V2_DATA (16 properties) - needs verification
  • SCRIPT_META_DATA (3 properties) - needs verification
  • FORTIMANAGER_META_DATA (5 properties)
  • SYSTEM_DATA (4 properties)
  • ERROR_RESPONSE (2 properties)

Endpoints (6/18) ⚠️

Complete:

  • ✅ GET /v2/setting/fortimanagers
  • ✅ POST /v2/setting/fortimanagers
  • ✅ GET /v2/setting/fortimanagers/{oid}
  • ✅ PUT /v2/setting/fortimanagers/{oid}
  • ✅ DELETE /v2/setting/fortimanagers/{oid}
  • ✅ GET /v2/system

Missing Response Definitions (12):

  • ❌ GET /v2/devices
  • ❌ PUT /v2/devices
  • ❌ GET /v2/devices/{deviceSN}
  • ❌ PUT /v2/devices/{deviceSN}
  • ❌ GET /v2/devices/{deviceSN}/regions/{region}/firmwareprofiles
  • ❌ GET /v2/setting/scripts
  • ❌ POST /v2/setting/scripts
  • ❌ GET /v2/setting/scripts/{oid}
  • ❌ PUT /v2/setting/scripts/{oid}
  • ❌ DELETE /v2/setting/scripts/{oid}
  • ❌ GET /v2/setting/scripts/{oid}/content
  • ❌ PUT /v2/setting/scripts/{oid}/content

Next Steps

Critical (Blocking Code Generation):

  1. Get response body examples for 12 missing endpoints
  2. Verify DEVICE_V2_DATA structure (all 16 fields correct?)
  3. Get firmware_profiles actual response structure
  4. Confirm HTTP status codes (200, 201, 204)

Implementation:

  1. Create schema parser
  2. Adapt endpoint generator from FortiCare
  3. Create templates
  4. Generate code
  5. Test and validate

Resources


Contributing

This package is part of the hfortix SDK family:

  • hfortix-core: Core HTTP client and utilities
  • hfortix-fortios: FortiOS REST API
  • hfortix-forticare: FortiCare Asset Management API
  • hfortix-fortiztp: FortiZTP Cloud API (this package)
  • hfortix: Meta package

See main repository for contribution guidelines.


License

[Your License Here]


Authors

[Your Name/Organization]


Last Updated: February 6, 2026
Schema Version: 2.0 (33% complete)
Status: Development (blocked - awaiting API documentation)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

hfortix_fortiztp-0.5.160.tar.gz (21.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

hfortix_fortiztp-0.5.160-py3-none-any.whl (27.5 kB view details)

Uploaded Python 3

File details

Details for the file hfortix_fortiztp-0.5.160.tar.gz.

File metadata

  • Download URL: hfortix_fortiztp-0.5.160.tar.gz
  • Upload date:
  • Size: 21.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for hfortix_fortiztp-0.5.160.tar.gz
Algorithm Hash digest
SHA256 503fbdd554477a4db5ca6a23118eef5dcbd3848ec5caf5696c88ba3d86c03de4
MD5 ec2823257000e6daf5738a227f55de0e
BLAKE2b-256 515376d6f4382ecd0a4d05f71e944b780585517e24c48fe6428b43790b025ee8

See more details on using hashes here.

File details

Details for the file hfortix_fortiztp-0.5.160-py3-none-any.whl.

File metadata

File hashes

Hashes for hfortix_fortiztp-0.5.160-py3-none-any.whl
Algorithm Hash digest
SHA256 967d05198c4c2177ed3433f6a8a423ebeae82df0aaa495cc5ce80efa41acb106
MD5 dc911572ab879aebc2bfdfbc045b1a0b
BLAKE2b-256 97a8ed9b6350d8f306a5aa56f36d32af93677e6c93701e3083c4bf1c8d80dc19

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page