openapi: 3.1.0
info:
  title: POSnavigator API Catalog
  version: 1.0.0
  description: |-
    Public index of every machine-readable POSnavigator API contract. Fetch this
    document first. Each listed URL is itself an OpenAPI 3.1 YAML file and is the
    complete manual for that API: schemas, error codes, examples, permissions,
    and the happy path. There is no second, hand-maintained Markdown contract.

    # Which API to use

    - Comparing Hungarian payment offers for a merchant: `agent-platform.yaml`
      (no API key). That is the public Agent Platform.
    - Refreshing provider knowledge, playbooks, proposals, bank export, or
      data-freshness timestamps: `provider-research.yaml` (admin `X-Api-Key`).
    - Editing a bank record, landing SEO, or device-landing copy: `banks.yaml`.
    - Products and device-sales configurations: `products.yaml`.
    - Preset search configs (wizard, hero, Arena, industry landings):
      `presetfilters.yaml`.
    - Running the same offer search as the wizard: `filters-offers.yaml`.
    - Embeddable mini-search widgets: `widgets.yaml` (admin key + widget scopes).
    - Two-bank comparison landings: `versus-landing-pages.yaml`.
    - Payment schemes, features, tips, devices, IT providers: `content-entities.yaml`.
    - Blog posts: `blogs.yaml`.
    - ÁSZF / privacy versions: `legal-documents.yaml` (reads are public).
    - Homepage hero funnel stats: `hero-entry-analytics.yaml`.
    - Agent discovery/API traffic stats: `agent-platform-metrics.yaml`.
    - Provider contacts, agreements, contracts: `provider-crm.yaml`.
    - Physical terminal orders for a bank: `device-orders.yaml`.
    - Internal kanban automation: `kanban.yaml` (separate `kb.` keys, not `pn_`).

    # Authentication

    These YAML files are public. The data operations they describe are not, except
    the Agent Platform and the legal GET endpoints.

    Most v1 APIs use `X-Api-Key: pn_...` created at `/user/api-keys`. Default keys
    include `bank:export`, `blog:read`, `blog:write`, `legal:write`,
    `presetfilter:read`, `presetfilter:write`, `versus-landing:read`,
    `versus-landing:write`, `widget:read`, `widget:write`, `agent-analytics:read`,
    and `hero-analytics:read`. Missing scopes return `403 INSUFFICIENT_PERMISSIONS`.
    Bank-scoped resources also require the key owner to be admin or listed on
    that bank; otherwise `403 FORBIDDEN`.

    Kanban uses a different key (`kb.<uuid>.<secret>`) in `Authorization: Bearer`
    or `X-Kanban-Api-Key`. A `pn_` key will not work there.

    # Response envelope (v1 X-Api-Key APIs)

    Success: `{ "success": true, "data": ... }`.
    Failure: `{ "success": false, "error": { "code", "message", "details"?, "retryAfter"? } }`.
    Branch on `error.code`. After a successful auth, responses carry
    `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`. A 429 also
    carries `Retry-After`. Default window: 100 requests per rolling hour per key.

    # Canonical host

    Use `https://posnavigator.eu`. Legacy `.hu` hosts redirect; authenticated
    writes should call `.eu` directly so the `X-Api-Key` header is not dropped.
servers:
  - url: https://posnavigator.eu
tags:
  - name: Discovery
