Skip to content

OpenAPI to MCP: what converts cleanly, what doesn't, and why

We ran Riviera's OpenAPI importer, as released to production, over thirteen public specifications in two separate sets and recorded what stopped each operation from becoming a tool. A handful of causes repeat across unrelated APIs. Some are fixes in your document and some are limits of the converter, and we say which.

By Riviera EngineeringPublished Claims checked

In short

  • Seven SaaS documents. The importer accepted 6 of the 7 as published, and the seventh once its whitespace was removed, because it is over the 1 MiB limit. YAML needed no conversion. 3 of the 7 produced any tools: 124 of their 538 operations (23 percent) became tools. The other four documents produced none.
  • Six documents chosen to show causes. 4 of 6 were accepted as published. 0 of the 82 operations in the documents that were analyzed became tools, and none did after the preparation the documentation asks for. The other two documents were not analyzed at all.
  • Mechanical edits help less than you might hope. Declaring one server and dropping the fields beside a $ref brought the seven documents to 157 of 538 operations (29 percent). Removing every authentication declaration as well reached 183 (34 percent), a diagnostic ceiling, not something a real import would give you. Most of what stayed excluded was in the schemas themselves, such as oneOf, anyOf and nullable.
  • A generated tool is the start of the work, not the end. The numbers count operations the importer could convert. We did not call these providers’ APIs and we did not call a model, so nothing here says that a generated tool works, or that an agent chooses it and fills it in correctly.
  • Both sets are small and were chosen. They describe these documents. They say nothing about how common any cause is across APIs.

Five different questions

“Does it convert?” hides five questions, and a number about one is not a number about the next. This guide answers the first three for the documents it studies, and says plainly that it answers neither of the last two.

QuestionWhat it asksMeasured here
1. Document acceptanceDid the importer read the document and report on its operations, or refuse it whole?Yes, per document
2. Operation conversionCan this operation be called exactly as the document describes it? An operation that converts is what this guide calls one that became a tool.Yes, per operation
3. Tool generationDoes a tool definition exist (name, description, input and output schema, request mapping) that a person can add to a draft? A write, a missing credential or a choice of authentication waits for that person.The definition, yes: every operation that converts has one. Of the 124 that converted in the seven SaaS documents, 3 need no decision and 121 wait for one. Adding them to a draft, no
4. Successful executionDoes a client calling the published tool get the right answer from the real API?No. We called no provider's API
5. Model tool selectionDoes a model pick the tool for a request and fill in its arguments correctly?No. We called no model

A tool can exist and still fail question 4, for instance because the document promised a field the API does not accept. It can pass question 4 and fail question 5, because an agent chooses from a name and a description written for people. Neither of those is a reason to avoid converting. Both are reasons not to read a conversion count as a working integration.

Why it isn’t mechanical

An OpenAPI operation describes an HTTP request for a developer. An MCP tool is something a model chooses by name and description, fills in from an input schema, and calls once. Mapping one to the other means answering questions the document often leaves open:

  • Which server does the call go to, and with which credential?
  • What are the exact arguments, and which are required?
  • What comes back, and what does the agent need to know about it?

A converter can guess. Riviera’s importer doesn’t. It creates a tool only when it can call the operation exactly as the document describes it, because a wrong guess sends a real request, possibly with a real credential, to the wrong place or with the wrong shape. So where a document is ambiguous or uses something the importer can’t reproduce faithfully, it excludes the operation and says why. That strictness is a design choice, and it is why the results below look the way they do. A more permissive converter would show higher counts and would also carry the guesses.

Two document sets, three scenarios

Two sets, never added together

SetDocumentsHow they were chosenWhat it can show
Seven SaaS documentsSvix, Unkey, Novu, Resend, Formbricks, Intercom, Dropbox SignBy written criteria fixed before the importer was run on any of them: published by the provider, a B2B SaaS product, 10 to 200 operations, OpenAPI 3.x, declares an HTTP bearer or header API key. Seven of twelve candidates met themWhat a small SaaS team with a bearer or API key API is likely to meet. The pool was twelve providers we already knew published a specification, mostly developer-facing, so it is not a random sample
Six exploratory documentsSwagger Petstore 3.0 and 3.1, SendGrid Mail, Twilio Verify, Discord, OpenAIDeliberately, to cover different versions, sizes, authentication declarations and input problemsWhich causes exist and what each looks like. Not how often

