>_ Analyst Engineering

API Design Review: The Analyst's Checklist Before the Contract Is Frozen

Written by Ahmed at Analyst Engineering, a Senior Technical Business Analyst with 10+ years in banking and payments delivery.

Cover for API design review, showing a flawed OpenAPI snippet annotated with review findings such as verb in path, float amount, and missing error model.

Key takeaways

  • An API design review happens before build, while changing the contract is cheap; once consumers integrate, every design flaw becomes a breaking change or a permanent workaround.
  • The analyst reviews what architects and developers are least placed to judge: whether resources, fields, enums, and state changes match the business domain and process.
  • Money should never be a floating point number in an API contract: use a decimal string with an explicit currency, or an integer in minor units, and apply the choice consistently.
  • State changes such as cancel or approve are safer as explicit actions like POST /payments/{id}/cancel than as a client-writable status field, because the server can enforce which transitions are legal.
  • A consistent error model, such as RFC 9457 Problem Details extended with stable error codes and field paths, lets consumers handle every endpoint's failures with one piece of code.

An API design review examines a proposed contract before anyone builds it, while changes still cost a conversation rather than a migration. Architects check the platform fit and developers check feasibility; the analyst checks what nobody else is placed to judge: whether the resources, fields, enums, and state changes actually match the business. That is where the most expensive API design flaws live.

To review an API design as an analyst, work through eight lenses: business semantics (names, enums, and glossary), operations and state (every process step and legal transition), data types (money, dates, identifiers, lengths, null versus absent), error model, collections (pagination, filtering, sorting), safety (idempotency and concurrency), asynchronous behavior, and evolution. Record each finding with its location, severity, and a concrete suggestion, and agree the blockers before the contract is frozen.

APIs for Analysts, advanced track. Builds on Part 4, how to document an API. Full learning path: APIs for Analysts.

Everything in this article applies to OpenAPI and GraphQL schemas alike. The full method for writing the contract you review is in API Documentation from Scratch.

Why review an API design before it is built?

Because the cost of changing a contract rises sharply at two moments: when code implements it, and far more when consumers integrate with it. After that second moment, renaming a field or changing a type is a breaking change that needs a new version, a deprecation period, and every consumer’s cooperation. Most “we’ll fix it in v2” decisions are never fixed.

A design-first process makes early review possible: the OpenAPI or GraphQL schema is written and reviewed first, then mocks let consumers and testers start while the build proceeds. The review is the gate between draft and implementation.

Who reviews what in an API design review?

Split the review by strength so it is thorough without being a committee.

ReviewerFocus
AnalystDomain naming, process coverage, state transitions, field meaning, lengths aligned with downstream systems, business error cases, consumer journeys
ArchitectPlatform standards, security model, integration pattern, versioning strategy, fit with other APIs
DeveloperFeasibility, performance implications, data ownership, implementation cost
TesterTestability: stable error codes, deterministic behavior, observable side effects
Consumer representativeWhether the journey is buildable without extra calls or guesswork

Lens 1: Do the names and enums match the business domain?

An API’s vocabulary becomes permanent the day consumers integrate, so it must be the business’s vocabulary, not the database’s.

  • Resources are domain nouns, plural, with no verbs: /payments, /refunds, /mandates. Not /createPayment or /txnProc.
  • Field names match the glossary. If operations, finance, and the scheme all say “creditor”, the field is creditor, not beneficiary in one API and payee in the next. The data dictionary is the reference.
  • No unexplained abbreviations. amt, ccy, and benef_nm save three characters and cost every future reader.
  • One casing convention everywhere. camelCase or snake_case, never both in one contract.
  • Enums are complete and future-aware. List every value the business actually uses, and state in the documentation that consumers must tolerate values added later. A status enum missing a rarely used value, such as a pending investigation state, is a production incident on its first occurrence.

Lens 2: Do the operations cover the process and its state changes?

Walk the business process and the resource lifecycle against the endpoints. Every step needs an operation; every legal transition needs a way to trigger it; every illegal one needs to be impossible.

The key design choice is how state changes happen:

ApproachExampleRisk
Client-writable statusPATCH /payments/{id} with {"status": "CANCELLED"}Clients can attempt any transition; rules scatter into validation code
Explicit actionPOST /payments/{id}/cancelThe server owns the transition and can refuse it with a clear reason

Explicit actions map directly onto a state machine: each transition becomes an operation with its own preconditions, errors, and audit trail. Cancelling a settled payment returns 409 with PAYMENT_NOT_CANCELLABLE, instead of silently accepting a status write that downstream systems then contradict.

