{
  "openapi": "3.1.0",
  "info": {
    "title": "AI with Pelumi Newsletter API",
    "version": "1.0.0",
    "summary": "Subscribe a person to the free AI with Pelumi weekly newsletter.",
    "description": "One public endpoint: add an email address to the AI with Pelumi newsletter, a free weekly guide to building with AI (content engines, no-code websites and agents, AI assistants, prompt to production). Only call it when the person who owns the email address has asked to subscribe. Calls from anywhere other than the signup form on aiwithpelumi.com get double opt-in: the person receives a confirmation email and joins the list only after clicking its link. Tell them to check their inbox. The response is the same whether or not the address was already subscribed.",
    "contact": {
      "name": "Pelumi Fatoye",
      "email": "pelumidev1@gmail.com",
      "url": "https://aiwithpelumi.com/"
    }
  },
  "externalDocs": {
    "description": "Site guide for agents",
    "url": "https://aiwithpelumi.com/llms.txt"
  },
  "servers": [
    {
      "url": "https://api.aiwithpelumi.com",
      "description": "Production"
    }
  ],
  "paths": {
    "/api/newsletter/subscribe": {
      "post": {
        "operationId": "subscribeToNewsletter",
        "summary": "Subscribe an email address to the newsletter",
        "description": "Sends a confirmation email to the address; the person is subscribed once they click the link in it (valid 7 days), and then gets a welcome email. No API key is needed. Rate limited to 5 attempts per address and 100 per client IP in any 10-minute window. Browser calls are only allowed from aiwithpelumi.com (CORS); server-side calls work from anywhere.",
        "tags": [
          "Newsletter"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SubscribeRequest"
              },
              "example": {
                "email": "reader@example.com",
                "first_name": "Ada"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Accepted. A confirmation email is on its way. Returned for new, pending and already-subscribed addresses alike.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubscribeResponse"
                },
                "example": {
                  "ok": true,
                  "message": "Check your inbox and click the link to confirm."
                }
              }
            }
          },
          "400": {
            "description": "The body was not JSON, or the email address is not valid. Fix the request before retrying.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "That doesn't look like an email address."
                }
              }
            }
          },
          "429": {
            "description": "Too many attempts for this address or IP. Wait at least 10 minutes before retrying.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Too many attempts. Try again in a few minutes."
                }
              }
            }
          },
          "500": {
            "description": "The subscriber could not be saved. Safe to retry once.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Something broke on my end. Try again."
                }
              }
            }
          },
          "502": {
            "description": "The confirmation email could not be sent. Safe to retry once.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Something broke on my end. Try again."
                }
              }
            }
          },
          "503": {
            "description": "The newsletter backend is temporarily unavailable. Retry later.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Newsletter backend is not configured."
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "SubscribeRequest": {
        "type": "object",
        "required": [
          "email"
        ],
        "properties": {
          "email": {
            "type": "string",
            "format": "email",
            "description": "The subscriber's email address. Case and surrounding spaces are normalised."
          },
          "first_name": {
            "type": "string",
            "maxLength": 80,
            "description": "Optional first name, used in emails."
          },
          "consent_text": {
            "type": "string",
            "maxLength": 500,
            "description": "Optional record of what the person agreed to. A default is stored when omitted."
          }
        }
      },
      "SubscribeResponse": {
        "type": "object",
        "required": [
          "ok",
          "message"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "const": true
          },
          "message": {
            "type": "string",
            "description": "Human-readable confirmation to show the person."
          }
        }
      },
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string",
            "description": "Human-readable reason the request failed."
          }
        }
      }
    }
  },
  "tags": [
    {
      "name": "Newsletter",
      "description": "Newsletter subscription"
    }
  ]
}