The first set answers “what would happen to a company like ours”, the second “what kinds of thing go wrong”. Their totals are reported separately throughout, and each set is summarized in its own section.

Three scenarios, kept apart

  1. As published. The exact bytes of the document go to the importer. This is what a developer experiences who pastes their document and presses Import.
  2. Documented preparation. Only the steps Riviera’s documentation tells you to take. JSON and YAML are both read, so there is no conversion. The preparation left is removing whitespace from a document that is only over the size limit, and, for a document over 200 operations, splitting it, which here means keeping the first 200. The content of the document is not edited.
  3. Mechanical diagnostic edits. The same what-if edits applied to every document: declare one absolute server, drop webhooks, drop fields written beside a $ref, and, in two variants, remove every authentication requirement. They change what the document says. They show what the first blocking cause was hiding, and they are never ordinary onboarding.

Two things about the method matter for reading the numbers. The importer records only the first cause that blocks an operation, so an operation with an unusable server and an unsupported schema is reported once, for the server. The diagnostic edits exist because of that. And an accepted document is not the same as converted operations: a document can be accepted and yield none, and we report both.

The importer is the production release of 11 October 2026 (commit 5f96038). The figures were recorded on a clean working tree at commit db47a91, whose importer source is identical to the release, with a limit of 1,048,576 bytes and 200 operations per document. Both document sets are fixed and hashed.

Seven SaaS documents

DocumentAs publishedAfter documented preparationWhat stopped the rest, first cause per operation
Svix0 of 44 became tools0 of 44
SERVER_REQUIRED 34
REF_SIBLINGS 8
METHOD_UNSUPPORTED 2
Unkey59 of 100 became tools59 of 100
REF_SIBLINGS 17
SCHEMA_UNSUPPORTED 14
SCHEMA_TYPE 8
SECURITY_UNSUPPORTED 2
NovuNot analyzed: DOCUMENT_LIMIT, 1,109,750 bytes0 of 59 (whitespace removed)
SERVER_REQUIRED 56
REF_CYCLE 3
Resend48 of 113 became tools48 of 113
BODY_OPTIONAL 30
SCHEMA_TYPE 24
SCHEMA_UNSUPPORTED 9
MEDIA_UNSUPPORTED 1
PARAMETER_STYLE 1
Formbricks17 of 40 became tools17 of 40
SCHEMA_TYPE 17
BODY_OPTIONAL 4
RESPONSE_VARIANTS 1
SCHEMA_UNSUPPORTED 1
Intercom0 of 108 became tools0 of 108
SERVER_REQUIRED 70
REF_SIBLINGS 30
REF_MISSING 8
Dropbox Sign0 of 74 became tools0 of 74
SECURITY_ALTERNATIVES 57
SECURITY_UNSUPPORTED 15
SCHEMA_UNSUPPORTED 2

As published, 6 of the 7 were accepted. Novu’s is 1,109,750 bytes, and removing whitespace brings it under the limit. After that, all 7 were accepted and 3 produced tools: Unkey, Resend and Formbricks. That is 124 of 538 operations (23 percent). Of the 124, 3 are ready to add and 121 wait for a decision. None of the 124 is a tool in a draft yet, and none is visible to an agent: that takes the steps described next.

What “waits for a decision” means

Converting an operation means the importer can describe the call exactly. It does not add anything to a project. A person chooses which operations to add to a draft, finishes any setup they need, and publishes. Of the 124 operations that converted, split by what a person still has to do:

  • 3 need nothing more. They are reads with no authentication: Unkey’s liveness check and two Formbricks endpoints, its health check and an environment read.
  • 121 need an ordinary choice in the product, and none needs a change to the document. The reasons overlap: 98 write data, so they are never preselected and each is added on purpose. 105 sit behind an HTTP bearer scheme, which does not say whether the token is one service token or each user’s own, so the product asks. 14 need an API key saved. 5 are marked deprecated in the source and are flagged for review.
  • The other 414 did not convert. Some need a change in the document (a server address, a field beside a $ref, a body that does not say it is required). Others use something the importer does not support today, such as oneOf, nullable or HTTP Basic, which a document edit would only hide. The sections below say which is which.

So the 124 is a count of operations the importer could convert, not of tools agents can use today. Even a tool that is added and published has still to be called against the real API, and chosen by a model, before it is useful. This guide tested neither.

