Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.getmaito.com/docs/llms.txt

Use this file to discover all available pages before exploring further.

Your custom website controls the reading and subscribe experience. Maito remains the source of truth for newsletter content and subscribers. This is useful when you want a fully custom newsletter archive, issue page, category page, or subscribe form while still writing and managing the newsletter in Maito.

How It Works

Your custom website should treat Maito as the source of truth. Maito stores:
  • Published newsletter issues
  • Issue slugs and public issue content
  • Newsletter categories
  • Subscribers
Your website controls:
  • The visual design
  • The homepage and archive layout
  • Individual issue pages
  • Category pages
  • The subscribe form experience
The important rule is that your Maito API key must stay on your server. Create the key in API > Authentication, then use it only from your backend routes. Browser code should call your own backend routes, and your backend routes should call Maito.
Visitor browser -> your website/backend -> Maito API
Do not put a Maito API key in frontend JavaScript, static site code, mobile app bundles, or public repositories.

Give This Prompt To An AI Builder

Use this prompt when asking Cursor, v0, Lovable, Replit, Bolt, or another AI builder to create a custom newsletter website.
Build a custom newsletter website for Maito.

Maito is the newsletter backend and source of truth. The website must show public newsletter issues, issue detail pages, categories, and a subscribe form.

Security requirements:
- Never expose the Maito API key in browser code.
- Store the API key as a server-side environment variable named MAITO_API_KEY.
- All browser requests must go to local backend routes in this project.
- Local backend routes must call the Maito API with:
  Authorization: Bearer process.env.MAITO_API_KEY
- The Maito API base URL is:
  https://api.getmaito.com/v1

Build these pages:

1. Newsletter homepage / archive
   - Fetch public sent issues from the server.
   - Use:
     GET https://api.getmaito.com/v1/newsletter/issues?status=sent&isPublic=true&limit=50
   - Render issue title, preview text, thumbnail if available, category if available, and link to the issue slug page.
   - Documentation:
     /api-reference/newsletter/list-issues

2. Issue detail page
   - Use a dynamic slug route.
   - Fetch one public issue by slug from the server.
   - Use:
     GET https://api.getmaito.com/v1/newsletter/issues/by-slug/{issueSlug}
   - Render subject, preview text, contentHtml, category, and sent date if available.
   - Documentation:
     /api-reference/newsletter/get-issue-by-slug

3. Categories
   - Fetch newsletter categories from the server.
   - Use:
     GET https://api.getmaito.com/v1/newsletter/categories
   - Render category navigation.
   - If building category archive pages, fetch public issues and filter by issue.category.slug or issue.categories.
   - Documentation:
     /api-reference/newsletter/list-categories

4. Subscribe form
   - The frontend form should submit only to a local backend route, for example /api/subscribe.
   - The local backend route should validate the email and then call Maito.
   - Use:
     POST https://api.getmaito.com/v1/newsletter/subscribers
     - Body example:
     {
       "email": "reader@example.com",
       "sourceType": "api",
       "source": "custom_website",
       "optInAttestation": true
     }
   - optInAttestation must be true only when the visitor explicitly submits the subscribe form.
   - Documentation:
     /api-reference/newsletter/create-subscriber

Recommended implementation if using Next.js App Router:
- Use server components or route handlers for Maito reads.
- Create app/page.tsx for the newsletter archive.
- Create app/issues/[slug]/page.tsx for issue pages.
- Create app/categories/[slug]/page.tsx only if category pages are needed.
- Create app/api/subscribe/route.ts for the subscribe form.
- Put MAITO_API_KEY in .env.local and never prefix it with NEXT_PUBLIC_.
- Return only the fields the frontend needs from local API routes.
- Show user-friendly subscribe success and error states.

Maito API responses use this shape:
{
  "ok": true,
  "data": {}
}

Error responses use this shape:
{
  "ok": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid request."
  }
}

Use these docs while building:
- API authentication: /api-reference/authentication
- API responses and errors: /api-reference/responses
- List issues: /api-reference/newsletter/list-issues
- Get issue by slug: /api-reference/newsletter/get-issue-by-slug
- List categories: /api-reference/newsletter/list-categories
- Create subscriber: /api-reference/newsletter/create-subscriber

API Overview

These are the main endpoints a custom newsletter website needs.
NeedEndpointReference
Show the archiveGET /v1/newsletter/issues?status=sent&isPublic=trueList issues
Show one issueGET /v1/newsletter/issues/by-slug/{issueSlug}Get issue by slug
Show categoriesGET /v1/newsletter/categoriesList categories
Subscribe a readerPOST /v1/newsletter/subscribersCreate subscriber
See Authentication for API key setup and Responses and errors for the response format.

Subscribe Forms

A custom subscribe form should call your own backend first. Your backend should:
  • Validate the email address
  • Optionally add rate limiting or CAPTCHA
  • Set optInAttestation: true only after the visitor submits the form
  • Call Maito with your server-side API key
For static websites without a backend, use a hosted subscribe widget instead of putting the API key in the browser.