{
  "openapi": "3.1.0",
  "info": {
    "title": "vCard QR Code Generator API",
    "version": "2026-05-21",
    "description": "Public API for AI agents and developers working with vCard contact payloads and vCard QR Code Generator product metadata."
  },
  "servers": [
    {
      "url": "https://vcardqrcodegenerator.com",
      "description": "Cloudflare Worker API"
    }
  ],
  "paths": {
    "/v1/health": {
      "get": {
        "operationId": "getHealth",
        "summary": "Check API availability",
        "responses": {
          "200": {
            "description": "API is reachable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Health"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/health": {
      "get": {
        "operationId": "getHealthApiAlias",
        "summary": "Check API availability through the /api alias",
        "responses": {
          "200": {
            "description": "API is reachable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Health"
                }
              }
            }
          }
        }
      }
    },
    "/v1/product": {
      "get": {
        "operationId": "getProductContext",
        "summary": "Get product and integration metadata",
        "responses": {
          "200": {
            "description": "Product metadata for AI agents and developers",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProductContext"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/product": {
      "get": {
        "operationId": "getProductContextApiAlias",
        "summary": "Get product and integration metadata through the /api alias",
        "responses": {
          "200": {
            "description": "Product metadata for AI agents and developers",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProductContext"
                }
              }
            }
          }
        }
      }
    },
    "/v1/vcard": {
      "post": {
        "operationId": "createVCardPayload",
        "summary": "Create a vCard QR payload",
        "description": "Returns standard vCard text suitable for QR encoding. The free website generator keeps QR rendering client-side for privacy.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VCardRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "vCard payload created",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "Idempotency-Key": {
                "$ref": "#/components/headers/IdempotencyKey"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VCardResponse"
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid input",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "Method not allowed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/vcard": {
      "post": {
        "operationId": "createVCardPayloadApiAlias",
        "summary": "Create a vCard QR payload through the /api alias",
        "description": "Returns standard vCard text suitable for QR encoding. Errors are always structured JSON with error.code, message, hint, docsUrl, and status.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VCardRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "vCard payload created",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "Idempotency-Key": {
                "$ref": "#/components/headers/IdempotencyKey"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VCardResponse"
                }
              }
            }
          },
          "400": {
            "description": "Structured JSON error response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Route or resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "Method not allowed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit guidance for future protected endpoints",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait before retrying."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/templates": {
      "get": {
        "operationId": "listVCardTemplates",
        "summary": "List vCard QR templates with cursor pagination",
        "description": "Returns public template metadata using a cursor pagination pattern for agent compatibility.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated template list",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TemplateListResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/templates": {
      "get": {
        "operationId": "listVCardTemplatesApiAlias",
        "summary": "List vCard QR templates through the /api alias",
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated template list",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TemplateListResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/jobs/vcard": {
      "post": {
        "operationId": "createVCardJob",
        "summary": "Create an async vCard payload job",
        "description": "Demonstrates the async job pattern for agent workflows. The current vCard payload job completes immediately because vCard creation is deterministic and lightweight.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VCardRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Job accepted",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string",
                  "format": "uri"
                },
                "description": "URL for polling job status."
              },
              "Idempotency-Key": {
                "$ref": "#/components/headers/IdempotencyKey"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/jobs/vcard": {
      "post": {
        "operationId": "createVCardJobApiAlias",
        "summary": "Create an async vCard payload job through the /api alias",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VCardRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Job accepted",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string",
                  "format": "uri"
                },
                "description": "URL for polling job status."
              },
              "Idempotency-Key": {
                "$ref": "#/components/headers/IdempotencyKey"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            }
          }
        }
      }
    },
    "/v1/jobs/{jobId}": {
      "get": {
        "operationId": "getJob",
        "summary": "Get async job status",
        "parameters": [
          {
            "$ref": "#/components/parameters/JobId"
          }
        ],
        "responses": {
          "200": {
            "description": "Job status",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/jobs/{jobId}": {
      "get": {
        "operationId": "getJobApiAlias",
        "summary": "Get async job status through the /api alias",
        "parameters": [
          {
            "$ref": "#/components/parameters/JobId"
          }
        ],
        "responses": {
          "200": {
            "description": "Job status",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            }
          }
        }
      }
    },
    "/v1/stream": {
      "get": {
        "operationId": "streamProgress",
        "summary": "Stream API progress events",
        "description": "Returns Server-Sent Events for agent workflows that need progress feedback. Current public operations are short, so this endpoint documents the streaming contract agents can rely on for longer-running future jobs.",
        "parameters": [
          {
            "name": "operation",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "default": "create_vcard_payload"
            },
            "description": "Operation name to stream progress for."
          }
        ],
        "responses": {
          "200": {
            "description": "SSE progress stream",
            "content": {
              "text/event-stream": {
                "schema": {
                  "type": "string",
                  "example": "event: progress\ndata: {\"step\":\"validate\",\"percent\":25}\n\n"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/stream": {
      "get": {
        "operationId": "streamProgressApiAlias",
        "summary": "Stream API progress events through the /api alias",
        "responses": {
          "200": {
            "description": "SSE progress stream",
            "content": {
              "text/event-stream": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "parameters": {
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": false,
        "schema": {
          "type": "string",
          "maxLength": 255
        },
        "description": "Optional retry key. The vCard payload endpoint is deterministic and echoes this header so agents can safely correlate retries."
      },
      "Limit": {
        "name": "limit",
        "in": "query",
        "required": false,
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 25,
          "default": 2
        },
        "description": "Maximum number of records to return."
      },
      "Cursor": {
        "name": "cursor",
        "in": "query",
        "required": false,
        "schema": {
          "type": "string"
        },
        "description": "Opaque cursor from the previous response pagination.next_cursor value."
      },
      "JobId": {
        "name": "jobId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "Job identifier returned by the async job creation endpoint."
      }
    },
    "headers": {
      "RateLimitLimit": {
        "schema": {
          "type": "integer",
          "example": 60
        },
        "description": "Maximum number of requests in the current window."
      },
      "RateLimitRemaining": {
        "schema": {
          "type": "integer",
          "example": 59
        },
        "description": "Requests remaining in the current window."
      },
      "RateLimitReset": {
        "schema": {
          "type": "integer",
          "example": 60
        },
        "description": "Seconds until the rate-limit window resets."
      },
      "IdempotencyKey": {
        "schema": {
          "type": "string"
        },
        "description": "Echo of the request Idempotency-Key header when supplied."
      }
    },
    "schemas": {
      "Health": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "service": {
            "type": "string"
          },
          "version": {
            "type": "string"
          }
        },
        "required": [
          "ok",
          "service",
          "version"
        ]
      },
      "ProductContext": {
        "type": "object",
        "additionalProperties": true
      },
      "VCardRequest": {
        "type": "object",
        "properties": {
          "fullName": {
            "type": "string",
            "description": "Contact display name. Required."
          },
          "organization": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "phone": {
            "type": "string"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "website": {
            "type": "string",
            "format": "uri"
          },
          "address": {
            "type": "string"
          },
          "note": {
            "type": "string"
          }
        },
        "required": [
          "fullName"
        ]
      },
      "VCardResponse": {
        "type": "object",
        "properties": {
          "vcard": {
            "type": "string"
          },
          "qrPayload": {
            "type": "string"
          },
          "generatorUrl": {
            "type": "string",
            "format": "uri"
          },
          "privacyNote": {
            "type": "string"
          }
        },
        "required": [
          "vcard",
          "qrPayload",
          "generatorUrl",
          "privacyNote"
        ]
      },
      "Template": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "useCase": {
            "type": "string"
          },
          "requiredFields": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "optionalFields": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "id",
          "name",
          "useCase",
          "requiredFields",
          "optionalFields"
        ]
      },
      "TemplateListResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Template"
            }
          },
          "pagination": {
            "type": "object",
            "properties": {
              "limit": {
                "type": "integer"
              },
              "cursor": {
                "type": "string"
              },
              "next_cursor": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "has_more": {
                "type": "boolean"
              }
            },
            "required": [
              "limit",
              "cursor",
              "next_cursor",
              "has_more"
            ]
          }
        },
        "required": [
          "data",
          "pagination"
        ]
      },
      "Job": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "object": {
            "type": "string",
            "enum": [
              "job"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "running",
              "succeeded",
              "failed"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "completed_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "links": {
            "type": "object",
            "properties": {
              "self": {
                "type": "string",
                "format": "uri"
              }
            },
            "required": [
              "self"
            ]
          },
          "result": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/VCardResponse"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "id",
          "object",
          "status",
          "created_at",
          "completed_at",
          "links",
          "result"
        ]
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              },
              "hint": {
                "type": "string"
              },
              "docsUrl": {
                "type": "string",
                "format": "uri"
              },
              "status": {
                "type": "integer"
              }
            },
            "required": [
              "code",
              "message",
              "hint",
              "docsUrl",
              "status"
            ]
          }
        },
        "required": [
          "error"
        ]
      }
    }
  }
}
