--- id: API-8 family: GR-API level: core profiles: [storage-api] posture: normative-target added: "1.0" changed: "1.0" source: https://flowdrop.io/spec/rules/gr-api/api-8 specification: FlowDrop Workflow Specification 1.0-draft licence: CC BY 4.0 --- # API-8 — Every refusal carries a stable machine-readable code *GR-API (Part I) · level: core · profiles: storage-api · added in 1.0* A client has to be able to tell one refusal from another without reading English. Codes are the contract; the message is for a person. ## The rule > **Normative.** This is the rule. > > 1. Every refusal an API door emits carries a stable, machine-readable `error_code` alongside the human-readable `error` string. > > 2. Message text is never contract: a client must not classify a refusal by matching its message, and an implementation must not treat wording as load-bearing. > > 3. A code has one published definition that a client and a test can both name by it, and once published a code's meaning never changes and the code is never reused. ## What it means The human-readable message on a refusal is for a person; it is never what a client is allowed to match against. A client that classifies a refusal by matching a substring of the message is reading a field that can be reworded at will, and a rewording that drops the substring it depended on reclassifies the refusal without anything failing anywhere. The `error_code` exists so a client never has to do that. A code, once published, keeps its meaning forever and is never reused for something else — the same status code can and does cover more than one reason, and the code is what tells those reasons apart. ## Example Two refusals on sibling doors share a status and nothing else. ```http title="Resuming a pipeline with no pause to resolve" verdict="409 NO_ACTIVE_PAUSE" POST /flowdrop/api/pipelines/{pipeline}/resume {} ``` ```http title="Cancelling a pipeline that already has a signal pending" verdict="409 INWARD_SIGNAL_ALREADY_PENDING" POST /flowdrop/api/pipelines/{pipeline}/cancel {} ``` Both are 409s; the code is what a client reads to tell one from the other. ## Why Recorded under OPEN-18. ## Related rules - Names: STORE-5, API-3, API-7 - Referenced by: STORE-5, API-3, API-7, INT-16 --- Rule identifiers are permanent and are never renumbered. This specification carries no implementation status: each implementation publishes its own standing against these rules. Licensed CC BY 4.0.