{
	"openapi": "3.1.0",
	"info": {
		"title": "Griflan Content API",
		"summary": "Read-only JSON access to the case studies, articles, and services published on griflan.com.",
		"description": "Griflan is a creative agency for branding, website design, web development, and digital experiences.\n\nThis API exposes the same content the website renders, as static JSON documents generated at build time. It is public, read-only, and needs no authentication or API key. There are no rate limits beyond ordinary CDN fair use, and responses are cached at the edge.\n\nRelated machine-readable resources:\n\n- `https://griflan.com/llms.txt` — site overview written for AI agents\n- `https://griflan.com/sitemap.xml` — every indexable page\n- `https://griflan.com/developers` — human-readable index of these resources\n\nEvery page on griflan.com also has a Markdown representation. Request the canonical URL with `Accept: text/markdown`, or append `.md` to the path (`https://griflan.com/work/upshop.md`). Responses carry `Vary: Accept`.",
		"version": "1.0.0",
		"contact": {
			"name": "Griflan",
			"url": "https://griflan.com/contact"
		},
		"termsOfService": "https://griflan.com/"
	},
	"servers": [
		{
			"url": "https://griflan.com",
			"description": "Production"
		}
	],
	"tags": [
		{ "name": "discovery", "description": "Entry points and machine-readable site files." },
		{ "name": "work", "description": "Case studies." },
		{ "name": "blog", "description": "Articles." },
		{ "name": "services", "description": "Services offered by the agency." }
	],
	"paths": {
		"/api/index.json": {
			"get": {
				"tags": ["discovery"],
				"operationId": "getApiIndex",
				"summary": "API index",
				"description": "Entry point listing every resource in this API and the site's machine-readable files.",
				"responses": {
					"200": {
						"description": "The API index.",
						"content": {
							"application/json": {
								"schema": { "$ref": "#/components/schemas/ApiIndex" }
							}
						}
					}
				}
			}
		},
		"/api/work.json": {
			"get": {
				"tags": ["work"],
				"operationId": "listWork",
				"summary": "List case studies",
				"description": "Every published case study, without body copy.",
				"responses": {
					"200": {
						"description": "A collection of case studies.",
						"content": {
							"application/json": {
								"schema": { "$ref": "#/components/schemas/WorkCollection" }
							}
						}
					}
				}
			}
		},
		"/api/work/{slug}.json": {
			"get": {
				"tags": ["work"],
				"operationId": "getWork",
				"summary": "Get a case study",
				"description": "A single case study, including its body copy as plain text.",
				"parameters": [
					{
						"name": "slug",
						"in": "path",
						"required": true,
						"description": "Case study slug, e.g. `upshop`.",
						"schema": { "type": "string" },
						"example": "upshop"
					}
				],
				"responses": {
					"200": {
						"description": "The case study.",
						"content": {
							"application/json": {
								"schema": { "$ref": "#/components/schemas/WorkDetail" }
							}
						}
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					}
				}
			}
		},
		"/api/blog.json": {
			"get": {
				"tags": ["blog"],
				"operationId": "listPosts",
				"summary": "List articles",
				"responses": {
					"200": {
						"description": "A collection of articles.",
						"content": {
							"application/json": {
								"schema": { "$ref": "#/components/schemas/PostCollection" }
							}
						}
					}
				}
			}
		},
		"/api/blog/{slug}.json": {
			"get": {
				"tags": ["blog"],
				"operationId": "getPost",
				"summary": "Get an article",
				"parameters": [
					{
						"name": "slug",
						"in": "path",
						"required": true,
						"description": "Article slug.",
						"schema": { "type": "string" }
					}
				],
				"responses": {
					"200": {
						"description": "The article.",
						"content": {
							"application/json": {
								"schema": { "$ref": "#/components/schemas/Post" }
							}
						}
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					}
				}
			}
		},
		"/api/services.json": {
			"get": {
				"tags": ["services"],
				"operationId": "listServices",
				"summary": "List services",
				"responses": {
					"200": {
						"description": "A collection of services.",
						"content": {
							"application/json": {
								"schema": { "$ref": "#/components/schemas/ServiceCollection" }
							}
						}
					}
				}
			}
		},
		"/.well-known/api-catalog": {
			"get": {
				"tags": ["discovery"],
				"operationId": "getApiCatalog",
				"summary": "API catalog (RFC 9727)",
				"description": "Linkset naming this API and pointing at its specification, documentation and metadata. Also advertised from every response with `Link: rel=\"api-catalog\"`.",
				"responses": {
					"200": {
						"description": "An RFC 9264 Linkset with the RFC 9727 profile.",
						"content": {
							"application/linkset+json": { "schema": { "type": "object" } }
						}
					}
				}
			}
		},
		"/llms.txt": {
			"get": {
				"tags": ["discovery"],
				"operationId": "getLlmsTxt",
				"summary": "Site overview for AI agents",
				"responses": {
					"200": {
						"description": "Plain-text site overview.",
						"content": {
							"text/plain": { "schema": { "type": "string" } }
						}
					}
				}
			}
		},
		"/sitemap.xml": {
			"get": {
				"tags": ["discovery"],
				"operationId": "getSitemap",
				"summary": "Sitemap",
				"responses": {
					"200": {
						"description": "An XML sitemap of every indexable page.",
						"content": {
							"application/xml": { "schema": { "type": "string" } }
						}
					}
				}
			}
		}
	},
	"components": {
		"responses": {
			"NotFound": {
				"description": "No record with that slug. Every path under /api returns this document rather than an HTML page.",
				"content": {
					"application/json": {
						"schema": { "$ref": "#/components/schemas/Problem" }
					}
				}
			}
		},
		"schemas": {
			"Problem": {
				"type": "object",
				"description": "Error document, following the member names of RFC 9457 problem details with additional fields naming where to look next. Served as application/json.",
				"required": ["title", "status", "code", "detail"],
				"properties": {
					"type": {
						"type": "string",
						"format": "uri",
						"description": "URI identifying the problem type."
					},
					"title": { "type": "string", "example": "Not Found" },
					"status": { "type": "integer", "example": 404 },
					"code": {
						"type": "string",
						"description": "Stable machine-readable error code.",
						"example": "not_found"
					},
					"detail": {
						"type": "string",
						"description": "What went wrong, in one sentence."
					},
					"resolution": {
						"type": "string",
						"description": "How to get to a valid request from here."
					},
					"documentation_url": { "type": "string", "format": "uri" },
					"openapi_url": { "type": "string", "format": "uri" },
					"index_url": { "type": "string", "format": "uri" },
					"available_endpoints": {
						"type": "array",
						"description": "Every path this API serves, templated where a slug is required.",
						"items": { "type": "string" }
					}
				}
			},
			"Meta": {
				"type": "object",
				"description": "Provenance fields present on every document.",
				"required": ["version", "generatedAt"],
				"properties": {
					"version": {
						"type": "string",
						"description": "API version this document was produced by.",
						"example": "1.0.0"
					},
					"generatedAt": {
						"type": "string",
						"format": "date-time",
						"description": "When the site was last built."
					}
				}
			},
			"Taxonomy": {
				"type": "object",
				"required": ["slug", "title"],
				"properties": {
					"slug": { "type": "string" },
					"title": { "type": "string" }
				}
			},
			"ApiIndex": {
				"allOf": [
					{ "$ref": "#/components/schemas/Meta" },
					{
						"type": "object",
						"required": ["name", "url", "resources"],
						"properties": {
							"name": { "type": "string" },
							"description": { "type": "string" },
							"url": { "type": "string", "format": "uri" },
							"openapi": { "type": "string", "format": "uri" },
							"documentation": { "type": "string", "format": "uri" },
							"resources": {
								"type": "object",
								"description": "Absolute URLs of the collection endpoints.",
								"additionalProperties": { "type": "string", "format": "uri" }
							},
							"files": {
								"type": "object",
								"description": "Absolute URLs of the site's machine-readable files.",
								"additionalProperties": { "type": "string", "format": "uri" }
							}
						}
					}
				]
			},
			"Work": {
				"type": "object",
				"required": ["id", "slug", "title", "url"],
				"properties": {
					"id": { "type": "string" },
					"slug": { "type": "string", "example": "upshop" },
					"title": { "type": "string", "example": "Upshop" },
					"description": { "type": "string" },
					"year": { "type": ["string", "null"] },
					"clientUrl": {
						"type": ["string", "null"],
						"description": "The client's own website."
					},
					"industries": {
						"type": "array",
						"items": { "$ref": "#/components/schemas/Taxonomy" }
					},
					"services": {
						"type": "array",
						"items": { "$ref": "#/components/schemas/Taxonomy" }
					},
					"updatedAt": { "type": ["string", "null"], "format": "date-time" },
					"url": {
						"type": "string",
						"format": "uri",
						"description": "Canonical page for this case study."
					},
					"markdownUrl": { "type": "string", "format": "uri" },
					"apiUrl": { "type": "string", "format": "uri" }
				}
			},
			"WorkDetail": {
				"allOf": [
					{ "$ref": "#/components/schemas/Meta" },
					{ "$ref": "#/components/schemas/Work" },
					{
						"type": "object",
						"properties": {
							"body": {
								"type": "string",
								"description": "Case study copy, as plain text."
							}
						}
					}
				]
			},
			"WorkCollection": {
				"allOf": [
					{ "$ref": "#/components/schemas/Meta" },
					{
						"type": "object",
						"required": ["count", "items"],
						"properties": {
							"count": { "type": "integer" },
							"items": {
								"type": "array",
								"items": { "$ref": "#/components/schemas/Work" }
							}
						}
					}
				]
			},
			"Post": {
				"allOf": [
					{ "$ref": "#/components/schemas/Meta" },
					{
						"type": "object",
						"required": ["id", "slug", "title", "url"],
						"properties": {
							"id": { "type": "string" },
							"slug": { "type": "string" },
							"title": { "type": "string" },
							"excerpt": { "type": "string" },
							"categories": {
								"type": "array",
								"items": { "$ref": "#/components/schemas/Taxonomy" }
							},
							"publishedAt": { "type": ["string", "null"], "format": "date-time" },
							"updatedAt": { "type": ["string", "null"], "format": "date-time" },
							"url": { "type": "string", "format": "uri" },
							"markdownUrl": { "type": "string", "format": "uri" },
							"apiUrl": { "type": "string", "format": "uri" }
						}
					}
				]
			},
			"PostCollection": {
				"allOf": [
					{ "$ref": "#/components/schemas/Meta" },
					{
						"type": "object",
						"required": ["count", "items"],
						"properties": {
							"count": { "type": "integer" },
							"items": {
								"type": "array",
								"items": { "$ref": "#/components/schemas/Post" }
							}
						}
					}
				]
			},
			"Service": {
				"type": "object",
				"required": ["id", "slug", "title"],
				"properties": {
					"id": { "type": "string" },
					"slug": { "type": "string" },
					"title": { "type": "string" }
				}
			},
			"ServiceCollection": {
				"allOf": [
					{ "$ref": "#/components/schemas/Meta" },
					{
						"type": "object",
						"required": ["count", "items"],
						"properties": {
							"count": { "type": "integer" },
							"items": {
								"type": "array",
								"items": { "$ref": "#/components/schemas/Service" }
							}
						}
					}
				]
			}
		}
	}
}
