Skip to main content
Aurikle
AI and systemsAurikle

How to write an API contract for custom software

Before two systems exchange data, the API contract names the path or the message, the required fields, the authentication, the error codes, the version, and who must approve an incompatible change. The requirements spec says what counts as done for the business. Acceptance criteria and user acceptance testing say how that result is shown on a screen. This note says how the fields and the errors line up when the two systems call each other.

On this page
  1. Keep the contract apart from the spec and from acceptance
  2. Name the path or the message first
  3. Put required fields in the schema
  4. Name the authentication the call uses
  5. Write the status code and what it means here
  6. Keep the document version apart from the interface version
  7. An incompatible change needs a named approval
  8. The contract is usable when name, fields, authentication, errors, and version are written
Matching serviceCustom software, websites, and applicationsRead this note

Keep the contract apart from the spec and from acceptance

The requirements spec answers which role finishes which task on which screen, who owns that line, and what this version leaves out. Acceptance criteria answer what a bystander can see in a demonstration. User acceptance testing answers whether the owner of that line did it, or watched it done. The API contract answers a different question: which path or which message the other side accepts, which missing field means the payload did not arrive, and which code comes back when authentication fails or the operation fails. The four can point at the same exchange by name. A business outcome is not rewritten as a path, and an error code is not ticked off as a sentence on the screen. See How to write a custom software requirements spec, How to write acceptance criteria for custom software, and How to run user acceptance testing for custom software.

Scope change is about whether the spec itself changes, and who may accept that change. See How to control scope changes in custom software. Delivery still sits under Custom software, websites, and applications. If the other side is equipment on site rather than another business screen, the fields still belong in this contract. How the equipment meets the systems already in use is in How to connect equipment to existing business systems. The cover of the contract carries its own version, the names of both systems, and the path where the contract is kept.

Name the path or the message first

The OpenAPI Specification 3.1.2, read on 28 October 2026, dates that version 19 September 2025. The page says the OpenAPI Specification defines a programming-language-agnostic interface description for HTTP APIs, so that people and computers can understand what a service can do without reading source code, finding extra documentation, or inspecting network traffic. It also says an OpenAPI Description must contain at least one of paths, components, or webhooks. The Paths Object holds the relative paths to the individual endpoints and their operations. The path is appended to the URL from the Server Object to form the full URL. The field name must begin with a forward slash.

The same page says an Operation Object describes a single operation on a path, and may include parameters, a request body, responses, and the security the operation uses. Where the exchange is not an HTTP call started by the caller, the webhooks field uses a unique key for each webhook, and a Path Item describes a request that the API provider may initiate, together with the expected responses. A queue or a file drop that matches neither of those is still given a unique message name in the contract, and the cover says it is not a path or a webhook from that page. An exchange with no name does not enter the contract. The pet-store samples on the page only show the format. They are not the project's paths.

Put required fields in the schema

OpenAPI 3.1.2 says the Schema Object is a superset of JSON Schema Draft 2020-12, and that keyword definitions follow JSON Schema unless the specification says otherwise. JSON Schema Validation, read on 28 October 2026, is Internet-Draft draft-bhutton-json-schema-validation-01. The page says it was published on 16 June 2022, expires on 18 December 2022, and has an intended status of Informational. The authors are A. Wright, H. Andrews, and B. Hutton. For the keyword required, the draft says the value must be an array whose elements are strings and are unique; an object is valid when every item in the array is the name of a property on that object; omitting the keyword has the same effect as an empty array.

Where a request or a response has required fields, those names go in required on that schema. A name that is not in the array is not required under the draft, and the receiver cannot later treat an empty value as a field the sender forgot. The company's own list is written on the contract and dated. The draft does not name the project's fields. If a parameter sits in the path, OpenAPI says that parameter's required field must be true. An optional field may appear in the schema and stay out of required. Amounts, document numbers, and statuses keep the names both sides already use. The contract does not invent a second name that exists only on the page.

Name the authentication the call uses