Unkey names its operations like /v2/apis.listKeys and calls them with POST, so its tools are almost all POST operations. Resend’s are a mix of reads, deletes and writes, but POST /emails, the operation that sends an email, was excluded with BODY_OPTIONAL. In the other set, SendGrid’s send operation reached the same cause once the diagnostic edits had cleared its server and reference problems. Two examples are not a pattern we can measure, but it is worth checking in your own document: the operation a product exists to perform may be the one with the richest request body.

What mechanical edits would change

These are diagnostics. They show the ceiling of editing the document, not what a developer can import.

Edit applied to the documentOperations that would become toolsDocuments with tools
None (documented preparation)124 of 5383 of 7
Drop the webhooks section124 of 5383 of 7
Drop fields written beside a $ref131 of 5383 of 7
Declare one absolute server150 of 5386 of 7
Remove every authentication requirement136 of 5384 of 7
Declare one server and drop the fields beside a $ref (structure fixed)157 of 5386 of 7
Declare one server and remove authentication176 of 5387 of 7
Structure fixed and authentication removed183 of 5387 of 7

Dropping the webhooks section changes nothing, because the importer now leaves it out on its own. Each other edit moves a few operations, and none moves most. With the structure fixed and authentication removed, 355 operations stayed excluded, and 220 of them, more than half, were stopped by a schema, led by SCHEMA_UNSUPPORTED 155 and SCHEMA_TYPE 61. An edit to a server or a reference does not fix those.

Six documents chosen to show causes

This is the first set we ran, on 8 October, with the importer as it was then. It is kept as it was chosen: six documents picked to show what goes wrong, with a different aim from the first set, so it is reported on its own and the figures are not added to the ones above. The counts below are from the release, not from that first run.

DocumentOperationsFirst run, 8 OctoberAs published, releaseAfter documented preparation, release
Swagger Petstore19Analyzed, 0 toolsAnalyzed, 0 of 19 became tools. SERVER_REQUIRED 190 of 19
Swagger Petstore, OpenAPI 3.1 edition3Not analyzed or refused: WEBHOOKS_UNSUPPORTEDAnalyzed, 0 of 3 became tools. REF_SIBLINGS 30 of 3
Twilio SendGrid, Mail API v33Analyzed, 0 toolsAnalyzed, 0 of 3 became tools. SERVER_REQUIRED 2, REF_SIBLINGS 10 of 3
Twilio, Verify API v257Analyzed, 0 toolsAnalyzed, 0 of 57 became tools. SECURITY_UNSUPPORTED 43, SECURITY_ALTERNATIVES 140 of 57
Discord, HTTP API246Not analyzed or refused: DOCUMENT_LIMITNot analyzed: DOCUMENT_LIMIT, 1,192,427 bytes0 of 200 (minify and first 200 operations)
OpenAI API359Not analyzed or refused: DOCUMENT_LIMITNot analyzed: DOCUMENT_LIMIT, 4,058,614 bytesNot analyzed: almost four times the size limit

4 of 6 were accepted as published, and 0 of the 82 operations in those four became tools. The other two were refused before any operation was looked at. After the preparation the documentation asks for, 5 of the 5 analyzable documents were accepted, and 0 of 282 operations became tools. What changed since the first run is what the importer can read: Petstore 3.1 is no longer refused for its one webhook, and OpenAI’s document is YAML, which the importer now reads, but at 4,058,614 bytes it is far over the limit. The rest are kept out by the causes in the next section: a server address, a $ref with a sibling field, and authentication.

With the same mechanical edits as above, the five analyzable documents reached 3 of 282 operations, and 21 when authentication was also removed. Discord is the first 200 of its 246 operations and the count is not a sample. Read these as a description of this set only.

What stopped operations

These are the first causes across the seven SaaS documents after documented preparation, with where the fix belongs. A fix in your document is a change you can make. A limit is something the importer does not map today, so editing the document would change what it promises rather than make it clearer.