Also check that server-owned fields are read-only. id, status, createdAt, and fees are set by the server. If the request schema lets a client send them, the design invites mass assignment, one of the risks covered in API security testing.

Lens 3: Are the data types safe and unambiguous?

This lens catches the defects that survive every other review, because the field exists; it is just subtly wrong.

DataSafe designCommon flaw
MoneyDecimal string plus currency, {"value": "1250.00", "currency": "EUR"}, or integer minor units plus currency, as Stripe’s amount: 2000"amount": 1250.00 as a floating point number, or no currency
TimestampsISO 8601 with offset, 2026-09-15T10:42:00ZLocal time with no zone; mixing epoch seconds and strings across endpoints
DatesISO 8601 date only, 2026-09-15, named for its meaning: requestedExecutionDateA field called date holding a timestamp, with no stated meaning
IdentifiersOpaque stringsIntegers that leak volumes and break when formats change
LengthsmaxLength aligned with downstream: ISO 20022 names are 140 characters, Max35Text for referencesNo limit in the API and truncation somewhere downstream
BooleansOnly for genuinely two-state factsisApproved that later needs “pending”, becoming a breaking change
Null vs absentStated per field: absent means “not provided”, null means “explicitly none”Undefined behavior that each consumer guesses
Formatspattern or format for IBAN, BIC, email, country codesFree text validated nowhere

The length row is where analysts contribute most. An API accepting 255-character names in front of a payment flow whose messages carry far less is a truncation defect by design, and the ISO 20022 truncation ledger shows how quietly that data disappears.

Lens 4: Is the error model consistent and useful?

Consumers should be able to handle every endpoint’s failures with one piece of code. That needs one structure, stable codes, and field paths.

A strong default is RFC 9457 Problem Details, the IETF standard for HTTP API errors, served as application/problem+json, extended with your own members:

{
  "type": "https://api.example.com/problems/validation",
  "title": "The request is invalid",
  "status": 400,
  "detail": "2 fields failed validation.",
  "instance": "/v1/payments",
  "traceId": "a1b2c3d4",
  "errors": [
    { "code": "FIELD_TOO_LONG", "field": "creditor.name", "message": "Maximum 70 characters." },
    { "code": "IBAN_CHECKSUM_INVALID", "field": "creditor.iban", "message": "Checksum failed." }
  ]
}

Review questions:

  • Is there one error structure across all endpoints?
  • Are error codes stable strings consumers can switch on, not just messages that may be reworded?
  • Does each field error carry a field path?
  • Is the 400 versus 422 convention stated and applied consistently?
  • Is every business rule in the requirements represented by a specific code?
  • Is it clear which errors are safe to retry, as in the error catalogue from Part 4?
  • Do errors avoid leaking internal details such as stack traces, SQL, or class names?

Lens 5: Do lists support pagination, filtering, and sorting?

Any endpoint returning a list will eventually return too much. Check the design before that happens.

QuestionWhy it matters
Is every list paginated with a maximum page size?Unbounded lists fail at volume and invite resource exhaustion
Cursor or offset?Cursors stay correct while data changes; offsets skip or repeat items when records are inserted mid-read
Is the default order stable and documented?Paging through an unstably ordered list produces duplicates and gaps
Are the filters the business needs present?Reconciliation needs date ranges and statuses; support needs lookup by your own reference
Is total count needed, and affordable?Counting large tables can be expensive; decide deliberately

Reconciliation is the use case to test this lens against. If operations cannot fetch “all payments settled yesterday” efficiently, the design is incomplete, whatever the happy path looks like.

Lens 6: Are creates and updates safe to retry and to run concurrently?

  • Idempotency on creates. Does every POST that creates something or moves money accept an idempotency key, with a documented retention window and a 409 for key reuse with a different body? See idempotency testing.
  • Concurrency on updates. When two clients update the same resource, does the design prevent lost updates, for example with an ETag returned on read and If-Match required on update, answering 412 Precondition Failed when the resource changed in between?
  • Timeout semantics. Does the documentation tell consumers what to do after a timeout, given the operation may have succeeded?

Lens 7: Are long-running operations designed as asynchronous?

If an operation cannot finish within a normal request timeout, such as settlement, screening, or a large export, the design must not pretend it can.

  • The create returns 202 Accepted or a clearly non-final status such as ACCP, with a way to get the outcome.
  • The outcome is available by polling a status resource, by webhook, or both, with the choice documented.
  • Final statuses are named, and the consumer knows which ones end the flow.
  • Webhook events are named consistently, and their delivery guarantees are documented, as covered in webhooks explained for analysts.

The difference between these designs is the subject of synchronous vs asynchronous.

