# Add an API revision by upload

`POST /v1/apis/{account}/{api}/revisions`. Changed on Oct 30, 2026.

> This reference is the **skmtc/skmtc-api** API on Hub. Star it to see each revision, and add a pipeline to get its changes. https://skmtc.dev/skmtc/apis/skmtc-api

Add a new revision to an existing API by uploading a schema document - the raw file bytes are the request body. The document is validated, content-addressed and deduplicated: re-uploading identical bytes (or a cosmetic reformat) is a no-op (`deduped: true`); changed bytes append a revision. Use this to record a new snapshot of an API whose schema is built locally and has no refetchable URL source.

## Request

- Method: `POST`
- Path: `/v1/apis/{account}/{api}/revisions`
- content-type: `application/octet-stream`
- `account` (path, string, required)
- `api` (path, string, required)
- `filename` (query, string): Original filename, used to detect JSON vs YAML.
- `originUrl` (query, string): As on `uploadApi`: the fetchable origin of these bytes, when known.

## Request body

Content type: `application/octet-stream`. Type: `string`.

## Response

### 201

The request has succeeded and a new resource has been created as a result.

Content type: `application/json`. Type: `object`.

The outcome of importing a schema document into the catalog.

- `api` (object, required): The API the schema belongs to - newly created, or extended with a revision.
  - `id` (string, required): Stable row id, immutable across slug renames - what cross-environment tooling (the staging-sync link ledger) keys on.
  - `owner` (object, required): A user or organization account - the polymorphic resource owner.
    - `id` (string, required): Stable row id, immutable across handle renames - what cross-environment tooling (the staging-sync link ledger) keys on.
    - `handle` (string, required): Unique URL handle, e.g. `acme`.
    - `displayName` (string, required)
    - `type` (enum, required): Whether an account represents a single person or an organization.
      - One of: `user`, `org`
    - `avatarUrl` (string, required): An absolute URL.
    - `bio` (string, required)
    - `location` (string)
    - `emailDomain` (string): The company's email domain, e.g. `stripe.com` - org accounts only. A user with a verified email at this domain can claim the org.
    - `claimStatus` (enum): Claim state of the org - org accounts only.
      - One of: `claimed`, `unclaimed`
    - `joinedAt` (string, required): When the account was created.
    - `url` (string, required): API self-link for this account.
    - `htmlUrl` (string, required): Web UI link for this account.
  - `slug` (string, required)
  - `name` (string, required): Human-readable title, from the document's `info.title`.
  - `displayName` (string): The name to SHOW, when the title alone is ambiguous - present only when this owner has another live API with the same `name`, and only when something distinguishing can be derived. Azure publishes one management client as dozens of fragment files sharing an `info.title`, so 67 catalog entries read `SqlManagementClient`. They are not duplicates and must not be merged - each is a different fragment - so the qualifier names the fragment: `SqlManagementClient (DatabaseSchema)`. Absent means `name` is unambiguous, or that nothing could be derived (an upload carries no path). Render `displayName ?? name`.
  - `visibility` (enum, required): Whether a resource is world-readable or restricted to its owner.
    - One of: `public`, `private`
  - `description` (string, required): One-line summary.
  - `category` (enum): The API's primary subject category. Absent when unresolved or not yet classified.
    - One of: `ai-machine-learning`, `developer-tools`, `cloud-infrastructure`, `security-identity`, `data-analytics`, `payments-finance`, `commerce-retail`, `marketing-advertising`, `sales-customer-support`, `business-operations-hr`, `communications-messaging`, `productivity-collaboration`, `media-content`, `maps-location`, `travel-transport-logistics`, `healthcare-life-sciences`, `iot-devices`, `government-public-data`, `education-research`
  - `readme` (string, required): Rendered README / long-form documentation, Markdown.
  - `providerName` (string): Provider / publisher name, e.g. `Stripe, Inc.`.
  - `homepageUrl` (string): The provider's homepage.
  - `logoUrl` (string): A logo for the API or its provider.
  - `isVerified` (boolean, required): Whether the entry has been verified by skmtc-hub.
  - `license` (object): License of the latest version's schema document, when declared.
    - `name` (string, required): License name, e.g. `Apache 2.0`.
    - `spdxId` (string): SPDX identifier, e.g. `Apache-2.0` - OpenAPI 3.1 `info.license.identifier`.
    - `url` (string): Link to the license text.
  - `sources` (array of ApiSource, required): Where this API's schema is fetched from.
    - `id` (string, required): Identifier of the source within its API.
    - `type` (enum, required): Where an API's schema document is fetched from.
      - One of: `direct_url`, `github`, `gitlab`, `stainless`, `google_discovery`, `upload`
    - `url` (string): Canonical fetch URL; absent for direct uploads.
    - `discoveredVia` (string): The discovery channel that surfaced this source - the harvester or aggregator it came from (e.g. `scalar`, `apis.guru`, `well-known-probe`). Absent for sources added by hand rather than through a seeding pipeline.
    - `isPrimary` (boolean, required): Whether this is the API's primary source.
    - `refetchEnabled` (boolean, required): Whether the source is refetched automatically (once a day) to pick up the latest version. Always `false` for uploads.
    - `lastCheckedAt` (string): When the source was last checked for changes.
    - `lastStatus` (enum): Outcome of the most recent check.
      - One of: `updated`, `unchanged`, `error`
    - `lastError` (string): Error message of the most recent failed check.
    - `createdAt` (string, required)
  - `versions` (array of ApiVersion, required): Publisher-declared versions, newest first. Empty for the long tail - most APIs publish one unversioned stream of revisions.
    - `label` (string, required): The publisher's name for the version, verbatim: `v3`, `2026-03`, …
    - `stability` (enum, required): Lifecycle stage of a publisher-declared API version. `retired` versions keep their archived revision history.
      - One of: `ga`, `beta`, `preview`, `deprecated`, `retired`
    - `isDefault` (boolean, required): The version an API's page shows when none is selected.
    - `sortRank` (integer, required): Display order, newest first (labels mix styles and never sort lexically).
    - `releasedAt` (string): Publisher release date, when known.
    - `eolAt` (string): Publisher end-of-support date, when known.
  - `lastCheckedAt` (string): When skmtc-hub last checked any of this API's sources for updates.
  - `lastUpdatedAt` (string): When the schema last changed: the newest revision's publisher date where there is one, else when skmtc-hub observed the change. The coalesce is deliberate and is NOT the conflation `publishedAt` avoids. "Updated" is a claim about a change having happened, which the existence of a revision establishes either way - unlike "published at", which names who produced it and when.
  - `latestVersionRef` (string): Content ref of the most recent version - its URL identifier. Absent if the latest is a link-only version (no stored document).
  - `versionCount` (integer, required)
  - `retiredAt` (string): When skmtc-hub retired this API: its sources stopped serving and no move or version change was found, or every one of its versions was retired. Absent for a current API. A retired API stays listed and keeps its history.
  - `starCount` (integer, required): Number of accounts that have starred this API.
  - `consumerCount` (integer, required): Number of projects consuming this API.
  - `createdAt` (string, required)
  - `updatedAt` (string, required)
  - `url` (string, required): An absolute URL.
  - `htmlUrl` (string, required): An absolute URL.
  - `viewer` (object, required): The requesting viewer's effective permissions on this API.
    - `canRead` (boolean, required): May view the resource.
    - `canWrite` (boolean, required): May edit metadata and settings (the `writer` relation).
    - `canAdmin` (boolean, required): May manage collaborators and delete the resource (the `admin` relation).
