# The three API tiers xly does not have one API — it has **three**, hosted in three independent Spring Boot services with different audiences and different operational contracts. Knowing which one you're talking to is the first step in any integration conversation. | Tier | Service | Context path | Audience | |---|---|---|---| | **Internal** | `xlyEntry` | `/xlyEntry` | The xly SPA itself (BACK + FROUNT). Not a stable contract for external callers. | | **External** | `xlyApi` | `/xlyApi` | Tenants and integrators calling xly from outside. The data-driven public API. | | **Inbound webhooks** | `xlyInterface` | `/xlyInterface` | Third-party systems pushing events into xly. Carries Swagger. | Each service builds to its own WAR and runs in its own JVM. They share nothing in process; they share **the database**, and that shared database is what makes their separation work — internal-API writes show up to external-API reads automatically because both run against the same schema. ## Why three tiers, not one Each tier answers a different question, and bundling them would sacrifice clarity: - **Internal** is large (universal CRUD over all metadata-driven modules), volatile (changes when the framework changes), and intentionally untyped (the SPA decides what to ask for, server obeys). - **External** is curated (only the endpoints integrators are allowed to use), versioned by `sApiCode`, and authenticated with bearer tokens — it survives across framework changes precisely because it's small and explicit. - **Inbound webhooks** receive untrusted bodies from third-party systems and route them to xly handlers. The Swagger UI lives here because that audience benefits most from interactive documentation. ## What each tier looks like at runtime - **Internal** — see [the four-table read](../reference/maintainer/runtime.md#the-four-table-read). One endpoint (`/business/getModelBysId`) returns the entire form layout; another (`/business/addUpdateDelBusinessData`) writes any row in any table the metadata names. Few endpoints, generic shapes. - **External** — most calls go through `/api/invoke/{sApiCode}`. The `sApiCode` is a row in the `sysapi` metadata table that names the SQL template, parameters, auth requirement, and target. New external APIs are *registered as data*, not as code — the same data-driven thesis the framework applies to its own forms. - **Inbound webhooks** — `/interfaceDefine/invoke/{interfaceInvoke}` receives a payload, looks up the matching handler in metadata, runs the configured SQL or stored procedure. Plus a few hard-coded receivers (`/Push`, `/Pull`, `/send/sendQw`) for specific partners. ## Where to look next - [API Reference (Internal)](../api-reference/internal.md) — the `xlyEntry` endpoints the SPA uses; not for external callers. - [API Reference (External)](../api-reference/external.md) — the `xlyApi` surface integrators consume, and the `sysapi`-driven `/api/invoke` pattern. - [API Reference (Webhooks)](../api-reference/webhooks.md) — the `xlyInterface` inbound surface and where Swagger UI is served. - [API Reference (Messaging)](../api-reference/messaging.md) — the ActiveMQ / RocketMQ event channels that complement the HTTP APIs.