CodeOperationsSeen inWhat it meansWhere the fix belongs
SERVER_REQUIRED160Svix, Novu, IntercomNo single server address to callYour document if there is none. Otherwise a limit: alternatives such as regions are not supported
SECURITY_ALTERNATIVES57Dropbox SignSeveral authentication options per operationYour document, by declaring the one an agent should use
REF_SIBLINGS55Svix, Unkey, IntercomFields written beside a $refYour document, by moving them into the referenced definition
SCHEMA_TYPE49Unkey, Resend, FormbricksA schema without one explicit, non-null type (nullable, unions, inferred types)A limit. Editing the document changes what it promises
BODY_OPTIONAL34Resend, FormbricksA request body that does not say required: trueYour document, if the body really is required. Otherwise a limit
SCHEMA_UNSUPPORTED26Unkey, Resend, Formbricks, Dropbox SignA schema keyword outside the supported list (oneOf, anyOf, nullable)A limit. Editing the document changes what it promises
SECURITY_UNSUPPORTED17Unkey, Dropbox SignAuthentication Riviera does not supply (HTTP Basic, a key in a cookie)A limit
REF_MISSING8IntercomA local reference that points at nothingYour document
REF_CYCLE3NovuA schema that refers back to itselfA limit. A bounded definition written for the agent avoids it
METHOD_UNSUPPORTED2SvixA method other than GET, POST, PUT, PATCH or DELETEA limit
MEDIA_UNSUPPORTED1ResendA body or response that is not application/json aloneYour document, where you can offer JSON alone. Otherwise a limit
PARAMETER_STYLE1ResendA query array not sent as repeated fieldsYour document, if the API accepts repeated fields. Otherwise a limit
RESPONSE_VARIANTS1FormbricksSuccess responses with different schemasYour document, if one schema can describe them. Otherwise a limit

The server address

The importer needs one absolute HTTPS server URL for each operation. It was the first cause for 34 operations in Svix, 56 in Novu and 70 in Intercom, and for all 19 of Swagger Petstore 3.0. Svix declares no servers at all, which is a fix in the document. Petstore declares a relative address:

"servers": [
  { "url": "/api/v3" }
]

A relative address means “the host this document was served from”, and a tool that is stored and called later has no such host. Intercom and Novu are different. Intercom declares three servers, one per region:

"servers": [
  { "url": "https://api.intercom.io",
    "description": "The production API server" },
  { "url": "https://api.eu.intercom.io",
    "description": "The european API server" },
  { "url": "https://api.au.intercom.io",
    "description": "The australian API server" }
]

A call can only go to one of them and the document does not say which an agent should use, so the importer won’t pick. Regions as alternatives are a limit of the importer today, not a mistake. You can declare the one agents should call, or give each region its own document and import them separately.

Sources: Swagger Petstore (Apache-2.0) and Intercom (MIT repository), abridged.

Authentication

72 of the 74 operations in Dropbox Sign had authentication as the first cause: SECURITY_ALTERNATIVES on 57 and SECURITY_UNSUPPORTED on 15. Its operations accept either an API key or an OAuth token, and the API key scheme is HTTP Basic:

"securitySchemes": {
  "api_key": { "type": "http", "scheme": "basic" }
},
"security": [
  { "api_key": [] },
  { "oauth2": ["account_access", "basic_account_info"] }
]

The importer asks for exactly one requirement per operation, and does not supply HTTP Basic. Declaring the one requirement an agent should use removes the alternatives, and whether that one works then depends on its scheme. HTTP Basic is a limit, not a mistake: you can’t fix it by editing the document. Twilio Verify, in the other set, is the same case: authentication was the first cause for all 57 of its operations. What was behind it is a separate question, and the schema section below shows part of it:

"securitySchemes": {
  "accountSid_authToken": { "type": "http", "scheme": "basic" },
  "access_token_bearer": { "type": "http", "scheme": "bearer" }
},
"security": [ { "accountSid_authToken": [] } ]

Supported today are no authentication, an API key in a header, an HTTP bearer token, OAuth client credentials, and per-user OAuth through your own authorization server. Credentials are stored encrypted and sent only to the API they were saved for, and agents never see them. The authentication documentation has the detail.

Sources: Dropbox Sign (MIT, declared in the document) and Twilio Verify API v2 (Apache-2.0), abridged.

Request bodies

In OpenAPI, a request body is optional unless it says required: true. The importer supports only required JSON bodies on write methods, so a body that does not say so is excluded. That is the first cause for 30 operations in Resend, including POST /emails:

"/emails": {
  "post": {
    "requestBody": {
      "content": {
        "application/json": {
          "schema": { "$ref": "#/components/schemas/SendEmailRequest" }
        }
      }
    }
  }
}