- `revision` (object, required): The revision created - or the pre-existing one when `deduped` is true.
  - `publishedAt` (string): When the change became public, by the publisher's account: for a git source, the merge time of the pull request that brought the commit into the tracked branch, else the committer date. **Absent when no publisher timestamp was ever known**, which is most of the non-git catalog. It used to fall back to `retrievedAt`, which passed skmtc-hub's own observation time off as the publisher's and made "updated 3d ago" mean two different things. `docs/api-versioning-vocabulary.md` is explicit that `retrievedAt` is always labelled as ours; read that field for the observation, and treat its absence here as "the publisher never said". Ordering still coalesces the two - a revision with no publisher date sorts by when it was retrieved - but the ORDER is not the same claim as the date.
  - `isLatest` (boolean, required)
  - `hasDocument` (boolean, required): Whether skmtc-hub stores the version's document. `false` for link-only history versions of git-sourced APIs; the document fields below are absent for those.
  - `documentUrl` (string): Upstream link to the document at this version (git-sourced APIs).
  - `commit` (object): The commit this version came from - present for git-sourced APIs.
    - `sha` (string, required): The commit SHA.
    - `message` (string, required): First line of the commit message.
    - `date` (string, required): Commit (author) date.
    - `htmlUrl` (string): Link to the commit on the host, when known.
  - `linkedRepositoryRun` (object): The workflow run that added this revision with a linked repository token. Absent for a revision added any other way.
    - `repository` (string, required): The repository, as `owner/name`.
    - `sha` (string, required): The commit the run ran on.
    - `runId` (string, required): GitHub's id of the workflow run.
    - `runAttempt` (string, required): The attempt of the run, from 1.
    - `workflowRef` (string, required): The workflow file and ref, e.g. `owner/name/.github/workflows/publish.yml@refs/heads/main`.
    - `htmlUrl` (string, required): Link to the run attempt on GitHub.
  - `specType` (enum, required): The spec family of an ingested API document.
    - One of: `openapi`, `swagger`
  - `specVersion` (string)
  - `documentVersion` (string)
  - `license` (object): License declared by the document - absent for link-only versions.
    - `name` (string, required): License name, e.g. `Apache 2.0`.
    - `spdxId` (string): SPDX identifier, e.g. `Apache-2.0` - OpenAPI 3.1 `info.license.identifier`.
    - `url` (string): Link to the license text.
  - `retrievedAt` (string, required)
  - `operationCount` (integer): Number of operations in the document - absent for link-only versions.
  - `schemaCount` (integer): Number of component schemas in the document - absent for link-only versions.
  - `serverUrl` (string): The document's first top-level server URL, as written: variables at their defaults, a relative URL left unresolved. Swagger 2 gives `schemes[0]://host` + `basePath`, or the bare `basePath` when the document has no `schemes` or no `host`. An empty string when the document declares no server. Absent when not derived yet, and for link-only versions.
  - `authSchemes` (array of AuthScheme): Auth mechanisms the document declares, sorted. Absent means not known (not derived yet, or a link-only version); it does not mean "none".
  - `documentFormat` (enum): Serialization of the stored document - absent for link-only versions.
    - One of: `json`, `yaml`
  - `byteSize` (integer): Size of the raw document, in bytes - absent for link-only versions.
  - `contentHash` (string): SHA-256 of the raw document bytes - absent for link-only versions.
  - `contentRef` (string): Short content ref (first 12 hex chars of `contentHash`) - the version's URL identifier (git-style). Absent for link-only versions, which have no bytes.
  - `url` (string, required): An absolute URL.
  - `htmlUrl` (string, required): An absolute URL.
