# 公開 API

> publicApi()——會員卡核驗、協會的公開資料、稅號、公開金鑰。無需憑證。

URL: https://developers.vimine.network/zh-hant/sdk/public/

```js
import { publicApi } from '@vimine/sdk';
const api = publicApi();                       // 或 vimine.public / vimineServer.public
```

既不需要憑證、也不需要登入的端點。可以在任何頁面、掃描器或伺服器上使用。`publicApi({ apiUrl?, fetch? })` 接受與其他類別相同的網路選項。

| 方法 | 端點 | |
|---|---|---|
| `verifyCard(cardToken)` | `GET /v1/verify/{card_token}` | “這張會員卡現在有效嗎？”——只傳回狀態和有效期截止時間 |
| `association(slug, { locale }?)` | `GET /v1/aps/{slug}` | 公開資料：品牌形象、會員卡類型及其會費、現行章程、協會如何接納會員、是否收集會員地址（`member_address`） |
| `validateFiscalCode(input)` | `POST /v1/validate/fiscal-code` | 結構和檢查碼；提供個人資訊時，還檢查其一致性——並說明稅號中包含什麼（`birth_date`、`birth_country`）。對於在國外出生的人，請傳送 `country` |
| `cardKeys()` | `GET /v1/card-keys` | 用於離線驗證權杖的公開金鑰（JWKS，Ed25519） |
| `confirmEnrollment(token, identification?, address?)` | `POST /v1/enroll/confirm` | 使用“確認您的申請”連結中的權杖——當某個系統為已有帳戶辦理入會時會傳送該連結；收到 `409 identification_required` 後帶上 `identification` 重試，收到 `409 address_required` 後帶上 `address` 重試 |
| `events.list(slug, params?)` · `events.get(slug, event, { locale }?)` | `GET /v1/aps/{slug}/events[/{event}]` | 協會的**公開**活動，附每種類型的剩餘名額（[指南](https://developers.vimine.network/zh-hant/guides/events/)） |
| `confirmRegistration(token)` | `POST /v1/registrations/confirm` | 使用嘉賓“確認您的報名”連結中的權杖：傳回該報名，確認後帶有 QR Code `token` |
| `viewRegistration(token)` | `POST /v1/registrations/view` | 讀取嘉賓專屬連結（確認名額的那封郵件中的連結）背後的名額：其狀態，以及在已確認期間的 QR Code `token`；在活動結束之前一直有效（自 0.3.2 起） |

```js
const { status, valid_until } = await api.verifyCard('vmt_…');
// { status: 'active', valid_until: '2027-03-31T22:59:59.000Z' } | { status: 'inactive', reason: 'expired' }

const { aps, membership_types, statuto } = await api.association('your-slug');

const check = await api.validateFiscalCode({ code: 'RSSMRA80A01H501U', first_name: 'Mario', last_name: 'Rossi', date: '1980-01-01', place: 'Roma', country: 'IT' });
// { valid: true, error: null, mismatches: [], hints: [], birth_date: '1980-01-01', birth_country: 'IT' }
// | { valid: false, error: 'mismatch', mismatches: ['date'], hints: [], birth_date: '1980-01-01', birth_country: 'IT' }

const { keys } = await api.cardKeys();   // [{ kty: 'OKP', crv: 'Ed25519', x, kid, use: 'sig', alg: 'EdDSA' }]

const { status, already, association } = await api.confirmEnrollment(token);   // 來自電子郵件中收到的連結
// { status: 'pending', already: false, association: { name, slug } } — 過期時傳回 400 invalid_token，409 statuto_outdated

// 409 identification_required：該帳戶尚未識別身份；err.errors 列出缺少的內容。詢問後重試：
await api.confirmEnrollment(token, { dob: '1985-03-10', birthplace: 'Lyon', birth_country: 'FR' });

// 409 address_required：協會要求每位會員提供地址。詢問後重試（如已提供身份識別資訊，一併帶上）：
await api.confirmEnrollment(token, undefined, { line: 'Via Roma 1', postal_code: '20100', city: 'Milano', province: 'MI' });
```

稅號是可選的：`error` 為 `invalid`、`mismatch` 或 `null`；當姓和名互換後稅號能對上時，`hints` 中包含 `names_swapped`。`identification` 中的出生資訊和地址都放在請求本文中傳送，絕不放在連結中。參見[沒有義大利稅號的會員](https://developers.vimine.network/zh-hant/guides/members-without-cf/)。

公開金鑰很少變化：請快取它們，每天重新載入一次，或在遇到未知的 `kid` 時重新載入。離線核驗的其餘內容見[嵌入與會員卡核驗](https://developers.vimine.network/zh-hant/guides/embed-and-verify/)。

這些端點按 IP 限制速率（核驗和稅號介面每分鐘 60 次請求）：如需更高的請求量，請使用帶有 `verify:read` 的機密用戶端。
