Skip to content

docs: Add service-to-service API standards - #894

Merged
mike-gorman-bitwarden merged 53 commits into
mainfrom
docs/service-to-service-api-standards
Oct 28, 2026
Merged

mike-gorman-bitwarden merged 53 commits into
mainfrom
docs/service-to-service-api-standards

Conversation

@mike-gorman-bitwarden

@mike-gorman-bitwarden mike-gorman-bitwarden commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

🎟️ Tracking

Follow-up to ADR-0036 (#865).

📔 Objective

Adds the service-to-service API standards under Server Architecture: an index page that links to one page per topic, covering contracts, payloads, creating, reading, updating, deleting, acting upon, and bulk processing resources.

What's different

If you have worked on the existing Api server, here is what changes when you build or call an API
that follows these standards. Comparisons are taken from the Api OpenAPI specs (internal: 632
operations; public: 28 operations). The standards apply only to new service-to-service APIs in new
services
. Nothing existing is changing.

At a glance

Area Existing APIs today APIs that follow the standards
Versioning Unversioned paths (/ciphers/{id}). Version in the path (/api/v1/users/{id}), with rules for breaking changes and Deprecation/Sunset headers.
Organization Usually in the path: 146 of 489 internal paths carry {orgId} (/organizations/{orgId}/users). Travels with the request as context. The path names only what is acted on (/api/v1/users).
Methods POST often stands in for other verbs: 46 paths delete through POST/PUT .../delete, and 36 paths accept both PUT and POST. DELETE deletes, PUT replaces. Anything else is an action (POST .../{id}/actions/{action}) or a bulk operation (POST ...:bulk-delete).
Payloads Flat models with an object type string ("object": "cipher"). Resources in a data envelope with id, type, and attributes; metadata in meta.
Read many Mostly unpaged. See below. Paged, filtered, sorted, and trimmed with standard query parameters. See below.
Errors ErrorResponseModel: one message plus a validationErrors map, returned as 400. An errors array; each error has a stable code, status, title, detail, id, and a source naming the field, parameter, or header. Validation failures are 422.
Enumerations Integers (72 of 77 enums), so 2 has to be looked up. Uppercase strings (CONFIRMED), compared case-insensitively.
Field names creationDate, revisionDate, organizationId, isTrusted. createdAt, updatedAt, createdBy; no Id suffix for references; no is prefix for booleans.
Concurrency Endpoint-specific, such as lastKnownRevisionDate on cipher updates. A version field on resources that detect conflicts; a stale version returns 409.
Validation Varies by endpoint. Every request is validated in full before processing, and all failures are reported at once.

Example: reading many resources

Most list endpoints today return everything in one response. Of the 69 internal GET endpoints that
return a list, 12 accept a paging parameter, and 11 of those are event logs. Paging, where it
exists, uses an opaque continuationToken with a fixed page size of 50 (only /notifications
accepts a pageSize). There are no totals, and filtering and sorting are not standardized: each
endpoint defines its own parameters, such as start, end, status, or includeGroups.

Today: list an organization's members. Every member comes back in one response.

GET /organizations/{orgId}/users
{
  "object": "list",
  "data": [
    {
      "object": "organizationUserUserDetails",
      "id": "…",
      "email": "alice@example.com",
      "status": 2
    }
  ],
  "continuationToken": null
}

With the standards: the same request, paged, filtered, and sorted with standard parameters. The
organization comes from the request context.

GET /api/v1/users?filter[status]=CONFIRMED&sort=email&page[number]=1&page[size]=50
{
  "data": [
    {
      "attributes": {
        "email": "alice@example.com",
        "status": "CONFIRMED"
      },
      "id": "…",
      "type": "user"
    }
  ],
  "meta": {
    "pageCount": 9,
    "pageNumber": 1,
    "pageSize": 50,
    "totalCount": 402
  }
}

What changes for you:

  • Paging is the norm. Read-many APIs SHOULD page. The caller chooses the page size, up to a
    maximum the API documents.
  • Two paging styles. Offset paging (page[number], page[size]) can report page and total
    counts. Cursor paging (page[size], page[after]) works like today's continuation token, but
    meta says explicitly whether more results follow (hasMore) instead of leaving the caller to
    infer it from a null token.
  • One way to filter, sort, and trim. filter[{field}] with wildcards, multiple values, and
    ranges; sort=-createdAt; and fields=email,status to return only some fields. The OpenAPI spec
    lists which fields support each.
  • Richer queries move to the body. POST /api/v1/users:search takes a JSON Logic expression for
    AND/OR combinations that do not fit in a URL, and returns the same shape as a read-many
    request.
  • Unsupported parameters are rejected, not ignored. A filter, sort, or paging parameter the API
    does not support returns 422, so a caller never silently receives unfiltered or unsorted data.

What does not change

  • Existing public and client-facing APIs keep their current conventions.
  • Handlers still take and return plain models. The envelope, paging metadata, and error format are
    meant to be produced by Bitwarden.Server.Sdk rather than written by hand.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Deploying contributing-docs with  Cloudflare Pages  Cloudflare Pages

Latest commit: c0f5ba4
Status: ✅  Deploy successful!
Preview URL: https://a7768609.contributing-docs.pages.dev
Branch Preview URL: https://docs-service-to-service-api.contributing-docs.pages.dev

View logs

@github-actions github-actions Bot added the adr label Oct 15, 2026
@mike-gorman-bitwarden
mike-gorman-bitwarden marked this pull request as ready for review October 18, 2026 10:24
@mike-gorman-bitwarden
mike-gorman-bitwarden requested a review from a team as a code owner October 18, 2026 10:24
mike-gorman-bitwarden and others added 6 commits October 18, 2026 06:24
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…API standards

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reword every API standards page to match the Service-to-service API
Standards page in Confluence, split across the existing topical pages.
Where the two disagreed, the repo's rules are kept.

- Answer anticipated questions in place with a new :::faq admonition
- Collect sources and RFC departures on the index
- Rename payload-shape, json-values, and methods to resource-fields,
  json, and verbs to match their titles
@mike-gorman-bitwarden
mike-gorman-bitwarden requested a review from a team as a code owner October 19, 2026 09:42
…ctions

Rename resource-fields back to payload-shape, since the page covers the
whole body and not only resource fields. Split it into envelope and
resource fields sections, each with its own example, and move its FAQ
answers into a section at the bottom.
Bring back changes made for reviewers on earlier API standards pull
requests that were lost when aligning with Confluence.

- Move "kebab" to the shared word list instead of inline ignores
- Exclude the public API and external-standard APIs from scope
- Encourage, rather than require, thinking in terms of resources
- Clarify a subject can be a collection of resources
- Say where create paths stop and allow sub-resource elements
- Link operationId to the OpenAPI Specification
Move the API standards back under the existing Server Architecture
section so the top level matches Getting Started, and restore that
section and the ADR links to match main.

- Reword the scope to acknowledge existing APIs predate the standards
- Remove Sources and RFC departures from the index; credit each source
  on the page where it applies
@github-actions github-actions Bot removed the adr label Oct 19, 2026
Rename the section to "APIs" and list it first under Server
Architecture to keep the sidebar alphabetical. Lead the scope with the
APIs the standards cover, then list what they do not cover.
Comment thread docs/architecture/server/apis/json.md Resolved
Comment thread docs/architecture/server/apis/jobs.md Resolved

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎨 The category is very long. I'd consider whether introducing a second grouping, consistent with the TOC, would help with organizing.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I don't know what you mean by "The category is very long."

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean the child pages?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, the page list within the "apis" category has a ton of entries in it. It would be helpful if the grouping in the sidebar reflected the grouping in the index.

@github-actions github-actions Bot added the adr label Oct 23, 2026
Comment thread docs/architecture/server/apis/jobs.md Resolved
Comment thread docs/architecture/server/apis/index.md Resolved

@withinfocus withinfocus left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A great first version of this!

@github-actions github-actions Bot added the adr label Oct 28, 2026
@mike-gorman-bitwarden
mike-gorman-bitwarden merged commit fe01b20 into main Oct 28, 2026
11 checks passed
@mike-gorman-bitwarden
mike-gorman-bitwarden deleted the docs/service-to-service-api-standards branch October 28, 2026 12:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants