Skip to content

Save (create or edit) a feed connection's credential. See

PUT
/admin/feed-connections/{code}/credentials
curl --request PUT \
--url http://localhost:3001/admin/feed-connections/string/credentials \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{}'

put_broker_connection_credentials for the order this follows and why — the only differences are parse_feed/test_feed in place of parse_broker/test_broker (feeds have no per-connection environment to thread through) and save_feed in place of save_broker.

code
required
string

Feed connection code

Media typeapplication/json

A submitted credential form: field name to raw string value, exactly as an HTML form or a JSON object would hand it over. Untyped on purpose — giving each broker its own typed request struct would just move the “which fields did they actually send” question from here into the handler, where the merge rule would have to be reimplemented per broker.

#[serde(flatten)] so the wire body is the field map itself ({"host": "...", "port": "4101"}), not {"fields": {...}} — the shape the cockpit form naturally produces.

object
key
additional properties
string

Example generated

{
"additionalProperty": "example"
}

Saved, tested where possible, and reloaded

Media typeapplication/json

Response body for a successful credential save.

reload is this connection’s own entry out of the reload report the save already triggered — not a second call the cockpit has to make — so the UI can say “applied” (a REST adapter, swapped live) or “restart required” (a FIX session) in the same response that confirms the write.

object
message

Present exactly when tested is false: TestOutcome::NotTestable’s own explanation (e.g. “FIX credentials are validated at session logon, not before save”), passed through so the cockpit renders the server’s reason instead of hardcoding its own guess at the wording. Always None when tested is true — a Failed test never reaches this response at all (422, before anything is written).

string
nullable
redacted
required

The credential view safe to put on the wire. state mirrors CredentialState so the cockpit can tell “needs setup” (unconfigured) apart from “stored but the master key does not open it” (error) — the distinction the whole credential store was built to preserve; collapsing them would invite an operator to re-enter a credential that is already there instead of fixing the key. fields is populated only when state is "configured"; message only when state is "error". Never carries a decrypted secret, in either state.

object
code
required
string
fields
required
Array<object>

One field of a credential as it may be shown on the wire. Named so the UI always knows the field exists — even when value is withheld — and can render a “leave blank to keep” input rather than an empty box that looks like the value was lost. secret is carried explicitly rather than left for a caller to infer from value.is_none(), so a future field that is merely absent (not secret) cannot be mistaken for one that is withheld.

object
hint

A display-only preview of a withheld value (see masked). Never a value the client may send back.

string
nullable
name
required
string
secret
required
boolean
value

The stored value, when it is safe to echo and safe to submit back unchanged. None for both secrets and masked identifiers — in either case the cockpit must leave the input blank, so that an untouched field submits empty and the merge rule keeps what is stored.

string
nullable
message

The reason a stored blob could not be used — set only when state == "error", and always a description, never the payload.

string
nullable
state
required

“configured” | “unconfigured” | “error”

string
updated_at
string format: date-time
nullable
reload
required

None only if the reload report (queried by this same connection’s code, right after the save that triggered it) somehow lacks an entry for it — never expected in practice, but a missing key is safer to surface as “unknown” than to synthesize an outcome for.

object
tested
required

Whether the credential was actually checked against the broker before being written — false for FIX (see credentials_api::test_broker), so the UI reports “not testable” rather than implying a pass it never earned.

boolean

Example generated

{
"message": "example",
"redacted": {
"code": "example",
"fields": [
{
"hint": "example",
"name": "example",
"secret": true,
"value": "example"
}
],
"message": "example",
"state": "example",
"updated_at": "2026-04-15T12:00:00Z"
},
"reload": {},
"tested": true
}

The request body was malformed, or could not be parsed into a credential (unknown field, …)

Not found

The credential did not authenticate; nothing was written

The credential store could not be read, the master key is invalid or unset, or the reload failed