REST API Specification Template (OpenAPI 3.2, RFC 9457)
HTTP/JSON API contract: auth, conventions, QUERY, streaming, pagination, RFC 9457 errors, endpoints, webhooks, OpenAPI 3.2 skeleton
Як використовувати: Use when designing or publishing an HTTP API. Fill the cross-cutting rules (auth, conventions, versioning, pagination, errors) before any endpoint, and keep the OpenAPI 3.2 file as the machine-readable source of truth. The main pitfall is adopting 3.2 features such as QUERY or itemSchema before consumers' tooling supports them.
Перегляд
REST API Specification: [API name] v[1]
Complete specification for an HTTP/JSON API: environments, security, conventions, versioning, pagination, idempotency, rate limits, errors as RFC 9457 problem details, endpoint-by-endpoint contracts, streaming responses, webhooks, an OpenAPI 3.2 skeleton, changelog and service levels. Based on HTTP semantics (RFC 9110), Problem Details for HTTP APIs (RFC 9457) and the OpenAPI Specification 3.2.0 (published September 2025). Replace every
[bracketed]value and every row marked Example. Worked examples use an order-management API.
Document control
| Field | Value |
|---|---|
| Document ID | [API-SPEC-ORDERS-001] |
| API name | [Orders API] |
| API version described | [v1] |
| Document version | [0.1] |
| Status | [Draft / In review / Approved / Deprecated] |
| Owner (team) | [@team-orders] |
| Technical contact | [@api-owner] |
| Classification | [Internal / Partner / Public] |
| Last updated | YYYY-MM-DD |
| Related | [OpenAPI file path], [System design], [Security architecture] |
Approvals
| Role | Name | Decision | Date |
|---|---|---|---|
| API owner | [@name] | [Approved / Changes requested] | YYYY-MM-DD |
| API governance / design review | [@name] | [Decision] | YYYY-MM-DD |
| Security | [@name] | [Decision] | YYYY-MM-DD |
| Consumer representative | [@name] | [Decision] | YYYY-MM-DD |
Revision history
| Version | Date | Author | Change summary |
|---|---|---|---|
| 0.1 | YYYY-MM-DD | [@name] | First draft for design review |
| 0.2 | YYYY-MM-DD | [@name] | Example: Switched list endpoints from offset to cursor pagination |
| 1.0 | YYYY-MM-DD | [@name] | Example: Approved for general availability |
Contents
- Overview
- Base URLs and environments
- Authentication and authorisation
- Conventions
- Versioning and deprecation
- Pagination, filtering and sorting
- Idempotency and concurrency
- Rate limiting
- Errors
- Resources and endpoints
- Webhooks
- OpenAPI 3.2 document
- Changelog
- Service levels and support
- Glossary and references
1. Overview
1.1 Purpose
[What business capability the API exposes and for whom. Example: "The Orders API lets partner storefronts create, read, update and cancel customer orders, and subscribe to order status changes."]
1.2 Audience and scope
| Item | Value |
|---|---|
| Intended consumers | Example: Partner storefronts, internal mobile apps, the support console |
| In scope | Example: Orders, order lines, shipments, refunds |
| Out of scope | Example: Product catalogue and pricing (see Catalogue API), payment capture |
| API style | REST over HTTPS, JSON bodies, resource-oriented URLs |
| Maturity | [Beta / Generally available / Deprecated] |
1.3 Resource model
The main resources and how they relate. Each resource has a stable, opaque identifier and its own collection URL.
2. Base URLs and environments
| Environment | Base URL | Data | Credentials | Rate limit tier |
|---|---|---|---|---|
| Production | https://api.[example].com/orders/v1 | Live customer data | Production client | Contracted tier |
| Sandbox | https://sandbox.api.[example].com/orders/v1 | Synthetic, reset weekly on Sunday 00:00 UTC | Sandbox client, self-service | 10 requests/s |
| Staging (internal) | https://staging.api.[example].internal/orders/v1 | Masked copy of production | Internal only | 50 requests/s |
| [Environment] | [URL] | [Data policy] | [Credentials] | [Tier] |
All environments accept TLS 1.2 or later only. Plain HTTP requests are rejected, not redirected, so that credentials are never sent in clear text.
3. Authentication and authorisation
3.1 Authentication methods
| Method | Use for | How to send | Lifetime |
|---|---|---|---|
| OAuth 2.0 client credentials | Server-to-server integrations | Authorization: Bearer <access_token> | Access token 15 min |
| OAuth 2.0 authorization code with PKCE | Apps acting for a signed-in user | Authorization: Bearer <access_token> | Access token 15 min, refresh token 30 days |
| OAuth 2.0 device authorization grant (RFC 8628) | Example: Warehouse handheld scanners and TV dashboards without a browser | Authorization: Bearer <access_token> after the user approves the code on another device | Access token 15 min |
| API key (deprecated) | Example: Read-only internal dashboards; being replaced by client credentials, sunset YYYY-MM-DD | X-API-Key: <key> header | Rotated every 90 days |
| [Method] | [Use] | [Header] | [Lifetime] |
Token endpoint: [https://auth.example.com/oauth2/token]. Tokens are JWTs
signed with [RS256 / ES256]; consumers must treat them as opaque. The
authorization server publishes RFC 8414 metadata at
[https://auth.example.com/.well-known/oauth-authorization-server], and
the OpenAPI document points to it with oauth2MetadataUrl so tools can
discover endpoints instead of hard-coding them. Schemes that are being
retired are marked deprecated: true in the OpenAPI document (section 12).
3.2 Scopes
| Scope | Grants | Typical consumer |
|---|---|---|
orders:read | Read orders, lines, shipments and refunds | Storefronts, support console |
orders:write | Create and update orders, cancel unshipped orders | Storefronts |
refunds:write | Create refunds up to the order total | Support console |
webhooks:manage | Register and delete webhook subscriptions | Partner back ends |
| [scope] | [Grant] | [Consumer] |
3.3 Authorisation rules
- A caller sees only orders belonging to its tenant (
tenantIdin the token). Requests for another tenant's order return404, not403, so that identifiers cannot be probed. - Missing or invalid credentials return
401with aWWW-Authenticateheader. A valid token without the required scope returns403. - [Additional rule, for example field-level restrictions on personal data.]
4. Conventions
4.1 Resource naming and URLs
- Collections are plural nouns in kebab-case:
/orders,/order-lines. - Single resources:
/orders/{orderId}. Nesting is limited to one level where the child cannot exist alone:/orders/{orderId}/shipments. - Actions that do not map to CRUD use a sub-resource verb with
POST:/orders/{orderId}/cancel. - URLs never contain file extensions, trailing slashes or verbs for CRUD.
4.2 HTTP methods
Methods follow RFC 9110 semantics.
| Method | Meaning | Safe | Idempotent | Typical success |
|---|---|---|---|---|
| GET | Read a resource or collection | Yes | Yes | 200 |
| POST | Create a resource or run an action | No | No (yes with Idempotency-Key) | 201 or 202 |
| PUT | Replace a resource completely | No | Yes | 200 |
| PATCH | Partial update with JSON Merge Patch (RFC 7396) | No | No | 200 |
| DELETE | Remove or disable a resource | No | Yes | 204 |
| QUERY | Search with a request body (complex filters too long or sensitive for a query string) | Yes | Yes | 200 |
QUERY is the safe, idempotent method with a request body being
standardised by the IETF HTTP working group; OpenAPI 3.2 describes it with
the query operation field. Offer it only where gateways, proxies and
client libraries in the consumer base support it, and keep an equivalent
POST /orders/search while support is uneven. Any other non-standard
method the API uses (for example PURGE on a cache endpoint) is described
under additionalOperations in the OpenAPI document, never by overloading
POST.
4.3 Data formats
| Topic | Rule | Example |
|---|---|---|
| Media type | application/json; charset=utf-8 for bodies; errors use application/problem+json | |
| Property casing | camelCase | customerId |
| Enumerations | UPPER_SNAKE_CASE strings; consumers must tolerate unknown values | PENDING_PAYMENT |
| Dates and times | ISO 8601 / RFC 3339 in UTC with Z | 2026-03-14T09:30:00Z |
| Dates only | ISO 8601 calendar date | 2026-03-14 |
| Money | Object with decimal string amount and ISO 4217 currency | {"amount": "149.90", "currency": "EUR"} |
| Identifiers | Opaque strings with a type prefix; never sequential integers | ord_01HV6Z3K8Q |
| Null and absent | Absent means "not set"; null only where documented | |
| Unknown fields | Consumers must ignore unknown response fields |
4.4 Standard headers
| Header | Direction | Purpose |
|---|---|---|
X-Request-Id | Both | Correlation ID; echoed in responses and logs; generated if absent |
Idempotency-Key | Request | Safe retries for POST (section 7) |
ETag / If-Match | Both | Optimistic concurrency (section 7.2) |
RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset | Response | Quota state (section 8) |
Deprecation, Sunset, Link | Response | Lifecycle signals (section 5) |
4.5 Streaming and sequential responses
Long exports and live feeds are streamed as a sequence of items rather than one large JSON document, so clients can process each item as it arrives.
| Use | Media type | Item | Notes |
|---|---|---|---|
| Example: Bulk export of orders | application/jsonl (JSON Lines) | One Order per line | Client reads line by line; connection closes at the end |
| Example: Live order status feed | text/event-stream (server-sent events) | One event per status change | Reconnect with Last-Event-ID to resume |
| [Use] | [Media type] | [Item schema] | [Notes] |
In OpenAPI 3.2 these responses declare itemSchema on the media type, so
the schema validates each item in the stream independently; schema
alone would describe the whole stream as one array.
5. Versioning and deprecation
5.1 Versioning scheme
The major version is in the path (/v1). Non-breaking changes are added
to the current major version without notice beyond the changelog.
| Change | Breaking? |
|---|---|
| Add an optional request field or a new response field | No |
| Add a new endpoint or a new enum value | No (consumers must tolerate unknown values) |
| Remove or rename a field, endpoint or enum value | Yes |
| Make an optional request field required | Yes |
| Change a field type, format or meaning | Yes |
| Tighten validation or change default sort order | Yes |
5.2 Deprecation policy
- Breaking changes ship in a new major version. The previous major version remains available for at least [12] months after the new one is GA.
- Deprecated endpoints return the
Deprecationheader (RFC 9745) with the date it was deprecated, and theSunsetheader (RFC 8594) with the removal date, plus aLinkheader pointing to the migration guide. - Consumers are notified by [email to registered contacts and the developer portal] at deprecation, at 90 days and at 30 days before sunset.
HTTP/1.1 200 OK
Deprecation: @1767225600
Sunset: Wed, 30 Jun 2027 23:59:59 GMT
Link: <https://developer.example.com/orders/migrate-v2>; rel="deprecation"
6. Pagination, filtering and sorting
6.1 Cursor pagination
Collections return a page of items and an opaque cursor for the next page. Cursors expire after [24 hours] and must not be parsed by consumers.
| Parameter | Type | Default | Maximum | Meaning |
|---|---|---|---|---|
limit | integer | 25 | 100 | Items per page |
cursor | string | none | Cursor from the previous response's nextCursor |
{
"data": [{"id": "ord_01HV6Z3K8Q", "status": "SHIPPED"}],
"nextCursor": "eyJjcmVhdGVkQXQiOiIyMDI2LTAzLTE0VDA5OjMwOjAwWiJ9",
"hasMore": true
}
6.2 Filtering
Filters are query parameters named after the field. Multiple values are comma-separated and combined with OR; different fields combine with AND.
| Pattern | Example | Meaning |
|---|---|---|
| Equality | status=SHIPPED,DELIVERED | Status is SHIPPED or DELIVERED |
| Range | createdAt[gte]=2026-03-01T00:00:00Z&createdAt[lt]=2026-04-01T00:00:00Z | Created in March 2026 |
| Search | q=smith | Free-text match on customer name and email |
6.3 Sorting
sort takes a comma-separated list of fields; a leading - means
descending. Default: -createdAt. Only fields listed per endpoint are
sortable; others return 400 with problem type invalid-sort.
7. Idempotency and concurrency
7.1 Idempotency keys
- Every
POSTthat creates a resource or moves money accepts anIdempotency-Keyheader (a client-generated UUID). - The server stores the key, request fingerprint and response for
[24 hours]. A repeat with the same key and body returns the stored
response with header
Idempotent-Replayed: true. - The same key with a different body returns
422with problem typeidempotency-key-reused. A request still in progress returns409.
7.2 Optimistic concurrency
GET responses include a strong ETag. PUT and PATCH require
If-Match; a stale ETag returns 412 Precondition Failed, and a missing
one returns 428 Precondition Required.
8. Rate limiting
| Tier | Sustained rate | Burst | Scope |
|---|---|---|---|
| Sandbox | 10 requests/s | 20 | Per client ID |
| Standard | 50 requests/s | 100 | Per client ID |
| Premium | [200] requests/s | [400] | Per client ID |
| Write endpoints | [20] requests/s | [40] | Per client ID, in addition to tier |
Each response carries RateLimit-Limit, RateLimit-Remaining and
RateLimit-Reset (seconds until the window resets). When the limit is
exceeded the API returns 429 with a Retry-After header. Clients
should retry with exponential backoff and jitter:
where is the retry attempt, = [0.5 s] and = [30 s].
9. Errors
9.1 Error format
Error responses use media type application/problem+json with the
standard members type, title, status, detail and instance, plus
the documented extension members below.
HTTP/1.1 422 Unprocessable Content
Content-Type: application/problem+json
X-Request-Id: 4b1f0c2e-1d3a-4c7a-9a77-0b0c6a5e2f11
{
"type": "https://api.example.com/problems/validation-failed",
"title": "Request validation failed",
"status": 422,
"detail": "2 fields are invalid.",
"instance": "/orders/v1/orders",
"requestId": "4b1f0c2e-1d3a-4c7a-9a77-0b0c6a5e2f11",
"errors": [
{"pointer": "/lines/0/quantity", "detail": "must be at least 1"},
{"pointer": "/shippingAddress/countryCode", "detail": "must be an ISO 3166-1 alpha-2 code"}
]
}
9.2 Problem type registry
| Type (suffix of base URI) | Status | Title | When it occurs | Client action |
|---|---|---|---|---|
validation-failed | 422 | Request validation failed | Body or parameters violate the schema | Fix the fields in errors[] |
invalid-sort | 400 | Unsupported sort field | sort names a non-sortable field | Use a listed sort field |
unauthenticated | 401 | Authentication required | Missing or expired token | Obtain a new token |
insufficient-scope | 403 | Missing scope | Token lacks the endpoint's scope | Request the scope |
not-found | 404 | Resource not found | Unknown ID or other tenant's resource | Check the ID |
order-not-cancellable | 409 | Order cannot be cancelled | Order already shipped | Create a return instead |
idempotency-key-reused | 422 | Idempotency key reused | Same key with a different body | Generate a new key |
precondition-failed | 412 | Resource changed | If-Match does not match current ETag | Re-read and retry |
rate-limited | 429 | Too many requests | Quota exceeded | Wait for Retry-After |
internal-error | 500 | Internal error | Unexpected server fault | Retry with backoff; quote requestId to support |
| [type] | [code] | [Title] | [Condition] | [Action] |
10. Resources and endpoints
10.1 Endpoint summary
| ID | Method | Path | Summary | Scope |
|---|---|---|---|---|
| EP-01 | GET | /orders | List orders | orders:read |
| EP-02 | POST | /orders | Create an order | orders:write |
| EP-03 | GET | /orders/{orderId} | Retrieve an order | orders:read |
| EP-04 | PATCH | /orders/{orderId} | Update shipping address or notes | orders:write |
| EP-05 | POST | /orders/{orderId}/cancel | Cancel an unshipped order | orders:write |
| EP-06 | GET | /orders/{orderId}/shipments | List shipments for an order | orders:read |
| EP-07 | POST | /orders/{orderId}/refunds | Refund part or all of an order | refunds:write |
| [EP-nn] | [Method] | [Path] | [Summary] | [Scope] |
10.2 Orders: create an order (EP-02)
Creates an order in status PENDING_PAYMENT. Prices are taken from the
catalogue at creation time; client-supplied prices are ignored.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
Idempotency-Key | header | UUID | Yes | Makes retries safe |
customerId | body | string | Yes | Existing customer ID, prefix cus_ |
lines | body | array of line | Yes | 1 to 200 lines |
lines[].sku | body | string | Yes | Catalogue SKU |
lines[].quantity | body | integer | Yes | 1 to 999 |
shippingAddress | body | Address | Yes | Delivery address |
notes | body | string | No | Up to 500 characters |
POST /orders/v1/orders HTTP/1.1
Host: api.example.com
Authorization: Bearer eyJhbGciOiJSUzI1NiJ9...
Content-Type: application/json
Idempotency-Key: 0b8f6a2e-3c1d-4e5f-8a9b-1c2d3e4f5a6b
{
"customerId": "cus_01HV5R2M7T",
"lines": [{"sku": "TSHIRT-BLK-M", "quantity": 2}],
"shippingAddress": {"line1": "12 Rue de Rivoli", "city": "Paris", "postalCode": "75001", "countryCode": "FR"}
}
HTTP/1.1 201 Created
Location: /orders/v1/orders/ord_01HV6Z3K8Q
ETag: "3f2a9c"
Content-Type: application/json
{
"id": "ord_01HV6Z3K8Q",
"status": "PENDING_PAYMENT",
"customerId": "cus_01HV5R2M7T",
"lines": [{"id": "lin_01HV6Z3KA1", "sku": "TSHIRT-BLK-M", "quantity": 2, "unitPrice": {"amount": "19.90", "currency": "EUR"}}],
"totalAmount": {"amount": "39.80", "currency": "EUR"},
"createdAt": "2026-03-14T09:30:00Z"
}
| Status | Meaning |
|---|---|
| 201 | Order created; Location points to it |
| 401 / 403 | Authentication or scope failure |
| 409 | Request with this Idempotency-Key still in progress |
| 422 | Validation failed, unknown SKU, or idempotency key reused |
| 429 | Rate limited |
Side effects: emits webhook order.created (section 11).
10.3 Orders: list orders (EP-01)
Returns orders for the caller's tenant, newest first by default.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
status | query | enum list | No | Filter by one or more statuses |
customerId | query | string | No | Filter by customer |
createdAt[gte], createdAt[lt] | query | date-time | No | Creation range |
sort | query | string | No | createdAt, -createdAt, totalAmount, -totalAmount |
limit, cursor | query | No | Section 6.1 |
GET /orders/v1/orders?status=SHIPPED&limit=2 HTTP/1.1
Authorization: Bearer eyJhbGciOiJSUzI1NiJ9...
Response: 200 with the paginated envelope in section 6.1.
10.4 Orders: cancel an order (EP-05)
Cancels an order that has not shipped. Returns the updated order with
status CANCELLED. An order with any shipment returns 409 with problem
type order-not-cancellable. Calling cancel on an already cancelled order
returns 200 with the unchanged order, so the action is idempotent.
| Status | Meaning |
|---|---|
| 200 | Cancelled, or already cancelled |
| 404 | Order not found for this tenant |
| 409 | Order already shipped |
10.5 [Resource]: [operation] ([EP-nn])
[Repeat the layout above for each remaining endpoint: purpose, parameter table, request example, response example, status table, side effects.]
11. Webhooks
11.1 Events
| Event type | Trigger | Payload |
|---|---|---|
order.created | Order created | Full order |
order.status_changed | Status transitions | Order ID, old and new status, timestamp |
shipment.created | Carrier label created | Shipment |
refund.succeeded | Refund settled | Refund |
| [event] | [Trigger] | [Payload] |
11.2 Delivery
- Payloads are
POSTed as JSON to the subscriber's HTTPS URL with headersWebhook-Id,Webhook-TimestampandWebhook-Signature. - The signature is HMAC-SHA256 over
id.timestamp.bodywith the subscription secret. Subscribers must verify it and reject timestamps older than [5 minutes] to block replays. - A
2xxresponse within [10 s] acknowledges delivery. Other responses are retried with exponential backoff for [72 hours], then the subscription is marked failing and the owner notified. - Delivery is at least once and not ordered. Subscribers deduplicate on
Webhook-Idand use theoccurredAtfield to discard stale updates.
{
"id": "evt_01HV7A0B2C",
"type": "order.status_changed",
"occurredAt": "2026-03-15T14:02:11Z",
"data": {"orderId": "ord_01HV6Z3K8Q", "from": "PAID", "to": "SHIPPED"}
}
12. OpenAPI 3.2 document
The authoritative machine-readable contract is [api/openapi.yaml],
written against OpenAPI 3.2.0.
12.1 Skeleton
The skeleton below shows the top-level structure, the shared components every endpoint reuses and one example of each 3.2 feature the API relies on.
openapi: 3.2.0
$self: https://api.example.com/orders/v1/openapi.yaml
info:
title: Orders API
version: 1.4.0
contact:
name: Orders team
email: [email protected]
servers:
- url: https://api.example.com/orders/v1
description: Production
- url: https://sandbox.api.example.com/orders/v1
description: Sandbox
security:
- oauth2: [orders:read]
tags:
- name: Orders
summary: Orders
description: Create, read, update and cancel customer orders.
kind: nav
- name: Order exports
summary: Exports
parent: Orders
kind: nav
- name: Beta
summary: Beta
description: Endpoints that may change without a major version.
kind: badge
paths:
/orders:
get:
operationId: listOrders
tags: [Orders]
parameters:
- $ref: '#/components/parameters/Limit'
- $ref: '#/components/parameters/Cursor'
responses:
'200':
description: A page of orders
content:
application/json:
schema:
$ref: '#/components/schemas/OrderPage'
default:
$ref: '#/components/responses/Problem'
post:
operationId: createOrder
tags: [Orders]
security:
- oauth2: [orders:write]
parameters:
- $ref: '#/components/parameters/IdempotencyKey'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/OrderCreate'
responses:
'201':
description: Created
content:
application/json:
schema:
$ref: '#/components/schemas/Order'
default:
$ref: '#/components/responses/Problem'
query:
operationId: searchOrders
summary: Search orders with a filter document in the body
tags: [Orders, Beta]
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/OrderSearch'
responses:
'200':
description: A page of matching orders
content:
application/json:
schema:
$ref: '#/components/schemas/OrderPage'
default:
$ref: '#/components/responses/Problem'
/orders/export:
get:
operationId: exportOrders
tags: [Order exports]
responses:
'200':
description: Orders streamed as JSON Lines, one order per line
content:
application/jsonl:
itemSchema:
$ref: '#/components/schemas/Order'
default:
$ref: '#/components/responses/Problem'
/cache/orders/{orderId}:
parameters:
- name: orderId
in: path
required: true
schema: {type: string}
additionalOperations:
PURGE:
operationId: purgeOrderCache
tags: [Orders]
responses:
'204':
description: Cached representation removed
components:
securitySchemes:
oauth2:
type: oauth2
oauth2MetadataUrl: https://auth.example.com/.well-known/oauth-authorization-server
flows:
clientCredentials:
tokenUrl: https://auth.example.com/oauth2/token
scopes:
orders:read: Read orders
orders:write: Create and update orders
deviceAuthorization:
deviceAuthorizationUrl: https://auth.example.com/oauth2/device_authorization
tokenUrl: https://auth.example.com/oauth2/token
scopes:
orders:read: Read orders
apiKey:
type: apiKey
in: header
name: X-API-Key
deprecated: true
parameters:
Limit:
name: limit
in: query
schema: {type: integer, minimum: 1, maximum: 100, default: 25}
Cursor:
name: cursor
in: query
schema: {type: string}
IdempotencyKey:
name: Idempotency-Key
in: header
required: true
schema: {type: string, format: uuid}
responses:
Problem:
description: Error
content:
application/problem+json:
schema:
$ref: '#/components/schemas/Problem'
schemas:
Problem:
type: object
properties:
type: {type: string, format: uri}
title: {type: string}
status: {type: integer}
detail: {type: string}
instance: {type: string}
Order:
type: object
required: [id, status, customerId, lines, totalAmount, createdAt]
properties:
id: {type: string, pattern: '^ord_'}
status: {type: string, enum: [PENDING_PAYMENT, PAID, SHIPPED, DELIVERED, CANCELLED]}
customerId: {type: string}
lines: {type: array, items: {$ref: '#/components/schemas/OrderLine'}}
totalAmount: {$ref: '#/components/schemas/Money'}
createdAt: {type: string, format: date-time}
OrderSearch:
type: object
properties:
status: {type: array, items: {type: string}}
customerIds: {type: array, maxItems: 500, items: {type: string}}
createdAfter: {type: string, format: date-time}
OrderCreate:
type: object
required: [customerId, lines, shippingAddress]
properties:
customerId: {type: string}
lines: {type: array, minItems: 1, maxItems: 200, items: {type: object}}
shippingAddress: {type: object}
OrderLine:
type: object
properties:
id: {type: string}
sku: {type: string}
quantity: {type: integer, minimum: 1}
unitPrice: {$ref: '#/components/schemas/Money'}
OrderPage:
type: object
properties:
data: {type: array, items: {$ref: '#/components/schemas/Order'}}
nextCursor: {type: [string, 'null']}
hasMore: {type: boolean}
Money:
type: object
required: [amount, currency]
properties:
amount: {type: string, pattern: '^-?\d+(\.\d{1,4})?$'}
currency: {type: string, minLength: 3, maxLength: 3}
12.2 OpenAPI 3.2 features used
Version 3.2.0 adds the features below. Record which ones the API uses so that consumers can check their tooling supports them.
| Feature | Field | Used here | Notes |
|---|---|---|---|
| QUERY method | query on the Path Item | Example: Yes, searchOrders (beta) | Keep a POST fallback until consumers confirm support |
| Other HTTP methods | additionalOperations | Example: Yes, PURGE on the cache path | Keys are the method name as sent on the wire; standard methods stay in their own fields |
| Streaming and sequential media types | itemSchema, itemEncoding | Example: Yes, JSON Lines export | Also covers text/event-stream, application/json-seq and multipart/mixed |
| Whole query string as one parameter | in: querystring | [No] | For APIs that accept a structured query string as one object |
| Device authorization flow | flows.deviceAuthorization | Example: Yes, handheld scanners | Requires deviceAuthorizationUrl and tokenUrl |
| Authorization server metadata | oauth2MetadataUrl | Example: Yes | Points to RFC 8414 metadata; TLS required |
| Deprecated security schemes | deprecated: true on a Security Scheme | Example: Yes, apiKey | Pair with the sunset policy in section 5 |
| Hierarchical, typed tags | summary, parent, kind on Tag | Example: Yes | kind values such as nav and badge drive documentation navigation |
| Document identity | $self | Example: Yes | Base URI for resolving references across files |
| [Feature] | [Field] | [Yes / No] | [Notes] |
12.3 Validation rules
Validation rules for the OpenAPI file:
| Check | Tool or method | Gate |
|---|---|---|
| File is valid OpenAPI 3.2 | [Linter, for example Spectral or Redocly CLI] | CI blocks merge |
| Style rules (casing, problem responses, operationId present) | Linter ruleset [path] | CI blocks merge |
| Breaking-change detection against the published version | [OpenAPI diff tool] | Requires API owner approval |
| Examples validate against schemas | Contract tests | CI blocks merge |
13. Changelog
| Date | API version | Type | Change | Consumer action |
|---|---|---|---|---|
| YYYY-MM-DD | 1.4.0 | Added | Example: refund.succeeded webhook | None |
| YYYY-MM-DD | 1.3.0 | Added | Example: sort=totalAmount on GET /orders | None |
| YYYY-MM-DD | 1.2.0 | Deprecated | Example: GET /orders?page= offset pagination; sunset YYYY-MM-DD | Move to cursor |
| [Date] | [x.y.z] | [Added / Changed / Deprecated / Removed / Fixed / Security] | [Change] | [Action] |
14. Service levels and support
14.1 Service level objectives
| Indicator | Objective | Measurement window | Measured as |
|---|---|---|---|
| Availability | Example: 99.95% | Calendar month | Share of non-5xx responses at the gateway, excluding planned maintenance |
| Latency, reads | p95 at or below 200 ms | Rolling 28 days | Gateway timing, GET endpoints |
| Latency, writes | p95 at or below 500 ms | Rolling 28 days | Gateway timing, POST, PATCH |
| Webhook delivery | 99% delivered within 60 s | Calendar month | Time from event to first attempt |
| [Indicator] | [Objective] | [Window] | [Method] |
Availability is computed as:
At 99.95% the monthly error budget is minutes of full outage.
14.2 Maintenance and support
| Item | Commitment |
|---|---|
| Planned maintenance | Announced 7 days ahead; [Sunday 02:00 to 04:00 UTC] |
| Status page | [https://status.example.com] |
| Support channel | [Developer portal ticket / email] |
| Response time, P1 (API unavailable) | [30 minutes, 24x7] |
| Response time, P3 (question) | [2 business days] |
15. Glossary and references
15.1 Glossary
| Term | Meaning |
|---|---|
| Consumer | An application that calls this API |
| Idempotency key | Client-generated value that makes a retried request safe |
| Problem details | Standard JSON error body defined by RFC 9457 |
| Cursor | Opaque pointer to a position in a result set |
| ETag | Version tag of a resource representation used for concurrency control |
| [Term] | [Meaning] |
15.2 References
| Reference | Used for |
|---|---|
| RFC 9110, HTTP Semantics | Methods, status codes, conditional requests |
| RFC 9457, Problem Details for HTTP APIs | Error format in section 9 |
| OpenAPI Specification 3.2.0 (spec.openapis.org/oas/v3.2.0) | Machine-readable contract in section 12 |
| RFC 8628, OAuth 2.0 Device Authorization Grant | Device flow in section 3.1 |
| RFC 8414, OAuth 2.0 Authorization Server Metadata | oauth2MetadataUrl |
| IETF HTTP QUERY method draft (safe method with body) | QUERY in section 4.2 |
| RFC 3339, Date and Time on the Internet | Timestamp format |
| RFC 7396, JSON Merge Patch | PATCH semantics |
| RFC 8594, The Sunset HTTP Header Field | Removal date signalling |
| RFC 6749 and RFC 7636, OAuth 2.0 and PKCE | Authentication flows |
| [Internal API style guide] | [Use] |
Standard and licence note
Based on the IETF specifications RFC 9110 (HTTP Semantics) and RFC 9457 (Problem Details for HTTP APIs) and on the OpenAPI Specification 3.2.0 (September 2025, Apache License 2.0), together with common industry practice for API design. This template is original text written for this collection and reproduces no text from those specifications; read them for their normative requirements. Example values are illustrative. Template licence: MIT.
Схожі шаблони
Event-Driven API Specification Template (AsyncAPI 3)
Async event contract: brokers, channels, operations, CloudEvents envelope, ordering, delivery, DLQ, schema evolution, AsyncAPI YAML
Архітектура та системний дизайнAPI Versioning and Deprecation Policy Template
API lifecycle policy: versioning scheme, compatibility promises, breaking changes, timelines, Deprecation and Sunset headers
Архітектура та системний дизайнAPI Design Guidelines Template (Company Style Guide)
Company API style guide: naming, methods, status codes, RFC 9457 errors, pagination, versioning, security, webhooks, governance