>_ Analyst Engineering

How to Write API Requirements That Developers Can Actually Build

Cover for a guide on how to write API requirements, from endpoint and schema to error contracts and acceptance criteria.

Good API requirements read like a contract: the endpoint, the request and response schema, every status code, the error behavior, and testable acceptance criteria for both valid and invalid input. Vague API requirements are where integrations break.

To write API requirements that a developer can actually build, you specify the contract precisely: the endpoint and method, the request schema with every field and constraint, the success response, every status code the endpoint can return, the error contract, and acceptance criteria that cover the happy path and every way the call can fail. That is the whole job. The most common failure in API requirements is writing “the system shall expose an API to create a payment” and considering the work done. That is not a requirement; it is a placeholder for one, and it guarantees the developer and the consuming team will fill the gaps with assumptions that disagree.

I have specified APIs for payment engines and watched integrations fail in production for one reason above all others: the requirement covered the happy path and nothing else. The 202 was specified; the rejection with reason code AC04 was not, so the consumer had no idea how to handle it. Writing API requirements well is a core skill of the technical business analyst, and it is mostly about precision and unhappy paths. The full method for reading and documenting an API end to end is in API Documentation from Scratch.

What should an API requirement include?

An API requirement is complete when a developer can build the endpoint and a tester can verify it without coming back to ask a single question. That means it covers these elements every time.

The endpoint and method: the resource path and the HTTP verb, for example POST /payments. The authentication and authorization: who can call it and how, because access rules are requirements, not afterthoughts. The request schema: every field, its type, whether it is required or optional, and its validation constraints, down to formats and length limits. The success response: the status code and the body schema returned when the call works. The error contract: every status code and error the endpoint can return, with meaning. The behavioral rules: idempotency, rate limits, ordering, timeouts. And the acceptance criteria: the specific pass-or-fail checks for valid and invalid inputs.

Skip any of these and you have left a gap that someone downstream will fill with a guess. The field you marked optional but the downstream bank treats as mandatory. The error code you never specified that the consumer now has to reverse-engineer from production. Each omission is a defect waiting to happen, and the discipline of completeness is what separates a requirement from a wish. The artifact templates that make this repeatable are in Real-World BA Deliverables.

How do you specify the request and response schema?

Specify the schema field by field, with the type, the required-or-optional status, and the constraint that makes each field valid. A schema written in prose is ambiguous; a schema written as a structured table or example payload is not.

Take a payment creation endpoint. The request needs the debtor account, the creditor account, the amount, the currency, an end-to-end reference, and a value date. For each one, state the type and the rule: amount is a positive decimal with at most two fraction digits, currency is a three-letter ISO 4217 code, the creditor name has a maximum length the downstream scheme enforces. Here is the level of concreteness to aim for:

POST /payments
{
  "debtorAccount":   "string, IBAN, required, validated mod-97",
  "creditorAccount": "string, IBAN, required",
  "creditorName":    "string, required, max 70 chars (scheme limit)",
  "amount":          "decimal, required, > 0, max 2 fraction digits",
  "currency":        "string, required, ISO 4217, must be supported",
  "endToEndId":      "string, required, unique per debtor, idempotency key",
  "valueDate":       "date, optional, not in the past"
}

The response schema gets the same treatment. On success the endpoint returns a status and a body: the assigned payment id, the end-to-end id echoed back, the initial status, and a timestamp. Specify each field so the consumer knows exactly what to store. The discipline here is the same one that underpins all good functional analysis: replace every vague noun with a typed, constrained, named field.

Why every API requirement needs an error contract

Most of an integration’s real behavior lives in how it fails, so the error contract is not optional. It defines every error the endpoint can return, the status code, the error or reason code, and the message, so the consuming team can handle each case instead of guessing.

