{
	"openapi": "3.1.0",
	"info": {
		"title": "Giltiq VAT Validation API",
		"version": "0.1.0",
		"description": "Multi-source EU VAT validation API for German SMEs doing cross-border B2B trade.\n\n**Key features:**\n- Real-time validation against VIES (EU Commission) and BZSt (German tax authority)\n- Automatic failover: if VIES is down, BZSt takes over — and vice versa\n- Qualified confirmation (§ 18e UStG) with company name, city, and ZIP matching\n- Intelligent caching with per-field staleness tracking\n- Per-minute and per-month rate limiting with upgrade nudges\n\n**Authentication:**\nMost endpoints require an API key passed in the `X-Api-Key` header, or a JWT Bearer token\nfor dashboard endpoints. Free tier: 100 validations/month.\n\n**Base URL:** `https://api.giltiq.de`\n",
		"contact": {
			"name": "Giltiq Support",
			"email": "hello@giltiq.de",
			"url": "https://giltiq.de"
		},
		"license": {
			"name": "Proprietary",
			"url": "https://giltiq.de/terms"
		},
		"termsOfService": "https://giltiq.de/terms"
	},
	"x-agent-instructions": {
		"description": "Instructions for LLM agents and MCP clients integrating with the Giltiq API.",
		"authentication": {
			"method": "api_key",
			"header": "X-Api-Key",
			"format": "gq_live_<random>",
			"obtain": "POST /v1/register with your agent_id to receive an API key immediately."
		},
		"quickstart": [
			"1. POST /v1/register with { \"agent_id\": \"your-agent-id\" } to get an API key.",
			"2. GET /v1/validate/{vat_id} with X-Api-Key header to validate a VAT ID.",
			"3. For qualified confirmation (§ 18e UStG), add requester_vat_id, company_name, company_city, company_zip query params."
		],
		"rate_limits": {
			"free": "100 validations/month, 10 validations/minute",
			"starter": "1000 validations/month",
			"business": "10000 validations/month"
		},
		"error_handling": "All errors return JSON with an `error.code` field. Retry on 503, fail fast on 400/401/429.",
		"caching": "Valid VAT IDs are cached for 24 hours. Pass `force_live=true` to bypass the cache."
	},
	"servers": [
		{
			"url": "https://api.giltiq.de",
			"description": "Production"
		}
	],
	"components": {
		"securitySchemes": {
			"ApiKeyAuth": {
				"type": "apiKey",
				"in": "header",
				"name": "X-Api-Key",
				"description": "API key in the format `gq_live_<random>`. Obtain one via POST /v1/register or the dashboard."
			},
			"BearerAuth": {
				"type": "http",
				"scheme": "bearer",
				"bearerFormat": "JWT",
				"description": "JWT token obtained from POST /v1/auth/login. Required for dashboard endpoints (API key management)."
			}
		},
		"headers": {
			"X-Giltiq-Usage": {
				"description": "Current usage count for the billing period in the format `used/limit` (e.g. `23/100`).",
				"schema": {
					"type": "string",
					"example": "23/100"
				}
			},
			"X-Giltiq-Upgrade": {
				"description": "Present when the caller is approaching or has exceeded the free tier limit. Contains a human-readable upgrade message.",
				"schema": {
					"type": "string",
					"example": "You have used 90% of your monthly quota. Upgrade at https://giltiq.de/pricing"
				}
			}
		},
		"schemas": {
			"Error": {
				"type": "object",
				"required": [
					"error"
				],
				"properties": {
					"error": {
						"type": "object",
						"required": [
							"code",
							"message"
						],
						"properties": {
							"code": {
								"type": "string",
								"example": "INVALID_VAT_ID"
							},
							"message": {
								"type": "string",
								"example": "The VAT ID format is invalid."
							},
							"request_id": {
								"type": "string",
								"example": "req_01HZ9X2Y3Z4A5B6C7D8E9F0G",
								"description": "Unique request identifier for debugging."
							}
						}
					}
				}
			},
			"ValidationResult": {
				"type": "object",
				"required": [
					"valid",
					"vat_id",
					"country_code",
					"vat_number",
					"source",
					"request_id",
					"requested_at"
				],
				"properties": {
					"valid": {
						"type": "boolean",
						"description": "Whether the VAT ID is registered and active.",
						"example": true
					},
					"vat_id": {
						"type": "string",
						"description": "The normalized VAT ID that was validated.",
						"example": "DE811575812"
					},
					"country_code": {
						"type": "string",
						"description": "ISO 3166-1 alpha-2 country code.",
						"example": "DE"
					},
					"vat_number": {
						"type": "string",
						"description": "The VAT number without the country code prefix.",
						"example": "811575812"
					},
					"company_name": {
						"type": [
							"string",
							"null"
						],
						"description": "Registered company name, if available from the validation source.",
						"example": "Bundeszentralamt für Steuern"
					},
					"company_address": {
						"type": [
							"string",
							"null"
						],
						"description": "Registered company address, if available.",
						"example": "An der Küppe 1, 53225 Bonn"
					},
					"source": {
						"type": "string",
						"enum": [
							"vies",
							"bzst",
							"cache"
						],
						"description": "Which validation source was used.",
						"example": "vies"
					},
					"source_timestamp": {
						"type": [
							"string",
							"null"
						],
						"format": "date-time",
						"description": "When the validation source last confirmed the result."
					},
					"cache": {
						"type": "boolean",
						"description": "Whether this result was served from the cache.",
						"example": false
					},
					"qualified_confirmation": {
						"type": [
							"object",
							"null"
						],
						"description": "Result of qualified confirmation (§ 18e UStG), only returned when requester_vat_id and company details are provided.",
						"properties": {
							"name_match": {
								"type": "string",
								"enum": [
									"A",
									"B",
									"C",
									"D"
								],
								"description": "A=match, B=no match, C=not checked, D=not provided by source."
							},
							"city_match": {
								"type": "string",
								"enum": [
									"A",
									"B",
									"C",
									"D"
								]
							},
							"zip_match": {
								"type": "string",
								"enum": [
									"A",
									"B",
									"C",
									"D"
								]
							},
							"confirmation_number": {
								"type": [
									"string",
									"null"
								],
								"description": "Official BZSt confirmation number for this check.",
								"example": "DE20230615123456"
							}
						}
					},
					"request_id": {
						"type": "string",
						"description": "Unique identifier for this request, for debugging and support.",
						"example": "req_01HZ9X2Y3Z4A5B6C7D8E9F0G"
					},
					"requested_at": {
						"type": "string",
						"format": "date-time",
						"description": "ISO 8601 timestamp of when the request was made."
					}
				}
			}
		}
	},
	"tags": [
		{
			"name": "Validation",
			"description": "Core VAT ID validation endpoints."
		},
		{
			"name": "Account",
			"description": "Usage statistics and account management."
		},
		{
			"name": "Auth",
			"description": "User registration, login, and API key management."
		},
		{
			"name": "System",
			"description": "Health probes and upstream source status."
		}
	],
	"paths": {
		"/health": {
			"get": {
				"summary": "Health check",
				"description": "Returns the current health status of the API server. No authentication required. Use this for uptime monitoring and liveness probes.",
				"operationId": "getHealth",
				"tags": [
					"System"
				],
				"responses": {
					"200": {
						"description": "API is operational",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"status": {
											"type": "string",
											"example": "ok"
										},
										"timestamp": {
											"type": "string",
											"format": "date-time"
										},
										"version": {
											"type": "string",
											"example": "0.1.0"
										}
									}
								},
								"example": {
									"status": "ok",
									"timestamp": "2026-03-25T10:00:00.000Z",
									"version": "0.1.0"
								}
							}
						}
					}
				}
			}
		},
		"/v1/status": {
			"get": {
				"summary": "Validation source status",
				"description": "Returns the current availability of the upstream validation sources (VIES and BZSt). Use this to check whether degraded service should be expected before making validation calls.",
				"operationId": "getStatus",
				"tags": [
					"System"
				],
				"responses": {
					"200": {
						"description": "Source status report (may be degraded if one source is unavailable)",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"sources": {
											"type": "object",
											"properties": {
												"vies": {
													"type": "object",
													"properties": {
														"status": {
															"type": "string",
															"enum": [
																"operational",
																"degraded",
																"unavailable"
															],
															"description": "Current status of the VIES upstream source."
														},
														"latency_ms": {
															"type": [
																"integer",
																"null"
															],
															"description": "Last measured latency in milliseconds. Null if the source has not been probed yet or is unavailable."
														},
														"last_checked": {
															"type": "string",
															"format": "date-time",
															"description": "ISO 8601 timestamp of the last health probe for this source."
														}
													}
												},
												"bzst": {
													"type": "object",
													"properties": {
														"status": {
															"type": "string",
															"enum": [
																"operational",
																"degraded",
																"unavailable"
															],
															"description": "Current status of the BZSt upstream source."
														},
														"latency_ms": {
															"type": [
																"integer",
																"null"
															],
															"description": "Last measured latency in milliseconds. Null if the source has not been probed yet or is unavailable."
														},
														"last_checked": {
															"type": "string",
															"format": "date-time",
															"description": "ISO 8601 timestamp of the last health probe for this source."
														}
													}
												},
												"cache": {
													"type": "object",
													"properties": {
														"status": {
															"type": "string",
															"enum": [
																"operational",
																"degraded",
																"unavailable"
															],
															"description": "Current status of the Redis cache."
														}
													}
												}
											}
										},
										"active_source": {
											"type": "string",
											"enum": [
												"vies",
												"bzst"
											],
											"description": "The upstream source currently being used for validation requests."
										},
										"failover_active": {
											"type": "boolean",
											"description": "True when the primary source (BZSt) is unavailable and VIES is serving as fallback, or vice versa."
										}
									}
								},
								"examples": {
									"operational": {
										"summary": "Both sources operational",
										"value": {
											"sources": {
												"vies": {
													"status": "operational",
													"latency_ms": 540,
													"last_checked": "2026-03-25T10:00:00.000Z"
												},
												"bzst": {
													"status": "operational",
													"latency_ms": 312,
													"last_checked": "2026-03-25T10:00:00.000Z"
												},
												"cache": {
													"status": "operational"
												}
											},
											"active_source": "bzst",
											"failover_active": false
										}
									},
									"degraded": {
										"summary": "BZSt unavailable, VIES serving as fallback",
										"value": {
											"sources": {
												"vies": {
													"status": "operational",
													"latency_ms": 540,
													"last_checked": "2026-03-25T10:00:00.000Z"
												},
												"bzst": {
													"status": "unavailable",
													"latency_ms": null,
													"last_checked": "2026-03-25T10:00:00.000Z"
												},
												"cache": {
													"status": "operational"
												}
											},
											"active_source": "vies",
											"failover_active": true
										}
									}
								}
							}
						}
					}
				}
			}
		},
		"/v1/validate/{vat_id}": {
			"get": {
				"summary": "Validate a VAT ID",
				"description": "Validates an EU VAT ID against VIES (EU Commission) and/or BZSt (German tax authority).\n\n**How it works:**\n1. The VAT ID format is checked against the per-country regex for all 27 EU member states.\n2. If a valid cached result exists (< 24h old), it is returned immediately with `cache: true`.\n3. Otherwise, VIES is queried. If VIES is unavailable, BZSt is used as fallback (for DE VAT IDs).\n4. The result is cached for future requests.\n\n**Qualified confirmation (§ 18e UStG):**\nPass `requester_vat_id`, `company_name`, `company_city`, and/or `company_zip` to request\na formal BZSt qualified confirmation. This produces a `qualified_confirmation` object with\nmatch codes (A=match, B=no match) and an official BZSt confirmation number.\nQualified confirmation is only available for **German VAT IDs** (DE prefix) and requires a paid plan.\n\n**Anonymous access:**\nWithout an API key, you get 10 lifetime free validations (VIES only, no qualified confirmation).\n",
				"operationId": "validateVatId",
				"tags": [
					"Validation"
				],
				"security": [
					{
						"ApiKeyAuth": []
					},
					{}
				],
				"parameters": [
					{
						"name": "vat_id",
						"in": "path",
						"required": true,
						"description": "The EU VAT ID to validate. Can be provided with or without the country code prefix (e.g. `DE811575812` or `811575812` for German IDs). Spaces and hyphens are stripped automatically.",
						"schema": {
							"type": "string",
							"example": "DE811575812"
						}
					},
					{
						"name": "requester_vat_id",
						"in": "query",
						"required": false,
						"description": "Your own VAT ID (as the requester). Required for qualified confirmation (§ 18e UStG). Must be a valid DE VAT ID.",
						"schema": {
							"type": "string",
							"example": "DE123456789"
						}
					},
					{
						"name": "company_name",
						"in": "query",
						"required": false,
						"description": "Company name to match against the BZSt registry for qualified confirmation.",
						"schema": {
							"type": "string",
							"example": "Acme GmbH"
						}
					},
					{
						"name": "company_city",
						"in": "query",
						"required": false,
						"description": "Company city to match against the BZSt registry for qualified confirmation.",
						"schema": {
							"type": "string",
							"example": "Berlin"
						}
					},
					{
						"name": "company_zip",
						"in": "query",
						"required": false,
						"description": "Company postal code to match against the BZSt registry for qualified confirmation.",
						"schema": {
							"type": "string",
							"example": "10115"
						}
					},
					{
						"name": "force_live",
						"in": "query",
						"required": false,
						"description": "Set to `true` to bypass the cache and always query the validation source in real time. Use sparingly — this counts against your rate limit and increases latency.",
						"schema": {
							"type": "string",
							"enum": [
								"true",
								"false",
								"1",
								"0"
							],
							"example": "false"
						}
					}
				],
				"responses": {
					"200": {
						"description": "Validation completed successfully",
						"headers": {
							"X-Giltiq-Usage": {
								"$ref": "#/components/headers/X-Giltiq-Usage"
							},
							"X-Giltiq-Upgrade": {
								"$ref": "#/components/headers/X-Giltiq-Upgrade"
							}
						},
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ValidationResult"
								},
								"examples": {
									"valid_basic": {
										"summary": "Valid German VAT ID (basic lookup)",
										"value": {
											"valid": true,
											"vat_id": "DE811575812",
											"country_code": "DE",
											"vat_number": "811575812",
											"company_name": "Bundeszentralamt für Steuern",
											"company_address": "An der Küppe 1, 53225 Bonn",
											"source": "vies",
											"source_timestamp": "2026-03-25T09:58:12.000Z",
											"cache": false,
											"qualified_confirmation": null,
											"request_id": "req_01HZ9X2Y3Z4A5B6C7D8E9F0G",
											"requested_at": "2026-03-25T10:00:00.000Z"
										}
									},
									"valid_qualified": {
										"summary": "Valid German VAT ID with qualified confirmation",
										"value": {
											"valid": true,
											"vat_id": "DE811575812",
											"country_code": "DE",
											"vat_number": "811575812",
											"company_name": "Bundeszentralamt für Steuern",
											"company_address": "An der Küppe 1, 53225 Bonn",
											"source": "bzst",
											"source_timestamp": "2026-03-25T10:00:00.000Z",
											"cache": false,
											"qualified_confirmation": {
												"name_match": "A",
												"city_match": "A",
												"zip_match": "A",
												"confirmation_number": "DE20260325123456"
											},
											"request_id": "req_02HZ9X2Y3Z4A5B6C7D8E9F0G",
											"requested_at": "2026-03-25T10:00:00.000Z"
										}
									},
									"invalid": {
										"summary": "Invalid / inactive VAT ID",
										"value": {
											"valid": false,
											"vat_id": "DE000000000",
											"country_code": "DE",
											"vat_number": "000000000",
											"company_name": null,
											"company_address": null,
											"source": "vies",
											"source_timestamp": "2026-03-25T10:00:00.000Z",
											"cache": false,
											"qualified_confirmation": null,
											"request_id": "req_03HZ9X2Y3Z4A5B6C7D8E9F0G",
											"requested_at": "2026-03-25T10:00:00.000Z"
										}
									},
									"cached": {
										"summary": "Result served from cache",
										"value": {
											"valid": true,
											"vat_id": "FR12345678901",
											"country_code": "FR",
											"vat_number": "12345678901",
											"company_name": "Example SAS",
											"company_address": "1 Rue de la Paix, 75001 Paris",
											"source": "cache",
											"source_timestamp": "2026-03-24T08:00:00.000Z",
											"cache": true,
											"qualified_confirmation": null,
											"request_id": "req_04HZ9X2Y3Z4A5B6C7D8E9F0G",
											"requested_at": "2026-03-25T10:00:00.000Z"
										}
									}
								}
							}
						}
					},
					"400": {
						"description": "Invalid VAT ID format",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/Error"
								},
								"example": {
									"error": {
										"code": "INVALID_VAT_ID",
										"message": "The VAT ID 'INVALID' does not match any known EU VAT format.",
										"request_id": "req_01HZ9X2Y3Z4A5B6C7D8E9F0G"
									}
								}
							}
						}
					},
					"401": {
						"description": "Invalid or missing API key",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/Error"
								},
								"example": {
									"error": {
										"code": "UNAUTHORIZED",
										"message": "Invalid or missing API key."
									}
								}
							}
						}
					},
					"402": {
						"description": "Free tier limit exhausted — upgrade required",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/Error"
								},
								"example": {
									"error": {
										"code": "PAYMENT_REQUIRED",
										"message": "Your free tier limit has been exhausted. Upgrade at https://giltiq.de/pricing"
									}
								}
							}
						}
					},
					"429": {
						"description": "Rate limit exceeded",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/Error"
								},
								"example": {
									"error": {
										"code": "RATE_LIMIT_EXCEEDED",
										"message": "Monthly limit of 100 validations reached. Upgrade your plan."
									}
								}
							}
						}
					},
					"503": {
						"description": "All validation sources are temporarily unavailable",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/Error"
								},
								"example": {
									"error": {
										"code": "SOURCE_UNAVAILABLE",
										"message": "All validation sources are currently unavailable. Please retry.",
										"request_id": "req_01HZ9X2Y3Z4A5B6C7D8E9F0G"
									}
								}
							}
						}
					}
				}
			}
		},
		"/v1/usage": {
			"get": {
				"summary": "Get monthly usage",
				"description": "Returns the current monthly usage statistics for the authenticated API key, including the plan tier, request count, remaining quota, and billing period dates.",
				"operationId": "getUsage",
				"tags": [
					"Account"
				],
				"security": [
					{
						"ApiKeyAuth": []
					}
				],
				"responses": {
					"200": {
						"description": "Usage statistics for the current billing period",
						"headers": {
							"X-Giltiq-Usage": {
								"$ref": "#/components/headers/X-Giltiq-Usage"
							}
						},
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"plan": {
											"type": "string",
											"enum": [
												"free",
												"starter",
												"business"
											],
											"description": "The current plan tier.",
											"example": "free"
										},
										"period": {
											"type": "object",
											"properties": {
												"start": {
													"type": "string",
													"format": "date-time",
													"description": "Start of the current billing period (first day of month)."
												},
												"end": {
													"type": "string",
													"format": "date-time",
													"description": "Start of the next billing period."
												}
											}
										},
										"requests": {
											"type": "object",
											"properties": {
												"used": {
													"type": "integer",
													"description": "Requests made this period.",
													"example": 23
												},
												"remaining": {
													"type": "integer",
													"description": "Requests remaining this period.",
													"example": 77
												},
												"limit": {
													"type": "integer",
													"description": "Total request limit for this period.",
													"example": 100
												}
											}
										}
									}
								},
								"example": {
									"plan": "free",
									"period": {
										"start": "2026-03-01T00:00:00.000Z",
										"end": "2026-04-01T00:00:00.000Z"
									},
									"requests": {
										"used": 23,
										"remaining": 77,
										"limit": 100
									}
								}
							}
						}
					},
					"401": {
						"description": "Invalid or missing API key",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/Error"
								}
							}
						}
					}
				}
			}
		},
		"/v1/register": {
			"post": {
				"summary": "Passwordless agent registration",
				"description": "Lightweight registration endpoint designed for LLM agents and automated integrations.\nNo password or email verification required — an API key is returned immediately.\n\nPass either an `email` (optional, for upgrade notifications) or an `agent_id` to identify\nyour agent instance. At least one must be provided.\n\n**Free tier:** 100 validations/month. Upgrade by contacting hello@giltiq.de.\n",
				"operationId": "register",
				"tags": [
					"Auth"
				],
				"x-agent-hint": "Use this endpoint to onboard your agent. Store the returned api_key securely.",
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"type": "object",
								"properties": {
									"email": {
										"type": "string",
										"format": "email",
										"description": "Optional email address for upgrade notifications. Must not be a disposable address.",
										"example": "agent@acme.de"
									},
									"agent_id": {
										"type": "string",
										"description": "Unique identifier for your agent instance (e.g. deployment ID, process name).",
										"example": "claude-mcp-prod-01"
									}
								}
							},
							"examples": {
								"with_agent_id": {
									"summary": "Agent registration (no email)",
									"value": {
										"agent_id": "claude-mcp-prod-01"
									}
								},
								"with_email": {
									"summary": "Agent registration with optional email",
									"value": {
										"email": "agent@acme.de",
										"agent_id": "claude-mcp-prod-01"
									}
								}
							}
						}
					}
				},
				"responses": {
					"201": {
						"description": "Registration successful — API key returned immediately",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"required": [
										"api_key",
										"tier",
										"quota"
									],
									"properties": {
										"api_key": {
											"type": "string",
											"description": "Your API key. **Store this securely — it is shown only once.**",
											"example": "gq_live_abcdefghij1234567890ABCDEFGHIJ"
										},
										"tier": {
											"type": "string",
											"enum": [
												"free"
											],
											"description": "Current plan tier.",
											"example": "free"
										},
										"quota": {
											"type": "integer",
											"description": "Monthly validation quota.",
											"example": 100
										}
									}
								},
								"example": {
									"api_key": "gq_live_abcdefghij1234567890ABCDEFGHIJ",
									"tier": "free",
									"quota": 100
								}
							}
						}
					},
					"400": {
						"description": "Validation error or disposable email",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/Error"
								}
							}
						}
					},
					"409": {
						"description": "Email already registered",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/Error"
								}
							}
						}
					},
					"429": {
						"description": "Too many registrations from this IP",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/Error"
								}
							}
						}
					}
				}
			}
		},
		"/v1/auth/signup": {
			"post": {
				"summary": "Create a new account",
				"description": "Register a new user account with email and password.\n\n**Human flow:** A verification email is sent. The account is active after the user clicks the\nverification link at `GET /v1/auth/verify-email?token=...`.\n\n**Agent/bot flow:** If a non-browser User-Agent is detected, the account is automatically\nverified and a JWT token is returned immediately — no email step required.\nFor agents, prefer `POST /v1/register` (passwordless, returns API key directly).\n",
				"operationId": "signup",
				"tags": [
					"Auth"
				],
				"x-mcp-exclude": true,
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"type": "object",
								"required": [
									"email",
									"password"
								],
								"properties": {
									"email": {
										"type": "string",
										"format": "email",
										"description": "Must be a real (non-disposable) email address.",
										"example": "dev@acme.de"
									},
									"password": {
										"type": "string",
										"minLength": 8,
										"description": "Minimum 8 characters.",
										"example": "s3cur3pass"
									}
								}
							}
						}
					}
				},
				"responses": {
					"201": {
						"description": "Account created",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"message": {
											"type": "string"
										},
										"user_id": {
											"type": "string",
											"example": "user_01HZ9X2Y3Z"
										},
										"token": {
											"type": "string",
											"description": "JWT token (only returned for auto-verified agent signups)."
										},
										"auto_verified": {
											"type": "boolean",
											"description": "True when account was auto-verified (agent/bot UA)."
										}
									}
								},
								"examples": {
									"human": {
										"summary": "Human signup — email verification required",
										"value": {
											"message": "Account created. A verification email has been sent.",
											"user_id": "user_01HZ9X2Y3Z"
										}
									},
									"agent": {
										"summary": "Agent signup — auto-verified",
										"value": {
											"message": "Account created and verified automatically.",
											"user_id": "user_01HZ9X2Y3Z",
											"token": "eyJhbGciOiJFUzI1NiJ9...",
											"auto_verified": true
										}
									}
								}
							}
						}
					},
					"400": {
						"description": "Validation error or disposable email",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/Error"
								},
								"examples": {
									"disposable": {
										"summary": "Disposable email rejected",
										"value": {
											"error": {
												"code": "DISPOSABLE_EMAIL",
												"message": "Disposable email addresses are not allowed. Please use a real email address."
											}
										}
									}
								}
							}
						}
					},
					"409": {
						"description": "Email already registered",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/Error"
								},
								"example": {
									"error": {
										"code": "CONFLICT",
										"message": "Email already registered"
									}
								}
							}
						}
					},
					"429": {
						"description": "Too many signups from this IP (3 per 24h)",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/Error"
								}
							}
						}
					}
				}
			}
		},
		"/v1/auth/verify-email": {
			"get": {
				"summary": "Verify email address",
				"description": "Verifies a user's email address using the token sent in the signup verification email. The token expires after 24 hours. Once verified, the user can log in and create API keys.",
				"operationId": "verifyEmail",
				"tags": [
					"Auth"
				],
				"x-mcp-exclude": true,
				"parameters": [
					{
						"name": "token",
						"in": "query",
						"required": true,
						"description": "The verification token from the signup email (64 hex characters).",
						"schema": {
							"type": "string",
							"example": "a1b2c3d4e5f6..."
						}
					}
				],
				"responses": {
					"200": {
						"description": "Email verified successfully",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"message": {
											"type": "string",
											"example": "Email verified successfully"
										}
									}
								}
							}
						}
					},
					"400": {
						"description": "Invalid or expired token",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/Error"
								},
								"examples": {
									"invalid": {
										"summary": "Token not found",
										"value": {
											"error": {
												"code": "INVALID_TOKEN",
												"message": "Invalid verification token"
											}
										}
									},
									"expired": {
										"summary": "Token expired",
										"value": {
											"error": {
												"code": "TOKEN_EXPIRED",
												"message": "Verification token expired"
											}
										}
									}
								}
							}
						}
					}
				}
			}
		},
		"/v1/auth/login": {
			"post": {
				"summary": "Log in with email and password",
				"description": "Authenticates a user and returns a short-lived JWT token (24h). Use this token as a Bearer token for dashboard endpoints (API key management). For validation endpoints, use an API key instead.",
				"operationId": "login",
				"tags": [
					"Auth"
				],
				"x-mcp-exclude": true,
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"type": "object",
								"required": [
									"email",
									"password"
								],
								"properties": {
									"email": {
										"type": "string",
										"format": "email",
										"example": "dev@acme.de"
									},
									"password": {
										"type": "string",
										"example": "s3cur3pass"
									}
								}
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Login successful",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"token": {
											"type": "string",
											"description": "JWT token. Include as `Authorization: Bearer <token>` on dashboard endpoints.",
											"example": "eyJhbGciOiJFUzI1NiJ9..."
										},
										"expires_in": {
											"type": "integer",
											"description": "Token lifetime in seconds.",
											"example": 86400
										}
									}
								},
								"example": {
									"token": "eyJhbGciOiJFUzI1NiJ9...",
									"expires_in": 86400
								}
							}
						}
					},
					"401": {
						"description": "Invalid email or password",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/Error"
								},
								"example": {
									"error": {
										"code": "UNAUTHORIZED",
										"message": "Invalid email or password"
									}
								}
							}
						}
					}
				}
			}
		},
		"/v1/auth/api-keys": {
			"post": {
				"summary": "Create a new API key",
				"description": "Creates a new API key for the authenticated user. The full key is returned **only once** — store it securely. Subsequent requests will only show the key prefix.",
				"operationId": "createApiKey",
				"tags": [
					"Auth"
				],
				"x-mcp-exclude": true,
				"security": [
					{
						"BearerAuth": []
					}
				],
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"type": "object",
								"properties": {
									"name": {
										"type": "string",
										"maxLength": 100,
										"description": "Optional label for this key (e.g. 'Production', 'CI/CD').",
										"example": "Production"
									}
								}
							}
						}
					}
				},
				"responses": {
					"201": {
						"description": "API key created (key shown once)",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"id": {
											"type": "string",
											"description": "Key prefix (12 chars), used as ID.",
											"example": "gq_live_abcd"
										},
										"key": {
											"type": "string",
											"description": "Full API key. Store this now — it will not be shown again.",
											"example": "gq_live_abcdefghij1234567890ABCDEFGHIJ"
										},
										"prefix": {
											"type": "string",
											"example": "gq_live_abcd"
										},
										"name": {
											"type": "string",
											"example": "Production"
										},
										"created_at": {
											"type": "string",
											"format": "date-time"
										}
									}
								}
							}
						}
					},
					"401": {
						"description": "Missing or invalid JWT token",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/Error"
								}
							}
						}
					}
				}
			},
			"get": {
				"summary": "List API keys",
				"description": "Lists all API keys for the authenticated user, including revoked keys. The full key is never returned — only the prefix and metadata.",
				"operationId": "listApiKeys",
				"tags": [
					"Auth"
				],
				"x-mcp-exclude": true,
				"security": [
					{
						"BearerAuth": []
					}
				],
				"responses": {
					"200": {
						"description": "List of API keys",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"api_keys": {
											"type": "array",
											"items": {
												"type": "object",
												"properties": {
													"id": {
														"type": "string",
														"example": "gq_live_abcd"
													},
													"prefix": {
														"type": "string",
														"example": "gq_live_abcd"
													},
													"name": {
														"type": "string",
														"example": "Production"
													},
													"created_at": {
														"type": "string",
														"format": "date-time"
													},
													"revoked": {
														"type": "boolean",
														"description": "True if the key has been revoked and is no longer usable."
													}
												}
											}
										}
									}
								},
								"example": {
									"api_keys": [
										{
											"id": "gq_live_abcd",
											"prefix": "gq_live_abcd",
											"name": "Production",
											"created_at": "2026-03-01T00:00:00.000Z",
											"revoked": false
										}
									]
								}
							}
						}
					},
					"401": {
						"description": "Missing or invalid JWT token",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/Error"
								}
							}
						}
					}
				}
			}
		},
		"/v1/auth/api-keys/{id}": {
			"delete": {
				"summary": "Revoke an API key",
				"description": "Revokes an API key by its prefix. Once revoked, the key can no longer be used for authentication. This action is irreversible.",
				"operationId": "revokeApiKey",
				"tags": [
					"Auth"
				],
				"x-mcp-exclude": true,
				"security": [
					{
						"BearerAuth": []
					}
				],
				"parameters": [
					{
						"name": "id",
						"in": "path",
						"required": true,
						"description": "The key prefix (first 12 characters of the key, returned when the key was created).",
						"schema": {
							"type": "string",
							"example": "gq_live_abcd"
						}
					}
				],
				"responses": {
					"200": {
						"description": "API key revoked",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"message": {
											"type": "string",
											"example": "API key revoked"
										}
									}
								}
							}
						}
					},
					"401": {
						"description": "Missing or invalid JWT token",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/Error"
								}
							}
						}
					},
					"404": {
						"description": "API key not found or does not belong to the authenticated user",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/Error"
								},
								"example": {
									"error": {
										"code": "NOT_FOUND",
										"message": "API key not found"
									}
								}
							}
						}
					}
				}
			}
		}
	}
}