The referenced schema lists from, to and subject as required, and the body itself is left unmarked. Setting the flag is a one-line fix, and it should be true to what the API does. There is a second step behind it, and the guide would be misleading if we skipped it: Resend’s to field is declared as one of a string or an array.

"to": {
  "description": "Recipient email address. For multiple addresses, send as an array of strings. Max 50.",
  "oneOf": [
    { "type": "string" },
    { "type": "array", "items": { "type": "string" }, "minItems": 1, "maxItems": 50 }
  ]
}

That is oneOf, which the importer does not map. We checked by hand: with the body marked required, POST /emails is excluded with SCHEMA_UNSUPPORTED for oneOf instead, and the same document declares bcc, cc and reply_to that way too, so more than one field would need a decision. Declaring to as an array only is a fair one when the API accepts a list: it tells the agent to always send one.

Media types work the same way. An operation that offers JSON next to XML or form encoding is excluded, because the importer accepts a body only when application/json is the single media type. If your API accepts JSON, you can often declare JSON alone for the agent-facing document.

Source: Resend (MIT repository), abridged.

Schema keywords

The importer reads a fixed list of schema keywords and excludes an operation that uses one outside it, rather than drop the keyword and promise something the tool doesn’t deliver. nullable is the clearest example. This one sits in the pagination data of a Twilio list response, not in anything an agent sends:

"meta": {
  "properties": {
    "next_page_url": { "type": "string", "format": "uri", "nullable": true }
  }
}

Where nothing else stops the operation, it still excludes the whole operation. Removing nullable makes the schema say the value is never null, which is less true, and that is a trade-off you decide. Today the importer has no way to express “a string or null”. The same applies to oneOf, anyOf, allOf and type arrays. In the seven SaaS documents, SCHEMA_TYPE and SCHEMA_UNSUPPORTED together were the first cause for 75 operations. Vendor extensions with names starting x- are not among the causes, since the importer ignores them, and formats it does not know are ignored too.

Source: Twilio Verify API v2 (Apache-2.0), abridged.

References

A $ref with a field beside it was the first cause for 55 operations, in Svix, Unkey and Intercom. It is allowed in OpenAPI 3.1, and SendGrid writes it:

"schema": { "type": "string", "$ref": "#/components/schemas/ContentEncoding" }

The importer can’t tell which of the two wins, and the fix it asks for is to move the field into the referenced definition. Dropping the field, as our diagnostic edit does, is cruder and can lose a constraint. A schema that refers back to itself is excluded too (REF_CYCLE), because it has no finite input schema an agent can fill in. Some exclusions are not about one operation: Discord’s references expand past the budget the importer shares across a whole document, and operations analyzed after it is spent fail with the same code, so that count says little about any one of them.

What you can do about excluded operations

You have more choices than editing your document, and only some of them change your API’s contract. In rough order of cost:

  1. Fix what is wrong or missing in the document. Declare a server where there is none, mark bodies required: true where they are, move fields beside a $ref into the definition, correct references that point at nothing, and declare the one authentication requirement an agent should use. These make the document more accurate for everyone who reads it, so they are worth doing whichever converter you use.
  2. Publish a document written for agents. Keep your full document as the source of truth and generate a smaller one from it: one server, one authentication requirement per operation, JSON bodies only, and the operations you want agents to use. Every simplification here is a promise about your API, so make sure it holds. Declaring to as an array is safe when the API accepts an array. Dropping nullable is not when it can return null.
  3. Choose what to expose. You probably don’t want 538 operations as tools. That is our judgment, not a finding of this study. Agents are asked to choose among whatever you give them, and a short list chosen for the jobs people actually bring is easier to describe, review and test. Start from those jobs and check which of their operations convert.
  4. Accept the limit and cover the operation another way. Where an operation uses something the importer does not map, such as HTTP Basic, regional servers or oneOf, a tool written by hand in an MCP server you run can do what a converter won’t. Riviera can also sit in front of an MCP server you already run, to edit and version what agents see.

Which of these applies depends on the cause. A server or a body flag is a fix. A nullable pagination field is a decision about your contract. HTTP Basic is a limit. The table above separates them, and the importer says which one it hit for each operation.

Why generated tools still need editing

Here is what the importer produced for one SendGrid operation, with the long text shortened, after a server was declared and the field beside a $ref was dropped. The same two of its three operations became tools: POST /v3/mail/batch as create_mail_batch and GET /v3/mail/batch/{batch_id} as get_mail_batch. The third, POST /v3/mail/send, is the one that sends email, and it stays out with BODY_OPTIONAL.

