The API maps a client interface onto the stored manifest
What an editor calls an interface entry and what the server stores as a manifest entry are the same thing under two vocabularies. This is the mapping, including what it deliberately ignores.
The rule
- A workflow's API accepts an
interfaceobject and maps it onto the stored input and output manifests. - An entry's client-side identifier becomes the server-side input name; renaming either is a breaking change for callers.
- An entry carries exactly one binding, whose node and port identifiers become the entry's
node_idandport; an entry carrying more than one binding is refused with 400 and nothing is stored. - An entry carrying no binding is a client-side draft: it is skipped, not stored, and not an error.
- A declared data type, a schema, a default value and free-form metadata on an entry are ignored on write; the type and schema are derived server-side from the bound port, and the other two have no server representation.
- Input-side author metadata (the entry's display name, description, examples and required flag) round-trips as author-written manifest metadata does; an output entry carries only its name and binding.
- The mapped manifests are applied before the workflow is validated, so whether a named node or port exists is decided by workflow validation and refused with 422; the API's own 400s cover the entry's shape only.
What it means
An interface entry can only ever name one binding. An entry naming two is
refused outright, before anything else about it is even looked at — a shape
failure, not a decision about whether the node or port it names exists. An
entry naming none is not a failure at all: it is a client-side draft, quietly
skipped, and never stored.
That shape check happens before the workflow is validated, so it answers a different question than validation does. A binding whose node or port is made up entirely is not caught here — it is caught by the same check that would catch it on a directly-stored port list, and answered with a different status. The API's own refusals stop at the entry's shape; whether what it points to is real is somebody else's answer.
Example
POST /api/flowdrop/workflows
{"name": "Over-bound", "nodes": [ … ], "interface": {"inputs": [
{"id": "numbers", "bindings": [
{"nodeId": "calc1", "portId": "values"},
{"nodeId": "calc1", "portId": "values"}
]}
]}}POST /api/flowdrop/workflows
{"name": "Draft entry", "nodes": [ … ], "interface": {"inputs": [
{"id": "draft", "bindings": []},
{"id": "numbers", "bindings": [{"nodeId": "calc1", "portId": "values"}]}
]}}PUT /api/flowdrop/workflows/{workflow}
{"name": "Ghost", "interface": {"inputs": [
{"id": "numbers", "bindings": [{"nodeId": "ghost_node", "portId": "values"}]}
]}}The draft entry is not stored either, but silently: the response's
interface.inputs names only numbers.