Skip to content

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 JobResponse envelope
  • 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 status field rather than assuming a 200 means the job completed.
  • The job_id in the response can be used to poll GET /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)