{
  "version": "2026-04-08",
  "publicAccessModes": [
    "batch CSV / portfolio audit",
    "embedded result panel",
    "API"
  ],
  "recommendedStartOrder": [
    {
      "mode": "batch CSV / portfolio audit",
      "reason": "Fastest route to a paid first proof and the shared property contract."
    },
    {
      "mode": "embedded result panel",
      "reason": "Fastest route into an existing screen once the first proof is working."
    },
    {
      "mode": "API",
      "reason": "Best for validating the live contract and usage boundaries before direct product delivery."
    }
  ],
  "implementationReadiness": {
    "summary": "Keep the buyer story on the three access modes. Reuse one shared property shape, start with one narrow surface, and expand only when repeated use is clear.",
    "items": [
      {
        "title": "1. Keep one shared property shape",
        "detail": "Reuse the same address-and-postcode shape across batch CSV, the hosted panel, and the live API lookup so the first proof does not turn into bespoke mapping work."
      },
      {
        "title": "2. Start with one narrow surface",
        "detail": "Validate a representative export or place the hosted panel into one screen before asking for deeper automation, sync, or broader API delivery."
      },
      {
        "title": "3. Expand only when repeated use is clear",
        "detail": "Broader delivery should stay behind the scenes until the shared access modes have shown repeated value and the extra build clearly reduces buyer friction."
      }
    ]
  },
  "starterExamples": {
    "apiLookupScript": {
      "href": "/templates/locastica-api-lookup-example.sh",
      "filename": "locastica-api-lookup-example.sh"
    },
    "embeddedPanelStarter": {
      "href": "/templates/locastica-embedded-panel-starter.html",
      "filename": "locastica-embedded-panel-starter.html"
    }
  },
  "sharedPropertyContract": {
    "requiredFields": [
      "address_line_1",
      "postcode"
    ],
    "optionalFields": [
      "property_reference",
      "address_line_2",
      "town_or_city",
      "uprn",
      "workflow_notes"
    ],
    "headerMappings": {
      "address_line_1": [
        "address1",
        "address_1",
        "property_address",
        "address_line1",
        "building_number"
      ],
      "postcode": [
        "zip",
        "postal_code",
        "post_code"
      ],
      "property_reference": [
        "property_id",
        "reference",
        "asset_id"
      ],
      "address_line_2": [
        "address2",
        "unit",
        "flat"
      ],
      "town_or_city": [
        "town",
        "city",
        "locality"
      ],
      "uprn": [
        "uprn_number",
        "unique_property_reference_number"
      ],
      "workflow_notes": [
        "notes",
        "comment",
        "branch_notes"
      ]
    },
    "starterAssets": {
      "csvTemplate": {
        "href": "/templates/locastica-portfolio-audit-template.csv",
        "filename": "locastica-portfolio-audit-template.csv"
      },
      "fieldGuide": {
        "href": "/templates/locastica-portfolio-audit-field-guide.json",
        "filename": "locastica-portfolio-audit-field-guide.json"
      },
      "exampleOutput": {
        "href": "/templates/locastica-portfolio-audit-example-output.csv",
        "filename": "locastica-portfolio-audit-example-output.csv"
      }
    },
    "reviewedBatchOutput": [
      "property_reference",
      "matched_address",
      "postcode",
      "council_name",
      "council_code",
      "licensing_decision",
      "scheme_name",
      "scheme_type",
      "fee_context",
      "evidence_url",
      "last_verified_at",
      "review_context",
      "soft_flag"
    ],
    "modeUsage": [
      {
        "key": "address_line_1",
        "label": "Address line 1",
        "detail": "Primary property address used for batch review and shown back to operators alongside the result.",
        "batchUsage": "Required input",
        "embeddedUsage": "Required input",
        "apiUsage": "Retain in your system for joins and display; not part of the current public lookup query."
      },
      {
        "key": "postcode",
        "label": "Postcode",
        "detail": "Canonical routing field used across every sellable access mode today.",
        "batchUsage": "Required input",
        "embeddedUsage": "Required input",
        "apiUsage": "Required public query parameter on `/api/v1/licensing/lookup`."
      },
      {
        "key": "property_reference",
        "label": "Property reference",
        "detail": "Your internal property, CRM, or portfolio identifier for reconciliation after the result is returned.",
        "batchUsage": "Optional input",
        "embeddedUsage": "Optional input",
        "apiUsage": "Retain in your own system for reconciliation; not part of the current public lookup query."
      },
      {
        "key": "workflow_notes",
        "label": "Workflow notes",
        "detail": "Operational context such as branch owner, review stage, or escalation cue for the first review.",
        "batchUsage": "Optional input",
        "embeddedUsage": "Optional input",
        "apiUsage": "Retain in your own system as review context; not part of the current public lookup query."
      }
    ],
    "guidanceNotes": [
      "Keep one canonical property shape in your own systems even though the current public API lookup only requires a postcode query.",
      "Address, property reference, and review context still matter for batch scoping, hosted-panel display, and downstream reconciliation after the lookup returns."
    ],
    "validation": {
      "endpoint": "/api/portfolio-audit/validate-sample",
      "acceptedTransports": [
        "application/json with csvText",
        "multipart/form-data with sampleFile"
      ],
      "responseFields": [
        {
          "key": "compatibilityStatus",
          "label": "Compatibility status",
          "detail": "Returns ready_for_scoping or needs_header_mapping for the uploaded sample."
        },
        {
          "key": "missingRequiredFields",
          "label": "Missing required fields",
          "detail": "Lists canonical fields still required before the batch can be scoped cleanly."
        },
        {
          "key": "matchedHeaders",
          "label": "Matched headers",
          "detail": "Shows which source headers already map onto the canonical contract."
        },
        {
          "key": "unmatchedHeaders",
          "label": "Unmatched headers",
          "detail": "Shows extra source columns that will need mapping or can be ignored."
        },
        {
          "key": "contractVersion",
          "label": "Contract version",
          "detail": "Echoes the current field-guide version so teams can pin the mapping they validated."
        }
      ],
      "exampleRequests": {
        "jsonBody": {
          "csvText": "property_address,post_code,asset_id,branch_notes\n10 High Street,SW1A 1AA,REF-1,Renewal review batch"
        },
        "multipartCurl": "curl -X POST https://locastica.com/api/portfolio-audit/validate-sample \\\n  -F \"sampleFile=@portfolio-export.csv;type=text/csv\""
      },
      "exampleResponse": {
        "success": true,
        "contractVersion": "2026-04-01",
        "sampleSummary": {
          "compatibilityStatus": "ready_for_scoping",
          "compatibleForScoping": true,
          "missingRequiredFields": [],
          "matchedHeaders": [
            {
              "canonicalKey": "address_line_1",
              "sourceHeader": "property_address"
            },
            {
              "canonicalKey": "postcode",
              "sourceHeader": "post_code"
            },
            {
              "canonicalKey": "property_reference",
              "sourceHeader": "asset_id"
            },
            {
              "canonicalKey": "workflow_notes",
              "sourceHeader": "branch_notes"
            }
          ],
          "unmatchedHeaders": []
        },
        "contract": {
          "version": "2026-04-01",
          "deliveryPath": "batch_csv_portfolio_audit",
          "inputContract": {
            "requiredFields": [
              "address_line_1",
              "postcode"
            ],
            "optionalFields": [
              "property_reference",
              "address_line_2",
              "town_or_city",
              "uprn",
              "workflow_notes"
            ]
          },
          "reviewedBatchOutput": [
            "property_reference",
            "matched_address",
            "postcode",
            "council_name",
            "council_code",
            "licensing_decision",
            "scheme_name",
            "scheme_type",
            "fee_context",
            "evidence_url",
            "last_verified_at",
            "review_context",
            "soft_flag"
          ]
        }
      }
    }
  },
  "embeddedPanel": {
    "demoPath": "/embed/licensing-result-demo",
    "iframeSnippet": "<iframe\n  src=\"https://locastica.com/embed/licensing-result-demo\"\n  title=\"Locastica licensing result panel\"\n  style=\"width:100%;max-width:460px;height:760px;border:0;\"\n  loading=\"lazy\"\n></iframe>",
    "starterAsset": {
      "href": "/templates/locastica-embedded-panel-starter.html",
      "filename": "locastica-embedded-panel-starter.html"
    },
    "inputFields": [
      {
        "key": "address_line_1",
        "label": "Address line 1",
        "detail": "Primary property address shown to the operator inside the panel."
      },
      {
        "key": "postcode",
        "label": "Postcode",
        "detail": "Required to resolve the council and property-level licensing position."
      },
      {
        "key": "property_reference",
        "label": "Property reference",
        "detail": "Optional CRM or portfolio ID echoed back next to the hosted panel result."
      },
      {
        "key": "workflow_notes",
        "label": "Workflow notes",
        "detail": "Optional branch, stage, or review context kept with the hosted panel result."
      }
    ],
    "visibleFields": [
      "Licensing decision",
      "Scheme and fee context",
      "Council evidence",
      "Freshness and review context",
      "Next action cue"
    ],
    "exampleHandoff": {
      "address_line_1": "12 Example Street",
      "postcode": "SE17 1PU",
      "property_reference": "STR-2048",
      "workflow_notes": "Renewal review in lettings compliance screen"
    },
    "executionContract": [
      {
        "title": "Hosted panel before native build",
        "detail": "The first implementation should place one hosted panel inside an existing product or operations screen before anyone commits to a deeper native build."
      },
      {
        "title": "Same property contract across steps",
        "detail": "Use the same property identifiers and review context from the batch audit so the panel reuses the same handoff rather than inventing a new delivery path."
      },
      {
        "title": "Read-only workflow proof first",
        "detail": "Treat the panel as a visible result surface first, then move to API write-back or broader product delivery only after repeated use is clear."
      }
    ],
    "guardrails": [
      "Not a white-label rebuild or bespoke UI programme for the first implementation.",
      "Not a hidden-evidence widget that strips council source or freshness context.",
      "Not a promise of full bidirectional sync before the hosted panel proves repeated value."
    ]
  },
  "apiLookup": {
    "starterAsset": {
      "href": "/templates/locastica-api-lookup-example.sh",
      "filename": "locastica-api-lookup-example.sh"
    },
    "quickstart": {
      "steps": [
        {
          "title": "Issue one key per environment or use case",
          "detail": "Keep production, staging, and one-off scripts on separate keys so rotation and revocation stay low-risk."
        },
        {
          "title": "Call the licensing lookup endpoint with a key header",
          "detail": "Use `Authorization: Bearer <api_key>` by default. `x-api-key` is also accepted when your client cannot set Authorization."
        },
        {
          "title": "Read usage headers on every response",
          "detail": "Professional includes 5000 requests per month across active keys and 60 requests per minute per key."
        }
      ],
      "request": {
        "method": "GET",
        "path": "/api/v1/licensing/lookup?postcode=SE17+1PU",
        "authenticationHeaders": [
          "Authorization: Bearer lk_live_your_key",
          "x-api-key: lk_live_your_key"
        ]
      },
      "curl": "# Replace the example key with the value you just issued in this workspace.\n\ncurl --request GET \"$LOCASTICA_BASE_URL/api/v1/licensing/lookup?postcode=SE17+1PU\" \\\n  -H \"Authorization: Bearer lk_live_your_key\" \\\n  -H \"Content-Type: application/json\"\n\n# Alternative header when Authorization is unavailable\n# -H \"x-api-key: lk_live_your_key\"",
      "responseHeaders": [
        "X-Api-Monthly-Limit",
        "X-Api-Monthly-Used",
        "X-Api-Monthly-Remaining",
        "X-Api-Monthly-Reset",
        "X-Api-Burst-Limit"
      ]
    },
    "lookupContract": [
      {
        "label": "Method",
        "value": "GET",
        "detail": "Call one lookup route per property check. The first public lookup stays intentionally narrow."
      },
      {
        "label": "Endpoint",
        "value": "/api/v1/licensing/lookup",
        "detail": "Use the same route across direct API delivery, embedded panels, and internal review steps."
      },
      {
        "label": "Required query",
        "value": "postcode",
        "detail": "The current live lookup requires a postcode query parameter on every request."
      },
      {
        "label": "Authentication",
        "value": "Authorization: Bearer <api_key> or x-api-key",
        "detail": "Malformed API credentials fail as API auth errors and do not fall back to browser-session lookup."
      },
      {
        "label": "Success model",
        "value": "200 with coverage and scheme data",
        "detail": "Successful responses include the coverage level, council context, scheme rows, and API usage headers."
      },
      {
        "label": "Out-of-scope signal",
        "value": "MINIMAL coverage with message",
        "detail": "Invalid or unsupported postcodes return a bounded response with an explicit message instead of implied certainty."
      }
    ],
    "boundaries": [
      "One postcode lookup at a time is the current public API surface; bulk portfolio work should start on the batch-audit path.",
      "Batch reviews, embedded panels, and later API mapping should reuse the same canonical field shape instead of inventing a custom payload per buyer.",
      "Webhooks, higher-volume traffic, and broader embedded rights stay part of Enterprise review rather than being implied by the self-serve API page.",
      "The first public lookup is intentionally read-only: prove repeated use before asking for write-back or system-of-record sync."
    ],
    "commercialNotes": [
      "Professional covers self-serve API access for your own team’s use.",
      "Embedded delivery, webhook delivery, and higher-volume usage move into Enterprise review instead of a published add-on.",
      "API access does not grant resale, customer-facing reuse, or white-label rights."
    ],
    "exampleResponse": {
      "postcode": "SE17 1PU",
      "ward": {
        "code": "E05011109",
        "name": "Faraday"
      },
      "council": {
        "code": "E09000028",
        "name": "London Borough of Southwark",
        "region": "London",
        "website": "https://www.southwark.gov.uk",
        "licensingUrl": "https://www.southwark.gov.uk/housing/landlords-and-tenants/houses-in-multiple-occupation-hmo",
        "dataQuality": "FULL",
        "lastVerified": "2026-03-15T00:00:00.000Z",
        "confidenceBand": "high"
      },
      "schemes": [
        {
          "id": "scheme_sel_southwark_001",
          "type": "selective",
          "name": "Borough-wide Selective Licensing",
          "status": "active",
          "lifecycleStatus": "active",
          "coverageType": "COUNCIL_WIDE",
          "fees": {
            "newApplicationFee": 925,
            "renewalFee": 750,
            "feeStructureType": "flat"
          },
          "sourceUrl": "https://www.southwark.gov.uk/housing/landlords-and-tenants/houses-in-multiple-occupation-hmo",
          "confidence": 0.96,
          "lastVerified": "2026-03-15T00:00:00.000Z"
        }
      ],
      "coverage": "FULL"
    }
  }
}