{
  "name": "get_mail_batch",
  "description": "**This operation allows you to validate a mail batch ID.**\n\nIf you provide a valid batch ID, this operation will return a `200` status code and the batch ID itself. [...]",
  "inputSchema": {
    "type": "object",
    "properties": {
      "path_batch_id": {
        "type": "string",
        "description": "Set this parameter to the batch ID that's associated with the mail send you want to retrieve."
      },
      "header_on_behalf_of": {
        "type": "string",
        "description": "Use the `on-behalf-of` header to make API calls for a particular Subuser through the parent account. [...]"
      }
    },
    "required": ["path_batch_id"],
    "additionalProperties": false
  },
  "outputSchema": {
    "title": "Mail Batch and Batch ID Response Schema",
    "type": "object",
    "properties": { "batch_id": { "type": "string", "description": "A mail batch ID." } }
  }
}

Three things in it come from how the document was written for people, not for a model.

  • The description is documentation. It opens with bold Markdown and the phrase “This operation allows you to”, then explains status codes. An agent choosing between tools needs to know when to use this one and what the identifier looks like.
  • Every header parameter becomes an input the agent can set. header_on_behalf_of lets a caller act as a Subuser through the parent account. That is a decision for you, not for a converter.
  • Argument names follow the document. path_batch_id describes where the value goes, not what it is.

We have not measured how these differences change which tool a model picks, so we make no claim about it. The mechanism is plain enough to act on: agents choose a tool and fill its inputs from its name, description and schema alone. In Riviera you rewrite those without touching your API or your OpenAPI document, and you can see a before and after.

Source: Twilio SendGrid Mail API (MIT), abridged, and the importer’s own output.

A checklist before you convert

  1. Keep the document under 1 MiB and at most 200 operations. JSON and YAML 1.2 both work. Remove whitespace if that is the only problem with the size.
  2. Declare one absolute HTTPS server URL. Leave out alternatives you don’t want agents to use.
  3. Use one security requirement per operation, with a scheme from the supported list. Declare credentials as schemes, not as header parameters.
  4. Mark request bodies required: true when they are, and offer application/json alone where you can.
  5. Describe one JSON object response for every success status, or a 204.
  6. Keep references local, with nothing written beside a $ref and no cycles.
  7. Look at the schemas your chosen operations use for nullable, type arrays and oneOf, anyOf and allOf, and decide what each should say.
  8. Import it, read the reasons, fix the first cause, and import again. Only the first cause per operation is shown.
  9. Then test what the importer can’t: call the tools against a test environment, and check which tool a model chooses for the requests your customers make.

Limits of this study

  • Thirteen documents in two sets, chosen. Nothing here says how common a cause is across APIs, or what share of any company’s operations would convert.
  • The seven SaaS documents were chosen by criteria fixed in advance from a pool of twelve providers we already knew. They are developer-facing, and a company’s own API may be described less carefully.
  • The importer reports only the first cause per operation, so the counts of causes understate how many there are.
  • The diagnostic edits are mechanical. They can be wrong for a real document, for example by dropping a constraint beside a $ref.
  • The Discord figures cover its first 200 operations in the importer’s order. That is not a sample. OpenAI’s document was not analyzable at all.
  • An accepted document and generated tools are not evidence that the tools work against the real API, or that agents use them well. We made no model calls and did not call these providers’ APIs.
  • Documents change. These ran on 10 and 11 October 2026 against the commits and hashes below, and providers may have corrected them since.
  • Riviera’s importer is strict on purpose. A converter with different goals would show different numbers, and the result for your documents will differ from ours.
  • The provider documents are their authors’ work. We quote short fragments to show what we found and don’t endorse or criticize any provider.

Reproducing the numbers

Each document is listed with the URL it was fetched from and its SHA-256, so you can fetch the same bytes and check them. Where the URL names a commit, the bytes cannot change. The two Swagger Petstore documents come from live demo servers, so a changed hash means the provider changed the document. Importing the same documents with Import an API on the Free plan gives you the as-published column. The documents, their hashes, the per-operation results and two scripts that check them are in a public repository. We have not published our importer, so the per-operation results can be read and compared but not regenerated from it.

