# Enmasse reference - GitOps for Zato configuration

The full reference of all options available in enmasse YAML configuration files.

This chapter is a reference for all the options available in enmasse YAML files, the platform's GitOps configuration format. For an overview of enmasse, see the [enmasse overview](https://zato.io/docs/admin/enmasse.html) page.

Every list item on this page also accepts `should_delete: true`, which deletes the object the item names instead of creating or updating it - see [Deleting objects](https://zato.io/docs/admin/enmasse.html#deleting-objects) for how a deletion is matched, ordered and refused.

## REST channels {#rest-channels}

Key: `channel_rest`

| Name | Required | Description |
| --- | --- | --- |
| `name` | Yes | Unique name of the REST channel |
| `service` | Yes | Name of the Zato service that the channel invokes |
| `url_path` | Yes | URL path that the channel listens on, e.g. `/api/v1/my-endpoint` |
| `security` | No | Name of a security definition to protect the channel with |
| `is_active` | No | Whether the channel accepts requests (default is `true`) |
| `method` | No | HTTP method the channel accepts, e.g. `GET` or `POST` (if omitted, all methods are accepted) |
| `data_format` | No | Expected data format of incoming requests, e.g. `json`, or `hl7-ccda` for a channel that [converts C-CDA documents to FHIR bundles](https://zato.io/docs/dev/healthcare/hl7/ccda/index.md) before its service runs |
| `content_type` | No | Content type that the channel expects in incoming requests |
| `timeout` | No | Request timeout in seconds |
| `groups` | No | List of security group names whose members are allowed to call this channel |
| `is_audit_log_active` | No | Whether the channel's traffic goes to the audit log (default is `true`, exported only when `false`) |
| `is_audit_export_payload_active` | No | Whether the channel's request and response payloads leave with the [OpenTelemetry export](https://zato.io/docs/admin/audit-log/opentelemetry.md) of the audit log (default is `false`, exported only when `true`) |
| `rate_limiting` | No | Rate limiting rules - see [rate limiting on REST channels](https://zato.io/docs/admin/enmasse-reference.html#rate-limiting-on-rest-channels) |
| `response_cache` | No | Response caching configuration - see [response caching on REST channels](https://zato.io/docs/admin/enmasse-reference.html#response-caching-on-rest-channels) |
| `is_deprecated` | No | Whether the channel is marked deprecated - it keeps serving but announces the deprecation in response headers (default is `false`) |
| `deprecation_sunset` | No | The retirement date announced in the `Sunset` response header, e.g. `2027-06-30` |
| `deprecation_successor` | No | URL of the replacement endpoint, announced in the `Link` response header |
| `use_queue` | No | Whether each request is stored in the channel's queue and acknowledged at once, with the service running from the queue - see [the queue on a channel](https://zato.io/docs/dev/delivery.md#the-queue-on-a-channel) (default `false`) |
| `queue_response` | No | With `use_queue`, a fixed body the channel acknowledges each request with instead of the default `{"is_ok": true, "cid": ...}` - JSON, XML or plain text by what it opens with, and a service's `get_queue_response` takes precedence over it |
| `max_retries` | No | With `use_queue`, how many times a run of the service that raised is retried within a round (default `0`, i.e. no retries) |
| `retry_sleep_time` | No | How many seconds to wait before the first retry, 8 at most (default `2`) |
| `retry_backoff_multiplier` | No | How many times longer each next wait is (default `2`) |
| `retry_backoff_threshold` | No | How many seconds all the waits may take together, once that is reached, no more retries take place (default `60`) |
| `use_dlq` | No | Whether a request that a round of the queue could not deliver moves to the channel's dead-letter queue (default `true`) |
| `dlq_action` | No | What happens to a request in the DLQ - `keep`, `retry`, `forward` or `discard` (default `keep`) |
| `dlq_retries` | No | With `retry`, how many more rounds of delivery a request gets before it stays in the DLQ (default `3`) |
| `dlq_retry_interval` | No | How many seconds a request stays in the DLQ before the action applies to it (default `60`) |
| `dlq_forward_to` | No | With `forward`, the name of the pub/sub topic the request is published to |
| `dlq_keep_header` | No | With `forward`, whether the DLQ header - why, when and after how many attempts the request was dead-lettered - goes with it (default `true`) |

```yaml
channel_rest:
  - name: enmasse.channel.rest.1
    service: demo.ping
    url_path: /enmasse.rest.1

  - name: enmasse.channel.rest.2
    service: demo.ping
    url_path: /enmasse.rest.2
    security: enmasse.basic_auth.1
    data_format: json

  - name: enmasse.channel.rest.ccda
    service: demo.ccda.store
    url_path: /enmasse.rest.ccda
    data_format: hl7-ccda

  - name: enmasse.channel.rest.orders
    service: orders.intake
    url_path: /enmasse.rest.orders
    data_format: json
    use_queue: true
    max_retries: 3
    retry_sleep_time: 5
    dlq_action: retry
    queue_response: '{"accepted": true}'
```

More details in the [REST channels](https://zato.io/docs/dev/rest/channels.html) chapter.

## Rate limiting on REST channels {#rate-limiting-on-rest-channels}

Rate limiting is configured as a nested `rate_limiting` key inside each `channel_rest` entry. It is a list of rules, evaluated top to bottom. The first rule whose address list matches the client IP is used. Within each rule, time ranges are checked in order, and the all-day default applies when no specific time range matches.

Each rule contains:

| Name | Required | Description |
| --- | --- | --- |
| cidr\_list | --- | List of IP addresses or ranges, e.g. `10.0.0.0/8` or `192.168.1.10`. If empty, the rule matches all clients. |
| time\_range | Yes | List of time range entries (see below). The first entry must be the all-day default (`is_all_day: true`). |

Each time range entry contains:

| Name | Required | Description |
| --- | --- | --- |
| is\_all\_day | Yes | `true` for the all-day default, `false` for a specific time range |
| time\_from | --- | Start time in `HH:MM` format (required when `is_all_day` is `false`) |
| time\_to | --- | End time in `HH:MM` format (required when `is_all_day` is `false`) |
| disabled | Yes | If `true`, the time range is skipped during evaluation |
| disallowed | Yes | If `true`, matching requests are silently dropped at the TCP level |
| rate | Yes | Requests per second (sustained) |
| burst | Yes | Maximum burst size before throttling |
| limit | Yes | Hard cap on total requests within the time unit |
| limit\_unit | Yes | Time unit for the hard cap - one of `second`, `minute`, `hour`, `day`, `month` |

```yaml
channel_rest:

  # Simple channel with 200 requests per minute, burst up to 50/s
  - name: crm.customer.get
    service: crm.customer.get-details
    url_path: /api/v1/customers
    rate_limiting:
      - cidr_list: []
        time_range:
          - is_all_day: true
            disabled: false
            disallowed: false
            rate: 50
            burst: 50
            limit: 200
            limit_unit: minute

  # Internal IPs get generous limits, everything else is silently dropped
  - name: billing.internal.sync
    service: billing.sync
    url_path: /internal/billing/sync
    rate_limiting:
      - cidr_list:
          - 10.0.0.0/8
          - 172.16.0.0/12
        time_range:
          - is_all_day: true
            disabled: false
            disallowed: false
            rate: 100
            burst: 200
            limit: 50000
            limit_unit: hour
      - cidr_list: []
        time_range:
          - is_all_day: true
            disabled: false
            disallowed: true
            rate: 0
            burst: 0
            limit: 0
            limit_unit: minute

  # Higher limits during the nightly batch window, stricter during the day
  - name: warehouse.inventory.update
    service: warehouse.inventory.bulk-update
    url_path: /api/v1/inventory
    rate_limiting:
      - cidr_list: []
        time_range:
          - is_all_day: true
            disabled: false
            disallowed: false
            rate: 20
            burst: 50
            limit: 5000
            limit_unit: hour
          - is_all_day: false
            time_from: "01:00"
            time_to: "03:00"
            disabled: false
            disallowed: false
            rate: 200
            burst: 500
            limit: 100000
            limit_unit: hour

  # Block a specific range, allow everyone else at 100/minute
  - name: public.search
    service: search.query
    url_path: /api/v1/search
    rate_limiting:
      - cidr_list:
          - 198.51.100.0/24
        time_range:
          - is_all_day: true
            disabled: false
            disallowed: true
            rate: 0
            burst: 0
            limit: 0
            limit_unit: minute
      - cidr_list: []
        time_range:
          - is_all_day: true
            disabled: false
            disallowed: false
            rate: 20
            burst: 40
            limit: 100
            limit_unit: minute

  # Strict daily budget - 10,000 requests per day, 10/s sustained
  - name: reports.generate
    service: reports.generate-pdf
    url_path: /api/v1/reports
    rate_limiting:
      - cidr_list: []
        time_range:
          - is_all_day: true
            disabled: false
            disallowed: false
            rate: 10
            burst: 20
            limit: 10000
            limit_unit: day
```

For a full explanation of all rate limiting concepts, see the [Rate limiting and firewall](https://zato.io/docs/admin/guide/rate-limit.html) chapter.

## Response caching on REST channels {#response-caching-on-rest-channels}

Response caching is configured as a nested `response_cache` key inside a `channel_rest` entry. On export, only the fields that differ from their defaults are written out.

| Name | Required | Description |
| --- | --- | --- |
| is\_enabled | --- | Whether the channel caches responses at all (default is `false`) |
| ttl | --- | How long a cached response lives (default is `5`) |
| ttl\_unit | --- | Unit for the TTL - one of `seconds`, `minutes` or `hours` (default is `minutes`) |
| is\_shared\_across\_callers | --- | Whether all the callers share one cache entry or each caller has its own (default is `false`) |
| vary\_by\_headers | --- | List of request headers whose values become part of the cache key |
| ignored\_query\_parameters | --- | List of query parameters left out of the cache key |
| include\_body\_in\_key | --- | Whether the request body becomes part of the cache key (default is `false`) |
| max\_body\_size | --- | The biggest response cached, in bytes (default is `1000000`) |
| cache\_on\_second\_request | --- | Whether a response is cached only once the same request repeats (default is `true`) |
| needs\_etag | --- | Whether cached responses include an `ETag` header (default is `false`) |
| coalesce\_timeout | --- | How long concurrent identical requests wait for the first one's response, in seconds (default is `15`) |

```yaml
channel_rest:

  - name: crm.customer.get
    service: crm.customer.get-details
    url_path: /api/v1/customers
    response_cache:
      is_enabled: true
      ttl: 10
      ttl_unit: minutes
      vary_by_headers:
        - X-Tenant-Id
```

The [Response caching](https://zato.io/docs/dev/api-management/response-caching.html) chapter explains all the fields in detail.

## SOAP channels {#soap-channels}

Key: `channel_soap`

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique name of the SOAP channel |
| service | Yes | Name of the Zato service that the channel invokes |
| url\_path | Yes | URL path that the channel listens on |
| security | --- | Name of a security definition to protect the channel with |
| soap\_action | --- | SOAP action the channel responds to |
| soap\_version | --- | SOAP protocol version (default is `1.1`) |
| use\_mtom | --- | Whether the channel accepts MTOM attachments (default is `false`) |
| method | --- | HTTP method the channel accepts (if omitted, all methods are accepted) |
| content\_type | --- | Content type that the channel expects in incoming requests |
| timeout | --- | Request timeout in seconds |
| groups | --- | List of [security group](https://zato.io/docs/security/groups.html) names whose members are allowed to call this channel |
| is\_audit\_log\_active | --- | Whether the channel's traffic goes to the audit log (default is `true`, exported only when `false`) |
| is\_audit\_export\_payload\_active | --- | Whether the channel's request and response payloads leave with the [OpenTelemetry export](https://zato.io/docs/admin/audit-log/opentelemetry.html) of the audit log (default is `false`, exported only when `true`) |
| rate\_limiting | --- | Rate limiting rules, with the same keys as on [REST channels](https://zato.io/docs/admin/enmasse-reference.html#rate-limiting-on-rest-channels) |
| response\_cache | --- | Response caching configuration, in the same format as on [REST channels](https://zato.io/docs/admin/enmasse-reference.html#response-caching-on-rest-channels) |
| use\_queue | --- | Whether each request is stored in the channel's queue and acknowledged at once, with the service running from the queue - see [the queue on a channel](https://zato.io/docs/dev/delivery.html#the-queue-on-a-channel) (default `false`) |
| queue\_response | --- | With `use_queue`, a fixed XML body the channel acknowledges each request with instead of the default envelope with `is_ok` and `cid` - a service's `get_queue_response` takes precedence over it |
| max\_retries | --- | With `use_queue`, how many times a run of the service that raised is retried within a round (default `0`, i.e. no retries) |
| retry\_sleep\_time | --- | How many seconds to wait before the first retry, 8 at most (default `2`) |
| retry\_backoff\_multiplier | --- | How many times longer each next wait is (default `2`) |
| retry\_backoff\_threshold | --- | How many seconds all the waits may take together, once that is reached, no more retries take place (default `60`) |
| use\_dlq | --- | Whether a request that a round of the queue could not deliver moves to the channel's dead-letter queue (default `true`) |
| dlq\_action | --- | What happens to a request in the DLQ - `keep`, `retry`, `forward` or `discard` (default `keep`) |
| dlq\_retries | --- | With `retry`, how many more rounds of delivery a request gets before it stays in the DLQ (default `3`) |
| dlq\_retry\_interval | --- | How many seconds a request stays in the DLQ before the action applies to it (default `60`) |
| dlq\_forward\_to | --- | With `forward`, the name of the pub/sub topic the request is published to |
| dlq\_keep\_header | --- | With `forward`, whether the DLQ header - why, when and after how many attempts the request was dead-lettered - goes with it (default `true`) |

```yaml
channel_soap:

  - name: enmasse.channel.soap.1
    service: demo.soap-input
    url_path: /soap/orders
    security: enmasse.basic_auth.1
    soap_action: urn:example:orders:create

  - name: enmasse.channel.soap.2
    service: demo.soap-attachments
    url_path: /soap/documents
    soap_version: "1.2"
    use_mtom: true

  - name: enmasse.channel.soap.3
    service: demo.soap-orders
    url_path: /soap/orders-queued
    soap_action: urn:example:orders:submit
    use_queue: true
    max_retries: 3
    dlq_action: forward
    dlq_forward_to: orders.undelivered
```

## Outgoing REST connections {#outgoing-rest-connections}

Key: `outgoing_rest`

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique name of the outgoing connection |
| host | Yes | Base host URL of the remote endpoint, e.g. `https://api.example.com` |
| url\_path | Yes | URL path appended to the host when making requests, e.g. `/v1/endpoint` |
| security | --- | Name of a security definition to use when connecting |
| data\_format | --- | Data format of outgoing requests, e.g. `json` |
| timeout | --- | Request timeout in seconds (default is `60`) |
| ping\_method | --- | HTTP method used to ping the connection (default is `GET`) |
| pool\_size | --- | Size of the connection pool (default is `20`) |
| tls\_verify | --- | Whether to verify the remote TLS certificate (default is `true`) |
| content\_type | --- | Content type header sent with outgoing requests |
| is\_audit\_log\_active | --- | Whether the connection's traffic goes to the audit log (default is `true`, exported only when `false`) |
| is\_audit\_export\_payload\_active | --- | Whether the connection's request and response payloads leave with the [OpenTelemetry export](https://zato.io/docs/admin/audit-log/opentelemetry.html) of the audit log (default is `false`, exported only when `true`) |
| max\_retries | --- | How many times a failed invocation is retried after a timeout, a connection error or an HTTP 429 response (default `0`, i.e. no retries) |
| retry\_sleep\_time | --- | How many seconds to wait before the first retry, 8 at most (default `2`) |
| retry\_backoff\_multiplier | --- | How many times longer each next wait is (default `2`) |
| retry\_backoff\_threshold | --- | How many seconds all the waits may take together, once that is reached, no more retries take place (default `60`) |
| use\_queue | --- | Whether a request that could not be delivered waits in the connection's queue and is retried until it goes through, with `max_retries` at 0 it is not queued (default `false`) |
| use\_dlq | --- | Whether a request that a round of the queue could not deliver moves to the connection's dead-letter queue (default `true`) |
| dlq\_action | --- | What happens to a request in the DLQ - `keep`, `retry`, `forward` or `discard` (default `keep`) |
| dlq\_retries | --- | With `retry`, how many more rounds of delivery a request gets before it stays in the DLQ (default `3`) |
| dlq\_retry\_interval | --- | How many seconds a request stays in the DLQ before the action applies to it (default `60`) |
| dlq\_forward\_to | --- | With `forward`, the name of the pub/sub topic the request is published to |
| dlq\_keep\_header | --- | With `forward`, whether the DLQ header - why, when and after how many attempts the request was dead-lettered - goes with it (default `true`) |

The delivery fields are exported only when they differ from their defaults - the [Delivery retries and dead-letter queues](https://zato.io/docs/dev/delivery.html) page explains what each one does.

```yaml
outgoing_rest:
  - name: enmasse.outgoing.rest.1
    host: https://example.com
    url_path: /api/v1
    data_format: json
    timeout: 60

  - name: enmasse.outgoing.rest.2
    host: https://example.com
    url_path: /api/v2
    security: enmasse.bearer_token.1
    tls_verify: false

  # A connection that retries failed invocations - with these settings, a call that keeps failing
  # sleeps 2s, 4s, 8s, 8s and 8s between attempts before giving up, about 30 seconds in total.
  - name: enmasse.outgoing.rest.3
    host: https://example.com
    url_path: /api/v3
    max_retries: 5
    retry_sleep_time: 2
    retry_backoff_multiplier: 2
    retry_backoff_threshold: 60

  # A connection with alert settings of its own - the ones left out stay at their defaults
  - name: enmasse.outgoing.rest.4
    host: https://example.com
    url_path: /api/v4
    alerts:
      status_codes: 404, 5xx
      status_code_threshold: 5
      connection_failures: 2
      max_latency: 2500
      email_connection: smtp:enmasse.smtp.1
```

The `alerts` mapping corresponds to the connection's Alerts tab - `is_active`, `consecutive_failures`, `error_rate`, `window`, `status_codes`, `status_code_threshold`, `status_codes_window`, `connection_failures`, `connection_failures_window`, `max_latency`, `latency_window`, `use_llm`, `email_connection` and `llm_connection` - and only the settings that differ from their defaults are exported.

See also: [Configuring REST API outgoing connections](https://zato.io/docs/dev/rest/outconns.html)

## Outgoing SOAP connections {#outgoing-soap-connections}

Key: `outgoing_soap`

There is no WSDL key - a connection needs only `host`, `url_path`, `soap_action` and `soap_version`, and services call it with Python objects.

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique name of the outgoing connection |
| host | Yes | Base host URL of the remote endpoint, e.g. `https://api.example.com` |
| url\_path | Yes | URL path appended to the host when making requests, e.g. `/v1/endpoint` |
| security | --- | Name of a security definition to use when connecting |
| soap\_action | --- | SOAP action header sent with requests |
| soap\_version | --- | SOAP protocol version (default is `1.1`) |
| data\_format | --- | Data format of outgoing requests |
| timeout | --- | Request timeout in seconds (default is `60`) |
| ping\_method | --- | HTTP method used to ping the connection (default is `GET`) |
| pool\_size | --- | Size of the connection pool (default is `20`) |
| tls\_verify | --- | Whether to verify the remote TLS certificate (default is `true`) |
| content\_type | --- | Content type header sent with outgoing requests |
| is\_audit\_log\_active | --- | Whether the connection's traffic goes to the audit log (default is `true`, exported only when `false`) |
| is\_audit\_export\_payload\_active | --- | Whether the connection's request and response payloads leave with the [OpenTelemetry export](https://zato.io/docs/admin/audit-log/opentelemetry.html) of the audit log (default is `false`, exported only when `true`) |
| max\_retries | --- | How many times a failed invocation is retried after a timeout, a connection error or an HTTP 429 response (default `0`, i.e. no retries) |
| retry\_sleep\_time | --- | How many seconds to wait before the first retry, 8 at most (default `2`) |
| retry\_backoff\_multiplier | --- | How many times longer each next wait is (default `2`) |
| retry\_backoff\_threshold | --- | How many seconds all the waits may take together, once that is reached, no more retries take place (default `60`) |
| use\_queue | --- | Whether a request that could not be delivered waits in the connection's queue and is retried until it goes through, with `max_retries` at 0 it is not queued (default `false`) |
| use\_dlq | --- | Whether a request that a round of the queue could not deliver moves to the connection's dead-letter queue (default `true`) |
| dlq\_action | --- | What happens to a request in the DLQ - `keep`, `retry`, `forward` or `discard` (default `keep`) |
| dlq\_retries | --- | With `retry`, how many more rounds of delivery a request gets before it stays in the DLQ (default `3`) |
| dlq\_retry\_interval | --- | How many seconds a request stays in the DLQ before the action applies to it (default `60`) |
| dlq\_forward\_to | --- | With `forward`, the name of the pub/sub topic the request is published to |
| dlq\_keep\_header | --- | With `forward`, whether the DLQ header - why, when and after how many attempts the request was dead-lettered - goes with it (default `true`) |

The delivery fields are exported only when they differ from their defaults - the [Delivery retries and dead-letter queues](https://zato.io/docs/dev/delivery.html) page explains what each one does.

```yaml
outgoing_soap:
  - name: enmasse.outgoing.soap.1
    host: https://example.com
    url_path: /SOAP
    security: enmasse.ntlm.1
    soap_action: urn:microsoft-dynamics-schemas/page/example:Create
    soap_version: "1.1"
    tls_verify: false
    timeout: 20

  # A connection that retries failed invocations - three retries with 1s, 2s and 4s sleeps between them
  - name: enmasse.outgoing.soap.2
    host: https://example.com
    url_path: /SOAP
    soap_action: urn:example:submit
    soap_version: "1.2"
    max_retries: 3
    retry_sleep_time: 1

  # A connection with alert settings of its own - the same mapping as on an outgoing REST connection, plus the SOAP faults
  - name: enmasse.outgoing.soap.3
    host: https://example.com
    url_path: /SOAP
    soap_action: urn:example:query
    alerts:
      status_codes: 5xx
      status_code_threshold: 3
      fault_codes: Receiver, Server
      fault_threshold: 3
      faults_window: 600
      connection_failures: 2
      email_connection: smtp:enmasse.smtp.1
```

The `alerts` mapping takes the same settings as the one of [outgoing REST connections](https://zato.io/docs/admin/enmasse-reference.html#outgoing-rest-connections) plus three of its own - `fault_codes`, `fault_threshold` and `faults_window` - and only the settings that differ from their defaults are exported.

`fault_codes` is a comma-separated list of the SOAP fault codes the connection alerts on, as the fault's envelope names them - the standard codes of either SOAP version, `Receiver` and `Server` for the endpoint's own faults, `Sender` and `Client` for the ones it blames the caller for, `VersionMismatch`, `MustUnderstand` and `DataEncodingUnknown`, and an endpoint's own code with its prefix, such as `x:Timeout`. The default is `Receiver, Server, Sender, Client`. A fault is counted under its code and never under `status_codes`, so the HTTP status it arrived with does not count it twice.

More details in the [Python SOAP](https://zato.io/docs/dev/examples/soap.html) chapter.

## Security definitions {#security-definitions}

Key: `security`

A definition that already exists in the environment is matched by name and updated in place on import, one that does not is created - the [import semantics](https://zato.io/docs/admin/enmasse.html#import-semantics) are described in the enmasse guide.

### basic\_auth {#basic_auth}

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique name of the security definition |
| type | Yes | Must be `basic_auth` |
| username | Yes | Username |
| password | --- | Password - can be set via an environment variable |
| realm | --- | HTTP [Basic Auth](https://zato.io/docs/security/basic-auth.html) realm - any text, such as `API` or the name of your system (default is `zato`) |
| is\_active | --- | Whether the definition is active (default is `true`) |

```yaml
security:
  - name: enmasse.basic_auth.1
    type: basic_auth
    username: enmasse.1
    password: Zato_Enmasse_Env.BasicAuth1
```

### apikey {#apikey}

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique name of the security definition |
| type | Yes | Must be `apikey` |
| password | --- | The [API key](https://zato.io/docs/security/api-keys.html) value - can be set via an environment variable |
| header | --- | Name of the HTTP header that holds the API key (default is `X-API-Key`) |
| is\_active | --- | Whether the definition is active (default is `true`) |

```yaml
security:
  - name: enmasse.apikey.1
    type: apikey
    username: enmasse.1
    password: Zato_Enmasse_Env.EnmasseApiKey1
```

### ntlm {#ntlm}

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique name of the security definition |
| type | Yes | Must be `ntlm` |
| username | Yes | Username, typically in `DOMAIN\user` format |
| password | --- | Password - can be set via an environment variable |
| is\_active | --- | Whether the definition is active (default is `true`) |

```yaml
security:
  - name: enmasse.ntlm.1
    type: ntlm
    username: enmasse\\user
    password: Zato_Enmasse_Env.NTLMPassword
```

### mtls {#mtls}

mTLS definitions are asymmetric - the path fields drive outgoing connections while the match criteria drive channels. One definition uses one set or the other. More details in the [mTLS](https://zato.io/docs/security/mtls/index.html) chapter.

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique name of the security definition |
| type | Yes | Must be `mtls` |
| cert\_path | --- | Path to the client certificate in PEM format, for outgoing connections |
| key\_path | --- | Path to the certificate's private key in PEM format - not needed when the certificate file contains the key |
| ca\_certs\_path | --- | Path to a CA bundle the remote server's certificate must chain up to |
| client\_cert\_fingerprint | --- | Expected SHA256 fingerprint of an inbound client certificate, for channels |
| client\_cert\_subject\_dn | --- | Expected subject DN of an inbound client certificate, for channels |
| is\_active | --- | Whether the definition is active (default is `true`) |

```yaml
security:
  - name: enmasse.mtls.1
    type: mtls
    cert_path: /opt/hot-deploy/ssl/client-cert.pem
    key_path: /opt/hot-deploy/ssl/client-key.pem
    ca_certs_path: /opt/hot-deploy/ssl/remote-ca.pem

  - name: enmasse.mtls.2
    type: mtls
    client_cert_fingerprint: 9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08
    client_cert_subject_dn: CN=client,O=Example,C=US
```

### spnego {#spnego}

Kerberos definitions are used with outgoing connections - the keytab is the credential, so there is no password. More details in the [Kerberos (SPNEGO)](https://zato.io/docs/security/kerberos/index.html) chapter.

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique name of the security definition |
| type | Yes | Must be `spnego` |
| principal | Yes | The Kerberos principal to authenticate as |
| keytab\_path | Yes | Path to the principal's keytab file, as mounted into the container |
| target\_spn | --- | Service principal name of the remote API, e.g. `HTTP@api.example.com` - derived from the target host name when absent |
| needs\_delegation | --- | Whether to delegate credentials to the remote service (default is `false`) |
| is\_active | --- | Whether the definition is active (default is `true`) |

```yaml
security:
  - name: enmasse.spnego.1
    type: spnego
    principal: enmasse@EXAMPLE.COM
    keytab_path: /opt/hot-deploy/krb5/enmasse.keytab
    target_spn: HTTP@api.example.com
```

### bearer\_token {#bearer_token}

A [bearer token](https://zato.io/docs/security/bearer-tokens/index.html) definition is either dynamic - Zato obtains and refreshes the token from a token endpoint - or static, with a fixed token that never changes. The presence of any of the `static_*` fields makes the definition static.

Fields of dynamic definitions:

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique name of the security definition |
| type | Yes | Must be `bearer_token` |
| username | Yes | Client ID used to obtain the token |
| auth\_endpoint | Yes | URL of the token endpoint |
| client\_auth\_method | --- | How Zato logs in to the token endpoint - `client_secret` (default) or `private_key_jwt`, which signs each token request with `private_key` instead of sending a secret |
| password | --- | Client secret, with `client_auth_method: client_secret` - can be set via an environment variable |
| private\_key | --- | PEM private key, with `client_auth_method: private_key_jwt` - set it via an environment variable, it is stored encrypted and never exported. An import that leaves it out keeps the key already stored |
| jwt\_algorithm | --- | Signing algorithm of the private key JWT - `RS384` (default), `RS256`, `PS256` or `ES384`, the last one for EC P-384 keys |
| key\_id | --- | `kid` header of each signed token request, for providers that pick the verification key by its ID |
| assertion\_audience | --- | `aud` claim of each signed token request - defaults to `auth_endpoint`, Auth0 needs the tenant URL with a trailing slash instead |
| certificate | --- | PEM certificate of the private key - with it, the `x5t` and `x5t#S256` thumbprint headers Microsoft Entra ID looks for are sent |
| grant\_type | --- | OAuth grant type (default is `client_credentials`) |
| client\_id\_field | --- | Name of the client ID field sent to the token endpoint (default is `client_id`) |
| client\_secret\_field | --- | Name of the client secret field sent to the token endpoint (default is `client_secret`) |
| data\_format | --- | Format of the token request (default is `form`) |
| extra\_fields | --- | List of additional fields to include in the token request, e.g. `audience=https://api.example.com` |
| scopes | --- | Scopes requested with each outgoing token |
| issuer | --- | Expected `iss` claim of inbound JWTs - defaults to the scheme and host of `auth_endpoint` |
| jwks\_url | --- | Where the identity provider publishes its signing keys - defaults to the issuer's discovery document |
| audience | --- | Expected `aud` claim of inbound JWTs - required for inbound verification, a definition without it never matches inbound traffic |
| claims | --- | List of `name=value` entries an inbound JWT must include in addition to the standard claims |
| identity\_claim | --- | Name of the claim that identifies the caller behind an inbound JWT, e.g. `preferred_username` - with it, the caller's identity is `<name>/<claim value>` rather than the definition's name alone |
| is\_active | --- | Whether the definition is active (default is `true`) |

Fields of static definitions:

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique name of the security definition |
| type | Yes | Must be `bearer_token` |
| static\_token | Yes | The token itself - can be set via an environment variable, is never exported |
| static\_header | --- | The header the token is sent in (default is `Authorization`) |
| static\_prefix | --- | The prefix before the token in the header (default is `bearer`) |
| is\_active | --- | Whether the definition is active (default is `true`) |

```yaml
security:
  - name: enmasse.bearer_token.1
    type: bearer_token
    username: enmasse.1
    password: Zato_Enmasse_Env.EnmasseBearerToken1
    auth_endpoint: https://example.com/oauth/token
    client_id_field: username
    client_secret_field: password
    grant_type: password
    data_format: form

  - name: enmasse.bearer_token.2
    type: bearer_token
    username: enmasse.2
    password: Zato_Enmasse_Env.EnmasseBearerToken2
    auth_endpoint: https://example.com/oauth/token
    extra_fields:
      - audience=https://api.example.com

  # A definition that logs in to the token endpoint with a private key JWT - there is no password,
  # the key comes from an environment variable and only its signature ever reaches the provider
  - name: enmasse.bearer_token.private_key_jwt
    type: bearer_token
    username: orders-backend
    auth_endpoint: https://fhir.example.com/oauth2/token
    client_auth_method: private_key_jwt
    jwt_algorithm: RS384
    key_id: orders-key-1
    private_key: Zato_Enmasse_Env.EnmasseBearerTokenPrivateKey
    scopes: system/Patient.read

  # A JWT definition with inbound verification
  - name: enmasse.bearer_token.inbound
    type: bearer_token
    username: enmasse.3
    password: Zato_Enmasse_Env.EnmasseBearerTokenInbound
    auth_endpoint: https://keycloak.example.com/realms/prod/protocol/openid-connect/token
    issuer: https://keycloak.example.com/realms/prod
    jwks_url: https://keycloak.example.com/realms/prod/protocol/openid-connect/certs
    audience: orders-api
    claims:
      - department=Accounting

  # A definition for people signing in to an MCP gateway with OAuth on - nothing is sent
  # to the identity provider, so there is no auth_endpoint and the username is a label
  - name: enmasse.bearer_token.mcp
    type: bearer_token
    username: mcp-billing
    issuer: https://keycloak.example.com/realms/prod
    audience: zato-mcp
    identity_claim: preferred_username
    claims:
      - groups=billing-agents

  # A static token sent as-is with each request
  - name: enmasse.bearer_token.3
    type: bearer_token
    static_token: Zato_Enmasse_Env.EnmasseStaticToken
    static_header: X-Auth-Token
    static_prefix: Token
```

### wss {#wss}

[WS-Security](https://zato.io/docs/security/ws-security.html) definitions attach to SOAP channels and outgoing SOAP connections. Each definition has a mode - `username_token`, `x509` or `saml` - and the mode determines which of the remaining fields apply.

Fields common to all modes:

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique name of the security definition |
| type | Yes | Must be `wss` |
| username | Yes | Username |
| mode | Yes | One of `username_token`, `x509` or `saml` |
| password | --- | Password - can be set via an environment variable |
| is\_active | --- | Whether the definition is active (default is `true`) |

Fields of the `username_token` mode:

| Name | Required | Description |
| --- | --- | --- |
| use\_digest | --- | Whether the password is sent in digest form, with a nonce and timestamp, instead of as text (default is `false`) |

Fields of the `x509` mode:

| Name | Required | Description |
| --- | --- | --- |
| sign | --- | Whether to sign messages with the signing key (default is `false`) |
| encrypt | --- | Whether to encrypt message bodies to the peer certificate (default is `false`) |
| signing\_key | --- | Your own private key, PEM |
| signing\_certificate\_chain | --- | Your own certificate and any intermediates, PEM - sent along so the receiver can verify the signature |
| decryption\_key | --- | The key that decrypts what arrives encrypted to you, PEM |
| peer\_certificate | --- | The other side's certificate, PEM - used both to encrypt to them and to pin their signatures |
| trust\_anchors | --- | CA certificates the other side's signing certificates may chain up to instead of pinning, PEM |

Fields of the `saml` mode:

| Name | Required | Description |
| --- | --- | --- |
| issuer | --- | Who vouches for the assertion |
| subject | --- | The user or system the assertion is about |
| audience | --- | Who the assertion is meant for |
| sign | --- | Whether to sign the assertion (default is `false`) - uses `signing_key` and `signing_certificate_chain`, with `trust_anchors` validating incoming assertions |

```yaml
security:
  - name: enmasse.wss.token
    type: wss
    username: enmasse.1
    password: Zato_Enmasse_Env.EnmasseWSSToken
    mode: username_token
    use_digest: true

  - name: enmasse.wss.x509
    type: wss
    username: enmasse.2
    mode: x509
    sign: true
    encrypt: true
    signing_key: |-
      -----BEGIN PRIVATE KEY-----
      ...
      -----END PRIVATE KEY-----
    signing_certificate_chain: |-
      -----BEGIN CERTIFICATE-----
      ...
      -----END CERTIFICATE-----
    decryption_key: |-
      -----BEGIN PRIVATE KEY-----
      ...
      -----END PRIVATE KEY-----
    peer_certificate: |-
      -----BEGIN CERTIFICATE-----
      ...
      -----END CERTIFICATE-----
    trust_anchors: |-
      -----BEGIN CERTIFICATE-----
      ...
      -----END CERTIFICATE-----

  - name: enmasse.wss.saml
    type: wss
    username: enmasse.3
    mode: saml
    issuer: https://idp.example.com
    subject: CN=Example Subject
    audience: https://api.example.com
    sign: true
    signing_key: |-
      -----BEGIN PRIVATE KEY-----
      ...
      -----END PRIVATE KEY-----
    signing_certificate_chain: |-
      -----BEGIN CERTIFICATE-----
      ...
      -----END CERTIFICATE-----
```

Further reading: [API authentication](https://zato.io/docs/dev/rest/authentication.html), [SOAP security](https://zato.io/docs/dev/soap/security/index.html)

## Rate limiting on security definitions {#rate-limiting-on-security-definitions}

Rate limiting on security definitions uses the same nested `rate_limiting` key inside each `security` entry. The rules apply to every channel that uses the definition - the limit follows the credential, not the endpoint. If a partner authenticates to five different channels, they all share one set of counters.

The rule and time range structure is identical to the [channel rate limiting](https://zato.io/docs/admin/enmasse-reference.html#rate-limiting-on-rest-channels) section above.

```yaml
security:

  # Partner gets 1,000 requests per hour across all channels they call
  - name: partner-acme
    type: basic_auth
    username: acme
    password: Zato_Enmasse_Env.AcmePassword
    rate_limiting:
      - cidr_list: []
        time_range:
          - is_all_day: true
            disabled: false
            disallowed: false
            rate: 20
            burst: 40
            limit: 1000
            limit_unit: hour

  # External vendor limited to 500/day, only from their known IP range
  - name: vendor-logistics
    type: apikey
    password: Zato_Enmasse_Env.LogisticsApiKey
    rate_limiting:
      - cidr_list:
          - 198.51.100.0/24
        time_range:
          - is_all_day: true
            disabled: false
            disallowed: false
            rate: 5
            burst: 10
            limit: 500
            limit_unit: day
      - cidr_list: []
        time_range:
          - is_all_day: true
            disabled: false
            disallowed: true
            rate: 0
            burst: 0
            limit: 0
            limit_unit: minute

  # Gold tier partner - 50,000 per hour
  - name: partner-gold
    type: basic_auth
    username: gold
    password: Zato_Enmasse_Env.GoldPassword
    rate_limiting:
      - cidr_list: []
        time_range:
          - is_all_day: true
            disabled: false
            disallowed: false
            rate: 100
            burst: 200
            limit: 50000
            limit_unit: hour

  # Silver tier partner - 5,000 per hour
  - name: partner-silver
    type: basic_auth
    username: silver
    password: Zato_Enmasse_Env.SilverPassword
    rate_limiting:
      - cidr_list: []
        time_range:
          - is_all_day: true
            disabled: false
            disallowed: false
            rate: 10
            burst: 20
            limit: 5000
            limit_unit: hour

  # Deny all traffic for a retired API key
  - name: apikey-retired
    type: apikey
    password: Zato_Enmasse_Env.RetiredKey
    rate_limiting:
      - cidr_list: []
        time_range:
          - is_all_day: true
            disabled: false
            disallowed: true
            rate: 0
            burst: 0
            limit: 0
            limit_unit: minute

  # Internal service account - higher limits during nightly ETL, strict during the day
  - name: etl-service-account
    type: basic_auth
    username: etl
    password: Zato_Enmasse_Env.EtlPassword
    rate_limiting:
      - cidr_list: []
        time_range:
          - is_all_day: true
            disabled: false
            disallowed: false
            rate: 10
            burst: 20
            limit: 1000
            limit_unit: hour
          - is_all_day: false
            time_from: "00:00"
            time_to: "04:00"
            disabled: false
            disallowed: false
            rate: 200
            burst: 500
            limit: 200000
            limit_unit: hour
```

For a full explanation of all rate limiting concepts, see the [Rate limiting and firewall](https://zato.io/docs/admin/guide/rate-limit.html) chapter.

## On-prem gateways {#on-prem-gateways}

Key: `on_prem_gateway`

An [on-prem gateway](https://zato.io/docs/admin/on-prem-gateway/index.html) connects a cloud-hosted Zato environment to systems on a private network. A file contains the name of a gateway, whether it is active, how it is enrolled again and the on-prem systems it provides access to. Enrollment tokens and keys are never exported.

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique name of the gateway |
| is\_active | --- | Whether the gateway may connect, `true` by default |
| is\_key\_reset\_required | --- | Whether a new enrollment token is accepted only after a key reset, `true` by default. When `false`, a new token replaces the key on file, as described in [Re-enrollment](https://zato.io/docs/admin/on-prem-gateway/index.html#re-enrollment) |
| hosts | --- | List of on-prem systems the gateway provides access to, as `host:port` |

A system belongs to exactly one gateway, so the same `host:port` must not appear under two gateways.

```yaml
on_prem_gateway:

  - name: head-office
    is_active: true
    hosts:
      - erp-db.corp.local:5432
      - crm.corp.local:443

  - name: data-center
    is_active: true
    is_key_reset_required: false
    hosts:
      - sap.corp.local:3300

outgoing_sql:

  - name: erp
    host: erp-db.corp.local
    port: 5432
    engine: postgresql
    db_name: production
    username: zato
    password: Zato_Enmasse_Env.ERPPassword
```

The outgoing connection names the host and the port of the on-prem system. No property of it refers to the gateway, so the same file applies whether the Zato environment runs in the cloud or on the private network.

## Quota tiers {#quota-tiers}

Key: `quota_tier`

A [quota tier](https://zato.io/docs/security/quota-tiers.html) is a named, reusable set of rate limiting rules. Instead of repeating the same `rate_limiting` block across many security definitions, define the rules once as a tier and reference it by name with a `quota_tier` key - on a security definition or on a [security group](https://zato.io/docs/admin/enmasse-reference.html#security-groups).

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique name of the tier |
| description | --- | Free-form description |
| rules | --- | List of rate limiting rules, structured like the [rate limiting](https://zato.io/docs/admin/enmasse-reference.html#rate-limiting-on-rest-channels) `rate_limiting` key |

A security definition either references a tier or has its own `rate_limiting` rules, never both. A YAML entry with both keys is rejected at import. When an import updates an existing definition, the key its YAML entry has replaces the other one stored in the database - a definition moved from its own rules to a tier loses its rules, and one moved from a tier to its own rules loses its tier.

```yaml
quota_tier:

  - name: tier.gold
    description: Gold partners - 50,000 requests per hour
    rules:
      - cidr_list: []
        time_range:
          - is_all_day: true
            disabled: false
            disallowed: false
            rate: 100
            burst: 200
            limit: 50000
            limit_unit: hour

security:

  - name: partner-gold
    type: basic_auth
    username: gold
    password: Zato_Enmasse_Env.GoldPassword
    quota_tier: tier.gold
```

The [Quota tiers](https://zato.io/docs/admin/guide/quota-tiers.html) chapter explains how tiers and direct rules interact.

## Scheduler jobs {#scheduler-jobs}

Key: `scheduler`

At least one interval field (`weeks`, `days`, `hours`, `minutes` or `seconds`) must be non-zero.

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique name of the scheduler job |
| service | Yes | Name of the Zato service that the job invokes |
| job\_type | Yes | Type of the job - must be `interval_based` |
| start\_date | Yes | Date and time when the job first becomes eligible to run, e.g. `2027-01-01 00:00:00` |
| is\_active | --- | Whether the job is active (default is `true`) |
| weeks | --- | Number of weeks between runs (default is `0`) |
| days | --- | Number of days between runs (default is `0`) |
| hours | --- | Number of hours between runs (default is `0`) |
| minutes | --- | Number of minutes between runs (default is `1`) |
| seconds | --- | Number of seconds between runs (default is `0`) |
| repeats | --- | How many times the job should run before stopping (default is unlimited) |
| extra | --- | List of extra lines passed to the service as input |

```yaml
scheduler:
  - name: enmasse.scheduler.1
    service: demo.ping
    job_type: interval_based
    start_date: '2027-01-11 11:23:52'
    seconds: 2
    is_active: true

  - name: enmasse.scheduler.2
    service: demo.ping
    job_type: interval_based
    start_date: '2027-02-19 12:00:00'
    hours: 3
```

For Python scheduler examples, visit the [scheduler examples](https://zato.io/docs/dev/examples/scheduler.html) page.

## SQL connections {#sql-connections}

Key: `sql`

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique name of the connection |
| type | Yes | Database engine type - one of `mysql`, `oracle`, `postgresql`, `mssql`, `snowflake` or `redshift` |
| host | Yes | Database server host |
| port | Yes | Database server port |
| db\_name | Yes | Name of the database to connect to |
| username | Yes | Database username |
| password | --- | Database password - can be set via an environment variable |
| pool\_size | --- | Size of the connection pool (default is `5`) |
| timeout | --- | Connection timeout in seconds |
| extra | --- | List of extra connection parameters, e.g. `connect_timeout=10` |
| audit\_log | --- | What the [audit log](https://zato.io/docs/admin/audit-log/index.html) records for the connection - one of `off`, `statement`, `statement-params` or `full` (default is `off`) |
| is\_audit\_export\_payload\_active | --- | Whether the statements and rows the audit log records leave with the [OpenTelemetry export](https://zato.io/docs/admin/audit-log/opentelemetry.html) (default is `false`, exported only when `true`) |
| ssl | --- | Whether to connect over TLS (default is `false`) |
| ssl\_ca\_file | --- | Path to a PEM file with the CA certificates that signed the server's certificate |
| ssl\_cert\_file | --- | Path to the client certificate, for mutual TLS |
| ssl\_key\_file | --- | Path to the client private key, for mutual TLS |
| ssl\_verify | --- | Whether to validate the server's TLS certificate (default is `true`) |
| is\_active | --- | Whether the connection is active (default is `true`) |

```yaml
sql:
  - name: enmasse.sql.1
    type: mysql
    host: 127.0.0.1
    port: 3306
    db_name: mydb
    username: enmasse.1
    password: Zato_Enmasse_Env.SQL_Password_1

  - name: enmasse.sql.2
    type: mssql
    host: 10.152.81.199
    port: 1433
    db_name: mydb
    username: enmasse.2
    password: Zato_Enmasse_Env.SQL_Password_2
    extra:
      - connect_timeout=10
    pool_size: 10
    audit_log: statement

  - name: enmasse.sql.3
    type: snowflake
    host: myorg-myaccount
    port: 443
    db_name: MYDB
    username: enmasse.3
    password: Zato_Enmasse_Env.SQL_Password_3
    extra:
      - warehouse=COMPUTE_WH
      - role=ANALYST
      - schema=PUBLIC

  - name: enmasse.sql.4
    type: redshift
    host: examplecluster.abc123xyz789.us-west-2.redshift.amazonaws.com
    port: 5439
    db_name: mydb
    username: enmasse.4
    password: Zato_Enmasse_Env.SQL_Password_4
    ssl: true
    ssl_ca_file: /path/to/ca.pem
```

With Snowflake, the `host` field is the account identifier, e.g. `myorg-myaccount`, not a hostname, and the `port` field is always `443`.

Database-specific guides: [MySQL](https://zato.io/docs/dev/examples/sql/mysql.html) · [PostgreSQL](https://zato.io/docs/dev/examples/sql/postgresql.html) · [Oracle](https://zato.io/docs/dev/examples/sql/oracle.html) · [Microsoft SQL Server](https://zato.io/docs/dev/examples/sql/mssql.html) · [Snowflake](https://zato.io/docs/dev/examples/sql/snowflake.html) · [Amazon Redshift](https://zato.io/docs/dev/examples/sql/redshift.html)

## MongoDB {#mongodb}

Key: `mongodb` (alias: `outgoing_mongodb`)

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique name of the connection |
| server\_list | Yes | One or more `host:port` entries, separated with newlines (default is `localhost:27017`) |
| username | --- | Username to authenticate with |
| password | --- | Password - can be set via an environment variable |
| auth\_source | --- | Database to authenticate against (default is `admin`) |
| replica\_set | --- | Name of the replica set to require, if any |
| app\_name | --- | Application name reported to the server (default is `Zato`) |
| pool\_size\_max | --- | Maximum size of the connection pool (default is `10`) |
| connect\_timeout | --- | Connection timeout in seconds (default is `10`) |
| server\_select\_timeout | --- | Server selection timeout in seconds (default is `5`) |
| is\_tls\_enabled | --- | Whether to connect over TLS (default is `false`) |
| tls\_ca\_certs\_file | --- | Path to a PEM file with the CA certificates that signed the server's certificate |
| tls\_cert\_key\_file | --- | Path to a combined client certificate and private key PEM file, for mutual TLS |
| is\_tls\_validation\_enabled | --- | Whether to validate the server's TLS certificate (default is `true`) |
| is\_active | --- | Whether the connection is active (default is `true`) |

```yaml
mongodb:
  - name: enmasse.mongodb.1
    server_list: localhost:27017
    username: enmasse
    password: Zato_Enmasse_Env.Enmasse_MongoDB_Password

  - name: enmasse.mongodb.2
    server_list: |-
      mongodb1.example.com:27017
      mongodb2.example.com:27017
    username: enmasse
    password: Zato_Enmasse_Env.Enmasse_MongoDB_Password
    replica_set: rs0
    is_tls_enabled: true
    tls_ca_certs_file: /path/to/ca.pem
    tls_cert_key_file: /path/to/client.pem
```

More details in the [MongoDB programming](https://zato.io/docs/dev/examples/mongodb.html) chapter.

## Email - IMAP {#email-imap}

Key: `email_imap`

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique name of the connection |
| host | Yes | IMAP server host |
| port | Yes | IMAP server port |
| username | Yes | Username |
| password | --- | Password - can be set via an environment variable |
| mode | --- | Connection mode, e.g. `ssl` or `plain` (default is `plain`) |
| timeout | --- | Connection timeout in seconds (default is `30`) |
| debug\_level | --- | Debug level for the IMAP library (default is `0`) |
| get\_criteria | --- | Criteria used to fetch messages (default is `{}`) |
| is\_active | --- | Whether the connection is active (default is `true`) |
| scheduler\_run\_every | --- | How often to poll the mailbox, e.g. `5` - requires the other scheduler fields too |
| scheduler\_run\_unit | --- | Unit for `scheduler_run_every` - one of `seconds`, `minutes`, `hours` or `days` |
| scheduler\_start\_date | --- | When to start polling, e.g. `2026-01-01T00:00:00` |
| scheduler\_service | --- | Service invoked for each message received from the mailbox |
| scheduler\_invoke\_with | --- | What `scheduler_service` receives on input - `message` (default) or `each_attachment` |
| is\_audit\_log\_active | --- | Whether the connection's traffic goes to the audit log (default is `true`, exported only when `false`) |
| is\_audit\_export\_payload\_active | --- | Whether the connection's request and response payloads leave with the [OpenTelemetry export](https://zato.io/docs/admin/audit-log/opentelemetry.html) of the audit log (default is `false`, exported only when `true`) |

If the scheduler fields are given, a scheduler job is auto-created for the connection. The job polls the mailbox on the configured interval and invokes `scheduler_service` with each message received. With `scheduler_invoke_with` set to `message`, the service is invoked once per message, with the message object on input. With `each_attachment`, the message's body is ignored and the service is invoked once per each of the message's attachments, with an attachment object on input. Messages are marked as seen automatically once the service returns without an exception, otherwise they are received anew on the next run. The fields `scheduler_run_every`, `scheduler_start_date` and `scheduler_service` must be given together.

```yaml
email_imap:
  - name: enmasse.email.imap.1
    host: imap.example.com
    port: 993
    username: enmasse@example.com
    password: Zato_Enmasse_Env.IMAPPassword

  - name: enmasse.email.imap.2
    host: imap.example.com
    port: 993
    username: enmasse@example.com
    password: Zato_Enmasse_Env.IMAPPassword
    scheduler_run_every: 5
    scheduler_run_unit: minutes
    scheduler_start_date: 2026-01-01T00:00:00
    scheduler_service: demo.ping
    scheduler_invoke_with: each_attachment
```

Read the [Python IMAP email](https://zato.io/docs/dev/examples/imap.html) guide, including Microsoft 365 and OAuth2.

## Email - SMTP {#email-smtp}

Key: `email_smtp`

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique name of the connection |
| host | Yes | SMTP server host |
| port | Yes | SMTP server port |
| username | --- | Username |
| password | --- | Password - can be set via an environment variable |
| mode | --- | Connection mode, e.g. `starttls` or `plain` (default is `plain`) |
| timeout | --- | Connection timeout in seconds (default is `60`) |
| ping\_address | --- | Email address used to ping the connection |
| is\_debug | --- | Whether to enable debug output (default is `false`) |
| is\_active | --- | Whether the connection is active (default is `true`) |
| is\_audit\_log\_active | --- | Whether the connection's traffic goes to the audit log (default is `true`, exported only when `false`) |
| is\_audit\_export\_payload\_active | --- | Whether the connection's request and response payloads leave with the [OpenTelemetry export](https://zato.io/docs/admin/audit-log/opentelemetry.html) of the audit log (default is `false`, exported only when `true`) |

```yaml
email_smtp:
  - name: enmasse.email.smtp.1
    host: smtp.example.com
    port: 587
    username: enmasse@example.com
    password: Zato_Enmasse_Env.SMTPPassword
```

More details in the [Python SMTP email](https://zato.io/docs/dev/examples/smtp.html) chapter.

## LDAP {#ldap}

Key: `ldap`

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique name of the connection |
| username | Yes | Distinguished name (DN) of the user to bind as |
| server\_list | Yes | Comma-separated list of LDAP servers, e.g. `127.0.0.1:389` |
| auth\_type | --- | Authentication type, e.g. `NTLM` or `SIMPLE` |
| password | --- | Password - can be set via an environment variable |
| is\_active | --- | Whether the connection is active (default is `true`) |

```yaml
ldap:
  - name: enmasse.ldap.1
    username: 'CN=enmasse,OU=testing,OU=Servers,DC=enmasse'
    auth_type: NTLM
    server_list: 127.0.0.1:389
    password: Zato_Enmasse_Env.Enmasse_LDAP_Password
```

See [custom authentication](https://zato.io/docs/dev/rest/custom-auth.html) for how to use LDAP credentials in services.

## OData {#odata}

Key: `odata`

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique name of the connection |
| address | Yes | Service root URL, e.g. `https://example.com/sap/opu/odata/sap/API_SALES_ORDER_SRV/` |
| odata\_version | --- | OData version, `2.0` or `4.0` (default is `4.0`) |
| auth\_type | --- | Authentication type, one of `no-auth`, `basic`, `bearer` or `oauth2` (default is `basic`) |
| username | --- | Username, for Basic Auth |
| secret | --- | Password or bearer token - can be set via an environment variable |
| token\_url | --- | OAuth2 token URL, e.g. `https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token` |
| tenant\_id | --- | OAuth2 tenant ID - when given, it is substituted into the token URL |
| client\_id | --- | OAuth2 client ID |
| client\_secret | --- | OAuth2 client secret - can be set via an environment variable |
| scopes | --- | OAuth2 scopes, e.g. `https://api.businesscentral.dynamics.com/.default` |
| needs\_csrf\_token | --- | Whether to exchange SAP X-CSRF-Token headers for write operations (default is `false`) |
| page\_size | --- | Server-driven page size requested via `Prefer: odata.maxpagesize` (default is `0`, meaning the page size is left to the server) |
| timeout | --- | Connection timeout in seconds (default is `60`) |
| pool\_size | --- | Connection pool size (default is `1`) |
| is\_active | --- | Whether the connection is active (default is `true`) |

```yaml
odata:
  - name: enmasse.odata.1
    address: https://example.com/sap/opu/odata/sap/API_SALES_ORDER_SRV/
    odata_version: "2.0"
    auth_type: basic
    username: enmasse.odata.user.1
    needs_csrf_token: true
    secret: Zato_Enmasse_Env.Enmasse_OData_Secret

  - name: enmasse.odata.2
    address: https://api.businesscentral.dynamics.com/v2.0/my-tenant/sandbox/api/v2.0/
    odata_version: "4.0"
    auth_type: oauth2
    token_url: https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token
    tenant_id: my-tenant
    client_id: my-client-id
    scopes: https://api.businesscentral.dynamics.com/.default
    client_secret: Zato_Enmasse_Env.Enmasse_OData_Client_Secret
```

More details in the [OData integrations](https://zato.io/docs/dev/odata/index.html) chapter.

## SMB {#smb}

Key: `smb` (alias: `outgoing_smb`)

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique name of the connection |
| host | Yes | SMB server host |
| port | --- | SMB server port (default is `445`) |
| username | --- | Username for NTLM authentication |
| password | --- | Password - can be set via an environment variable |
| is\_active | --- | Whether the connection is active (default is `true`) |

```yaml
smb:
  - name: enmasse.smb.1
    host: smb.example.com
    port: 445
    username: enmasse
    password: Zato_Enmasse_Env.Enmasse_SMB_Password
```

An SMB connection may also include a `schedules` list, each entry watching a directory and invoking a service once per file - see [file transfer in enmasse](https://zato.io/docs/dev/file-transfer/enmasse.html) for its fields, and the [file transfer](https://zato.io/docs/dev/file-transfer/index.html) chapter for everything else.

## FTP {#ftp}

Key: `ftp` (alias: `outgoing_ftp`)

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique name of the connection |
| host | Yes | FTP server host |
| port | --- | FTP server port (default is `21`) |
| username | --- | Username to log in with |
| password | --- | Password - can be set via an environment variable |
| use\_ssl | --- | Default is `false`. If `true`, the connection uses FTPS - FTP over TLS. |
| should\_store\_content | --- | Default is `false`. If `true`, the audit log keeps the bytes of each transferred file, in addition to the always-recorded metadata. |
| is\_active | --- | Whether the connection is active (default is `true`) |

```yaml
ftp:
  - name: enmasse.ftp.1
    host: ftp.example.com
    port: 21
    username: enmasse
    password: Zato_Enmasse_Env.Enmasse_FTP_Password
    use_ssl: true
```

An FTP connection may also include a `schedules` list, each entry watching a directory and invoking a service once per file - see [file transfer in enmasse](https://zato.io/docs/dev/file-transfer/enmasse.html) for its fields, and the [outgoing FTP connections](https://zato.io/docs/dev/file-transfer/ftp.html) page for everything else.

## SFTP {#sftp}

Key: `sftp` (alias: `outgoing_sftp`)

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique name of the connection |
| address | Yes | SFTP server address, optionally including a port, e.g. `example.com` or `example.com:22022` (default port is `22`) |
| username | --- | Username to log in with |
| password | --- | Password - can be set via an environment variable, and if the private key is encrypted, the password is its passphrase |
| private\_key | --- | Path to a private key file on the Zato server's filesystem, e.g. `/keys/id_ed25519` - the file is provided when the Zato container or server starts, typically through a mounted directory. If it is not given, system-level keys from `~/.ssh` are used. |
| strict\_host\_key\_checking | --- | Default is `true`, meaning the remote server's host key must already exist in `known_hosts` and connections to servers with unknown or changed keys are rejected. If `false`, keys of previously unknown hosts are accepted and recorded on first connection, while changed keys of known hosts are still rejected. |
| ignore\_host\_key\_changes | --- | Default is `false`. If `true`, any host key is accepted, known or changed, overriding `strict_host_key_checking` - meant for test servers and containers that regenerate their keys, never for production systems. |
| should\_store\_content | --- | Default is `false`. If `true`, the audit log keeps the bytes of each transferred file, in addition to the always-recorded metadata. |
| is\_active | --- | Whether the connection is active (default is `true`) |

```yaml
sftp:
  - name: enmasse.sftp.1
    address: sftp.example.com:22
    username: enmasse
    password: Zato_Enmasse_Env.Enmasse_SFTP_Password
    private_key: /keys/id_ed25519
    strict_host_key_checking: true
```

An SFTP connection may also include a `schedules` list, each entry watching a directory and invoking a service once per file - see [file transfer in enmasse](https://zato.io/docs/dev/file-transfer/enmasse.html) for its fields, and the [file transfer](https://zato.io/docs/dev/file-transfer/index.html) chapter for everything else.

## Confluence {#confluence}

Key: `confluence`

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique name of the connection |
| address | Yes | URL of the Confluence instance, e.g. `https://example.atlassian.net` |
| username | Yes | Username or email address |
| password | --- | API token or password - can be set via an environment variable |
| api\_version | --- | Confluence API version (default is `v1`) |
| is\_active | --- | Whether the connection is active (default is `true`) |

```yaml
confluence:
  - name: enmasse.confluence.1
    address: https://example.atlassian.net
    username: api_user@example.com
    password: Zato_Enmasse_Env.ConfluenceAPIToken
```

For calling external APIs in general, see [calling external REST APIs](https://zato.io/docs/dev/rest/calling-apis.html).

## Jira {#jira}

Key: `jira`

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique name of the connection |
| address | Yes | URL of the Jira instance, e.g. `https://example.atlassian.net` |
| username | Yes | Username or email address |
| password | --- | API token or password - can be set via an environment variable |
| api\_version | --- | Jira API version (default is `v1`) |
| is\_active | --- | Whether the connection is active (default is `true`) |

```yaml
jira:
  - name: enmasse.jira.1
    address: https://example.atlassian.net
    username: enmasse@example.com
    password: Zato_Enmasse_Env.JiraAPIToken
```

Practical examples are available in the [Jira integration examples](https://zato.io/docs/dev/examples/jira.html) chapter.

## Microsoft 365 {#microsoft-365}

Key: `microsoft_cloud`

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique name of the connection |
| client\_id | Yes | Azure application (client) ID |
| tenant\_id | Yes | Azure tenant ID |
| secret\_value | Yes | Client secret - can be set via an environment variable |
| scopes | --- | Space-separated list of OAuth scopes |
| is\_active | --- | Whether the connection is active (default is `true`) |

```yaml
microsoft_cloud:
  - name: enmasse.cloud.microsoft365.1
    client_id: 12345678-1234-1234-1234-123456789abc
    tenant_id: 87654321-4321-4321-4321-cba987654321
    secret_value: Zato_Enmasse_Env.Microsoft365SecretValue
    scopes: Mail.Read Mail.Send
```

Microsoft 365 IMAP connections are covered in the [Python IMAP email](https://zato.io/docs/dev/examples/imap.html) guide.

## Microsoft Teams {#microsoft-teams}

Key: `microsoft_teams`

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique name of the connection |
| client\_id | Yes | Azure application (client) ID |
| tenant\_id | Yes | Azure tenant ID |
| secret\_value | Yes | Client secret - can be set via an environment variable |
| scopes | --- | Space-separated list of OAuth scopes |
| is\_active | --- | Whether the connection is active (default is `true`) |

```yaml
microsoft_teams:
  - name: enmasse.chat.microsoft-teams.1
    client_id: 45678901-4567-4567-4567-4567890abcde
    tenant_id: 87654321-7654-7654-7654-fedcba987654
    secret_value: Zato_Enmasse_Env.MicrosoftTeamsSecretValue
    scopes: https://graph.microsoft.com/.default
```

Code examples are in the [Microsoft Teams](https://zato.io/docs/dev/examples/microsoft-teams.html) chapter.

## Slack {#slack}

Key: `slack`

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique name of the connection |
| token | Yes | Bot token - can be set via an environment variable |
| is\_active | --- | Whether the connection is active (default is `true`) |

```yaml
slack:
  - name: enmasse.chat.slack.1
    token: Zato_Enmasse_Env.SlackToken
```

Code examples are in the [Slack](https://zato.io/docs/dev/examples/slack.html) chapter.

## Odoo {#odoo}

Key: `odoo`

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique name of the connection |
| host | Yes | Odoo server host |
| user | Yes | Odoo username |
| database | Yes | Name of the Odoo database |
| port | --- | Odoo server port (default is `8069`) |
| password | --- | Password - can be set via an environment variable |
| protocol | --- | Protocol to use (default is `jsonrpc`) |
| pool\_size | --- | Size of the connection pool (default is `10`) |
| is\_active | --- | Whether the connection is active (default is `true`) |

```yaml
odoo:
  - name: enmasse.odoo.1
    host: odoo.example.com
    port: 8069
    user: admin
    password: Zato_Enmasse_Env.OdooPassword
    database: enmasse_db
```

Code examples are in the [Python Odoo integrations](https://zato.io/docs/dev/odoo/index.html) chapter.

## ElasticSearch {#elasticsearch}

Key: `elastic_search`

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique name of the connection |
| address\_list | Yes | Full URL or list of URLs of ElasticSearch servers, e.g. `https://elasticsearch:9200` - the scheme of each URL selects whether TLS is used |
| username | --- | Username to authenticate with, leave out if the server does not require authentication |
| password | --- | Password matching the username |
| timeout | --- | Request timeout in seconds (default is `90`) |
| is\_tls\_validation\_enabled | --- | Whether to verify the server's TLS certificate (default is `true`) |
| tls\_ca\_certs\_file | --- | Path to a PEM file with CA certificates to verify the server's certificate against |
| tls\_cert\_key\_file | --- | Path to a PEM file with a combined client certificate and private key, for mutual TLS |
| is\_active | --- | Whether the connection is active (default is `true`) |

```yaml
elastic_search:
  - name: enmasse.elastic.1
    address_list:
      - http://elasticsearch:9200
    timeout: 60
```

Usage examples: [Python ElasticSearch](https://zato.io/docs/dev/examples/search/elastic-search.html)

## LLM connections {#llm-connections}

Key: `llm`

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique name of the connection - services look it up with `self.llm` |
| model | Yes | Model name from the catalog, e.g. `Sonnet 5`, or a wire id entered by hand |
| address | Yes | Base URL of the API to call, e.g. `https://api.openai.com/v1` |
| secret | --- | API key - can be set via an environment variable, self-hosted endpoints may not need one |
| timeout | --- | How many seconds to wait for the provider's response (default is `60`) |
| max\_tokens | --- | The most tokens the model may generate per reply (default is `1024`) |
| max\_history\_turns | --- | How many past chat turns are sent to the provider (default is `20`) |
| chat\_expiry | --- | How many seconds a chat's history is kept after its last message (default is `86400`) |
| is\_active | --- | Whether the connection can be used (default is `true`) |
| alerts | --- | The alert settings the connection sets of its own - see below |

```yaml
llm:

  - name: My OpenAI
    model: gpt-4o-mini
    address: https://api.openai.com/v1
    secret: Zato_Enmasse_Env.My_OpenAI_API_Key
    timeout: 30

  - name: My Claude
    model: Sonnet 5
    address: https://api.anthropic.com
    secret: Zato_Enmasse_Env.My_Claude_API_Key

  # A connection with alert settings of its own - the same mapping as on an outgoing REST connection,
  # plus the completions and the tokens
  - name: My Monitored OpenAI
    model: gpt-4o
    address: https://api.openai.com/v1
    secret: Zato_Enmasse_Env.My_OpenAI_API_Key
    alerts:
      status_codes: 429, 5xx
      token_budget: 2000000
      token_budget_window: 3600
      truncations: 5
      refusals: 2
      email_connection: smtp:enmasse.smtp.1
```

The `alerts` mapping takes the same settings as the one of [outgoing REST connections](https://zato.io/docs/admin/enmasse-reference.html#outgoing-rest-connections), with `warning_latency` and `error_latency` in place of `max_latency`, plus six of its own - `truncations`, `truncations_window`, `refusals`, `refusals_window`, `token_budget` and `token_budget_window` - and only the settings that differ from their defaults are exported.

`status_codes` defaults to `429, 401, 403, 5xx` - a 429 is the provider's rate limit, a 401 or a 403 a key that is wrong or lacks access to the model, a 5xx the provider's own trouble. `truncations` is how many completions cut short for reaching the connection's `max_tokens` raise an alert within `truncations_window` seconds, `refusals` how many completions the provider declined or a content filter blocked - both arrive as an HTTP 200 and are told apart from an answer by nothing but the finish reason the provider sent. `token_budget` is how many tokens, input and output added up across every call, the connection may use within `token_budget_window` seconds, `10000000` in `86400` by default. The two latencies are in seconds and take fractions, `12.5` being twelve and a half seconds.

The [AI enmasse](https://zato.io/docs/ai/enmasse.html) chapter covers LLM connections in more detail.

## Security groups {#security-groups}

Key: `groups`

Each entry defines a named group of security definitions. Groups can then be referenced from REST channels to control access.

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique name of the group |
| members | --- | List of security definition names that belong to this group |
| quota\_tier | --- | Name of a [quota tier](https://zato.io/docs/admin/enmasse-reference.html#quota-tiers) that every member of the group follows, unless a member has its own rules or its own tier |

```yaml
groups:
  - name: enmasse.group.1
    members:
      - enmasse.basic_auth.1
      - enmasse.basic_auth.2
      - enmasse.apikey.1

  - name: enmasse.group.2
    quota_tier: tier.gold
    members:
      - enmasse.apikey.1
      - enmasse.apikey.2
```

On import, the `members` list of a group in the file replaces the group's current members. A security definition removed from the list is removed from the group and remains in the environment.

Groups are used together with REST channels - see [REST channels](https://zato.io/docs/dev/rest/channels.html) for details.

## MCP gateways {#mcp-gateways}

Key: `mcp_gateway`

Each entry defines an [MCP gateway](https://zato.io/docs/ai/mcp/index.html) that exposes services as tools for AI agents.

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique name of the gateway |
| url\_path | --- | URL path the MCP endpoint is exposed under, e.g. `/mcp/billing` (default is `/mcp`) |
| services | --- | List of service names exposed as tools |
| security\_groups | --- | List of security group names whose members may call the gateway - see [MCP gateway security](https://zato.io/docs/ai/mcp/security.html) |
| oauth | --- | Whether people sign in through an identity provider, as described under [OAuth for MCP gateways](https://zato.io/docs/ai/mcp/oauth.html) - one of the groups' members has to be a bearer token definition with an issuer and an audience (default is `false`) |
| oauth\_scopes | --- | With `oauth` on, the scopes the gateway's metadata document tells clients to ask for, separated with spaces, e.g. `openid profile` |
| is\_active | --- | Whether the gateway accepts requests (default is `true`) |
| is\_audit\_log\_active | --- | Whether the [MCP audit log](https://zato.io/docs/ai/mcp/audit-log.html) records the gateway's traffic (default is `false` when absent) |
| skills | --- | List of [skills](https://zato.io/docs/ai/skills/index.html) served as MCP prompts |
| session\_ttl | --- | Idle session TTL in seconds - `0`, the default, keeps the built-in 30 minutes |
| invoke\_timeout | --- | How many seconds one `tools/call` invocation may run for - `0`, the default, keeps the built-in 90 |
| validate\_input | --- | Whether tool arguments are [validated](https://zato.io/docs/ai/mcp/argument-validation.html) against each tool's schema (default is `false`) |
| allow\_agent\_filters | --- | Whether agents may attach per-call JSONata [response filters](https://zato.io/docs/ai/mcp/agent-filters.html) (default is `false`) |

A gateway also accepts the [response controls](https://zato.io/docs/ai/mcp/response-controls.html) settings - the `max_response_size`, `size_cap_mode`, `min_size_threshold` and `characters_per_token` response shaping fields plus all the `safeguards_*` fields for compaction, PII removal, secrets removal and content safety. The [AI enmasse](https://zato.io/docs/ai/enmasse.html) chapter lists every one of them with its default.

```yaml
mcp_gateway:
  - name: enmasse.mcp.gateway.1
    is_active: true
    is_audit_log_active: true
    url_path: /mcp/enmasse-1
    services:
      - crm.get-customer
      - crm.update-customer
    security_groups:
      - enmasse.group.1
    validate_input: true
    max_response_size: 2000
    safeguards_pii_enabled: true

  # A gateway people sign in to through the identity provider of its bearer token definition
  - name: enmasse.mcp.gateway.oauth
    url_path: /mcp/enmasse-oauth
    oauth: true
    oauth_scopes: openid profile
    services:
      - crm.get-customer
    security_groups:
      - enmasse.group.oauth
```

## Rule engine API {#rule-engine-api}

Key: `rule_engine_api`

Each entry exposes [rule engine](https://zato.io/docs/rule-engine/tutorial.html) rulesets over a REST endpoint.

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique name of the API endpoint |
| url\_path | --- | URL path the endpoint is exposed under (default is `/api/rules`) |
| rulesets | --- | List of ruleset names the endpoint serves |
| security\_groups | --- | List of security group names whose members may call the endpoint |
| is\_active | --- | Whether the endpoint accepts requests (default is `true`) |

```yaml
rule_engine_api:
  - name: enmasse.rules.1
    url_path: /api/rules/pricing
    rulesets:
      - pricing
      - discounts
    security_groups:
      - enmasse.group.1
```

## OpenAPI channels {#openapi-channels}

Key: `channel_openapi`

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique name of the OpenAPI channel |
| url\_path | Yes | URL path where the OpenAPI specification is served, e.g. `/openapi/my-api` |
| rest\_channel\_list | --- | List of REST channel names to include in the specification |
| is\_active | --- | Whether the channel is active (default is `true`) |

```yaml
channel_openapi:
  - name: enmasse.channel.openapi.1
    url_path: /openapi/enmasse-1
    rest_channel_list:
      - enmasse.channel.rest.1
      - enmasse.channel.rest.2
```

The [OpenAPI specifications](https://zato.io/docs/dev/rest/openapi.html) chapter explains how OpenAPI channels work.

## HL7 MLLP channels {#hl7-mllp-channels}

Key: `channel_mllp`

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique channel name |
| service | Yes | Service invoked for each incoming message |
| is\_active | --- | Whether the channel accepts connections (default `true`) |
| should\_validate | --- | Validate parsed messages against the HL7 schema (default `false`) |
| should\_parse\_on\_input | --- | Parse raw ER7 into structured objects before the service is invoked (default `true`) |
| should\_log\_messages | --- | Log incoming messages (default `false`) |
| should\_return\_errors | --- | Include error details in NAK responses (default `false`) |
| normalize\_line\_endings | --- | Convert CRLF/LF to CR (default `true`) |
| force\_standard\_delimiters | --- | Rewrite non-standard delimiters to `^~\&` (default `true`) |
| restore\_truncated\_msh | --- | Pad short MSH segments (default `true`) |
| split\_concatenated\_messages | --- | Split multi-MSH payloads into separate messages (default `true`) |
| use\_msh18\_encoding | --- | Use MSH-18 for character encoding (default `true`) |
| normalize\_obx2\_value\_type | --- | Fill empty OBX-2 with ST (default `true`) |
| replace\_invalid\_obx2\_value\_type | --- | Replace invalid OBX-2 with ST (default `true`) |
| normalize\_invalid\_escape\_sequences | --- | Strip unmatched escapes (default `true`) |
| normalize\_obx8\_abnormal\_flags | --- | Clear OBX-8 literal null (default `true`) |
| normalize\_quadruple\_quoted\_empty | --- | Strip multi-quote sequences (default `true`) |
| allow\_short\_encoding\_characters | --- | Pad short MSH-2 (default `true`) |
| fix\_off\_by\_one\_field\_index | --- | Remove spurious leading field (default `false`) |
| msh9\_message\_type | --- | Routing filter on MSH-9.1 |
| msh9\_trigger\_event | --- | Routing filter on MSH-9.2 |
| default\_character\_encoding | --- | Default encoding (default `utf-8`) |
| dedup\_ttl\_value | --- | Deduplication window value |
| dedup\_ttl\_unit | --- | Deduplication window unit (minutes, hours, or days) |
| is\_audit\_log\_active | --- | Whether the channel's traffic goes to the audit log (default `true`) |
| is\_audit\_export\_payload\_active | --- | Whether the channel's request and response payloads leave with the [OpenTelemetry export](https://zato.io/docs/admin/audit-log/opentelemetry.html) of the audit log (default is `false`, exported only when `true`) |
| alerts | --- | The alert settings the channel sets of its own - see below |

```yaml
channel_mllp:

  - name: enmasse.hl7.lab-results
    service: hl7.process-lab-results
    should_validate: true
    normalize_line_endings: true
    msh9_message_type: ORU

  - name: enmasse.hl7.admissions
    service: hl7.process-admissions
    msh9_message_type: ADT
    msh9_trigger_event: A01
    dedup_ttl_value: 60
    dedup_ttl_unit: minutes

  - name: enmasse.hl7.default
    service: hl7.catch-all
    is_default: true
    fix_off_by_one_field_index: true

  # A channel with alert settings of its own - the rejects alone are counted, two of them in ten minutes raise an alert
  - name: enmasse.hl7.orders
    service: hl7.process-orders
    msh9_message_type: ORM
    alerts:
      ack_codes: AR, CR
      ack_threshold: 2
      acks_window: 600
      traffic_expected: true
      silence_window: 1800
      email_connection: smtp:enmasse.smtp.1
```

The `alerts` mapping takes `is_active`, `consecutive_failures`, `error_rate`, `window`, `max_latency`, `latency_window`, `traffic_expected`, `silence_window`, `use_llm`, `email_connection` and `llm_connection`, the settings a REST channel has minus everything that reads an HTTP status, plus three of its own - `ack_codes`, `ack_threshold` and `acks_window` - and only the settings that differ from their defaults are exported.

`ack_codes` is a comma-separated list of the negative acknowledgment codes the channel alerts on, as they appear in MSA-1 of the ACK message - `AE` and `CE` say the service failed to process a message, `AR` and `CR` that the message was rejected, and nothing else is a code here. The default is `AE, AR, CE, CR`, and a channel names `AR, CR` alone when a failing service is already covered by its error rate. Every measure of a channel reads the acknowledgments it sends, so a channel with `is_audit_log_active` off has nothing counted about it.

For the full description of every field, see the [MLLP channel configuration reference](https://zato.io/docs/dev/healthcare/hl7v2/mllp/config.html).

## HL7 MLLP outgoing connections {#hl7-mllp-outgoing-connections}

Key: `outgoing_mllp`

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique connection name - services use it with `self.mllp` |
| address | Yes | Remote endpoint as `host:port`, e.g. `10.20.30.40:2575` |
| is\_active | --- | Whether the connection can be used (default `true`) |
| pool\_size | --- | How many connections the pool keeps open (default `10`) |
| start\_seq | --- | MLLP frame start bytes in hex (default `0b`) |
| end\_seq | --- | MLLP frame end bytes in hex (default `1c 0d`) |
| recv\_timeout | --- | How long to wait for the acknowledgment, in milliseconds (default `250`) |
| max\_msg\_size | --- | The biggest message sent and the biggest acknowledgment accepted, in bytes (default `2097152`, i.e. 2 MB) |
| read\_buffer\_size | --- | Socket read buffer, in bytes (default `32768`) |
| max\_wait\_time | --- | Default timeout for the dashboard invoke screen, in seconds (default `5`) |
| max\_retries | --- | How many times a send that no acknowledgment came back for is retried (default `0`, i.e. no retries) |
| retry\_sleep\_time | --- | How many seconds to wait before the first retry, 8 at most (default `2`) |
| retry\_backoff\_multiplier | --- | How many times longer each next wait is (default `2`) |
| retry\_backoff\_threshold | --- | How many seconds all the waits may take together, once that is reached, no more retries take place (default `60`) |
| use\_queue | --- | Whether a request that could not be delivered waits in the connection's queue and is retried until it goes through, with `max_retries` at 0 it is not queued (default `false`) |
| use\_dlq | --- | Whether a request that a round of the queue could not deliver moves to the connection's dead-letter queue (default `true`) |
| dlq\_action | --- | What happens to a request in the DLQ - `keep`, `retry`, `forward` or `discard` (default `keep`) |
| dlq\_retries | --- | With `retry`, how many more rounds of delivery a request gets before it stays in the DLQ (default `3`) |
| dlq\_retry\_interval | --- | How many seconds a request stays in the DLQ before the action applies to it (default `60`) |
| dlq\_forward\_to | --- | With `forward`, the name of the pub/sub topic the request is published to |
| dlq\_keep\_header | --- | With `forward`, whether the DLQ header - why, when and after how many attempts the request was dead-lettered - goes with it (default `true`) |
| circuit\_breaker\_threshold\_percent | --- | Failure percentage within the window that pauses sending (default `50`) |
| circuit\_breaker\_window\_seconds | --- | Length of the rolling window the failure percentage is computed over, in seconds (default `60`) |
| circuit\_breaker\_reset\_seconds | --- | How long sending stays paused before a trial message goes through, in seconds (default `60`) |
| should\_log\_messages | --- | Log outgoing traffic (default `false`) |
| logging\_level | --- | Log level for this connection (default `INFO`) |
| is\_audit\_log\_active | --- | Whether the connection's traffic goes to the audit log (default `true`) |
| is\_audit\_export\_payload\_active | --- | Whether the connection's request and response payloads leave with the [OpenTelemetry export](https://zato.io/docs/admin/audit-log/opentelemetry.html) of the audit log (default is `false`, exported only when `true`) |
| tls\_ca\_path | --- | Path to the CA bundle used to verify the remote server - setting it turns TLS on |
| tls\_cert\_path | --- | Path to the client certificate, for mTLS |
| tls\_key\_path | --- | Path to the client private key, for mTLS |
| alerts | --- | The alert settings the connection sets of its own - see below |

The delivery fields are exported only when they differ from their defaults - the [Delivery retries and dead-letter queues](https://zato.io/docs/dev/delivery.html) page explains what each one does.

```yaml
outgoing_mllp:

  - name: adt-outbound
    address: 10.20.30.40:2575

  - name: lab-outbound
    address: lab.example.com:2575
    recv_timeout: 500
    tls_ca_path: /path/to/ca.pem
    tls_cert_path: /path/to/client.pem
    tls_key_path: /path/to/client.key

  # A connection with alert settings of its own - the rejects alone are counted, two of them in ten minutes
  # raise an alert, as do five messages in ten minutes that no acknowledgment came back for
  - name: orders-outbound
    address: orders.example.com:2575
    alerts:
      ack_codes: AR, CR
      ack_threshold: 2
      acks_window: 600
      connection_failures: 5
      connection_failures_window: 600
```

The `alerts` mapping takes `is_active`, `consecutive_failures`, `error_rate`, `window`, `max_latency`, `latency_window`, `connection_failures`, `connection_failures_window`, `use_llm`, `email_connection` and `llm_connection`, plus three of its own - `ack_codes`, `ack_threshold` and `acks_window` - and only the settings that differ from their defaults are exported.

`ack_codes` is a comma-separated list of the negative acknowledgment codes the connection alerts on, as they appear in MSA-1 of the ACK message the remote system answers with - `AE` and `CE` say the remote system failed to process a message, `AR` and `CR` that it rejected the message, and these four are the only valid codes. The default is `AE, AR, CE, CR`. `connection_failures` counts the messages that got no acknowledgment at all - the wait for it ran out, the connection was refused or reset, the remote system closed it early or the TLS handshake failed. Every measure of a connection reads the acknowledgments it is answered, so a connection with `is_audit_log_active` off has nothing counted about it.

The [Sending HL7v2 over MLLP](https://zato.io/docs/dev/healthcare/hl7v2/mllp/outgoing.html) chapter explains how outgoing connections work.

## HL7 FHIR outgoing connections {#hl7-fhir-outgoing-connections}

Key: `outgoing_fhir`

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique connection name - services use it with `self.fhir` |
| address | Yes | URL of the FHIR server, including its base path, e.g. `https://fhir.example.com/r4` |
| security | --- | Name of a Basic Auth or OAuth security definition used for the requests - without one they are unauthenticated |
| is\_active | --- | Whether the connection can be used (default `true`) |
| pool\_size | --- | How many clients to keep open to the server (default `10`) |
| is\_audit\_log\_active | --- | Whether the connection's traffic goes to the audit log (default `true`) |
| is\_audit\_export\_payload\_active | --- | Whether the connection's request and response payloads leave with the [OpenTelemetry export](https://zato.io/docs/admin/audit-log/opentelemetry.html) of the audit log (default is `false`, exported only when `true`) |
| health\_check\_run\_every | --- | How often the connection's health check reads the server's CapabilityStatement - without it there is no health check |
| health\_check\_run\_unit | --- | The unit of `health_check_run_every` - `seconds`, `minutes`, `hours` or `days` (default `minutes`) |
| alerts | --- | The alert settings the connection sets of its own - see below |
| bulk\_export | --- | The bulk export the connection runs - what it exports, on what schedule and where the files go - see below |
| max\_retries | --- | How many times a failed invocation is retried after a timeout, a connection error or an HTTP 429 response (default `0`, i.e. no retries) |
| retry\_sleep\_time | --- | How many seconds to wait before the first retry, 8 at most (default `2`) |
| retry\_backoff\_multiplier | --- | How many times longer each next wait is (default `2`) |
| retry\_backoff\_threshold | --- | How many seconds all the waits may take together, once that is reached, no more retries take place (default `60`) |
| use\_queue | --- | Whether a request that could not be delivered waits in the connection's queue and is retried until it goes through, with `max_retries` at 0 it is not queued (default `false`) |
| use\_dlq | --- | Whether a request that a round of the queue could not deliver moves to the connection's dead-letter queue (default `true`) |
| dlq\_action | --- | What happens to a request in the DLQ - `keep`, `retry`, `forward` or `discard` (default `keep`) |
| dlq\_retries | --- | With `retry`, how many more rounds of delivery a request gets before it stays in the DLQ (default `3`) |
| dlq\_retry\_interval | --- | How many seconds a request stays in the DLQ before the action applies to it (default `60`) |
| dlq\_forward\_to | --- | With `forward`, the name of the pub/sub topic the request is published to |
| dlq\_keep\_header | --- | With `forward`, whether the DLQ header - why, when and after how many attempts the request was dead-lettered - goes with it (default `true`) |

The delivery fields are exported only when they differ from their defaults - the [Delivery retries and dead-letter queues](https://zato.io/docs/dev/delivery.html) page explains what each one does.

```yaml
outgoing_fhir:

  - name: FHIR.Sample
    address: https://fhir.example.com/r4

  - name: FHIR.Secured
    address: https://fhir.partner.example.com/r4
    security: enmasse.basic_auth.1
    pool_size: 20

  # A connection with a health check and alert settings of its own - the same mapping as on an outgoing REST connection,
  # plus the operation outcomes
  - name: FHIR.Monitored
    address: https://fhir.example.com/r4
    health_check_run_every: 5
    health_check_run_unit: minutes
    alerts:
      status_codes: 5xx
      status_code_threshold: 3
      outcome_codes: exception, timeout, not-found
      outcome_threshold: 3
      outcomes_window: 600
      connection_failures: 2
      email_connection: smtp:enmasse.smtp.1
```

The `alerts` mapping takes the same settings as the one of [outgoing REST connections](https://zato.io/docs/admin/enmasse-reference.html#outgoing-rest-connections) plus three of its own - `outcome_codes`, `outcome_threshold` and `outcomes_window` - and only the settings that differ from their defaults are exported.

`outcome_codes` is a comma-separated list of the FHIR issue codes the connection alerts on, as the `issue.code` of an OperationOutcome resource names them - lowercase names with dashes, such as `exception`, `not-found` or `too-costly`. The default is `exception, transient, timeout, throttled, lock-error, no-store, too-costly` - the codes that say the FHIR server itself is in trouble - and a connection adds `not-found` or `security` when a missing resource or a refused token is something someone has to act on. An OperationOutcome is counted under its issue code and never under `status_codes`, so the HTTP status it arrived with does not count it twice.

The health check reads `GET /CapabilityStatement` of the server as often as `health_check_run_every` says and writes each read to the audit log under the `fhir-health` source - the [health checks](https://zato.io/docs/admin/health-checks.html) chapter has the details.

The `bulk_export` mapping is the connection's Bulk export tab - an export of a whole patient group, or of the whole server, through the FHIR `$export` operation, with the NDJSON files delivered to the destinations named. Only the keys that differ from their defaults are exported, and a connection whose export is off and otherwise untouched is exported with no mapping at all.

| Name | Required | Description |
| --- | --- | --- |
| is\_active | --- | Whether the schedule runs (default `false`) - an export started by hand or from a service runs either way |
| level | --- | `group` for the patients of one Group resource, `patient` for every patient on the server, `system` for every resource there is (default `group`) |
| group\_id | --- | With `group`, the ID of the Group resource whose members are exported |
| patient\_ids | --- | With `patient`, a list of patient IDs narrowing the export to these patients alone - empty means all of them |
| types | --- | A list of the resource types to export, e.g. `Patient` and `Observation` - empty means every type the server supports |
| since | --- | Only resources changed after this moment, in FHIR instant format, e.g. `2026-01-01T00:00:00Z` |
| type\_filter | --- | A list of FHIR searches narrowing a resource type, e.g. `Observation?category=laboratory` |
| run\_every | --- | How often the export runs - without it there is no schedule |
| run\_unit | --- | The unit of `run_every` - `seconds`, `minutes`, `hours` or `days` (default `minutes`) |
| start\_date | --- | When the first scheduled export runs, in ISO-8601 format - empty means now |
| destinations | --- | A list of where each file goes - each entry has a `name`, a `type` of `sftp`, `kafka`, `hl7-fhir` or `service`, the `connection` or service of that type, `is_active` (default `true`) and the `options` of the type - SFTP takes `remote_path`, `/{job_id}/{file_name}` by default |
| delete\_files | --- | Whether the downloaded files are removed once every destination accepted them (default `true`) |
| delete\_on\_server | --- | Whether the server is told it can drop its copy of the export once the files are downloaded (default `true`) |

```yaml
outgoing_fhir:

  - name: FHIR.Registry
    address: https://fhir.example.com/r4
    security: enmasse.bearer_token.1
    bulk_export:
      is_active: true
      level: group
      group_id: diabetes-registry
      types:
        - Patient
        - Observation
      since: "2026-01-01T00:00:00Z"
      run_every: 1
      run_unit: days
      destinations:
        - name: archive
          type: sftp
          connection: enmasse.sftp.1
          options:
            remote_path: /exports/{job_id}/{file_name}
        - name: registry
          type: service
          connection: demo.fhir.load-registry
```

The [bulk export](https://zato.io/docs/dev/healthcare/hl7/fhir/bulk-export/index.html) page explains what each field does and how a service receives the files.

The [HL7 FHIR integrations](https://zato.io/docs/dev/healthcare/hl7/fhir/index.html) chapter explains how outgoing FHIR connections are used from a service.

## Kafka channels {#kafka-channels}

Key: `channel_kafka`

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique name of the Kafka channel |
| address | Yes | Kafka broker address, e.g. `localhost:9092` |
| topic | --- | Kafka topic to consume from |
| group\_id | --- | Consumer group ID |
| service | --- | Name of the Zato service invoked for each message |
| is\_active | --- | Whether the channel is active (default is `true`) |
| is\_audit\_log\_active | --- | Whether the channel's traffic goes to the audit log (default is `true`, exported only when `false`) |
| is\_audit\_export\_payload\_active | --- | Whether the channel's request and response payloads leave with the [OpenTelemetry export](https://zato.io/docs/admin/audit-log/opentelemetry.html) of the audit log (default is `false`, exported only when `true`) |
| security | --- | Name of the security definition the SASL mechanism takes its credentials from - a Basic Auth one for `PLAIN` and SCRAM, a Bearer token one for `OAUTHBEARER` |
| sasl\_mechanism | --- | SASL mechanism the brokers require - `PLAIN`, `SCRAM-SHA-256`, `SCRAM-SHA-512` or `OAUTHBEARER`. Given together with `security` or not at all |
| ssl | --- | Whether to use SSL (default is `false`) |
| ssl\_ca\_file | --- | Path to the CA certificate file |
| ssl\_cert\_file | --- | Path to the client certificate file |
| ssl\_key\_file | --- | Path to the client key file |

```yaml
channel_kafka:
  - name: enmasse.kafka.channel.1
    address: localhost:9092
    topic: incoming-events
    group_id: zato-consumers
    service: kafka.process-event

  - name: enmasse.kafka.channel.2
    address: broker1:9093
    topic: secure-events
    group_id: zato-secure
    service: kafka.process-secure
    security: enmasse.basic_auth.1
    sasl_mechanism: SCRAM-SHA-512
    ssl: true
    ssl_ca_file: /path/to/ca.pem
    ssl_cert_file: /path/to/cert.pem
    ssl_key_file: /path/to/key.pem
```

See [Kafka examples](https://zato.io/docs/dev/examples/kafka.html) for Python code.

## Kafka outgoing connections {#kafka-outgoing-connections}

Key: `outgoing_kafka`

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique name of the outgoing connection |
| address | Yes | Kafka broker address, e.g. `localhost:9092` |
| topic | --- | Default Kafka topic to publish to |
| is\_active | --- | Whether the connection is active (default is `true`) |
| is\_audit\_log\_active | --- | Whether the connection's traffic goes to the audit log (default is `true`, exported only when `false`) |
| is\_audit\_export\_payload\_active | --- | Whether the connection's request and response payloads leave with the [OpenTelemetry export](https://zato.io/docs/admin/audit-log/opentelemetry.html) of the audit log (default is `false`, exported only when `true`) |
| security | --- | Name of the security definition the SASL mechanism takes its credentials from - a Basic Auth one for `PLAIN` and SCRAM, a Bearer token one for `OAUTHBEARER` |
| sasl\_mechanism | --- | SASL mechanism the brokers require - `PLAIN`, `SCRAM-SHA-256`, `SCRAM-SHA-512` or `OAUTHBEARER`. Given together with `security` or not at all |
| ssl | --- | Whether to use SSL (default is `false`) |
| ssl\_ca\_file | --- | Path to the CA certificate file |
| ssl\_cert\_file | --- | Path to the client certificate file |
| ssl\_key\_file | --- | Path to the client key file |

```yaml
outgoing_kafka:
  - name: enmasse.kafka.outgoing.1
    address: localhost:9092
    topic: outgoing-events

  - name: enmasse.kafka.outgoing.2
    address: broker2:9093
    topic: secure-outgoing
    security: enmasse.bearer_token.1
    sasl_mechanism: OAUTHBEARER
    ssl: true
    ssl_ca_file: /path/to/ca.pem
    ssl_cert_file: /path/to/cert.pem
    ssl_key_file: /path/to/key.pem
```

See [Kafka examples](https://zato.io/docs/dev/examples/kafka.html) for Python code.

## IBM MQ channels {#ibm-mq-channels}

Key: `channel_ibm_mq`

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique name of the channel |
| address | Yes | Address of the queue manager as host:port, e.g. `mq.example.com:1414` |
| queue\_manager | --- | Name of the queue manager to connect to |
| mq\_channel\_name | --- | Name of the MQ server-connection channel, e.g. `DEV.APP.SVRCONN` |
| queue | --- | Queue to consume messages from |
| service | --- | Name of the Zato service invoked for each message |
| username | --- | Username the channel authenticates with |
| password | --- | Password - can be set via an environment variable |
| remove\_jms\_headers | --- | Whether JMS headers are stripped from incoming messages (default is `true`) |
| ssl | --- | Whether to connect over TLS (default is `false`) |
| cipher\_spec | --- | The MQ CipherSpec to use when TLS is on, e.g. `TLS_RSA_WITH_AES_256_CBC_SHA256` |
| ssl\_ca\_file | --- | Path to a PEM file with the CA certificates that signed the queue manager's certificate |
| ssl\_cert\_file | --- | Path to the client certificate, for mutual TLS |
| ssl\_key\_file | --- | Path to the client private key, for mutual TLS |
| is\_active | --- | Whether the channel is active (default is `true`) |

```yaml
channel_ibm_mq:
  - name: enmasse.ibm-mq.channel.1
    address: mq.example.com:1414
    queue_manager: QM1
    mq_channel_name: DEV.APP.SVRCONN
    queue: ORDERS.IN
    service: orders.process-order
    username: app
    password: Zato_Enmasse_Env.IBMMQPassword
```

## IBM MQ outgoing connections {#ibm-mq-outgoing-connections}

Key: `outgoing_ibm_mq`

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique name of the connection |
| address | Yes | Address of the queue manager as host:port, e.g. `mq.example.com:1414` |
| queue\_manager | --- | Name of the queue manager to connect to |
| mq\_channel\_name | --- | Name of the MQ server-connection channel, e.g. `DEV.APP.SVRCONN` |
| queue | --- | Default queue to send messages to |
| username | --- | Username the connection authenticates with |
| password | --- | Password - can be set via an environment variable |
| ssl | --- | Whether to connect over TLS (default is `false`) |
| cipher\_spec | --- | The MQ CipherSpec to use when TLS is on |
| ssl\_ca\_file | --- | Path to a PEM file with the CA certificates that signed the queue manager's certificate |
| ssl\_cert\_file | --- | Path to the client certificate, for mutual TLS |
| ssl\_key\_file | --- | Path to the client private key, for mutual TLS |
| is\_active | --- | Whether the connection is active (default is `true`) |

```yaml
outgoing_ibm_mq:
  - name: enmasse.ibm-mq.outgoing.1
    address: mq.example.com:1414
    queue_manager: QM1
    mq_channel_name: DEV.APP.SVRCONN
    queue: ORDERS.OUT
    username: app
    password: Zato_Enmasse_Env.IBMMQPassword
```

See [IBM MQ examples](https://zato.io/docs/dev/examples/ibm-mq.html) for Python code.

## AMQP channels {#amqp-channels}

Key: `channel_amqp`

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique name of the AMQP channel |
| address | Yes | Address of the broker as host:port, e.g. `localhost:5672` |
| queue | Yes | Queue to consume messages from |
| service | Yes | Name of the Zato service invoked for each message |
| username | --- | Username the channel authenticates with |
| password | --- | Password for the username above |
| is\_active | --- | Whether the channel is active (default is `true`) |
| consumer\_tag\_prefix | --- | Prefix of the consumer tag the channel identifies itself with |
| pool\_size | --- | How many connections to the broker to keep open (default is `10`) |
| ack\_mode | --- | What to tell the broker about each message, `ack` or `reject` (default is `ack`) |
| prefetch\_count | --- | How many messages to prefetch, `0` means no limit (default is `0`) |
| data\_format | --- | Format of incoming message bodies, e.g. `json` |

```yaml
channel_amqp:
  - name: enmasse.amqp.channel.1
    address: localhost:5672
    queue: orders
    service: orders.process-order
    username: zato
    password: Zato_Enmasse_Env.AMQPPassword

  - name: enmasse.amqp.channel.2
    address: broker1:5672
    queue: invoices
    service: invoices.process-invoice
    username: zato
    password: Zato_Enmasse_Env.AMQPPassword
    data_format: json
    pool_size: 20
```

See [AMQP examples](https://zato.io/docs/dev/examples/amqp.html) for Python code.

## AMQP outgoing connections {#amqp-outgoing-connections}

Key: `outgoing_amqp`

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique name of the outgoing connection |
| address | Yes | Address of the broker as host:port, e.g. `localhost:5672` |
| username | --- | Username the connection authenticates with |
| password | --- | Password for the username above |
| is\_active | --- | Whether the connection is active (default is `true`) |
| delivery\_mode | --- | `persistent` or `non_persistent` (default is `persistent`) |
| priority | --- | Priority stamped on published messages, 0-9 (default is `5`) |
| content\_type | --- | MIME type stamped on published messages, e.g. `application/json` |
| content\_encoding | --- | Content encoding property of published messages, e.g. `utf-8` |
| expiration | --- | Message expiration in milliseconds |
| pool\_size | --- | How many connections to the broker to keep open (default is `10`) |
| user\_id | --- | User ID stamped on published messages |
| app\_id | --- | Application ID stamped on published messages |

```yaml
outgoing_amqp:
  - name: enmasse.amqp.outgoing.1
    address: localhost:5672
    username: zato
    password: Zato_Enmasse_Env.AMQPPassword

  - name: enmasse.amqp.outgoing.2
    address: broker2:5672
    username: zato
    password: Zato_Enmasse_Env.AMQPPassword
    content_type: application/json
    priority: 7
```

See [AMQP examples](https://zato.io/docs/dev/examples/amqp.html) for Python code.

## Azure Service Bus channels {#azure-service-bus-channels}

Key: `channel_azure_service_bus`

Azure Service Bus channels accept the same fields as [AMQP channels](https://zato.io/docs/admin/enmasse-reference.html#amqp-channels) - the address is your namespace hostname with port 5671 and the username is your Shared Access Policy name.

```yaml
channel_azure_service_bus:
  - name: enmasse.azure.channel.1
    address: mycompany-dev.servicebus.windows.net:5671
    queue: flight-updates
    service: flights.process-update
    username: MyPolicyName
    password: Zato_Enmasse_Env.AzureServiceBusPassword
```

See [Azure Service Bus examples](https://zato.io/docs/dev/examples/azure-service-bus.html) for Python code.

## Azure Service Bus outgoing connections {#azure-service-bus-outgoing-connections}

Key: `outgoing_azure_service_bus`

Azure Service Bus outgoing connections accept the same fields as [AMQP outgoing connections](https://zato.io/docs/admin/enmasse-reference.html#amqp-outgoing-connections) - the address is your namespace hostname with port 5671 and the username is your Shared Access Policy name.

```yaml
outgoing_azure_service_bus:
  - name: enmasse.azure.outgoing.1
    address: mycompany-dev.servicebus.windows.net:5671
    username: MyPolicyName
    password: Zato_Enmasse_Env.AzureServiceBusPassword
```

See [Azure Service Bus examples](https://zato.io/docs/dev/examples/azure-service-bus.html) for Python code.

## GraphQL outgoing connections {#graphql-outgoing-connections}

Key: `outgoing_graphql`

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique name of the outgoing connection |
| address | Yes | URL of the GraphQL endpoint, e.g. `https://graph.microsoft.com/v1.0` |
| is\_active | --- | Whether the connection is active (default is `true`) |
| security | --- | Name of a security definition (Basic Auth, API key or OAuth) |
| default\_query\_timeout | --- | Query timeout in seconds (default is `60`) |
| extra | --- | JSON object of custom HTTP headers, e.g. `{"X-Tenant": "acme"}` |

```yaml
outgoing_graphql:
  - name: ms365-graph
    address: https://graph.microsoft.com/v1.0
    security: ms365-oauth
    default_query_timeout: 30

  - name: github-api
    address: https://api.github.com/graphql
    security: github-token
    default_query_timeout: 60
```

See [GraphQL examples](https://zato.io/docs/dev/examples/graphql.html) for Python code.

## gRPC outgoing connections {#grpc-outgoing-connections}

Key: `outgoing_grpc`

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique name of the outgoing connection |
| address | Yes | Host and port of the gRPC server, e.g. `billing.example.com:50051` |
| is\_active | --- | Whether the connection is active (default is `true`) |
| security | --- | Name of a security definition (Basic Auth, API key or OAuth) whose credentials are sent as call metadata |
| is\_tls | --- | Whether to connect over TLS (default is `true`) |
| tls\_ca\_certs\_file | --- | Path to a PEM file with CA certificates to verify the server's certificate against |
| proto\_path | --- | Path to a `.proto` file on the server - client code is generated out of it automatically |
| stub\_module | --- | Alternatively, the Python module with a pre-generated stub, e.g. `billing_pb2_grpc` |
| stub\_class | --- | Name of the stub class in `stub_module`, needed only when the module has more than one |
| ping\_timeout | --- | How many seconds to wait for the server when pinging (default is `10`) |
| max\_send\_message\_size | --- | The biggest message that can be sent, in bytes (default is `104857600`) |
| max\_recv\_message\_size | --- | The biggest message that can be received, in bytes (default is `104857600`) |

```yaml
outgoing_grpc:
  - name: billing
    address: billing.example.com:50051
    security: billing-api-key
    proto_path: /opt/zato/proto/billing.proto

  - name: inventory
    address: inventory.internal:50051
    is_tls: false
    stub_module: inventory_pb2_grpc
```

See [gRPC examples](https://zato.io/docs/dev/examples/grpc.html) for Python code.

## Pub/sub topics {#pubsub-topics}

Key: `pubsub_topic`

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique name of the topic |
| description | --- | Optional description of the topic |
| is\_active | --- | Whether the topic is active (default is `true`) |
| is\_audit\_log\_active | --- | Whether the topic's traffic goes to the audit log (default is `true`, exported only when `false`) |
| is\_audit\_export\_payload\_active | --- | Whether the topic's message payloads leave with the [OpenTelemetry export](https://zato.io/docs/admin/audit-log/opentelemetry.html) of the audit log (default is `false`, exported only when `true`) |

```yaml
pubsub_topic:
  - name: enmasse.topic.1
    description: Optional description for topic 1
  - name: enmasse.topic.2
```

Topics are part of the pub/sub system - the [pub/sub API](https://zato.io/docs/eda/api/rest.html) page has more.

## Pub/sub permissions {#pubsub-permissions}

Key: `pubsub_permission`

| Name | Required | Description |
| --- | --- | --- |
| security | Yes | Name of the security definition to grant permissions to |
| pub | --- | List of topic name patterns the security definition is allowed to publish to |
| sub | --- | List of topic name patterns the security definition is allowed to subscribe to |

```yaml
pubsub_permission:
  - security: enmasse.basic_auth.1
    pub:
      - enmasse.topic.1
      - enmasse.topic.2
    sub:
      - enmasse.topic.2
      - enmasse.topic.3

  - security: enmasse.basic_auth.2
    pub:
      - enmasse.topic.*
    sub:
      - enmasse.#
```

For background on pub/sub security, visit [pub/sub security](https://zato.io/docs/eda/security/index.html).

## Pub/sub subscriptions {#pubsub-subscriptions}

Key: `pubsub_subscription`

| Name | Required | Description |
| --- | --- | --- |
| security | Yes | Name of the security definition the subscription belongs to |
| delivery\_type | Yes | How messages are delivered - either `pull` or `push` |
| topic\_list | Yes | List of topic names to subscribe to |
| push\_rest\_endpoint | --- | Name of an outgoing REST connection to push messages to (required when `delivery_type` is `push` and pushing to a REST endpoint) |
| push\_service | --- | Name of a Zato service to push messages to (required when `delivery_type` is `push` and pushing to a service) |
| max\_retry\_time | --- | How long to retry delivery before giving up, e.g. `365d`, `48h` or `30m` |
| is\_delivery\_active | --- | Whether delivery is active (default is `true`) |

```yaml
pubsub_subscription:
  - security: enmasse.basic_auth.1
    delivery_type: pull
    max_retry_time: 365d
    topic_list:
      - enmasse.topic.1
      - enmasse.topic.2

  - security: enmasse.basic_auth.2
    delivery_type: push
    push_rest_endpoint: enmasse.outgoing.rest.1
    max_retry_time: 48h
    topic_list:
      - enmasse.topic.1

  - security: enmasse.basic_auth.3
    delivery_type: push
    push_service: demo.input-logger
    max_retry_time: 30m
    topic_list:
      - enmasse.topic.3
```

Endpoints and subscriptions are explained in the [pub/sub endpoints](https://zato.io/docs/eda/endpoint/index.html) chapter.

## Custom connectors {#custom-connectors}

Key: `custom_*`

Connection types built with the [Connector SDK](https://zato.io/docs/sdk/index.html) get a top-level key of their own, named after the type - a connector of type `crm` is configured under `custom_crm`.

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique name of the connection |
| is\_active | --- | Whether the connection can be used (default is `true`) |

Every other field is whatever the connector class declares - the fields are written to the YAML and read back exactly as the connector defines them.

```yaml
custom_crm:
  - name: enmasse.custom.crm.1
    address: https://crm.example.com
    username: api
    api_key: Zato_Enmasse_Env.CRMAPIKey
```

## Audit retention policies {#audit-retention-policies}

Key: `audit_retention`

Named [audit log](https://zato.io/docs/admin/audit-log/index.html) retention policies. Each policy says how long events and their payloads are kept and, optionally, where they are archived before deletion.

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique name of the policy |
| retention\_days | Yes | How many days events are kept |
| content\_retention\_days | --- | How many days payloads are kept - `0`, the default, means payloads are kept for as long as their events |
| archive\_dir | --- | Directory events are archived to before they are deleted |

```yaml
audit_retention:
  - name: enmasse.retention.1
    retention_days: 90
    content_retention_days: 7
    archive_dir: /opt/zato/audit-archive
```

## Attribute extraction rules {#attribute-extraction-rules}

Key: `audit_extraction`

Named sets of rules describing which searchable attributes to pull out of the messages the [audit log](https://zato.io/docs/admin/audit-log/index.html) records - an order ID in a JSON body, a correlation header, a match of a regular expression.

| Name | Required | Description |
| --- | --- | --- |
| name | Yes | Unique name of the rule set, after the channel or connection it applies to |
| source | --- | The audit source the set applies to, e.g. `rest-channel` |
| rules | Yes | List of extraction rules - each with `attr_name`, `rule_type` and `expression` |

Each rule contains:

| Name | Required | Description |
| --- | --- | --- |
| attr\_name | Yes | Name of the attribute the rule extracts, as it appears in searches |
| rule\_type | Yes | How the value is extracted - one of `json-path`, `xpath`, `header` or `regex` |
| expression | Yes | The path, header name or regular expression to extract with |

```yaml
audit_extraction:
  - name: crm.customer.get
    source: rest-channel
    rules:
      - attr_name: order_id
        rule_type: json-path
        expression: order.id
      - attr_name: correlation_id
        rule_type: header
        expression: X-Correlation-Id
```

## Read more {#read-more}

- The [enmasse overview](https://zato.io/docs/admin/enmasse.html) explains how enmasse works and how to use it
- [This complete DevOps tutorial](https://zato.io/tutorials/devops/deployment.html) discusses how to deploy your services and projects

## Learn more {#learn-more}

- [Production checklist](https://zato.io/docs/admin/production-checklist.html) - What to confirm before an environment takes real traffic
- [Audit log](https://zato.io/docs/admin/audit-log/) - Every request, response and error, and what you can do with them afterwards
- [Health checks](https://zato.io/docs/admin/health-checks.html) - Have Zato ping your outgoing connections instead of waiting for traffic to fail
- [Logging](https://zato.io/docs/admin/logging.html) - What is written where, and how to ship it to Splunk, Loki, Elastic or Datadog
- [GitOps with enmasse](https://zato.io/docs/admin/enmasse.html) - Keep the whole environment in git as YAML and import it anywhere