- `deduped` (boolean, required): True when identical content already existed; no new revision was created.
- `isNewApi` (boolean, required): True when the import created a brand-new API entry.
- `diffsPending` (boolean, required): True when the API's full revision history is still being archived + diffed in the background - a large GitHub history deferred to the diff-backfill queue so the import responds without waiting on minutes of container diffs. The returned `revision` (the newest) is complete; older revisions' diffs fill in shortly. False for single-revision imports, which diff inline.

Example response:

```json
{
  "api": {
    "id": "string",
    "owner": {
      "id": "string",
      "handle": "string",
      "displayName": "string",
      "type": "user",
      "avatarUrl": "string",
      "bio": "string",
      "location": "string",
      "emailDomain": "string",
      "claimStatus": "claimed",
      "joinedAt": "2026-10-30T12:00:00Z",
      "url": "string",
      "htmlUrl": "string"
    },
    "slug": "string",
    "name": "string",
    "displayName": "string",
    "visibility": "public",
    "description": "string",
    "category": "ai-machine-learning",
    "readme": "string",
    "providerName": "string",
    "homepageUrl": "string",
    "logoUrl": "string",
    "isVerified": true,
    "license": {
      "name": "string",
      "spdxId": "string",
      "url": "string"
    },
    "sources": [
      {
        "id": "string",
        "type": "direct_url",
        "url": "string",
        "discoveredVia": "string",
        "isPrimary": true,
        "refetchEnabled": true,
        "lastCheckedAt": "2026-10-30T12:00:00Z",
        "lastStatus": "updated",
        "lastError": "string",
        "createdAt": "2026-10-30T12:00:00Z"
      }
    ],
    "versions": [
      {
        "label": "string",
        "stability": "ga",
        "isDefault": true,
        "sortRank": 0,
        "releasedAt": "2026-10-30T12:00:00Z",
        "eolAt": "2026-10-30T12:00:00Z"
      }
    ],
    "lastCheckedAt": "2026-10-30T12:00:00Z",
    "lastUpdatedAt": "2026-10-30T12:00:00Z",
    "latestVersionRef": "string",
    "versionCount": 0,
    "retiredAt": "2026-10-30T12:00:00Z",
    "starCount": 0,
    "consumerCount": 0,
    "createdAt": "2026-10-30T12:00:00Z",
    "updatedAt": "2026-10-30T12:00:00Z",
    "url": "string",
    "htmlUrl": "string",
    "viewer": {
      "canRead": true,
      "canWrite": true,
      "canAdmin": true
    }
  },
  "revision": {
    "publishedAt": "2026-10-30T12:00:00Z",
    "isLatest": true,
    "hasDocument": true,
    "documentUrl": "string",
    "commit": {
      "sha": "string",
      "message": "string",
      "date": "2026-10-30T12:00:00Z",
      "htmlUrl": "string"
    },
    "linkedRepositoryRun": {
      "repository": "string",
      "sha": "string",
      "runId": "string",
      "runAttempt": "string",
      "workflowRef": "string",
      "htmlUrl": "string"
    },
    "specType": "openapi",
    "specVersion": "string",
    "documentVersion": "string",
    "license": {
      "name": "string",
      "spdxId": "string",
      "url": "string"
    },
    "retrievedAt": "2026-10-30T12:00:00Z",
    "operationCount": 0,
    "schemaCount": 0,
    "serverUrl": "string",
    "authSchemes": [
      "apiKey"
    ],
    "documentFormat": "json",
    "byteSize": 0,
    "contentHash": "string",
    "contentRef": "string",
    "url": "string",
    "htmlUrl": "string"
  },
  "deduped": true,
  "isNewApi": true,
  "diffsPending": true
}
```

