Skip to content

Configuration Properties

Philip Helger edited this page Jul 21, 2026 · 49 revisions

Configuration Properties

All properties are located in the file application.properties which resides in src/main/resources of the phoss-ap-webapp module.

All configuration properties are resolved according to the rules described in https://github.com/phax/ph-commons/wiki/ph-config

Duration values (since 0.9.0)

Many time-related properties accept a duration grammar since v0.9.0. The format is one or more [sign]<number><unit> segments, summed together, with optional whitespace between segments. Supported units:

Suffix Meaning
ns nanoseconds
us microseconds
ms milliseconds
s seconds
m minutes
h hours
d days

Examples: 5s, 1m 30s, 2d 12h, 90d.

The previous millisecond-typed keys (with .ms / .millis suffix) continue to be honored for backwards compatibility, but a deprecation warning is logged (once per key) when they are used. The legacy .ms / .millis keys will be removed in v1.0.0. Migrate to the new duration-grammar keys as soon as possible.

Table of Contents

General Configuration

  • global.debug: Enable or disable overall debug mode. Enables additional checks that should not be active in production (e.g. verbose logging, slower validation). Default is false.
  • global.production: Enable or disable overall production mode. When false, certain production-only functionality may be disabled. Default is false.
  • global.nostartupinfo: Set to true to suppress the startup information banner. Default is false.
  • global.datapath: The path where all relevant data files are stored (e.g. keystores, dumps, logs). Should be an absolute path in production (e.g. /var/phoss-ap/data).

Peppol Configuration

  • peppol.stage: The Peppol network stage. Either test or prod. Determines which PKI certificates and SML endpoints are used.
  • peppol.owner.seatid: The Peppol Seat ID of this AP (e.g. POP000000). Used in reporting and MLS processing.
  • peppol.owner.countrycode: The 2-letter country code of the AP operator. Used as C2 or C3 country in reporting context.
  • peppol.receiver-check.mode (since v0.1.3): Controls how incoming messages are verified against SMP registrations. Possible values:
    • none (default) — Receiver checks are disabled.
    • smp — Uses a fixed SMP URL for verification. Requires peppol.smp.url and phase4.endpoint.address to be set.
    • sml — Uses dynamic per-participant SMP resolution via the SML derived from the configured peppol.stage. Requires phase4.endpoint.address to be set.
  • peppol.smp.url: The URL of this AP's own SMP (e.g. http://localhost:8080). Required when peppol.receiver-check.mode=smp.
  • peppol.dns.servers (since v0.1.3): Comma-separated list of DNS server hostnames or IP addresses to use for Peppol NAPTR lookups (e.g. 8.8.8.8,8.8.4.4). Optional. When not set, the system default DNS resolver is used.
  • peppol.identifier.mode: The Peppol identifier validation mode. Either strict or lax. In strict mode (default), all Peppol identifier rules are enforced. In lax mode, identifier validation is more lenient. Default is strict.
  • peppol.revocation.soft-fail (since 0.9.0): Global soft-fail mode for certificate revocation checks. When true, certificate validation succeeds even if the revocation status cannot be determined (e.g. CRL/OCSP responder unreachable due to a network error). Maps to CertificateRevocationCheckerDefaults.setAllowSoftFail(boolean). Default is false (hard fail on indeterminate revocation status).

AS4 Keystore and Truststore

These properties configure the cryptographic material used by phase4 for AS4 message signing, encryption, and certificate validation.

AP Keystore (signing and decryption)

  • org.apache.wss4j.crypto.merlin.keystore.type: Keystore type. Either JKS or PKCS12. Default is JKS.
  • org.apache.wss4j.crypto.merlin.keystore.file: Path to the keystore file containing the AP certificate and private key.
  • org.apache.wss4j.crypto.merlin.keystore.password: Password for the keystore.
  • org.apache.wss4j.crypto.merlin.keystore.alias: Alias of the key entry within the keystore.
  • org.apache.wss4j.crypto.merlin.keystore.private.password: Password for the private key entry.

AP Truststore (validating remote AP certificates)

  • org.apache.wss4j.crypto.merlin.truststore.type: Truststore type. Either JKS or PKCS12. Default is PKCS12.
  • org.apache.wss4j.crypto.merlin.truststore.file: Path to the truststore file for validating incoming AS4 message signatures.
  • org.apache.wss4j.crypto.merlin.truststore.password: Password for the truststore.

phase4 / AS4 Internals

These properties are read directly by the embedded phase4 library and control its internal behavior. They are defined in com.helger.phase4.config.AS4Configuration. Defaults are normally appropriate for a Peppol AP — change them only if you understand the consequences.

  • phase4.manager.inmemory: Whether phase4's internal state managers (e.g. the incoming message ID duplicate cache) use the in-memory implementation. Default is true. phoss-ap operates with the in-memory phase4 managers; do not set this to false unless you have provided an alternative manager backend.
  • phase4.wss4j.syncsecurity: Force WSS4J sign/verify and encrypt/decrypt operations to be globally synchronized. Required when multiple worker threads send or receive AS4 messages concurrently within the same JVM and the underlying WSS4J/Santuario stack would otherwise be unsafe. Default is false.
  • phase4.default.profile (with fallback phase4.profile): The AS4 profile identifier used by phase4 when no profile is selected explicitly. For phoss-ap (which is a Peppol AP) the Peppol profile is selected programmatically, so this rarely needs to be set. Optional.
  • phase4.errormsg.include.stacktraces: Whether AS4 error signal messages returned to remote senders include Java stack traces. Default is false. Keep disabled in production — stack traces may leak internal details.
  • phase4.compatibility.domibus: Enable special Domibus interoperability tweaks. Default is false. Not applicable to standard Peppol exchanges.
  • phase4.http.response.accept.allstatuscodes: Whether phase4 accepts all HTTP response status codes from the remote AS4 endpoint (instead of rejecting status codes >= 300). Default is true (the behavior introduced in phase4 4.1.1). Set to false to restore the pre-4.1.1 behavior where only status codes < 300 were accepted.

