{
  "openapi": "3.1.0",
  "info": {
    "title": "BE Systematic by BrownHawke Engineering \u2014 Garage platform partner API",
    "version": "1.5.0",
    "description": "Partner API for a multi-site garage admin platform. Routes stay under /api/machine-viewer/v1. Examples use fictitious sandbox data only."
  },
  "servers": [
    {
      "url": "https://hawkeye.brownhawke.engineering/api/machine-viewer/v1",
      "description": "Production"
    },
    {
      "url": "https://hawkeye-next.brownhawke.engineering/api/machine-viewer/v1",
      "description": "Staging"
    }
  ],
  "security": [
    {
      "bearer": []
    }
  ],
  "tags": [
    {
      "name": "Sandbox"
    },
    {
      "name": "Organisation"
    },
    {
      "name": "Jobs"
    },
    {
      "name": "Import"
    },
    {
      "name": "Sage"
    },
    {
      "name": "Callbacks"
    }
  ],
  "components": {
    "securitySchemes": {
      "bearer": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "hkmvp_"
      },
      "site": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Hawkeye-Site",
        "description": "Required when using an organisation-wide key."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "ok": {
            "const": false
          },
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "unauthorized",
                  "rate_limited",
                  "module_off",
                  "invalid_request",
                  "invalid_json",
                  "invalid_callback_url",
                  "not_found",
                  "idempotency_key_reused",
                  "idempotency_in_progress",
                  "payload_too_large",
                  "account_full",
                  "internal_error",
                  "site_required",
                  "site_denied"
                ]
              },
              "message": {
                "type": "string"
              }
            }
          },
          "request_id": {
            "type": "string"
          }
        }
      }
    }
  },
  "paths": {
    "/connectors/garage-platform/sandbox/session": {
      "post": {
        "tags": [
          "Sandbox"
        ],
        "security": [],
        "operationId": "sandboxSession",
        "summary": "Mint a sandbox key and seed eight fictitious garages",
        "responses": {
          "200": {
            "description": "Sandbox session (key shown once)"
          },
          "403": {
            "description": "Sandbox switched off"
          }
        }
      }
    },
    "/connectors/garage-platform": {
      "get": {
        "tags": [
          "Organisation"
        ],
        "operationId": "describePlatform",
        "summary": "Profile, stage map and organisation",
        "responses": {
          "200": {
            "description": "Profile"
          }
        }
      }
    },
    "/connectors/garage-platform/org": {
      "get": {
        "tags": [
          "Organisation"
        ],
        "operationId": "getOrg",
        "summary": "The partner organisation",
        "responses": {
          "200": {
            "description": "Organisation"
          }
        }
      },
      "post": {
        "tags": [
          "Organisation"
        ],
        "operationId": "createOrg",
        "summary": "Create the organisation",
        "responses": {
          "201": {
            "description": "Created"
          }
        }
      }
    },
    "/connectors/garage-platform/sites": {
      "post": {
        "tags": [
          "Organisation"
        ],
        "operationId": "addSite",
        "summary": "Add a garage (site) to the organisation",
        "responses": {
          "200": {
            "description": "Organisation with sites"
          }
        }
      }
    },
    "/connectors/garage-platform/sites/{site_id}/keys": {
      "post": {
        "tags": [
          "Organisation"
        ],
        "operationId": "createSiteKey",
        "summary": "Mint a key limited to one site (shown once)",
        "parameters": [
          {
            "name": "site_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "description": "API key"
          }
        }
      }
    },
    "/connectors/garage-platform/org-key": {
      "post": {
        "tags": [
          "Organisation"
        ],
        "operationId": "createOrgKey",
        "summary": "Mint an organisation-wide key (send X-Hawkeye-Site on each call)",
        "responses": {
          "201": {
            "description": "API key"
          }
        }
      }
    },
    "/connectors/garage-platform/shared-knowledge": {
      "post": {
        "tags": [
          "Organisation"
        ],
        "operationId": "setSharedKnowledge",
        "summary": "Opt in or out of cross-site diagnosis (off by default)",
        "responses": {
          "200": {
            "description": "Organisation"
          }
        }
      }
    },
    "/connectors/garage-platform/jobs": {
      "post": {
        "tags": [
          "Jobs"
        ],
        "operationId": "upsertJob",
        "summary": "Create or update a job in the portal's own fields; returns diagnosis and a guide",
        "responses": {
          "200": {
            "description": "Updated"
          },
          "201": {
            "description": "Created"
          }
        }
      }
    },
    "/connectors/garage-platform/imports": {
      "post": {
        "tags": [
          "Import"
        ],
        "operationId": "importCsv",
        "summary": "Import customers, vehicles, invoices or jobs from CSV (dry_run supported)",
        "responses": {
          "200": {
            "description": "Preview or applied import"
          }
        }
      }
    },
    "/connectors/garage-platform/sage-export": {
      "get": {
        "tags": [
          "Sage"
        ],
        "operationId": "sageExport",
        "summary": "Export book-out lines as a Sage 50 UK audit-trail CSV",
        "responses": {
          "200": {
            "description": "CSV in the json csv field"
          }
        }
      }
    },
    "/connectors/garage-platform/sage-settings": {
      "get": {
        "tags": [
          "Sage"
        ],
        "operationId": "getSageSettings",
        "summary": "Nominal and VAT codes",
        "responses": {
          "200": {
            "description": "Settings"
          }
        }
      },
      "post": {
        "tags": [
          "Sage"
        ],
        "operationId": "setSageSettings",
        "summary": "Set nominal and VAT codes",
        "responses": {
          "200": {
            "description": "Settings"
          }
        }
      }
    },
    "/callback": {
      "get": {
        "tags": [
          "Callbacks"
        ],
        "operationId": "getCallback",
        "summary": "Registered callback (no secret)",
        "responses": {
          "200": {
            "description": "Callback"
          }
        }
      },
      "post": {
        "tags": [
          "Callbacks"
        ],
        "operationId": "setCallback",
        "summary": "Register a signed callback URL; job.guide.ready is off until listed",
        "responses": {
          "200": {
            "description": "Saved"
          }
        }
      }
    },
    "/job-cards/{external_id}/close": {
      "post": {
        "tags": [
          "Jobs"
        ],
        "operationId": "closeJob",
        "summary": "Record cause and rectification on completion (feeds the knowledge loop)",
        "parameters": [
          {
            "name": "external_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Closed"
          }
        }
      }
    },
    "/ping": {
      "get": {
        "tags": [
          "Organisation"
        ],
        "operationId": "ping",
        "summary": "Check a key",
        "responses": {
          "200": {
            "description": "Key works"
          }
        }
      }
    }
  }
}