FortiCare Asset Management API Client
Project description
hfortix-forticare
Python SDK for the Fortinet FortiCare Asset Management V3 API.
Overview
hfortix-forticare provides a fully typed Python interface to the FortiCare
Asset Management API, enabling programmatic access to:
- Product Management: Register, list, update, and decommission products
- License Management: Register, list, and download licenses
- Contract Management: View contract information
- Folder Management: Organize assets into folders
- Service Management: Register subscription services
Features
- Fully Typed —
py.typed+.pyistubs (PEP 561) for IDE auto-completion and static type checking - OAuth 2.0 — Built-in FortiCloud OAuth token acquisition, refresh, and lifecycle management
- Shared Sessions —
CloudSessionsupport for sharing credentials with other FortiCloud clients (e.g.hfortix-fortiztp) - Resilience — Optional rate limiting and circuit breaker (opt-in), automatic retries with backoff
- Auditing — Optional operation tracking and audit logging
Installation
pip install hfortix-forticare
Quick Start
1. Authentication
You have multiple options for authentication:
Option A: CloudSession (Recommended for Multi-Service)
from hfortix_core.session import CloudSession
from hfortix_forticare import FortiCare
# CloudSession manages tokens for multiple services
with CloudSession(api_id="your_api_id", password="your_password") as session:
fc = FortiCare(session=session) # Auto-uses "assetmanagement" client_id
products = fc.api.products.list.post()
# Token is automatically managed and shared efficiently
CloudSession can also configure rate limiting once for every client that uses it:
from hfortix_core.session import CloudSession
from hfortix_forticare import FortiCare
session = CloudSession(
api_id="your_api_id",
password="your_password",
# Global rate limiting - inherited by all clients
rate_limit=True,
rate_limit_max_requests=20, # 20 requests per window
rate_limit_window_seconds=60.0,
circuit_breaker=True,
)
fc = FortiCare(session=session) # Inherits 20 req/min
# Or override for a specific client
fc_fast = FortiCare(
session=session,
rate_limit_max_requests=50, # Override session's 20 req/min
)
Option B: Auto-Login with Credentials
from hfortix_forticare import FortiCare
# Auto-login with API credentials
fcc = FortiCare(
api_id="your_api_id",
password="your_password",
)
# Token is automatically obtained and managed
Option C: Use a Pre-Obtained OAuth Token
# Get token from the FortiCloud OAuth endpoint first:
# https://customerapiauth.fortinet.com/api/v1/oauth/token/
fcc = FortiCare(oauth_token="your_oauth_token_here")
2. Use the API
Wildcard note:
serial_numberfilters use SQLLIKEwildcards — use%(e.g."FGT%"), not*. It defaults to"%"(all products).
# List products with entitlements
products = fcc.api.products.list.post(
serial_number="FGT%",
status="Registered",
)
# Get product details
details = fcc.api.products.details.post(
serial_number="FGT90D1234567890",
)
# Register a product
result = fcc.api.products.register.post(
registration_units=[
{
"serialNumber": "FGT90D1234567890",
"description": "My FortiGate",
# ... other fields
}
]
)
# List contracts
contracts = fcc.api.contracts.list.post()
# List licenses
licenses = fcc.api.licenses.list.post()
# Manage folders
folders = fcc.api.folders.list.post()
# Always clean up when done
fcc.logout()
API Structure
The SDK mirrors the FortiCare Asset Management V3 API structure:
fcc.api.
├── products.
│ ├── list - List products with entitlements
│ ├── register - Register products and contracts
│ ├── details - Get product details
│ ├── description - Update product description
│ ├── location - Update product location
│ ├── folder - Update product folder
│ ├── decommission - Decommission products
│ └── transfer - Transfer products between accounts
├── licenses.
│ ├── list - List licenses
│ ├── register - Register a license
│ └── download - Download VM license file
├── contracts.
│ └── list - List contracts
├── folders.
│ ├── list - List asset folders
│ ├── create - Create new folder
│ └── delete - Delete folder
└── services.
└── register - Register subscription service
Responses
Every endpoint returns a FortiCareResponse object with attribute access
(responses are not subscriptable — use attributes or .get()):
response = fcc.api.products.list.post(serial_number="FGT%")
response.status # API status code (0 = success)
response.message # Error message (empty on success)
response.http_status_code # HTTP status code (200, 404, ...)
response.response_time # Request duration in seconds
response.raw # Full response as a plain dict
response.get("assets", []) # Dict-style access with default
# List responses expose typed collections
for asset in response.assets:
print(asset.serialNumber, asset.productModel)
Rate Limits
The FortiCare Asset Management API enforces the following limits server-side:
- 100 calls per minute
- 1000 calls per hour
- 10 errors per hour
- Batch operations: Max 10 units, max 5 errors per batch
Rate Limit Enforcement (opt-in)
Client-side enforcement is disabled by default. Enable it with
rate_limit=True (token bucket with queue support):
from hfortix_forticare import FortiCare
fcc = FortiCare(
api_id="your_api_id",
password="your_password",
rate_limit=True,
rate_limit_max_requests=100, # FortiCare: 100/min
rate_limit_window_seconds=60.0, # 60 second window
rate_limit_strategy="queue", # Queue excess requests
rate_limit_queue_size=50, # Max 50 queued requests
)
Rate limiting / circuit breaker parameters:
rate_limit: bool = False— Enable/disable rate limitingrate_limit_strategy: str = "queue"— Strategy:queue,drop, orraiserate_limit_max_requests: int = 100— Max requests per windowrate_limit_window_seconds: float = 60.0— Time window in secondsrate_limit_queue_size: int = 100— Max queued requestsrate_limit_queue_timeout: float = 30.0— Max wait time in queuerate_limit_queue_overflow: str = "block"— Overflow:block,drop, orraisecircuit_breaker: bool = False— Enable circuit breakercircuit_breaker_threshold: int = 5— Failures before openingcircuit_breaker_timeout: float = 60.0— Seconds before retrycircuit_breaker_half_open_calls: int = 3— Test calls in half-open state
Rate Limit Tracking (monitoring only)
Track your API usage to stay within limits — these counters are informational only and never block requests:
from hfortix_forticare import FortiCare
# Configure custom limits (all optional, default to None = no limit)
fcc = FortiCare(
api_id="...",
password="...",
rate_limit_calls_per_min=100, # FortiCare: 100/min
rate_limit_calls_per_hour=1000, # FortiCare: 1000/hour
rate_limit_errors_per_hour=10, # FortiCare: 10 errors/hour
)
products = fcc.api.products.list.post()
status = fcc.get_rate_limit_status()
print(f"Calls last min: {status['calls_last_min']}")
print(f"Calls last hour: {status['calls_last_hour']}")
print(f"Errors last hour: {status['errors_last_hour']}")
print(f"Within limits: {status['within_limits']}")
Error Handling
API-level errors are reported in the response body (.status != 0).
HTTP and network failures raise httpx exceptions; the opt-in rate
limiter and circuit breaker raise hfortix_core.exceptions types:
import httpx
from hfortix_core.exceptions import (
CircuitBreakerOpenError,
RateLimitExceededError,
)
try:
result = fcc.api.products.list.post(serial_number="FGT%")
if result.status == 0:
print("Success!")
else:
print(f"API Error: {result.message}")
except httpx.HTTPStatusError as e:
print(f"HTTP Error: {e.response.status_code}")
except httpx.TimeoutException:
print("Request timed out")
except httpx.RequestError as e:
print(f"Network error: {e}")
except CircuitBreakerOpenError:
print("Circuit breaker is open") # only with circuit_breaker=True
except RateLimitExceededError:
print("Rate limited") # only with rate_limit=True, strategy="raise"
Context Manager
Use as a context manager for automatic cleanup:
with FortiCare(oauth_token="...") as fcc:
products = fcc.api.products.list.post()
# ... use the client ...
# Automatically logged out
Configuration
fcc = FortiCare(
oauth_token="your_token",
# Default base URL:
base_url="https://support.fortinet.com/ES/api/registration/v3",
verify=True, # SSL verification
max_retries=3, # Retry attempts
connect_timeout=10.0, # Connection timeout (seconds)
read_timeout=300.0, # Read timeout (seconds)
)
OAuth Token Management
The SDK provides OAuth token lifecycle management for long-running
applications (available when initialized with api_id/password):
View Login Response
fcc = FortiCare(api_id="...", password="...")
response = fcc.login(force_refresh=True)
print(f"Access Token: {response['access_token']}")
print(f"Refresh Token: {response['refresh_token']}")
print(f"Expires In: {response['expires_in']} seconds")
Refresh Token
# Efficiently refresh token without re-entering credentials
# (requires a prior login(force_refresh=True) to obtain a refresh token)
refresh_response = fcc.refresh_token()
print(f"New token expires in: {refresh_response['expires_in']}s")
Track Token Expiration
# Check time remaining
remaining = fcc.get_token_time_remaining()
print(f"Token valid for {remaining} more seconds")
# Check if expired or expiring soon
if fcc.is_token_expired(buffer_seconds=300): # 5 min buffer
print("Token expiring soon, refreshing...")
fcc.refresh_token()
# Get comprehensive token info
info = fcc.get_token_info()
print(f"Created: {info['created_at_iso']}")
print(f"Expires: {info['expires_at_iso']}")
print(f"Time Remaining: {info['time_remaining']}s")
print(f"Expires Soon: {info['expires_soon']}")
Package Structure
hfortix_forticare/
├── __init__.py # Main FortiCare client
├── models.py # FortiCareResponse and typed wrappers
├── types.py # TypedDict definitions
└── api/
└── v3/
├── __init__.py # V3API class
├── products/ # Product endpoints
├── licenses/ # License endpoints
├── contracts/ # Contract endpoints
├── folders/ # Folder endpoints
└── services/ # Service endpoints
Requirements
- Python 3.9+
- httpx
- hfortix-core
License
Proprietary — free to use, but may not be resold or redistributed as a standalone product. See LICENSE for the full terms.
Copyright (c) 2025 Herman W. Jacobsen
Links
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file hfortix_forticare-0.5.164.tar.gz.
File metadata
- Download URL: hfortix_forticare-0.5.164.tar.gz
- Upload date:
- Size: 34.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
82fdf2c11c9f2e9c3bf5928468e3632cb6f2aae0946d6e61bf341fb9d2019ec1
|
|
| MD5 |
c5a07b9125c8f7c592e6e507624e79db
|
|
| BLAKE2b-256 |
3cbafc27800544d32c539158f9525f5e0019c26858ea503b2633cbb3bca6e3b6
|
File details
Details for the file hfortix_forticare-0.5.164-py3-none-any.whl.
File metadata
- Download URL: hfortix_forticare-0.5.164-py3-none-any.whl
- Upload date:
- Size: 68.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4ddfc9f6b3cf60a3e54b71d3296f0ff4c9825a4e7c141d49ce0e8fe5ffafed62
|
|
| MD5 |
395d1d91469e5d64730e500b2f128a0e
|
|
| BLAKE2b-256 |
da8368c7faf6edc2abb7d9e220a0cbfa18fa5252c5b77fee1e8db0f16576f61f
|