Lens 8: Can the contract evolve without breaking consumers?

  • Is the versioning strategy decided and stated: path, header, or date-based versions?
  • Does the documentation say consumers must ignore unknown fields and tolerate new enum values?
  • Are there fields likely to change shape soon, such as a boolean that will need a third state, or a single address string that must become structured? Fix those now.
  • Is there a deprecation policy with notice periods?

Designing for evolution is cheaper than managing breakage, and the change side is covered in API versioning and breaking changes.

What does a real design review look like?

Here is a first draft that reaches review more often than anyone admits:

paths:
  /createPayment:
    post:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                amt: { type: number }
                ccy: { type: string }
                date: { type: string }
                beneficiary_name: { type: string }
                accountNumber: { type: string }
                status: { type: string }
      responses:
        '200':
          description: OK
        '500':
          description: Error

And the review:

#LocationFindingSeveritySuggestion
1PathVerb in pathMajorPOST /v1/payments
2amtMoney as floating point, abbreviatedBlockerinstructedAmount: { value: "1250.00", currency: "EUR" } as decimal string
3ccyNo format or allowed valuesMajorISO 4217 code, enum of supported currencies
4dateAmbiguous meaning and formatBlockerrequestedExecutionDate, format: date, rules for past dates and holidays
5Casingsnake_case and camelCase mixedMinorOne convention across the API
6beneficiary_nameTerm not in glossary; no lengthMajorcreditor.name, maxLength aligned with downstream messages
7accountNumberFormat undefinedMajorcreditor.iban with checksum validation, or a typed account object
8statusServer-owned field writable by clientBlockerRemove from request; return in response
9SchemaNo required listMajorMark mandatory fields
10HeadersNo idempotency key on a money-moving createBlockerRequired Idempotency-Key header
11200Create returns OK with no bodyMajor201 with the created payment and its id, or 202 if asynchronous
12ErrorsOnly 500; no validation or business errorsBlocker400, 401, 403, 409, 422 with a shared error schema
13SecurityNo authentication definedBlockerSecurity scheme with scopes
14ExamplesNoneMinorA realistic named example per request and response

Fourteen findings in fifteen lines, six of them blockers. Each is a two-minute fix today and a versioned migration in a year. The corrected version of this endpoint is the one in Part 4.

How do you make API design review repeatable?

  • Adopt a published style guide instead of inventing one. The Zalando RESTful API Guidelines, the Microsoft REST API Guidelines, and Google’s API Improvement Proposals are all public and detailed.
  • Automate the mechanical checks. Linting with Spectral or Redocly enforces casing, required descriptions, error schemas, and examples on every pull request, so humans review meaning rather than formatting.
  • Keep a findings log per API. Recurring findings reveal where the style guide or templates need to change.
  • Review consumer journeys, not just endpoints. Walk one real flow end to end against the draft; missing operations show up immediately.

The APIs for Analysts learning path

Beginner: What is an API · API glossary · JSON for analysts · HTTP status codes · Your first collection · Why did my API request fail? · Reading an API contract

Intermediate: Analyze an API · Document an API · API test cases · Chaining and scripts · Webhooks · GraphQL

Advanced: POCs and demos · API design review (you are here) · Versioning and breaking changes · API security testing · API tests in CI

The takeaway

Review an API design before build, while changing it is cheap. As the analyst, own the lenses nobody else can judge well: domain names and enums, operations for every process step and state transition, and data types that will not corrupt money, dates, or lengths downstream. Then check the error model, list design, idempotency and concurrency, asynchronous behavior, and evolution plan. Record findings with severity and a concrete fix, automate the mechanical checks with a linter and a public style guide, and spend human review time on meaning.

For writing contracts that pass this review the first time, see API Documentation from Scratch, and for the requirements behind them, From Vague BR to Functional Requirements. Have a draft contract that needs a practitioner’s review? Book a 1:1 Tech BA Coaching Call.

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: API Design, OpenAPI, Design Review, Systems Analysis, Payments

About the author

Analyst Engineering is written by Ahmed, a Senior Technical Business Analyst with 10+ years of banking and payments delivery experience: ISO 20022 and SWIFT messaging, payments API integration, Kafka event validation, and production support. Every article comes from real delivery work, and each one is reviewed and updated as tools and standards change.

Free account

Practice on the Labs, keep your progress

A free account, no password: an email link signs you in. It saves your steps and self-assessments on the Labs, shows your missions on a dashboard, unlocks the solutions, and, if you tick the box, sends you new missions and articles when they ship.

Your email is used to sign you in. Nothing else, unless you ask. Privacy.