Markdown Editor

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

Kiến trúc & Thiết kế hệ thốngĐầy đủOpenAPI 3.1, RFC 9110, RFC 9457restapispecificationmath
Mở trong editorTải .md

Cách dùng: 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.

Xem trước

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

FieldValue
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 updatedYYYY-MM-DD
Related[OpenAPI file path], [System design], [Security architecture]

Approvals

RoleNameDecisionDate
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

VersionDateAuthorChange summary
0.1YYYY-MM-DD[@name]First draft for design review
0.2YYYY-MM-DD[@name]Example: Switched list endpoints from offset to cursor pagination
1.0YYYY-MM-DD[@name]Example: Approved for general availability

Contents

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

ItemValue
Intended consumersExample: Partner storefronts, internal mobile apps, the support console
In scopeExample: Orders, order lines, shipments, refunds
Out of scopeExample: Product catalogue and pricing (see Catalogue API), payment capture
API styleREST 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

EnvironmentBase URLDataCredentialsRate limit tier
Productionhttps://api.[example].com/orders/v1Live customer dataProduction clientContracted tier
Sandboxhttps://sandbox.api.[example].com/orders/v1Synthetic, reset weekly on Sunday 00:00 UTCSandbox client, self-service10 requests/s
Staging (internal)https://staging.api.[example].internal/orders/v1Masked copy of productionInternal only50 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

MethodUse forHow to sendLifetime
OAuth 2.0 client credentialsServer-to-server integrationsAuthorization: Bearer <access_token>Access token 15 min
OAuth 2.0 authorization code with PKCEApps acting for a signed-in userAuthorization: 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 browserAuthorization: Bearer <access_token> after the user approves the code on another deviceAccess token 15 min
API key (deprecated)Example: Read-only internal dashboards; being replaced by client credentials, sunset YYYY-MM-DDX-API-Key: <key> headerRotated 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

ScopeGrantsTypical consumer
orders:readRead orders, lines, shipments and refundsStorefronts, support console
orders:writeCreate and update orders, cancel unshipped ordersStorefronts
refunds:writeCreate refunds up to the order totalSupport console
webhooks:manageRegister and delete webhook subscriptionsPartner back ends
[scope][Grant][Consumer]

