- A single Python decorator,
@registry.register from typing import Annotatedfrom typing_extensions import Doc
Quick start
- Add a Python file to your custom registry package.
- Register one async function with
@registry.register(...). - Define typed inputs, read secrets with
secrets.get(...), and return JSON-serializable data.
What to define
- Use
tools.<integration>for the namespace. - Set
default_title,description,display_group,doc_url, andnamespacein@registry.register(...). - Define action inputs with type hints and
Field(..., description=...). - Define required credentials with
RegistrySecret(...)and pass them insecrets=[...]. - Read secret values with
secrets.get(...). - Return plain dicts, lists, strings, numbers, or booleans.
Declaring secret types
By default, secrets arecustom (arbitrary key-value). If your action requires an SSH key, mTLS certificate, or CA certificate, set secret_type so the credentials UI renders the correct form.
secret_type | Required keys | Description |
|---|---|---|
"custom" | Any | Generic key-value pairs (default) |
"ssh_key" | ["PRIVATE_KEY"] | SSH private key (PEM) |
"mtls" | ["TLS_CERTIFICATE", "TLS_PRIVATE_KEY"] | mTLS client certificate and key |
"ca_cert" | ["CA_CERTIFICATE"] | CA certificate bundle |
Examples
secret_type uses snake_case everywhere — Python declarations, the API, and the UI all use the same values (ssh_key, ca_cert, mtls, custom).
Use the same ${{ SECRETS... }} syntax as workflow actions.
Custom secrets (API keys, SSH, mTLS, CA bundles, and so on):
<provider_id>_oauth. The key is the provider ID in uppercase plus _USER_TOKEN or _SERVICE_TOKEN:
authorization_code:${{ SECRETS.<provider_id>_oauth.<PROVIDER_ID_UPPER>_USER_TOKEN }}client_credentials:${{ SECRETS.<provider_id>_oauth.<PROVIDER_ID_UPPER>_SERVICE_TOKEN }}
Python UDFs
Declare credentials in@registry.register(..., secrets=[...]).
RegistrySecret: static keys; setsecret_typetossh_key,mtls, orca_certwhen needed (secret types). Optional:optional,optional_keys.RegistryOAuthSecret: declares a dependency on an existing OAuth integration. Pass theprovider_idandgrant_typethat match the integration in your workspace (a mismatch — for example declaringauthorization_codewhen the integration usesclient_credentials— will not resolve).
secrets.get("<KEY>") (key only, e.g. GOOGLE_DRIVE_USER_TOKEN), not a SECRETS. path.
YAML
Underdefinition, set a secrets list (same validator as Python).
Custom (optional secret_type for structured secrets):
provider_id and grant_type must match an integration already configured in your workspace. Use ${{ SECRETS.<provider_id>_oauth.<TOKEN_KEY> }} in args. Set optional: true on an OAuth entry when it is not always required.
Example providers
Seeintegrations/google_drive.py and integrations/slack_sdk.py for UDFs that use OAuth credentials. See tracecat_registry/core/ssh.py for an ssh_key secret example.
For YAML templates, see microsoft_teams/send_message.yml (authorization_code), google_docs/create_document.yml (client_credentials), and microsoft_sentinel/.../get_alert_rule_template.yml (optional dual grant). See templates/tools/exa/search.yml for a simple API key template.
For the full list of built-in provider IDs, see tracecat/integrations/providers/__init__.py.