The integration manifest
Every integration must contain a manifest.json. This page documents every key and
its allowed values exactly as enforced by the validator
(python -m script.apexfest) and, for custom integrations, by the runtime loader.
Key ordering
The validator enforces a canonical key order: domain, name, then all remaining
keys in alphabetical order. Running the validator with --action generate re-sorts
the file for you.
Required keys
domain
The integration's unique identifier. Must be a string and must match the directory name of the integration, or validation fails with "Domain does not match dir name".
name
The human-readable name of the integration.
documentation
A URL to the integration's documentation.
- Built-in integrations: must begin with
https://www.apexinfosys.in/integrations(in practicehttps://www.apexinfosys.in/integrations/<domain>). - Custom integrations: must be an
httpsURL and must not point at the core documentation base — it should point at the custom integration's own docs.
codeowners
A list of GitHub handles (e.g. ["@developer"]) responsible for the integration.
The key is required (an empty list is accepted at schema level), but an integration
with a quality_scale of silver or higher must have at least one code owner.
Optional keys
integration_type
Defaults to "hub" when omitted. Allowed values:
| Value | Meaning |
|---|---|
device | Provides a single device |
entity | An entity base platform |
hardware | A hardware integration |
helper | A helper that operates on existing data/entities |
hub | Connects to a hub that exposes multiple devices |
service | A single service |
system | System-level integration |
virtual | A pointer entry with no code of its own (special schema, below) |
config_flow
Boolean. Set to true if the integration is set up from the UI via a
config flow.
dependencies / after_dependencies
Lists of other integration domains. dependencies are set up before your
integration; after_dependencies are only ordered before yours if they are going
to be set up anyway.
requirements
A list of PyPI requirement strings. Pin versions with == (the scaffolder enforces
this for the initial requirement).
iot_class
How the integration gathers data. Allowed values:
assumed_statecalculatedcloud_pollingcloud_pushlocal_pollinglocal_push
The IoT class is required for regular integrations ("Domain is missing an IoT
Class") and forbidden for entity platforms and a fixed list of system domains
such as api, auth, automation, config, frontend, hardware,
onboarding, raspberry_pi, recovery_mode, repairs, zone, etc. ("Domain
should not have an IoT Class"). Virtual integrations never carry one.
quality_scale
One of the scaled tiers or the non-scaled markers:
- Scaled:
bronze,silver,gold,platinum - Non-scaled:
custom,no_score,internal,legacy
silver and above require a non-empty codeowners list. Scaled integrations also
carry a quality_scale.yaml rules file (see the quality checklist).
single_config_entry
Boolean. If true, only one config entry of this integration may exist (used by
e.g. the sun integration).
loggers
List of logger names used by the integration's requirements, so log levels can be managed together with the integration.
disabled
A string; when present, explains why the integration is disabled.
preview_features
A mapping of feature slugs to an object with optional feedback_url,
learn_more_url, and report_issue_url (all URLs).
Discovery keys
zeroconf
A list where each item is either a service type string or a matcher object:
"zeroconf": [
"_mytype._tcp.local.",
{ "type": "_mytype._tcp.local.", "name": "myname*", "properties": { "key": "value" } }
]
type(required in object form)name,propertiesvalues — must be lowercasemacaddress,model,manufacturer— deprecated inzeroconf(use thepropertiesmatcher);macaddressmust be uppercase and contain a*wildcard, the others lowercase.
ssdp
A list of matcher dictionaries; each dictionary may contain arbitrary keys but must not be empty.
bluetooth
A list of matcher objects with the optional keys:
connectable(bool)service_uuid(lowercase string)service_data_uuid(lowercase string)local_name(string)manufacturer_id(int)manufacturer_data_start(list of ints)
dhcp
A list of matcher objects:
macaddress— uppercase, must contain a*wildcardhostname— lowercaseregistered_devices(bool)
usb
A list of matcher objects:
vid,pid— uppercaseserial_number,manufacturer,description— lowercaseknown_devices— list of strings
mqtt
A list of MQTT topic strings to subscribe to for discovery.
homekit
An object with an optional models list (device model prefixes to discover).
Virtual integrations
When integration_type is "virtual", a different, minimal schema applies:
{
"domain": "example",
"name": "Example",
"integration_type": "virtual",
"supported_by": "other_domain"
}
domain,name,integration_type: "virtual"are required.- Exactly one of
supported_by(another existing built-in domain — the validator checks it exists) oriot_standards(a list drawn fromhomekit,zigbee,zwave) may be present; they are mutually exclusive.
Custom-integration-only keys
Custom integrations use the same schema with these differences:
version
Required in practice. The schema marks it optional, but the validator emits
"No 'version' key in the manifest file" and the runtime loader blocks the
integration from loading if version is missing or invalid. The version must
parse under one of these strategies: CalVer, SemVer, SimpleVer, BuildVer, or PEP 440.
issue_tracker
URL of the custom integration's issue tracker.
import_executor
Boolean; whether the integration's code is imported in an executor.
documentation
Must be https and must not start with
https://www.apexinfosys.in/integrations — point it at your own documentation.
Additionally, the validator warns if a custom integration's domain collides with a built-in integration ("Domain collides with built-in core integration").
Validating your manifest
# validate everything
python -m script.apexfest --requirements --action validate
# validate a single integration directory
python -m script.apexfest --integration-path apexos/components/<domain>