{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://developer.dukkan.one/schemas/dukkan.app.schema.json",
  "title": "dukkan.app.toml",
  "description": "Declarative configuration of a Dukkan app: identity, requested scopes, redirect URIs, webhook topics, URLs and dev settings.",
  "type": "object",
  "properties": {
    "config_version": {
      "type": "number",
      "const": 1,
      "description": "Schema revision of this file; always 1 today."
    },
    "app": {
      "type": "object",
      "properties": {
        "name": {
          "type": "string",
          "minLength": 1,
          "maxLength": 120,
          "description": "Display name in the developer portal."
        },
        "client_id": {
          "description": "OAuth client id from the portal; set by `dukkan app config pull`.",
          "type": "string",
          "minLength": 1
        },
        "handle": {
          "description": "Marketplace handle, when listed.",
          "type": "string",
          "pattern": "^[a-z0-9][a-z0-9-]{1,62}$"
        },
        "api_version": {
          "default": "v1",
          "description": "Platform API contract version.",
          "type": "string",
          "const": "v1"
        }
      },
      "required": [
        "name"
      ]
    },
    "auth": {
      "type": "object",
      "properties": {
        "scopes": {
          "minItems": 1,
          "type": "array",
          "items": {
            "type": "string",
            "enum": [
              "clients:read",
              "clients:write",
              "discounts:read",
              "fulfillments:write",
              "inventory:read",
              "inventory:write",
              "orders:create",
              "orders:read",
              "orders:write",
              "products:read",
              "refunds:write"
            ]
          },
          "description": "Scopes the merchant is asked to grant. clients:read and clients:write unlock customer contact PII and are DPA-gated: the portal accepts them only from developers who accepted the data processing agreement."
        },
        "redirect_uris": {
          "minItems": 1,
          "maxItems": 10,
          "type": "array",
          "items": {
            "type": "string",
            "format": "uri"
          },
          "description": "Exact callback URLs; https, or http on localhost."
        }
      },
      "required": [
        "scopes",
        "redirect_uris"
      ]
    },
    "webhooks": {
      "default": {
        "topics": []
      },
      "type": "object",
      "properties": {
        "topics": {
          "default": [],
          "description": "Topics the app subscribes to after install.",
          "type": "array",
          "items": {
            "type": "string",
            "enum": [
              "order.created",
              "order.status_changed",
              "order.paid",
              "product.created",
              "product.updated",
              "product.deleted",
              "inventory.movement_created",
              "fulfillment.requested",
              "fulfillment.created",
              "fulfillment.updated",
              "refund.created",
              "app.uninstalled"
            ]
          }
        }
      }
    },
    "urls": {
      "default": {
        "install_path": "/dukkan/install",
        "callback_path": "/dukkan/callback",
        "webhook_path": "/dukkan/webhooks"
      },
      "type": "object",
      "properties": {
        "app_url": {
          "description": "Public origin of the deployed app.",
          "type": "string",
          "format": "uri"
        },
        "install_path": {
          "default": "/dukkan/install",
          "type": "string",
          "pattern": "^\\/[A-Za-z0-9/_-]*$"
        },
        "callback_path": {
          "default": "/dukkan/callback",
          "type": "string",
          "pattern": "^\\/[A-Za-z0-9/_-]*$"
        },
        "webhook_path": {
          "default": "/dukkan/webhooks",
          "type": "string",
          "pattern": "^\\/[A-Za-z0-9/_-]*$"
        }
      }
    },
    "dev": {
      "default": {
        "port": 3000,
        "tunnel": "cloudflared"
      },
      "type": "object",
      "properties": {
        "port": {
          "default": 3000,
          "type": "integer",
          "minimum": 1,
          "maximum": 65535
        },
        "tunnel": {
          "default": "cloudflared",
          "description": "How `dukkan app dev` obtains a public URL.",
          "type": "string",
          "enum": [
            "cloudflared",
            "none"
          ]
        }
      }
    }
  },
  "required": [
    "config_version",
    "app",
    "auth"
  ],
  "additionalProperties": false
}