See also phase4.endpoint.address and phase4.api.requiredtoken under API Configuration, phase4.dump.path and phase4.dump.mode under Logging and Diagnostics, and phase4.incoming.duplicatedisposal under Duplicate Detection Configuration.

SMP Client Configuration

These properties configure the SMP client used for outbound SMP lookups (to resolve receiver AP endpoints).

  • smpclient.truststore.type: Truststore type for SMP client TLS connections. Either JKS or PKCS12. Default is PKCS12.
  • smpclient.truststore.path: Path to the truststore file for SMP client connections.
  • smpclient.truststore.password: Password for the SMP client truststore.

Database Configuration

PostgreSQL and MySQL are the supported databases. The database schema is managed automatically via Flyway.

JDBC configuration properties are defined by JdbcConfigurationConfig from ph-db. All properties use the prefix phossap.jdbc..

  • phossap.jdbc.database-type: The target database type. Either PostgreSQL or MySQL.
  • phossap.jdbc.driver: The JDBC driver class. For PostgreSQL use org.postgresql.Driver. For MySQL use com.mysql.cj.jdbc.Driver.
  • phossap.jdbc.url: The JDBC URL of the database. Example for PostgreSQL: jdbc:postgresql://localhost:5432/phossap. Example for MySQL: jdbc:mysql://localhost:3306/phoss-ap?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false. It's recommended to not use the serverTimezone parameter.
  • phossap.jdbc.user: The database user.
  • phossap.jdbc.password: The password of the database user.
  • phossap.jdbc.schema: The database schema to use. For PostgreSQL defaults to public. Not used for MySQL (the database name in the JDBC URL serves this purpose).
  • phossap.jdbc.execution-time-warning.enabled: Enable or disable logging of long-running JDBC transactions. Default is true.
  • phossap.jdbc.execution-time-warning.ms: Threshold in milliseconds for the long-running JDBC transaction warning. Default is 1000.
  • phossap.jdbc.debug.connections: Enable or disable debug logging of JDBC connection lifecycle (open/close). Default is false.
  • phossap.jdbc.debug.transactions: Enable or disable debug logging of JDBC transactions (begin/commit/rollback). Default is false.
  • phossap.jdbc.debug.sql: Enable or disable debug logging of executed SQL statements. Default is false.

Connection Pooling

  • phossap.jdbc.pooling.max-connections: Maximum number of active connections in the pool. Default is 8.
  • phossap.jdbc.pooling.max-wait (since 0.9.0): Maximum time to wait for a connection from the pool before throwing an exception. Default is 10s.
  • phossap.jdbc.pooling.max-wait.millis (deprecated since 0.9.0; removal scheduled for v1.0.0): Legacy millisecond-typed key. Default is 10000.
  • phossap.jdbc.pooling.between-evictions-runs (since 0.9.0): Interval between runs of the idle connection evictor. Default is 5m.
  • phossap.jdbc.pooling.between-evictions-runs.millis (deprecated since 0.9.0; removal scheduled for v1.0.0): Legacy millisecond-typed key. Default is 300000.
  • phossap.jdbc.pooling.min-evictable-idle (since 0.9.0): Minimum idle time before a connection is eligible for eviction. Default is 30m.
  • phossap.jdbc.pooling.min-evictable-idle.millis (deprecated since 0.9.0; removal scheduled for v1.0.0): Legacy millisecond-typed key. Default is 1800000.
  • phossap.jdbc.pooling.remove-abandoned-timeout (since 0.9.0): Timeout before an abandoned connection can be removed. Default is 5m.
  • phossap.jdbc.pooling.remove-abandoned-timeout.millis (deprecated since 0.9.0; removal scheduled for v1.0.0): Legacy millisecond-typed key. Default is 300000.

Flyway

Configuration properties for Flyway database migrations, as defined by FlywayConfigurationBuilderConfig from ph-db. All properties use the prefix flyway. and fall back to the main JDBC properties if not explicitly set.

  • phossap.flyway.enabled: Enable or disable Flyway database migrations on startup. Default is true.
  • phossap.flyway.jdbc.url: Optional separate JDBC URL for Flyway migrations. Falls back to phossap.jdbc.url if not set.
  • phossap.flyway.jdbc.user: Optional separate database user for Flyway. Falls back to phossap.jdbc.user if not set.
  • phossap.flyway.jdbc.password: Optional separate database password for Flyway. Falls back to phossap.jdbc.password if not set.
  • phossap.flyway.jdbc.schema-create: Whether Flyway should attempt to create the database schema. Default is false.
  • phossap.flyway.baseline.version: The Flyway baseline version (integer). Used when baselining an existing database. Default is 0.
  • phossap.flyway.history-table (since 0.2.2): Custom name for the Flyway schema history table. If not set, the Flyway default (flyway_schema_history) is used.
  • phossap.flyway.debug-mode (since 0.2.2): Enable Flyway debug logging during migration execution. Default is false.
  • phossap.flyway.repair-mode (since 0.2.2): Run Flyway's repair() before executing migrations to fix inconsistencies in the schema history table. Default is false.

Peppol Reporting SQL Backend

The peppol-reporting library uses its own database for storing Peppol Reporting items (TSR/EUSR). It defines JDBC properties under the prefix peppol.reporting.jdbc. and Flyway properties under peppol.reporting.flyway.. See the peppol-reporting SQL backend configuration for the full list of properties.

