Help

Mutatio is a platform for recording and publicly sharing your project's changelogs via API.

1. Create a Project

After logging in, you can create a new project from your dashboard. Each project gets a unique API key.

2. Add Versions & Changelogs

You can add versions (e.g., v1.0, v2.0) and log your changes under each version.

3. Access Changelog via API

Changelogs are publicly accessible via:

https://mutatio.vercel.app/api/public/<API_KEY>

3.1 Sample API Response

Here's an example of the JSON structure returned by the public API endpoint:

{
  "data": {
    "id": "e2d5e002-6f74-4852-a869-b2be6f7c0339",
    "name": "Mutatio Project",
    "versions": [
      {
        "id": "aac33701-4bcf-4bf8-8056-a1fb7971e2c9",
        "name": "v1",
        "createdAt": "2025-05-16T10:40:29.255Z",
        "logs": [
          {
            "id": "d7d0818b-9511-40e3-80bf-1b58ee9cd853",
            "message": "(Example from BetterAuth) Authentication type missing on refershToken options",
            "createdAt": "2025-05-16T10:41:57.415Z"
          },
          {
            "id": "a4eac29c-4042-4a32-bfa9-b567ad259fc4",
            "message": "(Example from BetterAuth) Added c.authentication to refresh token",
            "createdAt": "2025-05-16T10:41:38.353Z"
          },
          {
            "id": "1b8918d7-33f2-45e6-b3af-3dbb40ac3c9d",
            "message": "(Example from BetterAuth) plugin: Error code support for haveibeenpwned plugin",
            "createdAt": "2025-05-16T10:41:07.589Z"
          }
        ]
      }
    ]
  }
}

4. Displaying Changelog on Your Website

The examples below using Next.js 15 with Server Actions:

// getData.ts
export async function getData() {
    const response = await fetch(`https://mutatio.vercel.app/api/public/${process.env.NEXT_PUBLIC_MUTATIO_API_KEY}`);
    const data = await response.json();
    return data.data;
}
// page.tsx
import React, { Suspense } from 'react';
import ChangelogsList from "./changelog-list";
import { getData } from "@/lib/changelog-utils";

export default async function ChangelogsPage() {
    const changeLogsPromise = getData();

    return (
        <div className="container mx-auto px-4 py-8">
            <h2>Project Changelogs</h2>
            <Suspense fallback={<div>Loading...</div>}>
                <ChangelogsList changeLogsPromise={changeLogsPromise} />
            </Suspense>
        </div>
    );
}
// changelog-list.tsx
"use client";

import { use } from "react";

interface Project {
    id: string;
    name: string;
    versions: Array<{
        id: string;
        name: string;
        createdAt: string;
        logs: Array<{
            id: string;
            message: string;
            createdAt: string;
        }>;
    }>;
}

export default function ChangelogsList({ changeLogsPromise }: { changeLogsPromise: Promise<Project> }) {
    const project = use(changeLogsPromise);

    return (
        <div className="space-y-8">
            <div key={project.id} className="border rounded-lg p-4 bg-gray-50 shadow-sm">
                <h2 className="text-xl font-bold mb-3">{project.name} Project</h2>

                {project.versions.map((version) => (
                    <div key={version.id} className="mb-6 pl-4 border-l-4 border-indigo-500">
                        <h3 className="text-lg font-semibold mb-2">
                            {version.name} - {new Date(version.createdAt).toLocaleDateString("en-US", {
                                year: "numeric",
                                month: "short",
                                day: "numeric",
                            })}
                        </h3>

                        <ul className="list-disc space-y-1 pl-6">
                            {version.logs.map((log) => (
                                <li key={log.id} className="text-gray-700">
                                    <p>{log.message}</p>
                                    <small className="text-xs text-gray-500">
                                        {new Date(log.createdAt).toLocaleDateString("en-US", {
                                            year: "numeric",
                                            month: "short",
                                            day: "numeric",
                                        })}
                                    </small>
                                </li>
                            ))}
                        </ul>
                    </div>
                ))}
            </div>
        </div>
    );
}

5. Caching with React Query (Recommended)

For better performance and user experience, we recommend using React Query (TanStack Query) to cache your changelog data. This prevents unnecessary API requests on page refreshes and provides automatic background updates.

// Use React Query for caching
import { useQuery } from '@tanstack/react-query'

function ChangelogsList() {
  const { data: project, isLoading, error } = useQuery({
    queryKey: ['changelogs'],
    queryFn: () => fetch('https://mutatio.vercel.app/api/public/YOUR_API_KEY')
      .then(res => res.json())
      .then(data => data.data),
    staleTime: 5 * 60 * 1000, // Consider data fresh for 5 minutes
  })

  if (isLoading) return <div>Loading...</div>
  if (error) return <div>Error loading changelogs</div>

  // Render your changelog data here
  return (
    <div>
      {/* Your existing changelog rendering logic */}
    </div>
  )
}

React Query provides automatic caching, background refetching, and optimistic updates, making your changelog display more efficient and responsive.

Need more help? Feel free to contact us at support@mutatio.pro.