Tom Smykowski API Endpoints
This document is the comprehensive API reference for Tom Smykowski. It covers every endpoint and parameter.
See also: Simple API Guide for a tutorial-style introduction with examples and common workflows.
Base URL
All endpoints are prefixed with /api/
Authentication
Authentication modes (configure via tom_config.yaml or env):
- none (default): No authentication required
- api_key: Requires API key in header (default X-API-Key)
- jwt: Bearer JWT via OAuth/OIDC providers
- hybrid: Accept either API key or JWT
When using jwt/hybrid, authorization policy applies (if configured): precedence allowed_users -> allowed_domains -> allowed_user_regex. Any match grants access. See OAuth Implementation for details.
Response Types
JobResponse (Default)
All command execution endpoints return a consistent JobResponse envelope:
{
"job_id": "abc123",
"status": "COMPLETE",
"result": {
"data": {
"show version": "..."
},
"meta": {
"cache": {...}
}
},
"attempts": 1,
"error": null
}
Raw Output Mode
For endpoints that support it, setting raw_output=true opts out of the JobResponse envelope and returns plain text (text/plain). This is useful for network engineers who want to pipe output directly to other tools.
Requires: wait=true
Error responses in raw output mode: - 404: Device/resource not found - 500: Failed to submit job to queue (infrastructure error) - 502: Device command execution failed
Endpoints
Device Command Execution
Single Command
POST /api/device/{device_name}/send_command
Send a single command to a device from inventory.
Request Body:
{
"command": "show version",
"wait": false,
"raw_output": false,
"timeout": 10,
"use_cache": false,
"cache_ttl": 300,
"cache_refresh": false,
"parse": false,
"parser": "textfsm",
"template": "cisco_ios_show_version.textfsm",
"include_raw": false,
"username": "optional",
"password": "optional"
}
Parameters:
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| command | string | required | Command to execute |
| wait | bool | false | Wait for job completion |
| raw_output | bool | false | Return plain text output (requires wait=true) |
| timeout | int | 10 | Timeout in seconds |
| use_cache | bool | false | Enable caching for this request |
| cache_ttl | int | null | Override default TTL in seconds |
| cache_refresh | bool | false | Force refresh, bypassing cache |
| parse | bool | false | Parse output using TextFSM/TTP |
| parser | string | "textfsm" | Parser to use ("textfsm" or "ttp") |
| template | string | null | Explicit template name for parsing |
| include_raw | bool | false | Include raw output with parsed result |
| username | string | null | Override username (requires password) |
| password | string | null | Override password (requires username) |
Returns:
- Default: JobResponse object
- With raw_output=true: Plain text device output
Multiple Commands
POST /api/device/{device_name}/send_commands
Send multiple commands to a device with optional per-command parsing configuration.
Simple Mode Request:
{
"commands": ["show version", "show ip int brief"],
"wait": true,
"parse": true,
"parser": "textfsm"
}
Advanced Mode Request (per-command control):
{
"commands": [
{
"command": "show version",
"parse": true,
"template": "custom_version.textfsm"
},
{
"command": "show ip int brief",
"parse": true
},
{
"command": "show running-config",
"parse": false
}
],
"wait": true
}
Raw Output Mode:
{
"commands": ["show version", "show ip int brief"],
"wait": true,
"raw_output": true
}
Raw output for multiple commands is formatted as:
### show version ###
<output>
### show ip int brief ###
<output>
Parameters:
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| commands | array | required | List of commands (strings or CommandSpec objects) |
| wait | bool | false | Wait for job completion |
| raw_output | bool | false | Return plain text output (requires wait=true) |
| timeout | int | 10 | Timeout in seconds |
| parse | bool | false | Default parse setting for commands |
| parser | string | "textfsm" | Default parser to use |
| include_raw | bool | false | Default include raw with parsed |
| use_cache | bool | true | Use cache for results |
| cache_refresh | bool | false | Force cache refresh |
| cache_ttl | int | null | Cache TTL in seconds |
| retries | int | 3 | Number of retries on transient failures |
| max_queue_wait | int | 300 | Max seconds to wait for device semaphore |
| username | string | null | Override credentials |
| password | string | null | Override credentials |
CommandSpec Fields (for advanced mode):
| Field | Type | Description |
|-------|------|-------------|
| command | string | The command to execute |
| parse | bool | Whether to parse this command |
| parser | string | Parser for this command ("textfsm" or "ttp") |
| template | string | Template file for this command |
| include_raw | bool | Include raw with parsed for this command |
Returns:
- Default: JobResponse object
- With raw_output=true: Plain text with all command outputs
Configuration Commands
POST /api/device/{device_name}/send_configs
Send configuration commands to a device from inventory. This uses netmiko's send_config_set or scrapli's send_configs under the hood, which handle entering and exiting config mode automatically.
This endpoint is fundamentally different from send_command/send_commands:
- No caching: Configuration push results are not cached
- No parsing: Output is not parsed with TextFSM/TTP
- No raw output mode: The endpoint always returns a
JobResponseenvelope - Different result shape: Returns a session transcript instead of per-command outputs
Request Body:
{
"config_lines": [
"interface GigabitEthernet0/1",
"description Uplink to core",
"ip address 10.0.1.1 255.255.255.0",
"no shutdown"
],
"wait": true,
"timeout": 30
}
Parameters:
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| config_lines | array | required | List of configuration commands to apply |
| wait | bool | false | Wait for job completion |
| timeout | int | 10 | Timeout in seconds |
| retries | int | 3 | Number of retries on transient failures |
| max_queue_wait | int | 300 | Max seconds to wait for device semaphore |
| username | string | null | Override credentials |
| password | string | null | Override credentials |
Returns: JobResponse object. When the job completes, the result field contains a ConfigExecutionResult:
{
"job_id": "abc123",
"status": "COMPLETE",
"result": {
"transcript": "configure terminal\nEnter configuration commands...\ninterface GigabitEthernet0/1\n..."
},
"attempts": 1,
"error": null
}
Error handling: Errors (connectivity issues, timeouts, authentication failures) are handled the same way as operational commands — the job moves to FAILED status with the error in the error field. CLI-level configuration errors (e.g. % Invalid input) are not currently detected; they will appear in the transcript.
Raw/Direct Host Endpoints
These endpoints bypass inventory lookup and connect directly to hosts. They support the same output modes, parsing, and caching options as the inventory-based endpoints.
Netmiko Command
POST /api/raw/send_netmiko_command
Scrapli Command
POST /api/raw/send_scrapli_command
Request Body (both endpoints):
{
"host": "192.168.1.1",
"device_type": "cisco_ios",
"command": "show version",
"port": 22,
"wait": true,
"timeout": 10,
"credential_id": "default",
"raw_output": false,
"parse": false,
"parser": "textfsm",
"template": null,
"include_raw": false,
"use_cache": false,
"cache_ttl": null,
"cache_refresh": false
}
Or with inline credentials:
{
"host": "192.168.1.1",
"device_type": "cisco_ios",
"command": "show version",
"username": "admin",
"password": "secret",
"wait": true,
"parse": true
}
Parameters:
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| host | string | required | Device hostname or IP |
| device_type | string | required | Device type (e.g., cisco_ios, arista_eos) |
| command | string | required | Command to execute |
| port | int | 22 | SSH port |
| wait | bool | false | Wait for job completion |
| timeout | int | 10 | Timeout in seconds |
| raw_output | bool | false | Return plain text output (requires wait=true) |
| parse | bool | false | Parse output using TextFSM/TTP |
| parser | string | "textfsm" | Parser to use ("textfsm" or "ttp") |
| template | string | null | Explicit template name for parsing |
| include_raw | bool | false | Include raw output with parsed result |
| use_cache | bool | false | Use cache for command results |
| cache_ttl | int | null | Cache TTL in seconds |
| cache_refresh | bool | false | Force refresh cache |
| credential_id | string | null | Stored credential ID |
| username | string | null | SSH username (requires password) |
| password | string | null | SSH password (requires username) |
Note: You must provide either credential_id OR username + password.
Returns:
- Default: JobResponse object
- With raw_output=true: Plain text device output
- With parse=true: JobResponse with parsed data in result
Job Management
Get Job Status
GET /api/job/{job_id}
Query Parameters:
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| parse | bool | false | Parse output using TextFSM/TTP |
| parser | string | "textfsm" | Parser to use |
| template | string | null | Template name for parsing |
| include_raw | bool | false | Include raw output with parsed |
Returns: JobResponse object or null if job not found
Inventory Management
Get Device Configuration
GET /api/inventory/{device_name}
Returns: DeviceConfig object
{
"adapter": "netmiko|scrapli",
"adapter_driver": "cisco_ios",
"adapter_options": {},
"host": "192.168.1.1",
"port": 22,
"credential_id": "default"
}
Export Inventory (DeviceConfig Format)
GET /api/inventory/export?filter_name={filter}
Parameters:
- filter_name (string, optional): Filter name (see filters endpoint)
Returns: Dictionary of device names to DeviceConfig objects
Export Raw Inventory
GET /api/inventory/export/raw?filter_name={filter}
Returns: Array of raw inventory nodes (format varies by inventory source)
List Available Filters
GET /api/inventory/filters
Returns: Dictionary of filter names to descriptions
List Inventory Fields
GET /api/inventory/fields
Returns: List of filterable fields for the current inventory source
Cache Management
Invalidate Device Cache
DELETE /api/cache/{device_name}
Returns:
{
"device": "router1",
"deleted_count": 15,
"message": "Invalidated 15 cache entries for router1"
}
Clear All Cache
DELETE /api/cache
Returns:
{
"deleted_count": 127,
"message": "Cleared 127 cache entries"
}
List Cache Keys
GET /api/cache
Parameters:
- device_name (string, optional): Filter keys by device name
Returns:
{
"device_filter": "router1",
"count": 3,
"keys": [
"router1:show version",
"router1:show ip int brief"
]
}
Get Cache Statistics
GET /api/cache/stats
Returns:
{
"enabled": true,
"total_entries": 127,
"devices_cached": 15,
"entries_per_device": {...},
"default_ttl": 300,
"max_ttl": 3600,
"key_prefix": "tom_cache"
}
Credentials
List Credentials
GET /api/credentials
Parameters:
- timeout (int, optional): Maximum wait time in seconds (default: 30)
Returns:
{
"credentials": ["default", "admin", "readonly"]
}
Monitoring
Get Worker Status
GET /api/monitoring/workers
Returns: Worker status based on heartbeats
Get Failed Commands
GET /api/monitoring/failed_commands
Parameters:
- device (string, optional): Filter by device name
- error_type (string, optional): Filter by error type
- since (int, optional): Unix timestamp for time range start
- limit (int, optional): Maximum results (default: 100)
Get Device Statistics
GET /api/monitoring/device_stats/{device_name}
Returns: Success/failure counts and error breakdown for a specific device
Get Summary Statistics
GET /api/monitoring/stats/summary
Returns: Global stats, worker breakdown, and top devices
Templates & Parsing
List TextFSM Templates
GET /api/templates/textfsm
Returns:
{
"custom": ["my_custom_template.textfsm"],
"ntc": ["cisco_ios_show_version.textfsm", "..."]
}
List TTP Templates
GET /api/templates/ttp
Returns:
{
"custom": ["my_custom_template.ttp"],
"ttp_templates": ["cisco_ios_show_ip_arp.txt", "cisco_ios_show_ip_ospf_database_router.txt", "..."]
}
Note: ttp_templates contains templates from the ttp-templates package (similar to ntc-templates for TextFSM).
Get Template Contents
GET /api/templates/{parser}/{template_name}
Retrieve the contents of a specific template.
Path Parameters:
- parser (string): Parser type ("textfsm" or "ttp")
- template_name (string): Template filename (extension optional)
Returns:
{
"name": "cisco_ios_show_version.textfsm",
"parser": "textfsm",
"source": "ntc",
"content": "Value VERSION (\\S+)\\nValue HOSTNAME (\\S+)\\n\\nStart\\n ^.*Version ${VERSION}.*"
}
Notes:
- For TextFSM, source is "custom" or "ntc"
- For TTP, source is always "custom"
Create Custom Template
POST /api/templates/{parser}
Create or upload a new custom template.
Path Parameters:
- parser (string): Parser type ("textfsm" or "ttp")
Request Body:
{
"name": "my_template.textfsm",
"content": "Value HOSTNAME (\\S+)\\n\\nStart\\n ^Hostname: ${HOSTNAME}",
"overwrite": false
}
Parameters:
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| name | string | required | Template filename (extension added if missing) |
| content | string | required | Template content |
| overwrite | bool | false | Replace existing template if it exists |
Returns:
{
"name": "my_template.textfsm",
"parser": "textfsm",
"created": true,
"validation_warnings": null
}
Validation: - TextFSM templates are compiled to check syntax before saving - TTP templates are instantiated to catch initialization errors - Templates are still created even if validation warnings are returned
Errors:
- 400: Template already exists (when overwrite=false)
- 400: Invalid template name (contains path separators or ..)
- 500: Cannot create template directory or write file
Delete Custom Template
DELETE /api/templates/{parser}/{template_name}
Delete a custom template. Only custom templates can be deleted; ntc-templates cannot be removed.
Path Parameters:
- parser (string): Parser type ("textfsm" or "ttp")
- template_name (string): Template filename
Returns:
{
"name": "my_template.textfsm",
"deleted": true
}
Errors: - 400: Cannot delete ntc-template - 404: Template not found
Find Matching Template
GET /api/templates/match
Parameters:
- command (string, required): Command to find template for
- device_type (string): Device type/platform (required if device not specified)
- device (string): Inventory device name (if provided, device_type is looked up)
- parser (string, optional): Parser type ("textfsm" or "ttp")
Returns:
{
"device_type": "cisco_ios",
"command": "show version",
"matches": [
{
"template_name": "cisco_ios_show_version.textfsm",
"source": "ntc-templates",
"parser": "textfsm"
}
]
}
Test Parsing
POST /api/parse/test
Test parsing without executing commands.
Request Body:
{
"raw_output": "Cisco IOS Software, Version 15.1...",
"parser": "textfsm",
"template": "cisco_ios_show_version.textfsm",
"device_type": "cisco_ios",
"command": "show version",
"include_raw": false
}
Parameters:
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| raw_output | string | required | Raw text output to parse |
| parser | string | "textfsm" | Parser to use ("textfsm" or "ttp") |
| template | string | null | Explicit template filename |
| device_type | string | null | Device type for template auto-discovery |
| command | string | null | Command for template auto-discovery |
| include_raw | bool | false | Include raw output in response |
Note: You must provide either template OR (device_type + command) for template discovery.
Returns: Parsed result with metadata
Metrics
Prometheus Metrics
GET /metrics
Note: This endpoint is outside the /api/ prefix and is unauthenticated.
Returns: Prometheus-format metrics
Error Responses
All errors return JSON with consistent structure:
{
"error": "Error Type",
"detail": "Detailed error message"
}
| Status Code | Error Type | Description |
|---|---|---|
| 400 | Bad Request | Validation error |
| 401 | Unauthorized | Authentication required |
| 403 | Forbidden | Authorization failed |
| 404 | Not Found | Resource not found |
| 404 | Template Not Found | Parsing template not found |
| 422 | Parsing Failed | Output parsing failed |
| 500 | Job Enqueue Failed | Failed to submit job to Redis/SAQ queue |
| 500 | Internal Server Error | Other server errors |
Note: When using raw_output=true, errors return plain text with appropriate HTTP status codes instead of JSON.
Wait Timeout Behavior
When wait=true, a 200 response may contain a JobResponse with a non-complete status (e.g. ACTIVE, QUEUED) if the wait timed out before the worker finished. This means:
- The job was accepted and is still running (or queued). It may complete successfully after the timeout.
- The response is not an error -- the HTTP status is still 200.
- Callers should check the
statusfield rather than assuming a 200 means the job completed. - The
job_idin the response can be used to pollGET /api/job/{job_id}for the final result.
Data Types
JobResponse
{
"job_id": "job-uuid",
"status": "NEW|QUEUED|ACTIVE|COMPLETE|FAILED|ABORTED|ABORTING",
"result": {
"data": {"command": "output"},
"meta": {"cache": {...}}
},
"attempts": 1,
"error": "error message (when failed)"
}
Note: The structure of result depends on the job type:
- Operational commands (send_command, send_commands): result contains {"data": {...}, "meta": {...}} (see CommandExecutionResult)
- Configuration push (send_configs): result contains {"transcript": "..."} (see ConfigExecutionResult)
CommandExecutionResult
Returned by operational command jobs (send_command, send_commands):
{
"data": {"show version": "...", "show ip int brief": "..."},
"meta": {"cache": {"cache_status": "miss", "commands": {...}}}
}
ConfigExecutionResult
Returned by configuration push jobs (send_configs):
{
"transcript": "configure terminal\nEnter configuration commands...\ninterface Gi0/1\n...\nend"
}
The transcript contains the full session output from entering config mode, applying each command, and exiting. This is useful for debugging but is not parsed or structured.
DeviceConfig
{
"adapter": "netmiko|scrapli",
"adapter_driver": "cisco_ios",
"adapter_options": {},
"host": "192.168.1.1",
"port": 22,
"credential_id": "default"
}
Configuration
Configuration is managed via tom_config.yaml or environment variables with TOM_ prefix.
Key settings:
- inventory_type: "yaml", "netbox", "nautobot", or "solarwinds"
- auth_mode: "none", "api_key", "jwt", or "hybrid"
- cache_enabled: Enable/disable caching (default: true)
- cache_default_ttl: Default cache TTL in seconds (default: 300)
- cache_max_ttl: Maximum allowed TTL in seconds (default: 3600)