3.3 Authorisation rules

  • A caller sees only orders belonging to its tenant (tenantId in the token). Requests for another tenant's order return 404, not 403, so that identifiers cannot be probed.
  • Missing or invalid credentials return 401 with a WWW-Authenticate header. A valid token without the required scope returns 403.
  • [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.

MethodMeaningSafeIdempotentTypical success
GETRead a resource or collectionYesYes200
POSTCreate a resource or run an actionNoNo (yes with Idempotency-Key)201 or 202
PUTReplace a resource completelyNoYes200
PATCHPartial update with JSON Merge Patch (RFC 7396)NoNo200
DELETERemove or disable a resourceNoYes204
QUERYSearch with a request body (complex filters too long or sensitive for a query string)YesYes200

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

TopicRuleExample
Media typeapplication/json; charset=utf-8 for bodies; errors use application/problem+json
Property casingcamelCasecustomerId
EnumerationsUPPER_SNAKE_CASE strings; consumers must tolerate unknown valuesPENDING_PAYMENT
Dates and timesISO 8601 / RFC 3339 in UTC with Z2026-03-14T09:30:00Z
Dates onlyISO 8601 calendar date2026-03-14
MoneyObject with decimal string amount and ISO 4217 currency{"amount": "149.90", "currency": "EUR"}
IdentifiersOpaque strings with a type prefix; never sequential integersord_01HV6Z3K8Q
Null and absentAbsent means "not set"; null only where documented
Unknown fieldsConsumers must ignore unknown response fields

4.4 Standard headers

HeaderDirectionPurpose
X-Request-IdBothCorrelation ID; echoed in responses and logs; generated if absent
Idempotency-KeyRequestSafe retries for POST (section 7)
ETag / If-MatchBothOptimistic concurrency (section 7.2)
RateLimit-Limit, RateLimit-Remaining, RateLimit-ResetResponseQuota state (section 8)
Deprecation, Sunset, LinkResponseLifecycle 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.

UseMedia typeItemNotes
Example: Bulk export of ordersapplication/jsonl (JSON Lines)One Order per lineClient reads line by line; connection closes at the end
Example: Live order status feedtext/event-stream (server-sent events)One event per status changeReconnect 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.

ChangeBreaking?
Add an optional request field or a new response fieldNo
Add a new endpoint or a new enum valueNo (consumers must tolerate unknown values)
Remove or rename a field, endpoint or enum valueYes
Make an optional request field requiredYes
Change a field type, format or meaningYes
Tighten validation or change default sort orderYes

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 Deprecation header (RFC 9745) with the date it was deprecated, and the Sunset header (RFC 8594) with the removal date, plus a Link header 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.

ParameterTypeDefaultMaximumMeaning
limitinteger25100Items per page
cursorstringnoneCursor 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.

PatternExampleMeaning
Equalitystatus=SHIPPED,DELIVEREDStatus is SHIPPED or DELIVERED
RangecreatedAt[gte]=2026-03-01T00:00:00Z&createdAt[lt]=2026-04-01T00:00:00ZCreated in March 2026
Searchq=smithFree-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 POST that creates a resource or moves money accepts an Idempotency-Key header (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 422 with problem type idempotency-key-reused. A request still in progress returns 409.

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

TierSustained rateBurstScope
Sandbox10 requests/s20Per client ID
Standard50 requests/s100Per 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:

twait=min⁡(tmax,  tbase⋅2n)+random(0,tbase)t_{wait} = \min\left(t_{max},\; t_{base} \cdot 2^{n}\right) + \text{random}(0, t_{base})

where nn is the retry attempt, tbaset_{base} = [0.5 s] and tmaxt_{max} = [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)StatusTitleWhen it occursClient action
validation-failed422Request validation failedBody or parameters violate the schemaFix the fields in errors[]
invalid-sort400Unsupported sort fieldsort names a non-sortable fieldUse a listed sort field
unauthenticated401Authentication requiredMissing or expired tokenObtain a new token
insufficient-scope403Missing scopeToken lacks the endpoint's scopeRequest the scope
not-found404Resource not foundUnknown ID or other tenant's resourceCheck the ID
order-not-cancellable409Order cannot be cancelledOrder already shippedCreate a return instead
idempotency-key-reused422Idempotency key reusedSame key with a different bodyGenerate a new key
precondition-failed412Resource changedIf-Match does not match current ETagRe-read and retry
rate-limited429Too many requestsQuota exceededWait for Retry-After
internal-error500Internal errorUnexpected server faultRetry with backoff; quote requestId to support
[type][code][Title][Condition][Action]

10. Resources and endpoints

10.1 Endpoint summary

IDMethodPathSummaryScope
EP-01GET/ordersList ordersorders:read
EP-02POST/ordersCreate an orderorders:write
EP-03GET/orders/{orderId}Retrieve an orderorders:read
EP-04PATCH/orders/{orderId}Update shipping address or notesorders:write
EP-05POST/orders/{orderId}/cancelCancel an unshipped orderorders:write
EP-06GET/orders/{orderId}/shipmentsList shipments for an orderorders:read
EP-07POST/orders/{orderId}/refundsRefund part or all of an orderrefunds: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.

ParameterInTypeRequiredDescription
Idempotency-KeyheaderUUIDYesMakes retries safe
customerIdbodystringYesExisting customer ID, prefix cus_
linesbodyarray of lineYes1 to 200 lines
lines[].skubodystringYesCatalogue SKU
lines[].quantitybodyintegerYes1 to 999
shippingAddressbodyAddressYesDelivery address
notesbodystringNoUp 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"
}
StatusMeaning
201Order created; Location points to it
401 / 403Authentication or scope failure
409Request with this Idempotency-Key still in progress
422Validation failed, unknown SKU, or idempotency key reused
429Rate 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.

ParameterInTypeRequiredDescription
statusqueryenum listNoFilter by one or more statuses
customerIdquerystringNoFilter by customer
createdAt[gte], createdAt[lt]querydate-timeNoCreation range
sortquerystringNocreatedAt, -createdAt, totalAmount, -totalAmount
limit, cursorqueryNoSection 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.

StatusMeaning
200Cancelled, or already cancelled
404Order not found for this tenant
409Order 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 typeTriggerPayload
order.createdOrder createdFull order
order.status_changedStatus transitionsOrder ID, old and new status, timestamp
shipment.createdCarrier label createdShipment
refund.succeededRefund settledRefund
[event][Trigger][Payload]

11.2 Delivery

  • Payloads are POSTed as JSON to the subscriber's HTTPS URL with headers Webhook-Id, Webhook-Timestamp and Webhook-Signature.
  • The signature is HMAC-SHA256 over id.timestamp.body with the subscription secret. Subscribers must verify it and reject timestamps older than [5 minutes] to block replays.
  • A 2xx response 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-Id and use the occurredAt field 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.

FeatureFieldUsed hereNotes
QUERY methodquery on the Path ItemExample: Yes, searchOrders (beta)Keep a POST fallback until consumers confirm support
Other HTTP methodsadditionalOperationsExample: Yes, PURGE on the cache pathKeys are the method name as sent on the wire; standard methods stay in their own fields
Streaming and sequential media typesitemSchema, itemEncodingExample: Yes, JSON Lines exportAlso covers text/event-stream, application/json-seq and multipart/mixed
Whole query string as one parameterin: querystring[No]For APIs that accept a structured query string as one object
Device authorization flowflows.deviceAuthorizationExample: Yes, handheld scannersRequires deviceAuthorizationUrl and tokenUrl
Authorization server metadataoauth2MetadataUrlExample: YesPoints to RFC 8414 metadata; TLS required
Deprecated security schemesdeprecated: true on a Security SchemeExample: Yes, apiKeyPair with the sunset policy in section 5
Hierarchical, typed tagssummary, parent, kind on TagExample: Yeskind values such as nav and badge drive documentation navigation
Document identity$selfExample: YesBase URI for resolving references across files
[Feature][Field][Yes / No][Notes]

12.3 Validation rules

Validation rules for the OpenAPI file:

CheckTool or methodGate
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 schemasContract testsCI blocks merge

13. Changelog

DateAPI versionTypeChangeConsumer action
YYYY-MM-DD1.4.0AddedExample: refund.succeeded webhookNone
YYYY-MM-DD1.3.0AddedExample: sort=totalAmount on GET /ordersNone
YYYY-MM-DD1.2.0DeprecatedExample: GET /orders?page= offset pagination; sunset YYYY-MM-DDMove to cursor
[Date][x.y.z][Added / Changed / Deprecated / Removed / Fixed / Security][Change][Action]

14. Service levels and support

14.1 Service level objectives

IndicatorObjectiveMeasurement windowMeasured as
AvailabilityExample: 99.95%Calendar monthShare of non-5xx responses at the gateway, excluding planned maintenance
Latency, readsp95 at or below 200 msRolling 28 daysGateway timing, GET endpoints
Latency, writesp95 at or below 500 msRolling 28 daysGateway timing, POST, PATCH
Webhook delivery99% delivered within 60 sCalendar monthTime from event to first attempt
[Indicator][Objective][Window][Method]

Availability is computed as:

A=requests−5xx responsesrequests×100%A = \frac{\text{requests} - \text{5xx responses}}{\text{requests}} \times 100\%

At 99.95% the monthly error budget is 0.0005×30×24×60≈21.60.0005 \times 30 \times 24 \times 60 \approx 21.6 minutes of full outage.

14.2 Maintenance and support

ItemCommitment
Planned maintenanceAnnounced 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

TermMeaning
ConsumerAn application that calls this API
Idempotency keyClient-generated value that makes a retried request safe
Problem detailsStandard JSON error body defined by RFC 9457
CursorOpaque pointer to a position in a result set
ETagVersion tag of a resource representation used for concurrency control
[Term][Meaning]

15.2 References

ReferenceUsed for
RFC 9110, HTTP SemanticsMethods, status codes, conditional requests
RFC 9457, Problem Details for HTTP APIsError 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 GrantDevice flow in section 3.1
RFC 8414, OAuth 2.0 Authorization Server Metadataoauth2MetadataUrl
IETF HTTP QUERY method draft (safe method with body)QUERY in section 4.2
RFC 3339, Date and Time on the InternetTimestamp format
RFC 7396, JSON Merge PatchPATCH semantics
RFC 8594, The Sunset HTTP Header FieldRemoval date signalling
RFC 6749 and RFC 7636, OAuth 2.0 and PKCEAuthentication 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.

Template liên quan