Skip to content
In this section

Flow externalId

Seller-scoped Flow externalId identity, collision, immutability, and runtime boundary contract.

Status: adopted contract; runtime implementation is pending the Flow aggregate.

externalId is the seller-provided join key for a Flow and its related artifacts. It is not a globally unique identifier and it is not an internal Flow ID.

Identity and uniqueness

The uniqueness key is the tuple:

(seller account, flow type, externalId)
  • seller account is the authenticated seller scope. A value in one seller's namespace does not collide with the same value in another seller's namespace.
  • flow type is the canonical Flow type, compared after the API's normal enum parsing. A value may be reused for a different Flow type in the same seller.
  • externalId is compared as the submitted identifier after the API's normal validation/normalisation. The runtime implementation must document that normalisation before accepting writes; it must not silently trim or case-fold values as an undocumented compatibility rule.

A create request whose tuple already exists is a conflict, not a second Flow. The API returns HTTP 409 Conflict and includes the existing Flow's canonical flowId in the error details. The response must not create or mutate any Flow, event, invoice, or other linked artifact.

This collision response is also the retry/idempotency rule for externalId: retrying a create with the same tuple converges on the existing flowId; it must never create a duplicate. A separate request idempotency key, if added to a Flow endpoint, cannot widen this uniqueness scope or override the conflict.

Immutability and lifecycle

externalId is write-once. It is required on Flow creation, is returned on reads, and cannot be changed by update, transition, close, or reopen operations. The seller cannot reuse the tuple after a Flow closes: closure does not release or recycle the uniqueness reservation. A replacement Flow must use a new externalId (or a different Flow type).

The identifier may be copied into events and invoice metadata as a join reference, but those copies do not establish identity and cannot be used to change the source Flow.

Runtime boundary

Runtime implementation is tracked separately in FLOW-09b / #3309. That follow-up is blocked on FLOW-00 / #3225, because the Flow aggregate and public endpoint do not exist yet.

This document is the contract for the future Flow aggregate only. There is currently no Flow aggregate, persistence constraint, handler, or public money-moving endpoint in this repository. No implementation may claim that 409, immutability, or Flow-linked artifact propagation is live until the aggregate, seller-scoped unique constraint, transaction boundary, and handlers are implemented and covered by runtime tests.

The implementation follow-up must at minimum prove:

  1. concurrent creates arbitrate on the seller/type/externalId unique constraint;
  2. the losing create returns 409 with the winner's flowId and creates no linked rows;
  3. update and lifecycle writes reject any externalId change before persistence;
  4. a closed Flow still reserves its tuple; and
  5. authenticated seller scope is part of every lookup and write.