The Security Scheme Object in OpenAPI 3.1.2 lists HTTP authentication, an API key in a header, a cookie, or a query parameter, mutual TLS, the common OAuth 2.0 flows defined in RFC 6749, and OpenID Connect. The valid values of type are apiKey, http, mutualTLS, oauth2, and openIdConnect. The page says that, as of 2020, the implicit flow is about to be deprecated by the OAuth 2.0 Security Best Current Practice, and that the authorization-code flow with PKCE is recommended for most use cases. That is the page's list and its recommendation. It is not an instruction to buy a particular product for this exchange.

The contract picks one scheme, writes it under security, and says whether the key is a header, a cookie, or a query parameter. A single operation may override the security declared for the whole API. The page says an empty array removes a top-level security declaration. If security is blank, and the contract does not say that this exchange is deliberately unauthenticated, the receiver does not let the call through on a spoken agreement. When a credential is rotated belongs in the company's own operations record. The contract names the scheme and the key. Passwords, tokens, and private keys are not pasted into the contract.

Write the status code and what it means here

The Responses Object maps an HTTP response code to the expected response. The page says the documentation is not expected to cover every possible code, because the codes may not be known in advance, but it is expected to cover a successful response and any known errors. The Responses Object must contain at least one response code, and if only one code is given it should be the response for a successful call. Status codes should be chosen from the codes registered in the IANA Status Code Registry. default may describe responses that are not listed code by code.

For this exchange the contract writes the success code and the codes for errors already known. Each code has a description of what the other side can see when that failure happens, not only the generic name of the code. An error that has not occurred is not given a project-specific number in advance. A code that is not listed uses default, and the description says "not listed in the contract". A custom code that is not in the registry is not written in that field. An operation whose success response and known errors are both still blank is not finished.

Keep the document version apart from the interface version

info.version is required. The page says it is the version of the OpenAPI Document, and that this is distinct from the version of the OpenAPI Specification, the version of the API being described, and the version of the OpenAPI Description. The openapi field is the version of the specification that the document uses, and the page says it is not the info.version string. If the cover has only info.version, it says whether that string is the document version or the interface version. When both are needed, they are two fields.

Semantic Versioning 2.0.0, read on 28 October 2026, shows no publication date. The author is Tom Preston-Werner. The summary says that, given MAJOR.MINOR.PATCH, you increment MAJOR for incompatible API changes, MINOR when you add functionality in a backward-compatible way, and PATCH for backward-compatible bug fixes. Rule 1 says software that uses Semantic Versioning must declare a public API. Rule 8 says the major version must be incremented if any backward-incompatible change is introduced to that public API. If the company uses this scheme, the cover says so, and the public API is this contract, not a meeting note that is still unfinished.

An incompatible change needs a named approval

Rule 3 says that once a version has been released, the contents of that version must not be modified, and any modification must be released as a new version. Rule 8 puts backward-incompatible changes on the major version. The page's answer on deprecation says that deprecating part of the public API should do two things: update the documentation so users know, and issue a new minor release that contains the deprecation. Before the functionality is removed in a major release, there should be at least one minor release that contains the deprecation, so users can move across. When an OpenAPI operation sets deprecated to true, the page says consumers should refrain from using it. The default is false.

The person who may approve an incompatible change for the next version is named on the cover, with the date of agreement. Semantic Versioning does not name that person. Without that line, an incompatible change to a path, a required field, or an error code is not released to the other side. The document may be edited first. Calls stay on the previous version until that person has signed. The scope-change note governs the business spec. It does not stand in for this signature. If the company uses Semantic Versioning, the major version increments after the signature, and the old version is not rewritten in place, under rule 3. If it does not use Semantic Versioning, the interface version string still changes to one that differs from the old version, and the cover says how numbers are assigned.

The contract is usable when name, fields, authentication, errors, and version are written

A line with no path or message name, with required fields neither listed in required nor marked as having none, with no authentication scheme, with no success code, or with the interface version not separated from the document version, does not go on the list both sides may call. Saying that the test environment can be tried first does not fill those fields.

Three checks decide whether the other side can use the contract: every exchange has a path or a message name, the required fields and the known error codes sit on that same line, and an incompatible change has an owner and a date of agreement. A blank item stays in draft. The other side does not go live against it.

Related notes