### 400

Binds a concrete HTTP `Status` to the shared `ApiError` body.

Content type: `application/json`. Type: `object`.

The uniform error envelope returned for every non-2xx response.

- `code` (enum, required): Machine-readable error category. Each value pairs with one HTTP status.
  - One of: `badRequest`, `unauthorized`, `forbidden`, `notFound`, `conflict`, `unprocessable`, `payloadTooLarge`, `unsupportedMediaType`, `documentTooLarge`, `webhookLimitReached`, `rateLimited`, `internal`, `unavailable`, `badGateway`, `notImplemented`
- `message` (string, required): Human-readable summary safe to surface to end users.
- `requestId` (string, required): Correlates the response with server logs for support.
- `details` (array of ErrorDetail)
  - `field` (string): Dotted path to the offending field, when applicable.
  - `message` (string, required): Human-readable explanation of this specific problem.

Example response:

```json
{
  "code": "badRequest",
  "message": "string",
  "requestId": "string",
  "details": [
    {
      "field": "string",
      "message": "string"
    }
  ]
}
```

### 401

Binds a concrete HTTP `Status` to the shared `ApiError` body.

Content type: `application/json`. Type: `object`.

The uniform error envelope returned for every non-2xx response.

- `code` (enum, required): Machine-readable error category. Each value pairs with one HTTP status.
  - One of: `badRequest`, `unauthorized`, `forbidden`, `notFound`, `conflict`, `unprocessable`, `payloadTooLarge`, `unsupportedMediaType`, `documentTooLarge`, `webhookLimitReached`, `rateLimited`, `internal`, `unavailable`, `badGateway`, `notImplemented`
