# Inbound Webhooks (`xlyInterface`)

`xlyInterface` is the smallest of the three Spring Boot WARs. Its job is
to **receive HTTP requests pushed in from third-party systems** —
WeChat, partner factories, vendor portals — and route them to xly
handlers. Entry class
`xlyInterface/src/main/java/com/xly/InterfaceApplicationBoot.java`,
context-path `/xlyInterface`.

This is the only one of the three services that ships **Swagger UI** —
the partner-facing audience benefits most from interactive try-it-out
documentation. The build pulls
`io.springfox:springfox-swagger-ui:2.9.2` and
`io.springfox:springfox-swagger2:2.9.2`. The UI is served at the
SpringFox default once the service is running:

```
http://<host>/xlyInterface/swagger-ui.html
```

(or the equivalent JSON descriptor at
`http://<host>/xlyInterface/v2/api-docs`).

> **Caveat:** the project pulls the SpringFox jars but does **not**
> register a `Docket` bean (no `@EnableSwagger2` or
> `@Bean Docket api()` anywhere in `xly-src`). The `swagger-ui.html`
> shell is served from the jar's static resources, but `/v2/api-docs`
> returns an effectively empty descriptor — the UI is "the dependency
> ships" rather than "a populated try-it-out console". A maintainer
> who wants the live API listed has to add a `Docket` bean.

## The data-driven receiver — `/interfaceDefine/*`

Mirror of the [external API's `/api/invoke`](external.md) pattern, but
for inbound calls:

| Endpoint | Method | Purpose |
|---|---|---|
| `/interfaceDefine/invoke/{interfaceInvoke}` | POST | Dispatch an inbound payload to the handler that `{interfaceInvoke}` names. |
| `/interfaceDefine/callthirdparty/{interfaceInvoke}` | POST | Forward to a configured outbound endpoint. The same URL also exists on `xlyApi`'s `InterfaceController` — duplication is intentional, the two services share the data-driven dispatcher pattern. |

Handler: `xlyInterface/src/main/java/com/xly/web/InterfaceController.java`.

The `{interfaceInvoke}` path variable looks up a metadata row that
declares the SQL or stored procedure to run, the parameter mapping, and
the response shape. Same data-driven philosophy as the rest of xly:
new inbound endpoints are added by inserting rows, not by writing Java.

## Hard-coded vendor receivers

A small number of receivers don't go through `/interfaceDefine` because
they have to match a partner's fixed URL spec.

| Endpoint | Method | Purpose |
|---|---|---|
| `/Push` | POST | Vendor (WeChat / similar) push receiver. |
| `/Pull` | POST | Vendor pull-pattern receiver. |
| `/getKey/{key}` | GET | Public key fetch for a partner-named `key`. |
| `/getKeyTest` | GET | Test-mode variant of `/getKey`. |
| `/send/sendQw` | POST | Enterprise-WeChat (企业微信) outbound message. **Stub on this branch** — the method body in `SendQwController` is `return "ok";`; scaffolded for token-fetch but not finished. |

Handlers: `xlyInterface/src/main/java/com/xly/web/WX_VendorWeb.java`
and `xlyInterface/src/main/java/com/xly/wechat/test/SendQwController.java`.

## Authentication

Webhook auth varies by partner. There is no single token-issuance
endpoint here (unlike `xlyApi`). Each handler picks its own scheme:
signature header, query-param secret, or pre-shared key validation
against `sysapibrand`. Read the specific controller before integrating.

## Where the metadata lives

The `/interfaceDefine/*` dispatcher consults metadata rows that name
the inbound handler. Inspect `sysapi`-family tables (`sysapi`,
`sysapibrand`, `sysapithirdparty`) plus any `interface*` tables in the
schema's auto-catalog for the current handler set. The bookkeeping
overlaps with the [External API](external.md)'s — the two services
share the API-definition data even though they expose it on different
URLs.

## What this service is *not*

- **Not authenticated by xly's session cookie.** Third-party callers
  do not have a user session. Auth is per-handler, not framework-wide.
- **Not for outbound calls.** Outbound dispatches (xly calling a
  partner) go through `xlyApi`'s `/interfaceDefine/callthirdparty/*`
  or `/thirdparty/*` controllers. The duplication is intentional:
  inbound and outbound have very different security postures.