This is the single biggest gap I see in API requirements. The author specifies the 201 Created and stops. But the consumer needs to know that a malformed IBAN returns 400 with error code INVALID_IBAN, that a closed account returns 422 with reason code AC04, that an unsupported currency returns 400 with UNSUPPORTED_CURRENCY, and that a duplicate end-to-end id returns 409 Conflict. Each of those is a branch the consumer’s code must handle, and if you do not specify it, they will discover it in production when a real payment hits the path.

In payments the error contract maps directly to customer experience. A reason code is not just a developer concern; it becomes the message a customer reads when their money does not move. Specifying which code maps to which customer-facing message is requirements work, and getting it wrong causes support incidents. The relationship between status codes, reason codes, and what the customer actually sees is something I dig into in PAIN vs pacs in ISO 20022, because the message types carry exactly this status information.

How do you write acceptance criteria for an API?

Write acceptance criteria as specific input-to-output assertions, one per scenario, covering the happy path and every failure. Each criterion states the request, the expected status code, the expected response body, and any side effect such as an event published or a row written.

For the payment endpoint, the happy-path criterion reads: given a valid payment request, the endpoint returns 202 with status RCVD, echoes the end-to-end id, assigns a payment id, and publishes a payment.received event keyed by that id. Then the failure criteria, one per branch: an invalid IBAN returns 400 with INVALID_IBAN and publishes no event; a closed account returns the payment accepted at ingestion but rejected downstream with AC04; a duplicate end-to-end id returns 409 and does not create a second payment. Notice each criterion is something a tester can turn directly into an automated check, which is the entire point.

This is where API requirements and testing become one skill. You cannot write good acceptance criteria for behavior you have never observed, which is why the strongest analysts verify the API before they finalize the spec. Chaining a request through the system to confirm what it actually does, then writing the criteria from observation, is the method I walk through in You Don’t Understand the System Until You Test It. For event-driven endpoints, asserting the published event is part of the contract, and automating that assertion is exactly what Automate Kafka Validation with Postman is built for.

Where API requirements fit with the rest of the spec

API requirements are the integration-level expression of your functional requirements. The functional requirement says the system must let a customer initiate a payment and learn its status. The API requirement says exactly how, at the wire level: POST /payments to create, GET /payments/{id} to poll, with these schemas and these codes.

This is also why API requirements pair naturally with a sequence view. An API rarely lives alone; a single business action fans out across several calls and events. Drawing that as a sequence diagram shows the order and the integration points, and the API requirements fill in the contract for each hop. And because each API call is a step in a larger flow, the events those calls trigger are themselves requirements, which is the subject of event-driven requirements. The three together, sequence, API contract, and event behavior, are how you fully specify a modern integration.

A quick checklist for API requirements

Before you call an API requirement done, run it against this list. Does it name the exact endpoint and method? Does it specify every request field with type, required status, and constraint? Does it define the success response schema and status code? Does it list every error with its status and code? Does it state idempotency, rate-limit, and timeout behavior? Does it include acceptance criteria for the happy path and every failure branch? Are those criteria grounded in observed behavior rather than assumption?

If you can answer yes to all of those, the developer can build without guessing and the tester can verify without arguing, which is the only standard that matters. Building this habit is one of the highest-leverage moves for a technical analyst, and the structured path through it, from reading contracts to writing them, is laid out in The Technical Skills Guide for BAs.

The takeaway

Write API requirements as a precise contract: endpoint and method, fully typed request and response schemas, every status code, a complete error contract, the behavioral rules, and acceptance criteria that cover the happy path and every failure. Ground all of it in how the API actually behaves, not how you assume it does.

Do that and your integrations stop breaking on the first rejection nobody specified. Start with API Documentation from Scratch and Real-World BA Deliverables, or browse everything at The Tech BA Toolkit.

Ahmed is a Senior Technical Business Analyst with 10+ years in banking and payments. He builds practical guides and tools for analysts at The Tech BA Toolkit.

Tags: Business Analysis, API, Requirements, Software Development, Banking

Newsletter

Subscribe

Practical, no-fluff playbooks for technical analysts who analyze, code, test, and support. New articles straight to your inbox.

No spam. Unsubscribe anytime.