- `message` (string, required): Human-readable summary safe to surface to end users.
- `requestId` (string, required): Correlates the response with server logs for support.
- `details` (array of ErrorDetail)
  - `field` (string): Dotted path to the offending field, when applicable.
  - `message` (string, required): Human-readable explanation of this specific problem.

Example response:

```json
{
  "code": "badRequest",
  "message": "string",
  "requestId": "string",
  "details": [
    {
      "field": "string",
      "message": "string"
    }
  ]
}
```

### 403

Binds a concrete HTTP `Status` to the shared `ApiError` body.

Content type: `application/json`. Type: `object`.

The uniform error envelope returned for every non-2xx response.

- `code` (enum, required): Machine-readable error category. Each value pairs with one HTTP status.
  - One of: `badRequest`, `unauthorized`, `forbidden`, `notFound`, `conflict`, `unprocessable`, `payloadTooLarge`, `unsupportedMediaType`, `documentTooLarge`, `webhookLimitReached`, `rateLimited`, `internal`, `unavailable`, `badGateway`, `notImplemented`
- `message` (string, required): Human-readable summary safe to surface to end users.
- `requestId` (string, required): Correlates the response with server logs for support.
- `details` (array of ErrorDetail)
  - `field` (string): Dotted path to the offending field, when applicable.
  - `message` (string, required): Human-readable explanation of this specific problem.

Example response:

```json
{
  "code": "badRequest",
  "message": "string",
  "requestId": "string",
  "details": [
    {
      "field": "string",
      "message": "string"
    }
  ]
}
```

### 404

Binds a concrete HTTP `Status` to the shared `ApiError` body.

Content type: `application/json`. Type: `object`.

The uniform error envelope returned for every non-2xx response.

- `code` (enum, required): Machine-readable error category. Each value pairs with one HTTP status.
  - One of: `badRequest`, `unauthorized`, `forbidden`, `notFound`, `conflict`, `unprocessable`, `payloadTooLarge`, `unsupportedMediaType`, `documentTooLarge`, `webhookLimitReached`, `rateLimited`, `internal`, `unavailable`, `badGateway`, `notImplemented`
- `message` (string, required): Human-readable summary safe to surface to end users.
- `requestId` (string, required): Correlates the response with server logs for support.
- `details` (array of ErrorDetail)
  - `field` (string): Dotted path to the offending field, when applicable.
  - `message` (string, required): Human-readable explanation of this specific problem.

Example response:

```json
{
  "code": "badRequest",
  "message": "string",
  "requestId": "string",
  "details": [
    {
      "field": "string",
      "message": "string"
    }
  ]
}
```

### 422

Binds a concrete HTTP `Status` to the shared `ApiError` body.

Content type: `application/json`. Type: `object`.

The uniform error envelope returned for every non-2xx response.

- `code` (enum, required): Machine-readable error category. Each value pairs with one HTTP status.
  - One of: `badRequest`, `unauthorized`, `forbidden`, `notFound`, `conflict`, `unprocessable`, `payloadTooLarge`, `unsupportedMediaType`, `documentTooLarge`, `webhookLimitReached`, `rateLimited`, `internal`, `unavailable`, `badGateway`, `notImplemented`
- `message` (string, required): Human-readable summary safe to surface to end users.
- `requestId` (string, required): Correlates the response with server logs for support.
- `details` (array of ErrorDetail)
  - `field` (string): Dotted path to the offending field, when applicable.
  - `message` (string, required): Human-readable explanation of this specific problem.

Example response:

```json
{
  "code": "badRequest",
  "message": "string",
  "requestId": "string",
  "details": [
    {
      "field": "string",
      "message": "string"
    }
  ]
}
```

## Changes

### Oct 30, 2026 (`2fe10b584fa2`)

- added `#/components/schemas/SourceRefetchStatus` to the `api/allOf[#/components/schemas/Api]/sources/items/lastStatus` response property `allOf` list for the response status `201`
- removed `#/components/schemas/SourceRefreshStatus` from the `api/allOf[#/components/schemas/Api]/sources/items/lastStatus` response property `allOf` list for the response status `201`

[Operation history](https://skmtc.dev/skmtc/apis/skmtc-api/changes/v1/apis/:account/:api/revisions/post)
