{
  "openapi": "3.1.0",
  "info": {
    "title": "doineed.email API",
    "version": "1.0.0",
    "summary": "Blunt answers to common email questions, as JSON and markdown.",
    "description": "Blunt answers to the email questions everyone asks. YES, NO, or IT DEPENDS—with the reasoning to back it up. No authentication and no request signing. https://doineed.email/api/v1/concepts.json changes only when content is deployed—cache it freely. https://doineed.email/api/v1/random is uncached by design. Unknown /api/* paths return the Error schema: {\"error\": {\"code\", \"message\", \"hint\", \"docs\"}}.\n\n## Versioning and deprecation\n\nThe API is versioned in the URL path; the current and only version is v1. Unversioned paths (/api/random, /api/concepts.json) are permanent aliases of v1 and every response carries an API-Version header. Within v1, changes are additive only: fields are never removed or retyped, and enums only grow. A breaking change would ship as /api/v2; v1 would then keep working for at least 6 months, signal its status with Deprecation and Sunset headers (RFC 9745/8594), and the timeline would be announced in https://doineed.email/llms.txt and https://doineed.email/agent.md.\n\n## Rate limits\n\nThe advisory budget is 60 requests per minute per client, declared on every API response via RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset, and RateLimit-Policy headers. Requests beyond what the platform tolerates receive 429 with a Retry-After header and the Error schema; honor Retry-After and back off. For bulk access, fetch /api/v1/concepts.json once (or /llms-full.txt) instead of polling /api/v1/random.",
    "contact": {
      "name": "The Resend team",
      "url": "https://doineed.email/contact"
    }
  },
  "externalDocs": {
    "description": "Agent guide: when to use this site and how to cite it.",
    "url": "https://doineed.email/agent.md"
  },
  "servers": [
    {
      "url": "https://doineed.email"
    }
  ],
  "tags": [
    {
      "name": "concepts",
      "description": "Answered \"Do I need…?\" questions about sending email."
    }
  ],
  "paths": {
    "/api/v1/concepts.json": {
      "get": {
        "operationId": "listConcepts",
        "tags": [
          "concepts"
        ],
        "summary": "List every concept",
        "description": "Returns all published concepts with their verdicts, qualifiers, excerpts, and canonical URLs. Static and cacheable; changes only on deploys. Also served at /api/concepts.json (permanent alias).",
        "responses": {
          "200": {
            "description": "Every published concept, sorted by slug.",
            "headers": {
              "API-Version": {
                "description": "Major version of the API that served the response.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "1"
                  ]
                }
              },
              "RateLimit-Limit": {
                "description": "Advisory request budget per window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Advisory requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Policy": {
                "description": "The declared policy, e.g. \"60;w=60\" (60 requests per 60s).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Concept"
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/UnexpectedError"
          }
        }
      }
    },
    "/api/v1/random": {
      "get": {
        "operationId": "getRandomConcept",
        "tags": [
          "concepts"
        ],
        "summary": "Get one random concept",
        "description": "Returns a single concept chosen uniformly at random on every request. Sent with Cache-Control: no-store and Access-Control-Allow-Origin: *. Also served at /api/random (permanent alias). For a page redirect instead of JSON, GET /random responds 307 to a random answer page.",
        "parameters": [
          {
            "name": "exclude",
            "in": "query",
            "required": false,
            "description": "Slug to exclude from the pool, so repeat calls can avoid returning the concept the caller already has.",
            "schema": {
              "type": "string",
              "enum": [
                "2048-bit-dkim",
                "accessible-emails",
                "amp-for-email",
                "bimi",
                "bounce-and-complaint-rates",
                "bulk-sender-requirements",
                "click-tracking",
                "custom-return-path",
                "custom-tracking-domain",
                "dedicated-ip",
                "dkim",
                "dkim-rotation",
                "dmarc",
                "dmarc-p-reject",
                "dmarc-reports",
                "domain-reputation",
                "domain-warmup",
                "double-opt-in",
                "email-verification",
                "gmail-postmaster-tools",
                "idempotency-keys",
                "ip-reputation",
                "my-own-mail-server",
                "no-reply-address",
                "one-click-unsubscribe",
                "open-tracking",
                "physical-address",
                "plain-text-version",
                "preference-center",
                "sending-subdomain",
                "signup-form-protection",
                "spam-checkers",
                "spam-trigger-words",
                "spf",
                "sunset-policy",
                "suppression-list",
                "throttling",
                "to-buy-an-email-list",
                "unsubscribe-link",
                "warmup-service"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One randomly selected concept.",
            "headers": {
              "API-Version": {
                "description": "Major version of the API that served the response.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "1"
                  ]
                }
              },
              "RateLimit-Limit": {
                "description": "Advisory request budget per window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Remaining": {
                "description": "Advisory requests remaining in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Policy": {
                "description": "The declared policy, e.g. \"60;w=60\" (60 requests per 60s).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Concept"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/UnexpectedError"
          }
        }
      }
    },
    "/{slug}.md": {
      "get": {
        "operationId": "getConceptMarkdown",
        "tags": [
          "concepts"
        ],
        "summary": "Get one concept as markdown",
        "description": "The full longform answer as raw markdown: the question as an H1, the verdict, the excerpt, the reasoning, and canonical links. The best representation for quoting or grounding.",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "description": "Slug of the concept.",
            "schema": {
              "type": "string",
              "enum": [
                "2048-bit-dkim",
                "accessible-emails",
                "amp-for-email",
                "bimi",
                "bounce-and-complaint-rates",
                "bulk-sender-requirements",
                "click-tracking",
                "custom-return-path",
                "custom-tracking-domain",
                "dedicated-ip",
                "dkim",
                "dkim-rotation",
                "dmarc",
                "dmarc-p-reject",
                "dmarc-reports",
                "domain-reputation",
                "domain-warmup",
                "double-opt-in",
                "email-verification",
                "gmail-postmaster-tools",
                "idempotency-keys",
                "ip-reputation",
                "my-own-mail-server",
                "no-reply-address",
                "one-click-unsubscribe",
                "open-tracking",
                "physical-address",
                "plain-text-version",
                "preference-center",
                "sending-subdomain",
                "signup-form-protection",
                "spam-checkers",
                "spam-trigger-words",
                "spf",
                "sunset-policy",
                "suppression-list",
                "throttling",
                "to-buy-an-email-list",
                "unsubscribe-link",
                "warmup-service"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The longform answer.",
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "description": "Unknown slug. Send Accept: text/markdown to receive a markdown body pointing at the site index.",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              },
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "responses": {
      "TooManyRequests": {
        "description": "Throttled by the platform. Honor Retry-After and back off.",
        "headers": {
          "Retry-After": {
            "description": "Seconds to wait before retrying.",
            "schema": {
              "type": "integer"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "UnexpectedError": {
        "description": "Any other error, including 404 for unknown /api/* paths. Always the Error schema.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    },
    "schemas": {
      "Concept": {
        "type": "object",
        "description": "One answered question. The verdict is the blunt answer; the qualifier carries the nuance—quote them together.",
        "additionalProperties": false,
        "required": [
          "slug",
          "question",
          "questionFull",
          "answer",
          "verdict",
          "qualifier",
          "lean",
          "excerpt",
          "learnMoreUrl",
          "url",
          "markdownUrl"
        ],
        "properties": {
          "slug": {
            "type": "string",
            "description": "URL-safe identifier of the concept.",
            "examples": [
              "dedicated-ip"
            ]
          },
          "question": {
            "type": "string",
            "description": "The question fragment, completing \"Do I need …?\"",
            "examples": [
              "a dedicated IP"
            ]
          },
          "questionFull": {
            "type": "string",
            "description": "The full question.",
            "examples": [
              "Do I need a dedicated IP?"
            ]
          },
          "answer": {
            "type": "string",
            "enum": [
              "yes",
              "ideally",
              "no",
              "depends"
            ],
            "description": "Machine-friendly verdict value."
          },
          "verdict": {
            "type": "string",
            "enum": [
              "YES",
              "IDEALLY",
              "NO",
              "IT DEPENDS"
            ],
            "description": "Display form of the verdict."
          },
          "qualifier": {
            "type": [
              "string",
              "null"
            ],
            "description": "Nuance attached to the verdict, e.g. \"most likely no\". Null when the verdict stands alone."
          },
          "lean": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "yes",
              "no",
              null
            ],
            "description": "Which way a hedged verdict leans. Null when the qualifier is neutral or absent."
          },
          "excerpt": {
            "type": "string",
            "description": "One-to-two sentence summary of the reasoning."
          },
          "learnMoreUrl": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri",
            "description": "Deep-dive link (usually resend.com). Null when none exists."
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Canonical page for this answer."
          },
          "markdownUrl": {
            "type": "string",
            "format": "uri",
            "description": "The full longform answer as raw markdown."
          }
        }
      },
      "Error": {
        "type": "object",
        "description": "Structured error returned for unknown /api/* paths.",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message",
              "hint",
              "docs"
            ],
            "properties": {
              "code": {
                "type": "string",
                "examples": [
                  "not_found"
                ]
              },
              "message": {
                "type": "string"
              },
              "hint": {
                "type": "string",
                "description": "What to call instead."
              },
              "docs": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      }
    }
  }
}