security: []
paths:
  /openapi/catalog.yaml:
    get:
      operationId: getOpenApiCatalog
      tags: [Discovery]
      security: []
      summary: Public index of every OpenAPI contract
      description: |-
        This document. Public: no API key, no rate limit. Fetch it first, pick the
        spec that matches the job, then GET that YAML and treat it as the complete
        manual. Linked from `/.well-known/agents.json` as `openapi_catalog`.
      responses:
        '200':
          description: OpenAPI YAML catalog
          content:
            application/yaml:
              schema:
                type: string
              example: 'openapi: 3.1.0'
  /openapi/agent-platform.yaml:
    get:
      operationId: getAgentPlatformOpenApi
      tags: [Discovery]
      summary: Public Agent Platform OpenAPI
      description: |-
        Public offer comparison and submit API. No API key. Use this for merchant
        ranking questions; do not rank from blog posts when this API is available.
      responses:
        '200':
          description: OpenAPI YAML
          content:
            application/yaml:
              schema:
                type: string
  /openapi/provider-research.yaml:
    get:
      operationId: getProviderResearchOpenApiRef
      tags: [Discovery]
      summary: Provider research, export, and freshness OpenAPI
      description: |-
        Admin-key knowledge store for playbooks, research runs, change proposals,
        lessons, canonical bank export, and data-freshness fields. The key owner
        must be an admin. Bank-scoped keys can read an export but cannot research.
      responses:
        '200':
          description: OpenAPI YAML
          content:
            application/yaml:
              schema:
                type: string
  /openapi/banks.yaml:
    get:
      operationId: getBanksOpenApi
      tags: [Discovery]
      summary: Bank object OpenAPI
      description: |-
        List banks the key can see, then GET or PATCH a single bank including
        landing SEO, FAQ, and device-landing fields. Admin-only fields reject
        non-admin keys with 403. Export and freshness live on provider-research.
      responses:
        '200':
          description: OpenAPI YAML
          content:
            application/yaml:
              schema:
                type: string
  /openapi/products.yaml:
    get:
      operationId: getProductsOpenApi
      tags: [Discovery]
      summary: Product object OpenAPI
      description: |-
        List products for a bank, then read, create, patch, or delete a product.
        Device fulfillment configurations have a dedicated sub-resource. Writes
        and device-configuration updates are admin-only.
      responses:
        '200':
          description: OpenAPI YAML
          content:
            application/yaml:
              schema:
                type: string
  /openapi/presetfilters.yaml:
    get:
      operationId: getPresetFiltersOpenApi
      tags: [Discovery]
      summary: PresetFilters OpenAPI
      description: |-
        CRUD for reusable offer-search presets. `filters` is a URL query string,
        not JSON, using the same keys as POST /api/v1/offers. Requires
        presetfilter:read or presetfilter:write on the key.
      responses:
        '200':
          description: OpenAPI YAML
          content:
            application/yaml:
              schema:
                type: string
  /openapi/filters-offers.yaml:
    get:
      operationId: getFiltersOffersOpenApi
      tags: [Discovery]
      summary: Filters and offers OpenAPI
      description: |-
        GET filter option IDs, then POST the same search body the wizard uses.
        Returned `sumprice` is a 48-month TCO total, not a monthly rate, from the
        same price engine as the public UI.
      responses:
        '200':
          description: OpenAPI YAML
          content:
            application/yaml:
              schema:
                type: string
  /openapi/widgets.yaml:
    get:
      operationId: getWidgetsOpenApi
      tags: [Discovery]
      summary: Widget configuration OpenAPI
      description: |-
        Admin-only list, get, and PATCH of embeddable mini-search widgets. There
        is no POST create on v1. Requires widget:read / widget:write. Published
        PATCH rebuilds the public embed snapshot.
      responses:
        '200':
          description: OpenAPI YAML
          content:
            application/yaml:
              schema:
                type: string
  /openapi/versus-landing-pages.yaml:
    get:
      operationId: getVersusLandingPagesOpenApi
      tags: [Discovery]
      summary: Versus landing pages OpenAPI
      description: |-
        Two-bank comparison landings. Bank pair order is normalized; one pair can
        have only one page. PATCH merges translations but replaces comparisonBlocks
        wholesale. Requires versus-landing:read / versus-landing:write.
      responses:
        '200':
          description: OpenAPI YAML
          content:
            application/yaml:
              schema:
                type: string
  /openapi/content-entities.yaml:
    get:
      operationId: getContentEntitiesOpenApi
      tags: [Discovery]
      summary: Content entities OpenAPI
      description: |-
        Shared list/create/get/patch/delete for paymentschemes, features, tipps,
        devices, and itproviders. knowledgeBaseOnly and responseMode=names exist
        for dictionary-style reads.
      responses:
        '200':
          description: OpenAPI YAML
          content:
            application/yaml:
              schema:
                type: string
  /openapi/blogs.yaml:
    get:
      operationId: getBlogsOpenApi
      tags: [Discovery]
      summary: Blog OpenAPI
      description: |-
        List, create, get, and PATCH blog posts. Creates always start as DRAFT
        in the draft category. HTML fragments go in excerptHtml and contentHtml.
        Call https://posnavigator.eu directly for authenticated writes.
      responses:
        '200':
          description: OpenAPI YAML
          content:
            application/yaml:
              schema:
                type: string
  /openapi/legal-documents.yaml:
    get:
      operationId: getLegalDocumentsOpenApi
      tags: [Discovery]
      summary: Legal documents OpenAPI
      description: |-
        Public GET of current or archived GTC and privacy HTML. POST /api/legal/update
        creates a new version and requires X-Api-Key plus legal:write. Versions
        are never deleted.
      responses:
        '200':
          description: OpenAPI YAML
          content:
            application/yaml:
              schema:
                type: string
  /openapi/hero-entry-analytics.yaml:
    get:
      operationId: getHeroEntryAnalyticsOpenApi
      tags: [Discovery]
      summary: Hero entry analytics OpenAPI
      description: |-
        Admin-only funnel aggregates from hero_entry_analytics_events. Requires
        hero-analytics:read. Not a GA4 export. Max range 90 days.
      responses:
        '200':
          description: OpenAPI YAML
          content:
            application/yaml:
              schema:
                type: string
  /openapi/agent-platform-metrics.yaml:
    get:
      operationId: getAgentPlatformMetricsOpenApi
      tags: [Discovery]
      summary: Agent platform metrics OpenAPI
      description: |-
        Admin-only traffic aggregates for discovery, schema, recommend, and the
        rest of /api/agent. Requires agent-analytics:read. discovery events are
        crawls, not proof of LLM use.
      responses:
        '200':
          description: OpenAPI YAML
          content:
            application/yaml:
              schema:
                type: string
  /openapi/provider-crm.yaml:
    get:
      operationId: getProviderCrmOpenApi
      tags: [Discovery]
      summary: Provider CRM OpenAPI
      description: |-
        Bank-scoped mini-CRM: contacts, agreements, contracts, CRM fields, and an
        append-only event log. Admin sees every bank; others only banks in their
        banks array. GET /api/v1/banks includes CRM summary columns.
      responses:
        '200':
          description: OpenAPI YAML
          content:
            application/yaml:
              schema:
                type: string
  /openapi/device-orders.yaml:
    get:
      operationId: getDeviceOrdersOpenApi
      tags: [Discovery]
      summary: Device orders OpenAPI
      description: |-
        List and inspect physical terminal orders for a bank, then POST a
        discriminated action. Requires device_order:read and/or device_order:write.
        Those scopes are not on a default newly created key; grant them in admin.
      responses:
        '200':
          description: OpenAPI YAML
          content:
            application/yaml:
              schema:
                type: string
  /openapi/kanban.yaml:
    get:
      operationId: getKanbanOpenApi
      tags: [Discovery]
      summary: Kanban machine OpenAPI
      description: |-
        Automated kanban board for scripts and agents. Uses kb. keys via
        Authorization Bearer or X-Kanban-Api-Key, not X-Api-Key. Own-task writes
        only; others are read and comment.
      responses:
        '200':
          description: OpenAPI YAML
          content:
            application/yaml:
              schema:
                type: string
