Knowledge base

http-webhook-url

<acct-file>set by the Hub

The address the node sends accounting records to
in the configuration this is a linehttp-webhook-urlinside the block <acct-file>
Accounting the node sends by itself

Usually accounting records sit in a file, and they have to be collected from the node. This line reverses the direction: the node itself sends batches of records to the given address with a POST request.

The file remains, and this is the main thing to understand. The path in the <acct-file> tag does not go anywhere — it becomes intermediate storage. Records accumulate in the file, the file goes to the address and is deleted only after a successful send.

Success is a 2xx response and nothing else. Any other response triggers a retry after a short delay. So an unavailable receiver causes accumulation, not loss — until the disk runs out of space.

The extension in the path decides the format. .json — records in NDJSON and the application/x-ndjson header; any other extension — CSV and text/csv. The type can be overridden only with a headers file (http-webhook-extra-headers).

The main trap is a receiver that constantly responds with something other than 2xx. A wrong token, a batch that is too large, an application error — the engine will retry endlessly while intermediate files pile up. A receiver failure looks not like an accounting error but like a growing disk.
What the Hub does. It writes it — this is our telemetry. The address is built as <Hub address>/api/telemetry/pmta/<node number>, and the whole block looks like this: records d, b, rb, t, feedback-loop, the default fields plus additions — time of the first attempt, time in queue, number of attempts, the Feedback-ID header — a batch once a minute, a 1 MB ceiling.

If the Hub has a local address, the block is not written at all — the node has nowhere to reach. Then telemetry goes by polling through the management interface, and this is visible in the configuration apply log.

The receiver responds quickly on purpose. TelemetryController checks the token, puts the body in the cache and queues a job — parsing happens in the background. Otherwise our analytics would slow down someone else’s mail server: the engine waits for a 2xx.

Recommended values

The address has to be complete, and preferably by name rather than by IP:

What Note
scheme https — otherwise the token will travel in plain text
port not specified — 443 for https, 80 for http
host name fully qualified; the engine will complete a partial one for DNS but leave it as is in the Host header
IPv6 address in square brackets

The file extension in the block tag is part of the configuration: .json gives NDJSON, everything else CSV.

Address parsing, the intermediate file rule, the 2xx success condition and the format depending on the extension come from the manual (§ 3.3.11.17, § 12.1.1). The analysis of our telemetry block is based on the Hub’s code.
Example configuration
# this is how it looks for us: the .json extension is required
<acct-file /var/log/pmta/mtahub-webhook.json>
    records d, b, rb, t, feedback-loop
    record-fields d  *
    http-webhook-url https://hub.example.com/api/telemetry/pmta/7    http-webhook-extra-headers /etc/pmta/mtahub-headers.txt
    http-webhook-max-interval 1m
    max-size 1M
</acct-file>
There is no token in the address on purpose: it is in the headers file, otherwise it would end up in the receiving side’s web server logs.
yellow — — directive names, blue — blocks. They are highlighted the same way in the text of the card.
▲

Common mistakes and problems

what people get wrong and how it ends3 mistakes▶

Treating the webhook as a stream with no files on disk

§ 12.1.1

What it costsRecords still accumulate in a file at the given path. Disk space is needed just as for regular accounting, and more when the receiver is unavailable.
How to spot itThe disk fills up with “file accounting turned off.”
How to do it rightMonitor the intermediate file directory and the receiver’s responses, not just free space.

Changing the path extension without thinking about the format

§ 12.1.1

What it costsThe record format and the content type header are taken from the extension. .log instead of .json — and the receiver gets CSV with text/csv instead of NDJSON, with nothing to parse the batch with.
How to spot itThe receiver responds with a parse error while sending works fine.
How to do it rightKeep .json for NDJSON; override the content type with a headers file if needed.

Putting the token in the address instead of the headers file

our experience

What it costsThe address ends up in the receiving side’s web server logs, and the token with it. Revoking it later is cheaper than scrubbing the logs.
How to spot itA long random string is visible in the webhook address.
How to do it rightMove the token into the http-webhook-extra-headers file as an Authorization header.
Compatibility
PowerMTA 6.0
described in the manual of this version · platform: any
The vendor does not state the first version for every directive — there is no note here. The name also appears in the 5.0 edition of the manual.
Reference data
Syntax
http-webhook-url <url>
Values
http[s]://HOST[:PORT][/PATH]
Applying
reload, no restart needed
Queue
will not touch what is already queued
Where to write it
<acct-file>
How many times
once in the block
Everything here comes from the manual, with the section.
Inheritance
There is no inheritance: the line lives inside its <acct-file> and applies to its record stream. There can be several accounting blocks, each with its own address — a file one and a webhook can work simultaneously, which makes a migration safe.
⇄

Related directives

5 relations

How to check on the node
The first sign of a healthy webhook is an empty intermediate file directory: the files are deleted after a successful send.
ls -la /var/log/pmta/mtahub-webhook*
A growing number of files means the receiver is not responding with 2xx. The engine log will show the reason; http-webhook-log-verbose adds details. From the receiver’s side a batch can be faked: curl -X POST -H ‘Authorization: Bearer TOKEN’ -H ‘Content-Type: application/x-ndjson’ –data-binary @batch.json URL.
In the Hub
Value
The Hub picks it itself — pace, warm-up stage, metrics
Cost of a mistake
reversible: harms only while it is set
Scenarios
Collect telemetry