The JMS connector
How to consume messages from a message broker and turn each one into a flow execution: what the connector is, how to configure and start it, what guarantee it gives you, and what it does when things go wrong.
What it is
A separate process. It subscribes to a queue on your broker, and for every message it receives it makes one call to the flow’s queued endpoint:
The server does not know the broker exists. From its side these are ordinary submissions to
POST /flows/{tenant}/{flow}/enqueue, so execution, retries, backoff and the dead-letter queue
are the platform’s normal queued behaviour — see Queues, retries and the
DLQ. The connector’s job stops at getting the bytes accepted.
A flow fed by this connector that declares routes: must also declare serve_by_name: true, or it
is refused at publication: its messages arrive through /enqueue, which serves a flow with routes
only when it asks. See Served by name.
It talks STOMP 1.2, over plain TCP or over TLS. Any broker that exposes a STOMP endpoint works; “JMS” is the shape of the integration, not the wire protocol.
Configuration
Configuration lives in the front matter of the same .flow.md file you deploy. The platform
reads trigger to check that it names a connector and passes over the other trigger keys
below; the connector reads them all. max_message_bytes is read by
both, so one value sets the platform’s limit and the connector’s. One file describes both halves.
The connector reads its keys as the platform reads the front matter, comments included:
trigger_queue: orders # the order feed is the queue orders (see
Comments).
| Key | Type | Default | Meaning |
|---|---|---|---|
trigger |
string | required | Must be jms, in lower case and with nothing after it. A file is skipped, with a line at debug, when none of its keys starts with trigger or, before its first _, is within two letters of it, or when its trigger names another connector; the cases that stop the connector instead are under What stops the connector at start. |
trigger_queue |
string | required | Broker queue name. Subscribed as /queue/<name>. |
trigger_connection |
string | required | stomp://host:port, or stomp+ssl://host:port for STOMP over TLS, and nothing else: no user, no password, nothing after the port. Literal text and {{ ctx.KEY }} of a key the flow’s config: declares; see Configuration values. |
trigger_login |
string | none | The user the connector sends to the broker in CONNECT. Needs trigger_passcode_secret. Literal text and {{ ctx.KEY }} of a key the flow’s config: declares; see Configuration values and Broker login. |
trigger_passcode_secret |
string | none | The key of the secret that holds the broker passcode, read from NEXUS_SECRET_<KEY>. Needs trigger_login and a stomp+ssl:// connection. |
trigger_tls_ca_cert |
path | none | A PEM file of the certificates that sign the broker’s certificate. Without it, the public roots are trusted. Needs a stomp+ssl:// connection. |
trigger_content_type |
string | application/json |
The Content-Type a message is submitted with when its frame has no STOMP content-type header, such as application/xml. Checked as a media type when the connector starts; nothing is substituted. See From broker message to submission. |
trigger_concurrency |
integer | 1 |
Number of workers for this flow. Each opens its own connection and its own subscription. At least 1. |
max_message_bytes |
integer | 1048576 |
Largest message body the connector will forward. Must be greater than zero. trigger_max_body_bytes is a deprecated alias. |
flow: and tenant: are read too — they are what the submission URL is built from.
One pair of quotes around a value, "…" or '…', is stripped, the same way the platform strips
it.
What stops the connector at start
The connector reads its flow files once, when it starts, and stops before it consumes anything at the first key it cannot read as written. The error names the file’s key:
- A key that starts with
trigger, or that is within two letters of it (Trigger_queue,triger_queue), and is not one of the keys above: “trigger_queuis not a key of the jms connector; its keys aretrigger, …”, followed by “did you meantrigger_queue?” when one is that close. The value is not repeated. - Such keys without a
trigger:key: “the file hasTrigger,trigger_queuebut notrigger:key”. triggerempty, in another case (JMS), with a space or tab and more afterjms(jms extra), or quoted with blanks around it (" jms"): “triggeris empty”, or “triggermust be exactlyjms, in lower case, with nothing after it”. The first word oftriggerends at the first space or tab; a first word other thanjmsin any case,jms2included, names another connector, and the file is skipped with a line atdebug.- A value that is not of its kind. A number must be a whole number at or above its minimum:
trigger_concurrency: 0gives “trigger_concurrencyis “0”: it must be an integer, at least 1”. Nothing is rounded up to the minimum, there is no maximum, and a text key must not be empty. - A
trigger_connectionthat is notstomp://host:portorstomp+ssl://host:port, after its{{ ctx.KEY }}values are read. The error names the key and never the address:
| Address | Error |
|---|---|
tcp://broker:61613 |
trigger_connection must start with stomp:// or stomp+ssl:// |
stomp://user:pass@broker:61613 |
trigger_connection has a user and password: the user goes in trigger_login and the passcode in trigger_passcode_secret |
stomp://broker, stomp://broker:0 |
trigger_connection needs a port from 1 to 65535 |
stomp://broker:61613/queue |
trigger_connection has something after the port |
stomp://bad host:61613 |
trigger_connection needs a host of letters, digits, ., - and _, or an IPv6 address in brackets |
- A
trigger_content_typethat is not a media type,xmlorapplication/included: “trigger_content_typeis not a media type such asapplication/xmlortext/plain; charset=utf-8”. The value is not repeated. - A broker login or a CA file that cannot be used. The error names the key and the variable, never the user, the passcode or a byte of the file:
| Case | Error |
|---|---|
trigger_login without trigger_passcode_secret |
trigger_login is set without trigger_passcode_secret: a broker login needs both |
trigger_passcode_secret without trigger_login |
trigger_passcode_secret is set without trigger_login: a broker login needs both |
trigger_login holding a line break or a NUL |
trigger_login holds a line break or a NUL, which a STOMP CONNECT frame cannot carry |
trigger_passcode_secret: my key |
trigger_passcode_secret must be a secret key of letters, digits, _, . and - |
NEXUS_SECRET_<KEY> not set |
trigger_passcode_secret: environment variable NEXUS_SECRET_<KEY> is not set |
NEXUS_SECRET_<KEY> set to an empty value |
trigger_passcode_secret: environment variable NEXUS_SECRET_<KEY> is set but empty |
NEXUS_SECRET_<KEY> holding a line break or a NUL |
trigger_passcode_secret: environment variable NEXUS_SECRET_<KEY> holds a line break or a NUL, which a STOMP CONNECT frame cannot carry |
NEXUS_SECRET_<KEY> that is not UTF-8 |
trigger_passcode_secret: environment variable NEXUS_SECRET_<KEY> is not UTF-8, which a STOMP CONNECT frame cannot carry |
trigger_passcode_secret with a stomp:// connection |
trigger_passcode_secret needs a stomp+ssl:// connection: on stomp:// the passcode would cross the network in clear |
trigger_tls_ca_cert with a stomp:// connection |
trigger_tls_ca_cert needs a stomp+ssl:// connection |
trigger_tls_ca_cert naming a file that cannot be read |
`trigger_tls_ca_cert`: not readable, or not a regular file, or over the size limit |
trigger_tls_ca_cert naming a file that is not PEM |
trigger_tls_ca_cert: not a PEM file of certificates |
trigger_tls_ca_cert naming a certificate that cannot be a trust anchor |
trigger_tls_ca_cert: a certificate in it cannot be a trust anchor |
trigger_tls_ca_cert naming a PEM file with no certificate |
trigger_tls_ca_cert holds no certificate |
One file stopped stops the whole process, with every flow it serves, other tenants’ included.
nexus validate and nexus deploy refuse a flow whose trigger is not exactly jms or vfs:
trigger: jsm gives “trigger names no connector: it must be one of jms, vfs; did you
mean jms?”, and the hint comes only when a name is within two letters of the value. A typo
in the name of another trigger key passes nexus deploy and shows at the connector’s next
restart. Restart it after changing a trigger key, and read its first lines.
Configuration values
trigger_connection and trigger_login hold literal text and {{ ctx.KEY }} of a key the flow declares in
config:. The connector reads each such
key from NEXUS_CONFIG_<KEY> when it starts, once, and puts the value in its place:
config: [ORDERS_BROKER]trigger_connection: "stomp://{{ ctx.ORDERS_BROKER }}:61613"nexus validate and nexus deploy refuse any other {{ }} in the key, and a key config: does
not declare, naming the key:
| Written | Refusal |
|---|---|
{{ $.host }} |
trigger_connection: only {{ ctx.<KEY> }} of a key declared in config: may be written in a connector key |
{{ ctx.BROKER }} without BROKER in config: |
trigger_connection: {{ ctx.BROKER }} names a key that config: does not declare |
An environment variable written directly in the key is refused at publication too; see What a flow may read.
Three cases stop the connector before it consumes anything. The error names the key and the variable, never a value:
| Case | Error |
|---|---|
| The variable is not set | `trigger_connection` cannot be resolved: NEXUS_CONFIG_ORDERS_BROKER is not set |
| The variable is set and empty | `trigger_connection` cannot be resolved: NEXUS_CONFIG_ORDERS_BROKER is empty |
The value holds {{ |
`trigger_connection` cannot be resolved: NEXUS_CONFIG_ORDERS_BROKER holds {{, which cannot be substituted |
A half-built broker address would otherwise produce a connector that runs and quietly consumes
nothing. A value read from the variable is not read again. nexus serve checks the same variable at
its own start, as for every config: key; see
How configuration is named.
An address with a user and password, stomp://user:pass@host:port, is not a login: it stops
the connector at start, as above. The login has keys of its own.
Broker login
A broker that asks for a user and a passcode gets them in the STOMP CONNECT frame, as the
login and passcode headers:
trigger_connection: stomp+ssl://broker.example.com:61614trigger_tls_ca_cert: /etc/nexus/broker-ca.pemtrigger_login: orders-apptrigger_passcode_secret: orders-broker- The passcode is never written in the flow file.
trigger_passcode_secretnames a secret, as thekey:of asecret_readstep does, and the connector reads its value fromNEXUS_SECRET_<KEY>: the key upper-cased, with-and.turned into_.orders-brokeris read fromNEXUS_SECRET_ORDERS_BROKER. Nothing is substituted in this key. - The passcode travels only over TLS. A passcode on a
stomp://connection stops the connector at start, whatever the host,localhostincluded. Enable STOMP over TLS on the broker (ActiveMQ’sstomp+ssltransport connector, RabbitMQ’s STOMP TLS listener, an Artemis acceptor withsslEnabled) and pointtrigger_connectionat that port. - The passcode is read once, at start. To change it, set the new value and restart the connector. It appears in no log line and no error.
trigger_loginandtrigger_passcode_secretgo together. Astomp://orstomp+ssl://connection without either connects as before, with no login.
stomp+ssl:// opens TLS 1.3 or 1.2 before CONNECT and checks the broker’s certificate against
the host written in trigger_connection; an IP address is checked against the certificate’s IP
addresses. Without trigger_tls_ca_cert, the public roots are trusted, the same set the
connector trusts for the platform. With it, only the certificates of that file are, so a broker
whose certificate a private CA signs needs it. The file is read at start, where a bad file stops
the connector, and again at every connect, so a replaced CA file takes effect at the next connect.
A certificate that does not verify fails the session, which reconnects after its wait; nothing is
sent to the broker, and no setting turns the check off. The connector presents no client
certificate.
When the broker answers CONNECT with an ERROR frame, a wrong user or passcode for instance,
the worker stops instead of reconnecting, with one line at error: “worker stopped — the broker
refused the STOMP CONNECT; nothing was taken from the queue; check trigger_login,
trigger_passcode_secret and the broker’s own log, then restart the connector”. The line names
the worker, the tenant, the flow and whether a login was sent (login_sent), and nothing the
broker said; the broker’s own log says why it refused. Nothing was taken off the queue. The other
workers and flows of the connector keep running.
The connector reads the environment it was given. Unlike nexus, it does not load a .env
file.
A key written more than once is read in file order: every occurrence must be valid, so a malformed one stops the connector, naming the key, whichever side of a valid one it is on; when all are valid, the last stands.
A configured flow
---flowmarkdown_version: "0.1"flow: order-intaketenant: acmetrigger: jmstrigger_queue: ORDERS_INconfig: [ORDERS_BROKER]trigger_connection: "stomp://{{ ctx.ORDERS_BROKER }}:61613"trigger_concurrency: 2max_message_bytes: 1048576queue_max_attempts: 5queue_initial_delay_ms: 1000effects: [http_egress]---
## Step: normalise```ntd{ "orderId": "{{ $.orderId }}", "total": {{ $.total }}, "receivedAt": "{{ date_format(now()) }}"}```
## Step: forwardeffects: [http_egress]endpoint: https://orders.example.com/ingestmethod: POSTcontent_type: application/jsonStarting it
The binary is nexus-connector, delivered built alongside the platform. Give it one or more
flow files:
$ nexus-connector --server http://localhost:9090 \ --store /var/lib/nexus/jms.db \ order-intake.flow.md invoice-intake.flow.md| Flag | Default | Meaning |
|---|---|---|
--server <url> |
http://localhost:9090 |
Base URL of the server. Also read from NEXUS_SERVER_URL. |
--store <path> |
nexus-jms-connector.db |
Local database used for crash recovery. Created if absent. |
--api-key <key> |
none | Sent as Authorization: Bearer <key> on every request the connector makes. Also read from NEXUS_API_KEY. |
<flows...> |
required | One or more .flow.md paths. At least one must carry a JMS trigger. |
At startup, in this order: anything left in the local store from a previous run is submitted
first; then each file is read. Files are skipped or refused as described under
What stops the connector at start. A file that cannot be
read is fatal, and so is one the platform cannot parse when one of its trigger keys names jms,
in any case: the connector exits naming the file, rather than starting with one queue silently
unconsumed. A file with a JMS trigger is read with the platform’s own parser. The connector refuses to start
on a file the platform cannot parse when one of its trigger keys names jms, and on a file whose
tenant or flow breaks the rule for a name that becomes a path.
A file the platform parses but nexus validate refuses for another reason does not stop it. If no file carries a JMS trigger, it exits.
Rows an earlier release stored under a tenant or flow that breaks that rule are the exception
to the first step: they are not submitted, and every start logs one ERROR per pair, whose
remedy says to set the names the flow file declares on those rows of pending_messages in the
local store, which sends them at the next start, or to delete the rows to drop the messages.
If the connector cannot read what the local store holds in flight, it logs an ERROR, submits
none of it, and starts. The rows stay in the store and are submitted at the next start that can
read them. Do not delete the store: those rows are the only copy of messages already taken off
the broker.
Then it runs until Ctrl+C. Operational output goes to stderr, never to stdout, and RUST_LOG
sets its level. Colour codes are added only when stderr is a terminal and NO_COLOR is unset or
empty, so a redirected log stays plain text. A RUST_LOG that is not valid Unicode is read as
unset.
When RUST_LOG is set, it is used as written, so RUST_LOG=debug also shows each file skipped; a
part of it that cannot be read is left out and named on stderr, and when no part can be read only
error lines show. When it is not set, or is empty, it depends on the target, the name after the
level on each line: nexus_connector shows from info up, every other target only at error.
nexus_connector is on the lines that announce the replay of the local store, the workers started
and the stop, such as starting connector workers and shutting down. The workers’ lines and the
retries of a submission, at start and while running, are under nexus_jms_connector::worker, so
without RUST_LOG connected to broker, reconnecting and the retry lines stay hidden. The two
warnings of a /connector/events report the server refuses or that cannot be sent are under
nexus_connector and show without RUST_LOG. A RUST_LOG that names only other targets, such
as RUST_LOG=reqwest=debug, hides every line of the connector, its error lines included;
RUST_LOG=error,reqwest=debug keeps them. A
connector with messages in its local store and the server down shows
replaying <n> pending message(s) from local store, then no line while it retries.
From broker message to submission
| What the broker sends | What the connector does with it |
|---|---|
| The message body | Becomes the request body of POST /flows/{tenant}/{flow}/enqueue, byte for byte. |
The message-id header |
Becomes the message’s identity for deduplication, and is recorded in the log. |
The ack header |
Used to acknowledge that one message. |
The content-type header |
Becomes the submission’s Content-Type, as written, parameters included. |
| Everything else | Not forwarded. Other broker headers and JMS properties do not reach the flow. |
The submission’s Content-Type is, in this order:
- the message’s STOMP
content-typeheader, the first one when the frame repeats it, its name in lower case exactly and its value unescaped as STOMP 1.2 defines (\cis:); - otherwise the flow’s
trigger_content_type; - otherwise
application/json.
The type is chosen once, when the message is taken off the broker, and kept with it in the local
store: a message submitted again at the next start (see Delivery guarantee below) keeps its
type. A message stored by an earlier connector, which kept no type, is submitted as
application/json, as that connector submitted it.
The value is sent as it is. The server decides what it accepts and how it reads it, and the flow
reads the result as $: see /enqueue for the
types it reads. A body the server cannot read as its type is answered with 400: the connector
quarantines that message, body included, and moves on to the next one (see Permanent refusals
below). Nothing is retried with another type.
A message whose content-type header is not a media type, such as xml, is not submitted. It is
quarantined in the local store, body included, as a 400 would be, before it is acknowledged to
the broker, so no restart submits it, and the worker moves on to the next one. The line message quarantined — its STOMP `content-type` header is not a media type,
at warn under nexus_jms_connector::worker, names the flow and the tenant, never the header’s
value or the body; without RUST_LOG it stays hidden.
The connector and the server read the same max_message_bytes out of the same front matter, so
the two ceilings agree by construction — raise it in the file and both halves move together. What
they do not share is the installation-wide default underneath it: a flow that declares nothing gets
the server’s max_message_bytes from system_config, and if an operator has lowered that below
1 MiB, the connector will forward messages the server then refuses with 413. See
Limits.
Ordering: one worker consumes and submits one message at a time, in the order the broker
delivers them. With trigger_concurrency above 1 there are that many independent consumers and
nothing preserves order between them.
Delivery guarantee
At-least-once. A message that reaches the connector is submitted at least once; it can be submitted twice. Make the flow tolerate a repeated message.
The mechanism, per message, in this order:
- Write the message to the local store.
- Report
connector_received. ACKthe broker — the message leaves the queue.POSTit to/enqueue, retrying every failure until a 2xx: 1 second, doubling to a 60-second ceiling, forever.- Mark it delivered in the local store.
The store is what makes step 3 safe: once the bytes are on local disk the broker’s copy is no longer needed, and the submission can take as long as it takes. Steps 4 and 5 do not depend on the broker connection — a drop mid-retry changes nothing.
At the next start, everything still marked in flight is submitted again, with the Content-Type
chosen when it was taken off the broker, and then marked delivered, before any worker connects. A broker that redelivers a message-id already marked
delivered gets an ACK, and the message is dropped rather than submitted twice.
Three things produce a duplicate:
- A crash between the server accepting a submission and step 5. The message is still marked in flight, so it is submitted again at the next start.
- A broker that does not set
message-id. The connector assigns a fresh identity to each delivery, so nothing matches on redelivery and the dedupe check cannot fire. Most brokers set it. - A delivery the local store cannot record. The server accepted the message, but the store
could not mark it delivered (a full disk, a read-only file). It stays in flight and is
submitted again at the next start; an
ERRORnames the message and says so. The connector then stops taking messages off the broker and reconnects, and a start that meets the same failure stops replaying there and leaves the rest for the next start. While the store stays unwritable this costs one duplicate per reconnect, not one per message.
Records of delivered messages older than 24 hours are discarded when the connector starts. Deleting the store file discards them all, and discards anything still in flight with them.
Oversized messages
A body larger than max_message_bytes is discarded as it is read. The message is ACKed
— it is gone from the broker — and never forwarded. A connector_oversized event is reported.
This is a drop, not a dead-letter: after the ACK there is no copy anywhere. Set the limit
deliberately, and if losing a message is unacceptable, make the producer refuse to publish one
that large.
The size field on that event is reported as zero, because the body is thrown away as it is read rather than buffered.
Note the asymmetry: a message stopped here, by the connector’s own limit, is dropped and no copy
survives. One the platform refuses with 413 is kept — see below.
Permanent refusals
The connector retries a rejected submission — but only where retrying can work. Network failures,
429 and 5xx are retried; 400, 401, 403 and 413 are final answers and end the attempt.
| Status | What it means | What happens to the message |
|---|---|---|
401, 403 |
The key is wrong, revoked, expired, or not allowed on this flow or tenant | The message stays in the connector’s pending store and the worker stops. Fix the key, restart, and replay_pending submits it. |
400 |
The platform cannot read the message as the content type it was submitted with, or the document is nested too deeply to be queued | Quarantined in the local store, body included, and the worker carries on |
413 |
The message is over the platform’s ceiling for this flow | Quarantined in the local store, body included, and the worker carries on |
429 |
Rate limited | Waits for Retry-After when the server sends one (seconds form, capped at 5 minutes), otherwise backs off, then retries |
5xx, network |
The platform is down or restarting | Backs off and retries |
The distinction is what is wrong. On 401/403 nothing is wrong with the message, so it is kept
untouched; a worker that carried on would burn the rest of the queue against the same refusal. On
400 and 413 the message is the problem, so it is set aside and work continues. That 401
really does mean “wrong credential” is guaranteed by the platform: the gate answers 503, never
401, when it cannot decide.
Every permanent refusal is logged at error with the status, tenant, flow and what to do about it.
Quarantined messages are not evicted by the 24-hour cleanup — they hold the only surviving copy of a
message that has already been acknowledged to the broker, so inspect the store after one of these.
404 is still retried indefinitely, on purpose: a flow that is not deployed yet, or is disabled,
and a suspended tenant all answer it, and each can pass without anyone touching the message.
A flow withdrawn with nexus undeploy answers 404 too, so the connector keeps retrying and the
message stays at its source until the flow is deployed again or the connector is stopped.
When the broker connection drops
The session ends and the worker reconnects. It waits 2 seconds, then 4, 8, 16, 32, and 60
thereafter. A session that stayed up at least 30 seconds before failing resets the wait to 2
seconds, so an occasional drop does not push a healthy connector into minute-long gaps. It keeps
trying, except after an ERROR in answer to CONNECT.
A broker that is unreachable at startup behaves the same way — the worker retries until it
answers. So does a port on which no broker listens, a connection the broker closes before it
answers, and a TLS handshake that fails. An address that is not stomp://host:port or
stomp+ssl://host:port never gets this far: it stops the connector at start. The one answer that
stops the worker is an ERROR frame in answer to CONNECT; see Broker login.
Events it reports
The connector calls POST /connector/events/{tenant}/{flow} so that a message picked up from a
broker appears in the same structured log as an HTTP request. The call is fire-and-forget: a
failure is logged and message processing continues.
| Event | When | Carries |
|---|---|---|
connector_received |
The message is on local disk, not yet submitted | Correlation ID, message ID, worker number |
connector_oversized |
A message exceeded the size limit and was dropped | Message ID, worker number |
The connector generates one correlation ID per message, reports it on connector_received, and
sends it as X-Correlation-ID on the submission. The connector_received and queue_enqueued
entries therefore carry the same ID, and so does everything the flow logs when the worker picks
the message up. See Logging and audit.
A complete setup
Register the tenant, deploy the flow, and issue the key the connector will present:
$ nexus tenant create --id acme --display-name "Acme Ltd"$ nexus deploy order-intake.flow.md --version 1.0.0$ nexus keys create --tenant acme --label jms-connector \ --scopes '*' --flows order-intakecreated API key id=1 key: nxk_4f19c0b27ad3489e93f5c1e6a70d2b84
$ export NEXUS_CONFIG_ORDERS_BROKER=broker.example.com$ nexus serve --port 9090Give the connector its own key, scoped to the one flow it submits to with --flows. It authenticates
like any other caller — there is no connector-shaped exemption — so a shared key would mean revoking
it takes the other callers down too.
Point the connector at both the broker and the server:
$ export NEXUS_CONFIG_ORDERS_BROKER=broker.example.com$ export NEXUS_API_KEY=nxk_4f19c0b27ad3489e93f5c1e6a70d2b84$ nexus-connector --server http://localhost:9090 \ --store /var/lib/nexus/jms.db \ order-intake.flow.mdWithout a key the connector gets 401 on its first submission and stops, leaving the message
recoverable on the broker: a credential refusal is terminal, not something to retry forever.
Publish a JSON message to ORDERS_IN, and it arrives as the flow’s input:
{ "orderId": "A-1", "total": 42 }The flow runs on the platform’s queue worker, so its result is not returned anywhere — whatever the integration is for has to happen in an effect. Follow the message by its correlation ID in the log, or watch the Queue page of the management UI.
To change the flow’s steps, deploy a new version; the queue worker resolves the newest artifact
when it picks a message up, and the connector does not need restarting. To change any
trigger_* key, restart the connector — it reads the file once, at startup.
Not supported
A client certificate for the broker: the login is a user and a passcode. Topics — the
subscription is always a queue. Broker headers and message properties are not passed to the
flow. The connector does not sign its submissions, so a server started with NEXUS_WEBHOOK_SECRET set rejects
them.
A push subscription to a third-party product: the connector consumes a broker queue and nothing else, and nothing in the platform registers with another product to be notified. A source that has to announce itself calls the flow’s endpoint directly and needs no connector; see the HTTP API reference.