When sharing the same database as phoss-ap, set a custom Flyway history table to avoid conflicts:

  • peppol.reporting.flyway.history-table: Custom name for the Flyway schema history table used by peppol-reporting. If not set, the Flyway default (flyway_schema_history) is used — which would conflict with the phoss-ap history table when using the same database. Example: flyway_schema_history_reporting.

Peppol Report Sending SQL Backend

The peppol-ap-support library uses its own database for tracking Peppol Report sending state. It defines JDBC properties under the prefix peppol.report.jdbc. and Flyway properties under peppol.report.flyway.. See the peppol-ap-support SQL backend configuration for the full list of properties.

When sharing the same database as phoss-ap, set a custom Flyway history table to avoid conflicts:

  • peppol.report.flyway.history-table: Custom name for the Flyway schema history table used by peppol-ap-support. If not set, the Flyway default (flyway_schema_history) is used — which would conflict with the phoss-ap history table when using the same database. Example: flyway_schema_history_report.

API Configuration

  • phase4.endpoint.address: The public AS4 endpoint URL of this AP (e.g. https://ap.example.com/as4). Used by phase4 for endpoint comparison and in reporting.
  • phase4.api.requiredtoken: The API token required for authenticating REST API calls (sent via X-Token header). If empty or not set, API authentication is disabled.

Document Storage

Document payloads (SBD files) are stored outside the database. The storage backend is selected via storage.mode — the local filesystem (default), Amazon S3, or a custom backend provided via SPI.

  • storage.mode: The document storage backend. One of filesystem (default), s3, or spi. When set to s3, documents are stored in an S3 bucket and their paths are recorded as s3://bucket/key URIs in the database. When set to filesystem, documents are stored as flat files on disk. When set to spi (since 0.10.4), documents are stored via a deployment-provided IDocumentPayloadManagerProviderSPI implementation (see Runtime Extensions).
  • storage.spi.id: (Required when storage.mode=spi, since 0.10.4) The ID of the IDocumentPayloadManagerProviderSPI provider to use, matched against the provider's getID(). Startup fails if unset or if no provider with that ID is on the classpath.
  • storage.inbound.path: Base path for inbound document storage. Used by the filesystem and s3 modes — as a filesystem directory when storage.mode=filesystem, or as a key path component when storage.mode=s3. Default is ${user.home}/phoss-ap/inbound.
  • storage.outbound.path: Base path for outbound document storage. Used by the filesystem and s3 modes — as a filesystem directory when storage.mode=filesystem, or as a key path component when storage.mode=s3. Default is ${user.home}/phoss-ap/outbound.

S3 Storage Backend (since 0.1.1)

These properties configure the S3 bucket used as the document storage backend when storage.mode=s3. All document payloads (both inbound and outbound) are stored in this bucket. Document paths in the database are recorded as s3://bucket/key URIs.

  • storage.s3.bucket: (Required when storage.mode=s3) The S3 bucket name for document storage.
  • storage.s3.region: (Required when storage.mode=s3) The AWS region of the S3 bucket (e.g. eu-central-1).
  • storage.s3.access-key-id: AWS access key ID for S3 access. Optional — if not set, the default AWS credential chain is used (IAM roles, environment variables, etc.).
  • storage.s3.secret-access-key: AWS secret access key for S3 access. Optional — if not set, the default AWS credential chain is used.
  • storage.s3.endpoint (since 0.2.2): Custom S3 endpoint URL for S3-compatible providers (e.g. MinIO, Garage). Optional — if not set, standard AWS S3 is used.
  • storage.s3.path-style-access (since 0.2.2): Enable S3 path-style access instead of virtual-hosted style. Required by most S3-compatible providers. Default is false.

Note: The S3 storage backend is independent of the S3 forwarding mode (forwarding.mode=s3_link). S3 storage affects where the AP persists document payloads internally, while S3 forwarding controls how received documents are delivered to the Receiver Backend. Both can be used simultaneously.

Outbound S3 Submission (since 0.1.1)

These properties configure the AP's ability to fetch outbound documents from an S3 bucket provided by the Sender Backend, instead of receiving the document payload inline via the HTTP request body.

When enabled, the Sender Backend uploads the document to its own S3 bucket and then calls the POST /api/outbound/submit-s3 endpoint with the S3 bucket/key reference plus Peppol metadata. The AP fetches the document from S3 and processes it through the normal outbound pipeline.

  • outbound.s3.enabled: Enable or disable the /api/outbound/submit-s3 endpoint. Default is false.
  • outbound.s3.bucket: Default S3 bucket from which the AP fetches sender-uploaded documents. Can be overridden per request in the JSON body. Optional if always specified in the request.
  • outbound.s3.region: (Required when outbound.s3.enabled=true) The AWS region of the sender's S3 bucket (e.g. eu-central-1).
  • outbound.s3.access-key-id: AWS access key ID for accessing the sender's S3 bucket. Optional — if not set, the default AWS credential chain is used.
  • outbound.s3.secret-access-key: AWS secret access key for accessing the sender's S3 bucket. Optional — if not set, the default AWS credential chain is used.
  • outbound.s3.endpoint (since 0.2.2): Custom S3 endpoint URL for S3-compatible providers (e.g. MinIO, Garage). Optional — if not set, standard AWS S3 is used.
  • outbound.s3.path-style-access (since 0.2.2): Enable S3 path-style access instead of virtual-hosted style. Required by most S3-compatible providers. Default is false.

Note: The sender's S3 bucket (configured here) may differ from the AP's storage S3 bucket (configured under storage.s3.*). The outbound S3 submission endpoint fetches from the sender's bucket and stores through the AP's own IDocumentPayloadManager (which may itself be S3-backed or filesystem-backed).

Sending Configuration

  • peppol.sending.enabled: Enable or disable outbound AS4 sending. Set to false to operate as a receive-only AP. Default is true.
  • outbound.dev-loopback.enabled (since v0.10.2): Development/testing aid. When set to true and peppol.stage=test, outbound sending bypasses the SMP/SML lookup and sends the generated AS4 message back to this AP's own AS4 endpoint (phase4.endpoint.address), using the AP's own AS4 certificate as the receiver certificate. This enables local end-to-end testing without SMP/SML registration or a public HTTPS endpoint for the test participant. Requires phase4.endpoint.address to be set. Only effective on the Peppol test stage — it is treated as disabled on the production stage regardless of this flag. Default is false.

Receiving Configuration

  • peppol.receiving.enabled: Enable or disable inbound AS4 receiving. Set to false to operate as a send-only AP. Default is true.

Forwarding Configuration

  • forwarding.mode: (Required) Selects the active forwarding implementation. One of: http_post_sync, http_post_async, s3_link, sftp, filesystem, spi. Must be explicitly configured — there is no default.
  • forwarding.c4countrycode.modes (since v0.1.3): Comma-separated list of modes to try (in order) for automatically determining the C4 country code after successful inbound forwarding. Available modes: receiver_pid (derive from receiver participant ID scheme), business_card (look up from Peppol Directory Business Card via SMP). The asynchronous reporting API (POST /api/inbound/report) always remains available as an additional fallback. Default is empty (no automatic determination). Example: receiver_pid,business_card.

SPI Forwarding (since v0.10.0)

  • forwarding.spi.id: (Required when forwarding.mode=spi) Stable ID of a deployment-provided IDocumentForwarderProviderSPI. The provider must be on the runtime classpath and registered through META-INF/services/com.helger.phoss.ap.api.spi.IDocumentForwarderProviderSPI. After the provider creates the forwarder, the AP calls initFromConfiguration(config, "forwarding."), so the SPI-provided forwarder may read any additional forwarding.* keys it needs.

Whether the SPI-provided forwarder participates in synchronous delivery confirmation (and therefore yields an AP vs AB MLS response — see Forwarding Process) is determined by the IDocumentForwarder#isWithDeliveryConfirmation() value returned by the provider's forwarder instance.

Example:

forwarding.mode=spi
forwarding.spi.id=docnut
forwarding.endpoint=https://backend.example.com/inbound

HTTP POST Forwarding

  • forwarding.http.endpoint: The URL of the Receiver Backend endpoint to POST the SBD to.

Custom HTTP Headers (since v0.2.0)

Custom HTTP headers can be added to every forwarding request using indexed properties. This is useful for authentication (e.g., Bearer tokens, API keys) or passing custom metadata to the Receiver Backend.

  • forwarding.http.headers.{n}.name: The header name (case-insensitive). {n} is a 1-based index.
  • forwarding.http.headers.{n}.value: The header value.

Headers are read sequentially starting from index 1. The sequence stops at the first missing .name entry.

Example:

forwarding.http.headers.1.name=Authorization
forwarding.http.headers.1.value=Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
forwarding.http.headers.2.name=X-Tenant-ID
forwarding.http.headers.2.value=customer-42

The HTTP client used for forwarding is configured via HttpClientSettingsConfig from ph-web with the prefix forwarding.. All properties below are optional and have sensible defaults.

Timeouts

  • forwarding.http.timeout.connect.millis (or .seconds, .minutes, .hours): Connect timeout for the HTTP POST.
  • forwarding.http.timeout.response.millis (or .seconds, .minutes, .hours): Response/read timeout for the HTTP POST.
  • forwarding.http.timeout.connectionrequest.millis (or .seconds, .minutes, .hours): Timeout for obtaining a connection from the pool.

Retry

  • forwarding.http.retry.count: Number of HTTP-level retries (integer, >= 0). Not set by default.
  • forwarding.http.retry.interval.millis (or .seconds, .minutes, .hours): Interval between HTTP-level retries.
  • forwarding.http.retry.always: Whether to retry on all failures (boolean). Default is the HttpClient default.

Proxy

  • forwarding.http.proxy.enabled: Enable a separate HTTP proxy for forwarding requests. Default is false.
  • forwarding.http.proxy.host: Proxy hostname.
  • forwarding.http.proxy.port: Proxy port (integer).
  • forwarding.http.proxy.username: Proxy authentication username.
  • forwarding.http.proxy.password: Proxy authentication password.
  • forwarding.http.proxy.nonProxyHosts: Pipe-separated list of hosts that bypass the proxy.

TLS

  • forwarding.http.tls.checks.disabled: Disable all TLS checks (hostname + certificate). Default is false. Security risk — use only for testing.
  • forwarding.http.tls.hostname-check.disabled: Disable TLS hostname verification only. Default is false.
  • forwarding.http.tls.certificate-check.disabled: Disable TLS certificate verification only. Default is false.

Miscellaneous

  • forwarding.http.useragent: Custom User-Agent header for forwarding requests.
  • forwarding.http.follow-redirects: Whether to follow HTTP redirects. Default is the HttpClient default.
  • forwarding.http.keep-alive: Whether to use HTTP keep-alive connections. Default is the HttpClient default.
  • forwarding.http.dnsclientcache.use: Whether to use the DNS client cache.
  • forwarding.http.protocol-upgrade.enabled: Enable HTTP/2 protocol upgrade. Default is the HttpClient default.

S3 Forwarding

  • forwarding.s3.bucket: The S3 bucket name where received SBDs are stored.
  • forwarding.s3.region: The AWS region of the S3 bucket (e.g. eu-central-1).
  • forwarding.s3.access-key-id: AWS access key ID for S3 access. Optional if using IAM roles.
  • forwarding.s3.secret-access-key: AWS secret access key for S3 access. Optional if using IAM roles.
  • forwarding.s3.endpoint (since 0.2.2): Custom S3 endpoint URL for S3-compatible providers (e.g. MinIO, Garage). Optional — if not set, standard AWS S3 is used.
  • forwarding.s3.path-style-access (since 0.2.2): Enable S3 path-style access instead of virtual-hosted style. Required by most S3-compatible providers. Default is false.
  • forwarding.s3.key-prefix: Optional prefix (folder path) for S3 object keys.
  • forwarding.s3.write-metadata (since v0.10.2): Whether to additionally upload a JSON metadata sidecar object next to each SBD. Either true or false (default). When enabled, the sidecar object uses the same key as the uploaded SBD but with a .json extension instead of .xml (e.g. <key-prefix><sbdhInstanceID>.json alongside <key-prefix><sbdhInstanceID>.xml), is stored with content type application/json, and contains the same JSON metadata as the SFTP and filesystem sidecars (the full inbound transaction as returned by the inbound transaction REST API). A failure to write the sidecar is logged but does not fail the forwarding.

SFTP Forwarding

  • forwarding.sftp.host: The hostname or IP address of the SFTP server.
  • forwarding.sftp.port: The port of the SFTP server. Default is 22.
  • forwarding.sftp.connectiontimeoutms: Connection timeout in milliseconds. Default is defined by ISftpSettingsHost.DEFAULT_CONNECTION_TIMEOUT_MS.
  • forwarding.sftp.user: The username for SFTP authentication.
  • forwarding.sftp.password: The password for SFTP authentication. Either this or a key pair must be provided.
  • forwarding.sftp.keypair.privatekeypath: Path to the private key file for key-based authentication.
  • forwarding.sftp.keypair.publickeypath: Path to the public key file for key-based authentication.
  • forwarding.sftp.keypair.passphrase: Optional passphrase for the key pair.
  • forwarding.sftp.knownhostspath: Path to the SSH known_hosts file for host key verification. Optional — if not set, host key checking may be skipped.
  • forwarding.sftp.maxconnections: Maximum number of parallel SFTP connections. Default is defined by ISftpSettingsHost.DEFAULT_MAX_CONNECTIONS.
  • forwarding.sftp.uploaddir: The remote directory on the SFTP server where SBDs are uploaded.
  • forwarding.sftp.write-metadata: (since v0.10.2) Whether to additionally upload a JSON metadata sidecar next to each SBD. Either true or false (default). When enabled, the sidecar uses the same base name as the uploaded SBD but with a .json extension (e.g. 20260702120000_abc.json alongside 20260702120000_abc.xml) and contains the same JSON metadata as the filesystem forwarder (the full inbound transaction as returned by the inbound transaction REST API, including id, senderID, receiverID, docTypeID, processID, as4MessageID, sbdhInstanceID, status, attemptCount, receivedDT and the remaining transaction fields). Like the SBD itself, the sidecar is written atomically (.tmp then rename). A failure to write the sidecar is logged but does not fail the forwarding.

Filesystem Forwarding (since v0.2.0)

Writes the received SBD to a local directory. Useful for integrations where the Receiver Backend picks up files from a shared filesystem or NFS mount.

  • forwarding.filesystem.directory: (Required when forwarding.mode=filesystem) The absolute path of the target directory. Created automatically if it does not exist.
  • forwarding.filesystem.layout: File layout mode. Either flat (default) or per-transaction.
    • flat — All files are written directly into the configured directory. Each transaction produces two files: {sbdhInstanceID}.xml (the SBD) and {sbdhInstanceID}.json (metadata).
    • per-transaction — Each transaction gets its own subdirectory named by SBDH Instance ID, containing sbd.xml and metadata.json.

Files are written atomically using a .tmp extension and renamed after the transfer completes, so the Receiver Backend never sees partial files. If a file with the same SBDH Instance ID already exists (e.g., due to duplicate detection in store_and_flag mode), a numeric suffix is appended to ensure uniqueness.

The metadata JSON file contains: sbdhInstanceID, senderID, receiverID, docTypeID, processID, as4MessageID, c1CountryCode, and receivedDT.

Delivery confirmation: No — MLS response code is AB (Accepted Blind), same as S3 and SFTP modes.

Secondary Forwarders (since v0.9.0)

In addition to the primary forwarder configured under forwarding.*, up to 10 secondary forwarders can be configured to receive a copy of every successfully forwarded inbound document. Secondaries are useful for fanning out received messages to additional environments (e.g. duplicating from TEST to both a Dev and a QA backend) without affecting the primary delivery.

Semantics:

  • Secondary forwarders are dispatched fire-and-forget, asynchronously, only after the primary forwarder succeeded (they never run if the primary fails).
  • No retries are performed for secondaries. If a secondary forward fails, the failure is logged at WARN (or ERROR for exceptions) and the next secondary continues.
  • Secondary outcomes have no effect on the inbound transaction status, MLS response, retry scheduling, or circuit breaker.
  • A failing secondary does not prevent later secondaries from running.
  • No inbound_forwarding_attempt rows are persisted for secondaries — visibility is via log messages and OpenTelemetry spans only.

Configuration:

Secondary forwarders are configured using indexed keys with the prefix forwarding.secondary.{n}., where {n} is a 1-based index in the range 110. Iteration starts at 1 and stops at the first index where no .mode key is set. Defining a secondary at index 11 or higher causes the AP to fail to start with an InitializationException. Each secondary uses the same key suffixes as the primary, just with the new prefix.

  • forwarding.secondary.{n}.mode: (Required to define a secondary) The forwarding mode for this secondary. Same values as forwarding.mode: http_post_sync, http_post_async, s3_link, sftp, filesystem, spi.

All other forwarder-specific keys are read with the forwarding.secondary.{n}. prefix in place of forwarding.. For example:

  • HTTP: forwarding.secondary.{n}.http.endpoint, forwarding.secondary.{n}.http.headers.1.name, forwarding.secondary.{n}.http.timeout.connect.millis, etc.
  • S3: forwarding.secondary.{n}.s3.bucket, forwarding.secondary.{n}.s3.region, etc.
  • SFTP: forwarding.secondary.{n}.sftp.host, forwarding.secondary.{n}.sftp.user, etc.
  • Filesystem: forwarding.secondary.{n}.filesystem.directory, forwarding.secondary.{n}.filesystem.layout.
  • SPI (since v0.10.0): forwarding.secondary.{n}.spi.id, plus any keys read by the SPI-provided forwarder using the same forwarding.secondary.{n}. prefix.

Secondaries may use a different mode from the primary and from each other.

Example — primary HTTP plus two HTTP secondaries (Dev + QA):

# Primary - mandatory, drives SLA and retries
forwarding.mode=http_post_sync
forwarding.http.endpoint=https://prod-backend.example/inbound

# Secondary #1 - Dev environment
forwarding.secondary.1.mode=http_post_async
forwarding.secondary.1.http.endpoint=https://dev-backend.example/inbound
forwarding.secondary.1.http.headers.1.name=Authorization
forwarding.secondary.1.http.headers.1.value=Bearer dev-token

# Secondary #2 - QA environment
forwarding.secondary.2.mode=http_post_async
forwarding.secondary.2.http.endpoint=https://qa-backend.example/inbound

Example — primary HTTP plus a filesystem secondary for archival:

forwarding.mode=http_post_sync
forwarding.http.endpoint=https://prod-backend.example/inbound

forwarding.secondary.1.mode=filesystem
forwarding.secondary.1.filesystem.directory=/var/lib/phoss-ap/archive
forwarding.secondary.1.filesystem.layout=per-transaction

Observability: Each secondary dispatch is wrapped in a phoss.ap.inbound.forward.secondary OpenTelemetry span carrying the phoss.ap.transaction.id, phoss.ap.sbdh.instance_id, and phoss.ap.forwarder.index attributes; the inner forwarder-specific span (phoss.ap.forwarder.dispatch) is set as today.

Retry Configuration

Retry behavior is defined via customizable Java interfaces. The following properties configure the default retry strategy.

  • retry.sending.max-attempts: Maximum number of AS4 sending attempts for outbound transactions before marking as permanently failed. Default is 3.
  • retry.sending.initial-backoff (since 0.9.0): Initial backoff interval between sending retries. Default is 3m.
  • retry.sending.initial-backoff.ms (deprecated since 0.9.0; removal scheduled for v1.0.0): Legacy millisecond-typed key. Default is 180000.
  • retry.sending.backoff-multiplier: Multiplier applied to the backoff interval after each failed attempt (exponential backoff). Default is 2.0.
  • retry.sending.max-backoff (since 0.9.0): Maximum backoff interval. Default is 1h.
  • retry.sending.max-backoff.ms (deprecated since 0.9.0; removal scheduled for v1.0.0): Legacy millisecond-typed key. Default is 3600000.
  • retry.forwarding.max-attempts: Maximum number of forwarding attempts for inbound transactions before marking as permanently failed. Default is 3.
  • retry.forwarding.initial-backoff (since 0.9.0): Initial backoff interval between forwarding retries. Default is 1m.
  • retry.forwarding.initial-backoff.ms (deprecated since 0.9.0; removal scheduled for v1.0.0): Legacy millisecond-typed key. Default is 60000.
  • retry.forwarding.backoff-multiplier: Multiplier applied to the backoff interval after each failed forwarding attempt. Default is 2.0.
  • retry.forwarding.max-backoff (since 0.9.0): Maximum backoff interval for forwarding retries. Default is 1h.
  • retry.forwarding.max-backoff.ms (deprecated since 0.9.0; removal scheduled for v1.0.0): Legacy millisecond-typed key. Default is 3600000.
  • retry.scheduler.interval (since 0.9.0): Interval at which the retry scheduler checks for transactions eligible for retry. Default is 1m. Safe to enable on all instances — uses SKIP LOCKED for work distribution.
  • retry.scheduler.interval.ms (deprecated since 0.9.0; removal scheduled for v1.0.0): Legacy millisecond-typed key. Default is 60000.
  • retry.scheduler.batch-size (since 0.1.2): Maximum number of transactions to retry per scheduler cycle (inbound and outbound each). Must be >= 1. Default is 50.

Circuit Breaker

Per-C3 circuit breaker for outbound AS4 sending. Implemented in-memory using Failsafe. See Retry and Resilience Patterns for details.

  • circuit-breaker.failure-threshold: Number of consecutive failures to a C3 endpoint before the circuit breaker opens. Default is 5.
  • circuit-breaker.open-duration (since 0.9.0): Duration the circuit breaker stays open before transitioning to half-open. Default is 1m.
  • circuit-breaker.open-duration.ms (deprecated since 0.9.0; removal scheduled for v1.0.0): Legacy millisecond-typed key. Default is 60000.
  • circuit-breaker.half-open-max-attempts: Number of probe attempts allowed through in half-open state to test if the C3 endpoint has recovered. Default is 1.

Verification Configuration

  • verification.outbound.enabled: Enable or disable optional verification of outbound documents before AS4 sending. Default is false.
  • verification.inbound.enabled: Enable or disable optional verification of inbound documents before forwarding. Default is false.
  • verification.phorm.url: Base URL of the phorm Validation Service used for document verification (e.g. http://localhost:8080). Default is http://localhost:8080.
  • verification.phorm.token: The X-Token header value required by the phorm Validation Service for authentication. If empty, no token is sent.

The built-in verification implementation (phoss-ap-validation module) calls the phorm Validation Service's /api/dd_and_validate/ endpoint. The service auto-detects the document type and validates it against Peppol BIS rules. If the overall validation conformance is INVALID, the document is rejected. Custom verification logic can also be provided via the pluggable IDocumentVerifier SPI.

MLS Configuration

  • mls.sending.enabled (since 0.1.2): Global switch to enable or disable all outbound MLS sending. When set to false, the AP will not send any MLS responses (neither success nor failure) for inbound transactions. Default is true.
  • mls.type: The MLS sending strategy for this AP instance (as C3). Either FAILURE_ONLY or ALWAYS_SEND. Default is ALWAYS_SEND. This value is captured per inbound transaction at reception time. Only effective when mls.sending.enabled is true.

Reporting Configuration

  • peppol.reporting.schedule.enabled: Enable or disable the reporting schedule. Default is true.
  • peppol.reporting.schedule.day-of-month: Day of the month on which reporting is submitted (1-31). Default is 2.
  • peppol.reporting.schedule.hour: Hour of the day at which reporting is submitted (0-23). Default is 6.
  • peppol.reporting.schedule.minute: Minute of the hour at which reporting is submitted (0-59). Default is 7.

Duplicate Detection Configuration

  • duplicate.detection.as4.mode: Behavior when an AS4 Message ID duplicate is detected. Either reject or store_and_flag. Default is reject.
  • duplicate.detection.sbdh.mode: Behavior when an SBDH Instance Identifier duplicate is detected. Either reject or store_and_flag. Default is reject.
  • phase4.incoming.duplicatedisposal: Duration that AS4 Message IDs of received messages are kept in phase4's in-memory duplicate cache. Within this window an incoming message with a previously seen AS4 Message ID is detected as a duplicate (and then handled according to duplicate.detection.as4.mode). Accepts the duration grammar (e.g. 10m, 1h 30m) — see the Duration values section at the top of this page. Default is 10m. Defined by phase4 (AS4Configuration).
  • phase4.incoming.duplicatedisposal.minutes (deprecated; scheduled for removal in a future phase4 major version): Legacy minute-typed key for the same setting. A plain integer (minutes). Default is 10. When set, a deprecation warning is logged at startup; prefer the unit-less phase4.incoming.duplicatedisposal form above.

Archival Configuration

  • archival.scheduler.enabled: Enable or disable the periodic archival scheduler. Default is true. Safe to enable on all instances — uses SKIP LOCKED for work distribution.
  • archival.scheduler.interval (since 0.9.0): Interval at which the archival scheduler runs. Default is 1h.
  • archival.scheduler.interval.ms (deprecated since 0.9.0; removal scheduled for v1.0.0): Legacy millisecond-typed key. Default is 3600000.
  • archival.scheduler.batch-size (since 0.1.2): Maximum number of transactions to archive per scheduler cycle (inbound and outbound each). Must be >= 1. Default is 100.

Cleanup Configuration (since 0.9.0)

Periodically deletes archived inbound and outbound transactions whose completed_dt is older than the configured retention. Both the database row (and its archived attempt rows) and the associated document file are removed. Cleanup operates only on archive tables — primary tables are never touched.

Preconditions (validated at startup, otherwise InitializationException):

  • archival.scheduler.enabled must be true. Cleanup only operates on already-archived rows; it cannot run without the archiver feeding it.
  • cleanup.scheduler.retention must be at least 2 days.
  • cleanup.scheduler.retention must be greater than 2 × archival.scheduler.interval, so the archiver has time to land completed transactions before cleanup considers them.

Document file deletion is attempted before the row is deleted: a transient storage error leaves the row for the next cycle so that orphan files cannot accumulate.

Duration values use suffixes: ns, us, ms, s, m, h, d. Examples: 90d, 2d 12h, 36h. See the ph-config Duration values format.

  • cleanup.scheduler.enabled: Enable or disable the cleanup scheduler. Default is false.
  • cleanup.scheduler.interval: Interval at which the cleanup scheduler runs. Default is 24h.
  • cleanup.scheduler.retention: Retention duration. Archived transactions whose completed_dt is older than this are eligible for cleanup. Default is 90d. Minimum is 2d.
  • cleanup.scheduler.batch-size: Maximum number of archived transactions to clean up per scheduler cycle (inbound and outbound each). Must be >= 1. Default is 100.

Directory Sender Configuration (since v0.2.0)

Optional directory-based batch sender that watches a directory for pre-built SBD (Standard Business Document) XML files and submits them via the normal outbound pipeline. Files are moved to success/ or error/ subdirectories after processing, with a JSON result file written alongside each. A pending/ subdirectory is used during processing to prevent duplicate pickup.

  • dirsender.enabled: Enable or disable the directory sender. Default is false.
  • dirsender.directory: (Required when enabled) Absolute path to the watch directory. The directory must exist. Subdirectories pending/, success/, and error/ are created automatically.
  • dirsender.scan-interval (since 0.9.0): Interval between directory scans. Default is 30s.
  • dirsender.scan-interval.ms (deprecated since 0.9.0; removal scheduled for v1.0.0): Legacy millisecond-typed key. Default is 30000.
  • dirsender.initial-delay (since 0.9.0): Delay before the first scan after startup. Default is 30s.
  • dirsender.initial-delay.ms (deprecated since 0.9.0; removal scheduled for v1.0.0): Legacy millisecond-typed key. Default is 30000.

Only files with the .xml extension in the watch directory root are picked up. Files must be complete, valid Peppol SBD documents (SBDH envelope + business document). Raw business documents without SBDH are not supported — use the REST API (POST /api/outbound/submit/...) for those.

On startup, files found in the pending/ directory from a previous run are recovered: the database is checked to determine whether each file was already submitted, and files are moved to the appropriate target directory. Files with no database entry are moved back to the watch directory for reprocessing.

HTTP Proxy Configuration

These settings are needed when the AP runs behind an outbound proxy server. They affect AS4 sending, SMP lookups, CRL downloads, and reporting submission.

  • http.proxy.enabled: Enable or disable the use of an outbound HTTP proxy. Default is false.
  • http.proxy.host: Proxy host name or IP address.
  • http.proxy.port: Proxy port number.
  • http.proxy.username: Optional username for proxy authentication.
  • http.proxy.password: Optional password for proxy authentication.
  • http.proxy.nonProxyHosts: Pipe-separated list of hosts that should bypass the proxy (e.g. localhost|127.0.0.1).

Shutdown and Startup Recovery

  • shutdown.timeout (since 0.9.0): Maximum time to wait for in-flight sending and forwarding operations to complete during graceful shutdown. After this timeout, remaining tasks are interrupted. Default is 30s.
  • shutdown.timeout.ms (deprecated since 0.9.0; removal scheduled for v1.0.0): Legacy millisecond-typed key. Default is 30000.
  • startup.recovery.enabled: Enable or disable stale transaction recovery at startup. When true, transactions left in transient states (sending, forwarding) from a previous unclean shutdown are reset to their retry-eligible states (failed, forward_failed) with next_retry_dt = NOW(). Default is true.

See also the Spring Boot properties server.shutdown and spring.lifecycle.timeout-per-shutdown-phase in the Spring Boot / Server Configuration section.

Management Status Endpoint

The AP exposes a JSON status endpoint at GET /management/status that returns non-sensitive configuration values, version information, and runtime metadata. It is intended for health probes, dashboards, and operational tooling.

  • management.status.enabled (since v0.1.3): Enable or disable the status endpoint. When false, the endpoint returns {"status.enabled": false} instead of the full status data. Default is true.

See API Specification for the full response schema.

Logging and Diagnostics

  • phase4.dump.path: Directory path where AS4 message dumps (request/response) are stored for debugging purposes. If not set, no dumps are created. Example: /var/phoss-ap/data/phase4-dumps/.
  • phase4.dump.mode: Controls the file layout of AS4 message dumps. Either direction or grouped. Default is direction.
    • direction — the existing behavior: dumps are placed into separate incoming/ and outgoing/ subdirectories.
    • grouped — correlated messages of a single AS4 exchange (UserMessage + SignalMessage) are placed together in a shared directory under grouped/<date>/<correlation-id>/. For inbound exchanges the correlation ID is the internal unique request ID; for outbound exchanges it is the sanitized AS4 Message ID.

Sentry Error Tracking

Optional integration with Sentry for real-time error tracking and alerting. Sentry is fully disabled by default and activates only when the sentry.dsn property is set and the sentry-logback dependency is on the classpath.

When active, a Logback SentryAppender is registered automatically. Additionally, a SentryNotificationHandler is registered that reports business-level failure events (e.g. sending failures, forwarding failures, verification rejections, reporting failures) to Sentry with structured attributes.

  • sentry.dsn: The Sentry Data Source Name (DSN) for your project (e.g. https://<key>@sentry.io/<project>). If not set, Sentry is fully disabled. Treat as a secret — place it in application-private.properties or inject via environment variable.
  • sentry.send-default-pii: Enable sending of Personally Identifiable Information such as request headers and IP addresses. See the Sentry PII documentation for details. Default is true.
  • sentry.logging.minimum-event-level: The minimum Logback level at which log events are sent to Sentry as events. Default is ERROR.
  • sentry.logging.minimum-breadcrumb-level: The minimum Logback level at which log events are captured as Sentry breadcrumbs. Default is INFO.

OpenTelemetry

Optional integration with OpenTelemetry for metrics, traces and logs. See OpenTelemetry Integration for the topology, emitted metrics, span names, attribute keys, and configuration via standard OTel environment variables.

  • otel.enabled (since 0.9.0): Set to true to bootstrap the OpenTelemetry SDK at application startup via the autoconfigure module. Default is false. All other behavior (OTLP endpoint, protocol, resource attributes, sampler, exporters) is configured via the standard OpenTelemetry environment variables / system properties — for example OTEL_SERVICE_NAME, OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_PROTOCOL, OTEL_RESOURCE_ATTRIBUTES. See the OpenTelemetry Java SDK configuration reference for the full list.

Spring Boot / Server Configuration

Standard Spring Boot properties for configuring the embedded server.

  • server.port: The HTTP port on which the AP listens. Default is 8080.
  • server.shutdown: Shutdown mode. Set to graceful to enable graceful shutdown (stop accepting new requests, drain in-flight requests). Default is immediate.
  • spring.lifecycle.timeout-per-shutdown-phase: Maximum time Spring Boot waits for the servlet container to drain in-flight HTTP requests during graceful shutdown. Example: 30s. Default is 30s.
  • server.forward-headers-strategy: Strategy for handling forwarded headers when running behind a reverse proxy. Set to native when behind a proxy.
  • spring.servlet.multipart.max-file-size: Maximum file size for multipart uploads (document submission). Example: 100MB.
  • spring.servlet.multipart.max-request-size: Maximum request size for multipart uploads. Example: 100MB.

Clone this wiki locally