DocumentOpenAPISource URLSHA-256
Svix3.0.2https://raw.githubusercontent.com/svix/svix-webhooks/ae6b40db923f8182756e03b982000035412cb47a/server/openapi.jsonaabd08dc1ba56a5dc3e1888143929caf496ddc2259c42daefcc174f39ac7f53a
Unkey3.1.0https://raw.githubusercontent.com/unkeyed/unkey/d00fc71f507640eb1cdddef4ca7f8eda773a8cd9/svc/api/openapi/openapi-generated.yamlc16a030718afce144f187ee6ffec11371f072c280f34ba01827294cb9dbb7c54
Novu3.0.0https://raw.githubusercontent.com/novuhq/novu/c4d3eda128c0a2da19c5b674305bdebd0deccb62/apps/api/swagger-spec.json2f15679db6aa96bf85be22d2eb6b05ca0600ffce653c45f5331d4bac77d45d56
Resend3.1.2https://raw.githubusercontent.com/resend/resend-openapi/8916b099d7f52b8552a2e1ef38a7f16fcd17864c/resend.yamld75e4e44f9fa0a70e26506998c1ed57f9e3b1a4bd38691bbcc67776894ceff4a
Formbricks3.1.0https://raw.githubusercontent.com/formbricks/formbricks/2c5c3b104bfccabc44c2460e2488eac14d8910c9/docs/api-v2-reference/openapi.yml1cac4c8f314ed18460306ded1b0edb93e51a5591896c090af71424ac2f10a9d0
Intercom3.0.1https://raw.githubusercontent.com/intercom/Intercom-OpenAPI/73332394d9913db5c0bafebafc9f62375b9800e6/descriptions/2.11/api.intercom.io.yaml41c83541883c96f5400f5731cf10e6898641c68fc9984256f866fe4f721d37c6
Dropbox Sign3.0.3https://raw.githubusercontent.com/hellosign/hellosign-openapi/f7f2ad4ff87eb222b0965957fe5f4a550e1b410d/openapi.yamld1d9b4ddee8dbbf1b4881d48d42f0db2a67ff42245697ace8480f35ca52722aa
DocumentLicenceSource URLSHA-256
Swagger Petstore (SmartBear, swagger-api/swagger-petstore)Apache-2.0, declared in the document's info.licensehttps://petstore3.swagger.io/api/v3/openapi.json00441c05add60f28da55eb4563d3fb6bbda364ba8eb7b381e2e2c98613005c82
Swagger Petstore, OpenAPI 3.1 edition (SmartBear, swagger-api/swagger-petstore)Apache-2.0, declared in the document's info.licensehttps://petstore31.swagger.io/api/v31/openapi.jsonb493226aa87181e5de361eb453a2daedd869b715b9112a9cd9a73ea362882409
Twilio SendGrid, Mail API v3 (twilio/sendgrid-oai)MIT, declared in the document's info.license (and the repository licence)https://raw.githubusercontent.com/twilio/sendgrid-oai/fb95a935c87b79f7f982ac34bd37adab1f697dbc/spec/json/tsg_mail_v3.json4ba24d0feb8a6b347f60528161d1cf0e7591987d2b3a64a6533685dc2b39d19f
Twilio, Verify API v2 (twilio/twilio-oai)Apache-2.0, declared in the document's info.license (repository licence MIT)https://raw.githubusercontent.com/twilio/twilio-oai/141f1201b55abcc16b3aa8089e71c4a927326975/spec/json/twilio_verify_v2.jsonbee888a5f4c53e422604cafbd610ffe23b46db5789dab9ef516980a188e480bb
Discord, HTTP API (discord/discord-api-spec)MIT, declared in the document's info.licensehttps://raw.githubusercontent.com/discord/discord-api-spec/1ff2dee3677fabef7b49f942bbae93d06c0c9f2c/specs/openapi.json7fd37d558c01b7a1a16287bd31cb2b65abfaa372c18e912dc67fbeead5e23653
OpenAI API (openai/openai-openapi)MIT, declared in the document's info.license (and the repository licence)https://raw.githubusercontent.com/openai/openai-openapi/e95c0fe615f45a19e8878af923a729948445a6bd/openapi.yaml8f037f570565278e84c57ef1f1777c1c8ede954da7b428d70ec93dc294781ba7

The exploratory set’s first run, on 8 October 2026 with the importer at commit 625ce0d, is the “First run” column in its section. It is kept as recorded and was not rerun.