API v1 → v2 Migration Guide

ReadMe API v2 is the best way to programmatically access your ReadMe data once you have migrated to ReadMe Refactored. We’re giving you access to the very same API that ReadMe’s developers use to build ReadMe. Let’s try it out.

🚧

ReadMe's API v2 is currently in beta.

This API and its docs are a work in progress. While we don’t expect any major breaking changes, you may encounter occasional issues as we work toward a stable release. Make sure to check out our API migration guide, and feel free to reach out if you have any questions or feedback!

Make your first API v2 Request

We’re going to use cURL in this example, but any HTTP client should work too.

Let’s start with a request to get details about your project.

curl -X GET https://api.readme.com/v2/projects/me --header “Authorization: Bearer {your-api-key}”

In the Authorization header you’ll need to add an API key. Learn more about ReadMe API keys here.

When you run this cURL command you will see a bunch of JSON that includes most of the details of your project. If that’s the case, you’ve successfully made your first API v2 request. If not, contact support and we’ll help you figure it out!

Most parts of this cURL command can be reused for your other API requests. Here are the most important points:

  • https://api.readme.com/v2/ will be the start of every API call. You can put it into a constant and reuse it for all your API requests.
  • The Authorization header will always be how you provide your API key. The value must include the string Bearer, then a space, then your API key.
  • The GET HTTP method return data, but will never change data.
  • The POST HTTP method requests generally create data (such as guides or custom pages), but is also used for more complex requests like search.
  • The PATCH HTTP method is used for editing data that already exists.
  • The PUT HTTP method is used for creating data (if you have the URI) or replacing data that already exists.
  • The DELETE HTTP method is used for deleting data that already exists.

What are the new API endpoints?

While the URLs changed, we worked to make them intuitive to use. You can find the full list of API v2 endpoints here, but let’s walk through an example below.

Here’s a comparison of the old and new endpoints to get a list of all of your custom pages.

Old Endpoint:

GET https://dash.readme.com/api/v1/custompages

New Endpoint:

GET https://api.readme.com/v2/versions/{version}/custom_pages

Major changes

Authentication

As mentioned previously, authentication has changed:

ReadMe API v1 previously used Basic Authentication and has now moved to Bearer Authentication.

Here's what a cURL request looked like previously in API v1:

curl -X GET https://dash.readme.com/api/v1 --user {your-api-key}:

Here's what it looks like in API v2:

curl -X GET https://api.readme.com/v2/projects/me --header “Authorization: Bearer {your-api-key}”

Hostname

As mentioned previously, the hostname has changed:

Specifying Project Version

The project version has moved from a header into the URL:

  • We've also dropped the v prefix from the version (e.g., GET https://api.readme.com/v2/versions/1.0/custom_pages).
  • In the old API if you wanted the stable version you could leave the header out. In the new API you can use the word stable (e.g., GET https://api.readme.com/v2/versions/stable/custom_pages).

Resource Identifiers

Resources are identified via URIs and slugs:

We've heard your feedback that using hexadecimal object IDs (e.g., 5f92cbf10cf217478ba93561) in API v1 to identify resources (e.g., API definitions, categories, etc.) make it difficult to build scalable integrations (e.g., integrations that might update many API definitions at once across several project versions).

We now use slugs and URIs to identify resources.

For example, to retrieve all of the API schemas for a given project version, you'd make a request to GET /v2/versions/{version}/apis and your response may look something like this:

{
  "total": 1,
  "data": [
    {
      ...
      "created_at": "2025-01-27T16:33:27.193Z",
      "type": "openapi",
      "uri": "/versions/1.0/apis/petstore.json",
    }
  ]
}

For this API definition resource, the URI is /versions/1.0/apis/petstore.json and the slug is petstore.json. You can use the URI and slug for this API definition to make read/writes.

For example, you can make the following API request to retrieve information about your petstore.json API definition:

curl -X GET https://api.readme.com/v2/versions/1.0/apis/petstore.json --header “Authorization: Bearer {your-api-key}”

Response Body Shapes

The response body shape has changed:

We offer consistent snake_case field names and have structured the responses in anticipation of growing these responses to include more useful data over time.

Here's what it looked like before in API v1:

[
  {
    "metadata": {
      "image": [],
      "title": "",
      "description": "",
      "keywords": ""
    },
    "mdx": {
      "altBody": "",
      "status": "rdmd"
    },
    "algolia": {
      "recordCount": 1,
      "publishPending": false
    },
    "title": "Welcome to the API",
    "slug": "welcome-to-the-api",
    "body": "We've got endpoints galore",
    "html": "",
    "htmlmode": false,
    "fullscreen": false,
    "hidden": true,
    "revision": 2,
    "_id": "673974422297a9aa6fc28b2b",
    "createdAt": "2025-01-16T21:12:34.267Z",
    "updatedAt": "2025-01-16T21:12:34.267Z",
    "lastUpdatedHash": "1608f5b78bac84444acc76ce134667c318bbc6ee",
    "__v": 0
  }
]

And here's what it looks like now in API v2:

{
  "total": 1,
  "data": [
    {
      "appearance": {
        "fullscreen": false
      },
      "content": {
        "body": "We've got endpoints galore",
        "type": "markdown"
      },
      "metadata": {
        "description": null,
        "image": {
          "uri": null,
          "url": null
        },
        "keywords": null,
        "title": null
      },
      "privacy": {
        "view": "public"
      },
      "slug": "welcome-to-the-api",
      "title": "Welcome to the API",
      "updated_at": "2025-01-16T21:15:53.484Z",
      "links": {
        "project": "/projects/me"
      },
      "uri": "/versions/1.0/custom_pages/welcome-to-the-api"
    }
  ]
}

Pagination

Pagination has changed:

In API v2 we no longer use the Link header that we used in API v1. In API v2 we have a new "Collection" format that includes pagination metadata alongside the data you requested. Here's an example.

{
  "total": 5,
  "page": 2,
  "per_page": 2,
  "paging": {
    "next": "/images?page=3&per_page=2",
    "previous": "/images?page=1&per_page=2",
    "first": "/images?page=1&per_page=2",
    "last": "/images?page=3&per_page=2"
  },
  "data": [
    {
      /* image object */
    },
    {
      /* image object */
    }
  ]
}

total, page and per_page (previously perPage) behave like they did in API v1, giving you all the important quantity-related metadata.

paging is where it gets interesting. The paging object contains four URIs. These are API calls you can make to get additional pages of content.

  • next is the page of content immediately following the current page. If the current page is the last page, this will be null
  • previous is the page of content immediately before the current page. If the current page is page 1, this will be null
  • first is the very first page of content. This will always have a value.
  • last is the very last page of content. This will always have a value.

Note: These pagination links will retain the query parameters used in your API call. In fact you shouldn't need to modify the pagination URLs in any way!