Orizn Visa API · v1.1

API文档

生产可用的签证情报 — 49,750 组护照/目的地组合,每组 30 项数据,支持 15 种语言。覆盖 8 个产品模块的 28 个 REST 端点。

OpenAPI 3.0.3 规范
可自动导入 Postman、Insomnia、RapidAPI,或用任意语言生成客户端 SDK。
60 秒跑通第一次调用

快速开始

每个 Orizn 账户都自带个人 API 密钥。将它放入 x-api-key 请求头(或?api_key= 查询参数)即可开始调用。

在特定技术栈里开发? 集成教程 带你从空文件夹一路走到跑通调用 — MCP、REST、JavaScript、Python、Rust、LangChain、React 和 Next.js。那些页面上的每个代码块都在发布前实际执行过。

# Free key: evaluation only. Shipping to users? -> commercial license required.
curl "https://visa.orizn.app/api/v1/visa?passport=FRA&destination=JPN&lang=en" \
  -H "x-api-key: YOUR_API_KEY"
GET /api/v1/visa/check?passport=FRA&destination=JPN

无需密钥 — 直接在浏览器中实时运行此演示调用。你将从 API 获得真实的 200 响应,同源。

基础URL: https://visa.orizn.app · JSON 输入/输出 · UTF-8 · 所有公开端点开放 CORS。

1. 认证

共有三种认证方式,取决于端点:

1 · API 密钥

x-api-key 请求头

产品代码的默认方式。也可作为 ?api_key= 查询参数传入。

2 · 公开

无需凭证

统计、评分、实时、注册、联盟相关流程。 /visa/check 在从 visa.orizn.app, localhost或 Chrome 扩展调用时也无需密钥。

3 · 会话

orizn_token cookie

控制台端点(密钥轮换、Stripe 结账/门户、分析)。在控制台登录后自动设置。

# 1) API key — recommended
curl "https://visa.orizn.app/api/v1/visa?passport=FRA&destination=JPN" \
  -H "x-api-key: YOUR_API_KEY"

# 2) API key via query string (only when headers can't be set)
curl "https://visa.orizn.app/api/v1/visa?passport=FRA&destination=JPN&api_key=YOUR_API_KEY"

# 3) Session cookie (dashboard endpoints)
curl "https://visa.orizn.app/api/v1/visa/auth/ensure-key" \
  --cookie "orizn_token=YOUR_SESSION"

切勿把密钥暴露在交付给不受信任用户的客户端代码中 — 请经由你的后端代理。密钥可以随时轮换,入口在 控制台.

所有端点共同遵循的规则

约定

ISO 3166-1 alpha-3
所有护照和目的地代码均为 3 位 ISO 代码(FRA、USA、JPN)。支持 199 个国家 — 权威列表见 /api/v1/visa/stats。
版本策略
/v1/ is stable and stays reachable. Additive changes ship without notice — new fields, new enum members, new endpoints. Breaking changes (a removed or renamed field, a narrowed type, a removed endpoint) never land in v1: they ship as /v2, and v1 keeps answering. Pin nothing; parse defensively and ignore unknown fields.
Deprecation
Six months of notice before anything in v1 stops working, counted from the dated changelog entry. During that window every affected response carries Deprecation and Sunset headers (RFC 9745 / RFC 8594) plus a Link header to the migration note, so your monitoring sees it before your users do. No silent removals, no shortened windows.
CORS
每个公开端点都返回 Access-Control-Allow-Origin: *。所有数据端点均已实现 OPTIONS 预检。
内容协商
/visa 和 /visa/check 端点支持 Accept: text/markdown,返回适合人类阅读的 Markdown 而非 JSON — 非常适合聊天工具。
幂等性
POST /register、POST /affiliate/register、POST /affiliate/ios-purchase 和 POST /devices 均按其自然键(email、transaction_id、device_token)幂等。
时间
所有时间戳均为带 UTC 后缀的 ISO 8601。月度配额在每月 1 日重置(UTC)。
28 个端点 · 8 个模块

2. 端点

所有端点都位于 https://visa.orizn.app. 每个路径下方的标签标明认证方式和最低套餐。 公开端点带有 运行 按钮,可直接在本页发起调用。

签证数据

The endpoints you'll actually call from product code.

GET/api/v1/visaapi key · 任意套餐

完整签证情报

旗舰端点。返回 30 项数据:所需文件、办理流程、费用、使馆信息、过境规定、疫苗接种、安全提示、逾期滞留处罚等 — 支持 15 种语言。按套餐分级:free 返回核心字段及升级预览;starter 解锁除远程工作签证和互惠历史外的全部扩展字段;pro 及以上返回全部内容,包括双向使馆信息。

参数
参数类型必填描述
passportstringISO 3166-1 alpha-3(如 FRA)。
destinationstringISO 3166-1 alpha-3(如 JPN)。
langstring15 种受支持代码之一(见「语言」)。免费套餐仅限英语 — 其他语言需要 Starter 及以上。
示例
curl "https://visa.orizn.app/api/v1/visa?passport=FRA&destination=JPN" \
  -H "x-api-key: YOUR_API_KEY"
响应 · 200 OK
{
  "data": {
    "passport": "FRA",
    "destination": "JPN",
    "requirement": "visa_free",
    "visa_free_days": 90,
    "visa_required": false,
    "description": "French citizens can enter Japan visa-free for up to 90 days.",
    "documents_required": ["Valid passport (3 months)", "Return or onward ticket"],
    "process": ["No prior formalities", "Immigration form on arrival"],
    "tips": ["Carry proof of sufficient funds"],
    "country_info": { "currency": "JPY", "language": "Japanese", "timezone": "UTC+9", "capital": "Tokyo" },
    "verified": true,
    "transit_visa": { "hubs": [{ "airport": "NRT", "city": "Tokyo", "transit_visa_required": false, "transit_free_hours": 24 }] },
    "passport_validity_months": 3,
    "visa_fee": { "single_entry": { "amount": 0, "currency": "JPY" } },
    "processing_days": { "standard": null, "express": null },
    "photo_specs": { "width_mm": 35, "height_mm": 45, "background": "white" },
    "vaccinations_required": [],
    "insurance_required": { "required": false },
    "overstay_penalty": { "fine_per_day": "Variable + deportation", "ban_days": 365, "criminal": true },
    "entry_by_mode": { "air": 90, "land": 90, "sea": 90 },
    "safety": { "level": 1, "advisory": "Exercise normal precautions", "source": "diplomatie.gouv.fr" },
    "health_requirements": { "covid_test": false, "quarantine_days": 0 },
    "embassy": {
      "your_embassy_at_destination": { "name": "Ambassade de France au Japon", "city": "Tokyo", "phone": "+81 3 5798 6000" },
      "visa_application_embassy": { "name": "Ambassade du Japon en France", "city": "Paris" }
    }
  },
  "meta": { "lang": "en", "api_version": "1.1", "coverage": "199 passports x 250 destinations", "languages": 15, "data_points": 30 }
}
错误码
400护照/目的地缺失或非 ISO3,不支持的 lang401缺少 api key403密钥无效/已停用,或免费套餐使用非 en 语言404该组合无数据429超出月度配额
备注设置 Accept: text/markdown 可获得适合人类阅读的 Markdown 而非 JSON。会累加 requests_month 和 requests_total。
GET/api/v1/visa/checkapi key · 任意套餐

快速签证查询

轻量级「是/否」查询 — 仅返回签证要求类型和可停留时长。内嵌的 _upgrade_preview 字段会统计完整 /visa 端点将返回的内容,无需第二次调用即可驱动升级引导界面。

参数
参数类型必填描述
passportstringISO 3166-1 alpha-3。
destinationstringISO 3166-1 alpha-3。
示例
curl "https://visa.orizn.app/api/v1/visa/check?passport=FRA&destination=JPN" \
  -H "x-api-key: YOUR_API_KEY"

响应 · 200 OK
{
  "passport": "FRA",
  "destination": "JPN",
  "requirement": "visa_free",
  "visa_free_days": 90,
  "visa_required": false,
  "_hint": "Upgrade to get documents, process, embassies, photo specs and 28 more fields.",
  "_upgrade_preview": {
    "documents_required": 4,
    "process_steps": 3,
    "embassy_info": true,
    "transit_visa": true,
    "visa_fees": false,
    "vaccinations": 0,
    "safety_advisory": "level 1",
    "languages": 15,
    "upgrade_url": "https://visa.orizn.app/visa-api/pricing"
  }
}
错误码
400参数缺失或非 ISO3401无 api key 且未从白名单 Referer/Origin 调用403api key 无效404未找到该组合429超出月度配额
备注仅当 Referer 包含 visa.orizn.app、localhost,或 Origin 以 chrome-extension:// 开头时才接受无密钥调用 — 公开落地页演示和浏览器扩展正是靠它驱动。支持 Accept: text/markdown。
GET/api/v1/visa/bulkapi key · hobby 及以上

单本护照批量查询目的地

一次往返查询单本护照对最多 25 个目的地。传入逗号分隔的 destinations 列表(必填,每次最多 25 个)。返回的每一对护照×目的地计为一次月度配额请求。返回扩展字段的精选子集(费用、安全、健康、疫苗、保险、入境方式、远程工作)。

参数
参数类型必填描述
passportstringISO 3166-1 alpha-3。
destinationstring逗号分隔的 ISO3 列表,如 JPN,THA,BRA。省略则返回全部目的地。
langstring默认 en。15 种受支持代码之一。
示例
curl "https://visa.orizn.app/api/v1/visa/bulk?passport=FRA" \
  -H "x-api-key: YOUR_API_KEY"
响应 · 200 OK
{
  "passport": "FRA",
  "lang": "en",
  "total": 199,
  "destinations": [
    {
      "destination": "JPN",
      "requirement": "visa_free",
      "visa_free_days": 90,
      "description": "Visa-free for up to 90 days.",
      "passport_validity_months": 3,
      "visa_fee": { "single_entry": { "amount": 0, "currency": "JPY" } },
      "safety": { "level": 1 },
      "health_requirements": { "covid_test": false },
      "vaccinations_required": [],
      "insurance_required": { "required": false },
      "entry_by_mode": { "air": 90, "land": 90, "sea": 90 },
      "remote_work_visa": { "available": false }
    }
  ]
}
错误码
400护照缺失/无效、目的地列表格式错误、不支持的 lang401缺少 api key403套餐低于 Hobby404该护照无数据429超出月度配额
备注方法是 GET(不是 POST)。一次批量调用始终只计 1 次配额。
GET/api/v1/visa/groupapi key · hobby 及以上

团体出行 — 多护照交集

为团体旅行而生:传入 2-10 本护照,返回所有成员都能前往的每个目的地,附每本护照的明细和全团最严格的要求。默认当每本护照均为 visa_free、eta、visa_on_arrival 或 e_visa 时目的地才符合条件 — 用 allow 参数收窄或放宽(如 allow=visa_free 表示仅限免签)。group_visa_free_days 是全团的最短可停留天数,即共同行程的约束值。目的地按最容易到达排序。每对护照×目的地计为一次请求。

参数
参数类型必填描述
passportsstring逗号分隔的 ISO3 列表,2 到 10 个不同代码。示例:USA,FRA,IND。
allowstring逗号分隔的合格要求类型。默认:visa_free,eta,visa_on_arrival,e_visa。
示例
curl "https://visa.orizn.app/api/v1/visa/group?passports=USA,FRA,IND" \
  -H "x-api-key: YOUR_API_KEY"
响应 · 200 OK
{
  "passports": ["USA", "FRA", "IND"],
  "allow": ["visa_free", "eta", "visa_on_arrival", "e_visa"],
  "total": 97,
  "excluded": { "requirement_not_allowed": 100, "incomplete_data": 4 },
  "destinations": [
    {
      "destination": "FJI",
      "group_requirement": "visa_free",
      "group_visa_free_days": 120,
      "by_passport": {
        "USA": { "requirement": "visa_free", "visa_free_days": 120 },
        "FRA": { "requirement": "visa_free", "visa_free_days": 120 },
        "IND": { "requirement": "visa_free", "visa_free_days": 120 }
      }
    }
  ]
}
错误码
400护照少于 2 本或多于 10 本、非 ISO3 代码、allow 中含未知要求类型401缺少 api key403套餐低于 Hobby404其中一本护照无数据429超出月度配额
备注非常适合静修营和团体旅行:一次调用回答“大家都能去哪?”。一次团体调用始终只计 1 次配额。
POST/api/v1/visa/decisionapi key · 任意套餐

Itinerary decision — answers a trip, not a pair

Post a whole trip — passport, ordered stops with dates, transit stops, passport expiry — and get a per-step decision plus the blockers only a full itinerary reveals: days accumulated across repeat visits to the same country, passport validity measured against each arrival date, and an expiry that falls before the last exit. Every field states its granularity (pair or destination) and every gap comes back as status: "unknown" with a reason, never as a default value. verdict is no_blocker_found or blocked — it reports what the data supports, it is not legal advice.

请求体
{
  "passport": "FRA",
  "residence": "VNM",
  "passport_expiry": "2027-03-01",
  "itinerary": [
    { "country": "THA", "from": "2026-09-01", "to": "2026-09-20" },
    { "country": "VNM", "from": "2026-09-20", "to": "2026-10-10" },
    { "country": "THA", "from": "2026-10-10", "to": "2026-10-25" }
  ],
  "transit": ["SGP"],
  "purpose": "tourism"
}
示例
curl -X POST "https://visa.orizn.app/api/v1/visa/decision" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "passport": "FRA", "residence": "VNM", "passport_expiry": "2027-03-01", "itinerary": [ { "country": "THA", "from": "2026-09-01", "to": "2026-09-20" }, { "country": "VNM", "from": "2026-09-20", "to": "2026-10-10" }, { "country": "THA", "from": "2026-10-10", "to": "2026-10-25" } ], "transit": ["SGP"], "purpose": "tourism" }'
响应 · 200 OK
{
  "data": {
    "passport_country": "FRA",
    "steps": [
      {
        "country": "THA", "from": "2026-09-01", "to": "2026-09-20", "days": 20,
        "admission": "allowed",
        "regime": { "status": "known", "value": "visa_free", "granularity": "pair",
                    "source_url": null, "last_verified": null },
        "max_stay": { "status": "known", "days": 30, "granularity": "pair", "basis": "visa_free_days" },
        "passport_validity_months": { "status": "known", "months": 6, "granularity": "destination" }
      }
    ],
    "transit": [
      { "country": "SGP", "status": "destination_rule", "granularity": "destination",
        "note": "Applies to the airport, not to this nationality. Confirm with the carrier before booking." }
    ],
    "passport": { "expiry": "2027-03-01", "status": "checked", "valid_through_itinerary": true,
                  "per_destination": [{ "country": "THA", "arrival": "2026-09-01",
                                        "required_months": 6, "satisfied": true }] },
    "blockers": [
      { "type": "stay_exceeds_allowance", "country": "THA",
        "detail": "Itinerary spends 36 day(s) in THA, above the 30-day allowance recorded for this pair." }
    ],
    "unknowns": [
      { "field": "residence",
        "reason": "Residence is not a dimension of the dataset. Decisions assume a passport holder applying as a national; residence permits may grant additional rights not modelled here." }
    ],
    "verdict": "blocked"
  },
  "meta": { "api_version": "1.0", "pairs_charged": 3, "max_steps": 12 }
}
错误码
400invalid JSON, non-ISO3 code, non-calendar date, to before from, or more than 12 steps401缺少 api key403invalid or inactive key404no visa data for that passport at all429超出月度配额
备注Billing: one request per distinct country resolved (stops + transit), like /bulk — a 3-country trip costs 3, and meta.pairs_charged tells you exactly what was billed. Max 12 itinerary steps and 12 transit countries per call.
GET/api/v1/visa/changes公开 — 无需认证不计入配额

Policy change feed — temporarily unavailable

This endpoint currently returns 503 for every caller and is not part of any plan. The previous feed compared two internal tables rather than official gazettes, so it was withdrawn instead of being sold as verified change data. It will come back only once it is sourced from official publications and each event carries a named, verified source. No client integration was affected — the endpoint had never been called. Need change monitoring before then? Write to [email protected] and we will tell you honestly where we are.

示例
curl "https://visa.orizn.app/api/v1/visa/changes"
响应 · 200 OK
{
  "error": "The policy-change feed is being rebuilt on verified official sources.",
  "status": "unavailable",
  "contact": "[email protected]"
}
错误码
503feed withdrawn pending verified official sources — Retry-After: 86400
备注Do not build against this endpoint yet. Webhooks and device push subscriptions are unaffected.
GET/api/v1/visa/stats公开 — 无需认证不计入配额

覆盖统计

公开端点,无需认证,边缘缓存 1 小时。可在营销页面上展示实时覆盖数据,以及各签证要求类别的组合数量分布。

示例
curl "https://visa.orizn.app/api/v1/visa/stats"

响应 · 200 OK
{
  "coverage": {
    "visa_details": 49750,
    "passports": 199,
    "destinations": 250,
    "passport_index_pairs": 49750,
    "translations": 696500,
    "languages": 15
  },
  "supported_languages": [
    { "code": "en", "name": "English" },
    { "code": "fr", "name": "Français" }
  ],
  "requirement_distribution": {
    "visa_free": 14210,
    "visa_required": 12740,
    "e_visa": 4830,
    "visa_on_arrival": 5102,
    "eta": 2103,
    "no_admission": 600
  },
  "api_version": "1.0",
  "docs": "https://visa.orizn.app"
}
备注Cache-Control: public, max-age=3600。可放心从静态前端调用。
护照评分

公开的通行力评分 — 单本护照或并列对比。

GET/api/v1/visa/score公开 — 无需认证不计入配额

护照通行力评分

单本护照的综合通行力评分和全球排名。评分综合考虑免签/落地签/电子签数量、目的地多样性和经济权重。公开 — 无需密钥。

参数
参数类型必填描述
passportstringISO 3166-1 alpha-3。
示例
curl "https://visa.orizn.app/api/v1/visa/score?passport=FRA"

响应 · 200 OK
{
  "passport": "FRA",
  "score": 96.4,
  "rank": 3,
  "breakdown": {
    "visa_free":       { "count": 158, "weight": 0.55 },
    "visa_on_arrival": { "count": 17, "weight": 0.15 },
    "e_visa":          { "count": 20, "weight": 0.10 },
    "diversity":       { "continents": 6, "weight": 0.10 },
    "economic":        { "score": 88,    "weight": 0.10 }
  },
  "total_accessible": 195
}
错误码
400passport 参数缺失或格式错误404护照不在索引中500内部错误
备注返回结构由 computePassportScore() 决定。字段名可能演进 — 请依赖文档中的键名,而非字段顺序。
GET/api/v1/visa/score/compare公开 — 无需认证不计入配额

对比两本护照

两本护照的并列对比:各自评分、彼此独有的目的地差集,以及归一化的双护照组合评分(单本护照最多可达 199 个目的地 → 1000 分)。适用于双重国籍计算器和第二本护照落地页。

参数
参数类型必填描述
passport1string第一本护照,ISO 3166-1 alpha-3。
passport2string第二本护照,ISO 3166-1 alpha-3。必须与 passport1 不同。
示例
curl "https://visa.orizn.app/api/v1/visa/score/compare?passport1=FRA&passport2=MAR"

响应 · 200 OK
{
  "passport1": { "code": "FRA", "score": 96.4, "rank": 3 },
  "passport2": { "code": "MAR", "score": 41.2, "rank": 75 },
  "combined": {
    "score": 988,
    "total_accessible": 197,
    "only_passport1": ["USA", "CAN", "GBR"],
    "only_passport2": ["DZA", "TUN"],
    "both": ["JPN", "THA", "BRA"],
    "neither": ["PRK"]
  },
  "share_text": "FRA + MAR unlock 197/250 destinations — share your dual-passport score on https://visa.orizn.app"
}
错误码
400参数缺失或两本护照相同404任一护照不在索引中500内部错误
实时动态

实时 SSE 流 + 最近快照,适合社交证明组件。

GET/api/v1/visa/live公开 — 无需认证不计入配额

实时活动流(SSE)

Server-Sent Events。全球每次成功的 /visa 或 /visa/check 调用都会产生一个事件,含护照、目的地和时间戳。无新流量时每 2 秒发送一条 `: keepalive` 注释。适合落地页的社交证明滚动条。

示例
curl "https://visa.orizn.app/api/v1/visa/live"
响应 · 200 OK
// Content-Type: text/event-stream

data: {"passport":"USA","destination":"JPN","timestamp":"2026-05-31T09: 14: 00Z"}

data: {"passport":"IND","destination":"ARE","timestamp":"2026-05-31T09: 13: 58Z"}

: keepalive
备注Cache-Control: no-store,Connection: keep-alive。EventSource 客户端会在网络中断后自动重连。
GET/api/v1/visa/live/recent公开 — 无需认证不计入配额

最近活动快照

与 /live 相同的数据,但以单个 JSON 快照返回 — 最近 20 个事件、汇总计数器和今日最热门的 5 条查询走廊。边缘缓存 5 秒。

示例
curl "https://visa.orizn.app/api/v1/visa/live/recent"

响应 · 200 OK
{
  "entries": [
    { "passport": "USA", "destination": "JPN", "timestamp": "2026-05-31T09: 14: 00Z" },
    { "passport": "IND", "destination": "ARE", "timestamp": "2026-05-31T09: 13: 58Z" }
  ],
  "stats": { "today": 14328, "this_week": 92041, "total": 1248302 },
  "top_corridors": [
    { "pair": "USA→JPN", "count": 412 },
    { "pair": "IND→ARE", "count": 388 },
    { "pair": "DEU→THA", "count": 301 }
  ]
}
备注Cache-Control: public, max-age=5.
推送通知

为设备(iOS / Android)订阅政策变更提醒。

POST/api/v1/visa/devicesapi key · 任意套餐不计入配额

注册设备接收推送

订阅 APNs / FCM 设备令牌,在签证政策变化时接收推送通知。每台设备关注一本护照,可选目的地愿望清单和一组偏好(即时提醒、每周摘要、仅愿望清单、仅利好变化)。

请求体
{
  "device_token": "8a3f...e2b1",
  "passport_iso3": "FRA",
  "platform": "ios",
  "bundle_id": "com.orizn-visa",
  "wishlist_iso3": ["THA", "JPN", "BRA"],
  "locale": "en",
  "tz": "Europe/Paris",
  "premium": false,
  "preferences": {
    "instant": true,
    "digest_weekly": true,
    "only_wishlist": false,
    "only_positive": false
  }
}
示例
curl -X POST "https://visa.orizn.app/api/v1/visa/devices" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "device_token": "8a3f...e2b1", "passport_iso3": "FRA", "platform": "ios", "bundle_id": "com.orizn-visa", "wishlist_iso3": ["THA", "JPN", "BRA"], "locale": "en", "tz": "Europe/Paris", "premium": false, "preferences": { "instant": true, "digest_weekly": true, "only_wishlist": false, "only_positive": false } }'
响应 · 200 OK
{ "device_id": 42 }
错误码
400缺少 device_token、passport_iso3 无效,或 wishlist_iso3 不是数组401缺少 api key403api key 无效500内部错误
备注按 device_token 执行 upsert — 重复提交同一令牌会更新已有订阅。
PATCH/api/v1/visa/devices/{id}api key · 任意套餐不计入配额

更新设备订阅

更新订阅的任意字段子集 — 护照、愿望清单、语言、时区、premium 标记、偏好。至少需要一个字段。

请求体
{
  "wishlist_iso3": ["THA", "JPN", "BRA", "PRT"],
  "preferences": { "only_wishlist": true }
}
示例
curl -X PATCH "https://visa.orizn.app/api/v1/visa/devices/42" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "wishlist_iso3": ["THA", "JPN", "BRA", "PRT"], "preferences": { "only_wishlist": true } }'
响应 · 200 OK
{ "updated": true, "device_id": 42 }
错误码
400请求体无效、没有可更新的字段、护照或愿望清单格式错误401缺少 api key403api key 无效404设备未找到
DELETE/api/v1/visa/devices/{id}api key · 任意套餐不计入配额

取消设备订阅

永久删除设备订阅。用户撤销通知或卸载应用时调用。

示例
curl -X DELETE "https://visa.orizn.app/api/v1/visa/devices/42" \
  -H "x-api-key: YOUR_API_KEY"
响应 · 200 OK
{ "deleted": true, "device_id": 42 }
错误码
401缺少 api key403api key 无效404设备未找到
Webhooks

服务器到服务器的政策变更推送。HMAC 签名的载荷。

GET/api/v1/visa/webhooksapi key · business 及以上不计入配额

列出你的 webhook

返回你账户下的所有 webhook 订阅,包括筛选条件、最近触发时间和失败计数器。

示例
curl "https://visa.orizn.app/api/v1/visa/webhooks" \
  -H "x-api-key: YOUR_API_KEY"
响应 · 200 OK
{
  "webhooks": [
    {
      "id": 17,
      "url": "https://your-app.com/orizn-hook",
      "passport_filter": ["FRA"],
      "destination_filter": null,
      "active": true,
      "created_at": "2026-05-29T09: 14: 00Z",
      "last_triggered_at": "2026-05-31T08: 02: 11Z",
      "failures": 0
    }
  ]
}
错误码
401缺少 api key403密钥无效或套餐低于 Business
POST/api/v1/visa/webhooksapi key · business 及以上不计入配额

创建 webhook

注册一个 URL,当政策变更命中你的筛选条件时接收 POST。响应中含一次性 secret — 立即保存,之后不再显示。签名验证使用以该 secret 为密钥、对原始请求体计算的 HMAC-SHA256。

请求体
{
  "url": "https://your-app.com/orizn-hook",
  "passport_filter": ["FRA"],
  "destination_filter": ["THA", "JPN"]
}
示例
curl -X POST "https://visa.orizn.app/api/v1/visa/webhooks" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "url": "https://your-app.com/orizn-hook", "passport_filter": ["FRA"], "destination_filter": ["THA", "JPN"] }'
响应 · 200 OK
{
  "webhook": {
    "id": 17,
    "url": "https://your-app.com/orizn-hook",
    "passport_filter": ["FRA"],
    "destination_filter": ["THA", "JPN"],
    "active": true,
    "secret": "whsec_4f2a91c8...e2b1",
    "created_at": "2026-05-31T09: 14: 00Z"
  },
  "message": "Webhook created. Store the secret — it won't be shown again."
}
错误码
400请求体或 url 无效401缺少 api key403密钥无效或套餐低于 Business
备注返回 201 Created。
DELETE/api/v1/visa/webhooks?id={id}api key · business 及以上不计入配额

删除 webhook

永久删除你名下的 webhook 订阅。

参数
参数类型必填描述
idintWebhook id,来自 list/create。
示例
curl -X DELETE "https://visa.orizn.app/api/v1/visa/webhooks?id=42?id=42" \
  -H "x-api-key: YOUR_API_KEY"
响应 · 200 OK
{ "deleted": true, "id": 17 }
错误码
400缺少 id 查询参数401缺少 api key403密钥无效或套餐低于 Business404webhook 未找到或不属于你
团队密钥

按环境划分的子密钥,共享主账户配额。

GET/api/v1/visa/team-keysapi key · business 及以上不计入配额

列出团队密钥

返回你账户下的所有团队子密钥。每个团队密钥继承所有者的套餐并共享同一月度配额 — 适合隔离环境或归因用量。

示例
curl "https://visa.orizn.app/api/v1/visa/team-keys" \
  -H "x-api-key: YOUR_API_KEY"
响应 · 200 OK
{
  "team_keys": [
    {
      "id": 7,
      "api_key": "orizn_visa_team_a1b2c3...",
      "name": "ci-staging",
      "active": true,
      "requests_month": 14823,
      "requests_total": 184238,
      "created_at": "2026-05-12T11: 04: 00Z"
    }
  ]
}
错误码
401缺少 api key403密钥无效或套餐低于 Business
POST/api/v1/visa/team-keysapi key · business 及以上不计入配额

创建团队密钥

创建新的团队子密钥。密钥以 orizn_visa_team_ 为前缀,可立即用于 x-api-key 请求头。与所有者账户共享配额。

请求体
{ "name": "ci-staging" }
示例
curl -X POST "https://visa.orizn.app/api/v1/visa/team-keys" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "ci-staging" }'
响应 · 200 OK
{
  "team_key": {
    "id": 7,
    "api_key": "orizn_visa_team_a1b2c3...",
    "name": "ci-staging",
    "active": true,
    "requests_month": 0,
    "requests_total": 0,
    "created_at": "2026-05-31T09: 14: 00Z"
  },
  "message": "Team key created. It shares the monthly quota of the owner account."
}
错误码
400name 缺失/为空401缺少 api key403密钥无效或套餐低于 Business
备注返回 201 Created。
DELETE/api/v1/visa/team-keys?id={id}api key · business 及以上不计入配额

停用团队密钥

软删除 — 将 active 置为 false。使用该密钥的请求立即开始返回 403。

参数
参数类型必填描述
idint团队密钥 id。
示例
curl -X DELETE "https://visa.orizn.app/api/v1/visa/team-keys?id=42?id=42" \
  -H "x-api-key: YOUR_API_KEY"
响应 · 200 OK
{ "deactivated": true, "team_key": { "id": 7, "name": "ci-staging" } }
错误码
400缺少 id 查询参数401缺少 api key403密钥无效或套餐低于 Business404未找到、不属于你,或已停用
账户与计费

自助注册、密钥轮换,以及 Stripe 托管的计费流程。

POST/api/v1/visa/register公开 — 无需认证不计入配额

注册(获取免费 API 密钥)

自助注册。返回 free 套餐 API 密钥(每月 50 次请求)。按邮箱幂等 — 重复注册返回已有密钥而不会创建重复账户。

请求体
{ "name": "Ada Lovelace", "email": "[email protected]" }
示例
curl -X POST "https://visa.orizn.app/api/v1/visa/register" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Ada Lovelace", "email": "[email protected]" }'
响应 · 200 OK
{
  "api_key": "orizn_visa_a06113a2e4f0...",
  "plan": "free",
  "message": "API key created successfully."
}
错误码
400JSON 无效、缺少 name/email、邮箱格式错误500数据库错误
GET/api/v1/visa/auth/ensure-key会话 cookie不计入配额

获取当前登录用户的 API 密钥

控制台辅助端点:先用 api.orizn.app/auth/me 校验 orizn_token cookie,再返回对应的 visa_api_users 记录 — 若该 Orizn 账户还没有密钥,则以 free 套餐自动创建。

示例
curl "https://visa.orizn.app/api/v1/visa/auth/ensure-key" \
  --cookie "orizn_token=YOUR_SESSION"
响应 · 200 OK
{
  "user": {
    "id": 42,
    "orizn_id": "01HZ...",
    "email": "[email protected]",
    "name": "Ada Lovelace",
    "photo": "https://...",
    "plan": "pro",
    "api_key": "orizn_visa_a06113...",
    "requests_month": 14238,
    "requests_total": 412938,
    "monthly_limit": 250000,
    "created_at": "2026-04-12T11: 04: 00Z"
  }
}
错误码
400无法从会话解析用户身份401orizn_token cookie 缺失或无效
POST/api/v1/visa/auth/regenerate-key会话 cookie不计入配额

轮换 API 密钥

生成新密钥并作废旧密钥。怀疑密钥泄露时使用。仅影响所有者本身,不影响团队子密钥。

示例
curl -X POST "https://visa.orizn.app/api/v1/visa/auth/regenerate-key" \
  --cookie "orizn_token=YOUR_SESSION" \
  -H "Content-Type: application/json" \
  -d '{}'
响应 · 200 OK
{
  "api_key": "orizn_visa_b71224...",
  "message": "API key rotated. Update your clients."
}
错误码
400无法解析用户身份401会话缺失或无效404该用户没有有效的 API 账户
POST/api/v1/visa/stripe/checkout会话 cookie不计入配额

发起付费套餐结账

返回 Stripe Checkout 会话 URL。将用户重定向过去;支付成功后 Stripe 回调我们的 webhook 完成套餐升级。年付且携带有效 affiliate_id 可获 30 天试用。

请求体
{
  "plan": "pro",
  "billing": "monthly",
  "affiliate_id": "aff_4f2a91c8"
}
示例
curl -X POST "https://visa.orizn.app/api/v1/visa/stripe/checkout" \
  --cookie "orizn_token=YOUR_SESSION" \
  -H "Content-Type: application/json" \
  -d '{ "plan": "pro", "billing": "monthly", "affiliate_id": "aff_4f2a91c8" }'
响应 · 200 OK
{ "url": "https://checkout.stripe.com/c/pay/cs_test_..." }
错误码
400套餐无效、该套餐不支持年付、无法解析邮箱401会话缺失或无效
备注plan:hobby、starter、pro、business 之一。billing:monthly | annual。
POST/api/v1/visa/stripe/portal会话 cookie不计入配额

打开 Stripe 计费门户

返回进入 Stripe 客户门户的一次性 URL — 发票、支付方式、套餐变更、取消订阅。

示例
curl -X POST "https://visa.orizn.app/api/v1/visa/stripe/portal" \
  --cookie "orizn_token=YOUR_SESSION" \
  -H "Content-Type: application/json" \
  -d '{}'
响应 · 200 OK
{ "url": "https://billing.stripe.com/p/session/..." }
错误码
400无法解析邮箱401会话缺失或无效404没有 Stripe 客户(很可能仍在免费套餐)
联盟计划

推荐订阅可赚取 15% 佣金 — 网页 + iOS。

POST/api/v1/visa/affiliate/register公开 — 无需认证不计入配额

成为联盟伙伴

开通合作伙伴账户。我们签发一个 affiliate_id(格式 aff_<8 位十六进制>),嵌入你的 checkout URL 后,你推荐的每笔订阅可赚取 15% 佣金。按邮箱幂等。

请求体
{
  "name": "Ada Lovelace",
  "email": "[email protected]",
  "website": "https://travelblog.example",
  "payment_method": "paypal",
  "payment_info": "[email protected]",
  "source": "web"
}
示例
curl -X POST "https://visa.orizn.app/api/v1/visa/affiliate/register" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Ada Lovelace", "email": "[email protected]", "website": "https://travelblog.example", "payment_method": "paypal", "payment_info": "[email protected]", "source": "web" }'
响应 · 200 OK
{
  "affiliate_id": "aff_4f2a91c8",
  "dashboard_url": "https://visa.orizn.app/affiliate?aff=aff_4f2a91c8&email=ada%40example.com",
  "message": "Affiliate account ready. Share your link to earn 15% commission."
}
错误码
400JSON 无效、字段缺失、email/website/payment_method 格式错误409唯一约束竞争 — 请重试500内部错误
备注应用商店联盟伙伴的 website 可以是字面量 ios-app。首次注册返回 201,联盟伙伴已存在时返回 200。
POST/api/v1/visa/affiliate/track-click公开 — 无需认证不计入配额

记录联盟点击

为 affiliate_id 累加点击计数。可从落地页和广告素材中即发即忘地调用。

请求体
{ "affiliate_id": "aff_4f2a91c8" }
示例
curl -X POST "https://visa.orizn.app/api/v1/visa/affiliate/track-click" \
  -H "Content-Type: application/json" \
  -d '{ "affiliate_id": "aff_4f2a91c8" }'
响应 · 200 OK
{ "ok": true }
错误码
400affiliate_id 缺失或格式错误404联盟伙伴未找到或已停用500内部错误
POST/api/v1/visa/affiliate/apply-referralapi key · 任意套餐不计入配额

将推荐关系绑定到用户

注册后将你的账户绑定到推荐人 — 典型场景是 iOS 应用在注册后收集推荐码。需要你的 API 密钥:被推荐账户即密钥所有者。设置 referred_by;推荐人从你未来的订阅中赚取 15%。

请求体
{ "referral_code": "aff_4f2a91c8" }
示例
curl -X POST "https://visa.orizn.app/api/v1/visa/affiliate/apply-referral" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "referral_code": "aff_4f2a91c8" }'
响应 · 200 OK
{
  "ok": true,
  "message": "Referral applied successfully. The referrer will earn 15% commission on your future subscriptions.",
  "referred_by": "aff_4f2a91c8"
}
错误码
400字段缺失、格式错误,或尝试自我推荐401缺少 api key403api key 无效404推荐码无效或已停用500内部错误
GET/api/v1/visa/affiliate/stats公开 — 无需认证不计入配额

联盟控制台数据

联盟账户的累计与本月业绩:点击、转化、推荐用户、收入、按产品和平台的佣金明细,以及最近 20 笔交易。通过 orizn_token cookie(Orizn 账户登录)或 affiliate_id + email 查询参数认证。

参数
参数类型必填描述
affiliate_idstring无会话 cookie 时必填。格式 aff_<8 位十六进制>。
emailstring无会话 cookie 时必填。必须与联盟伙伴的邮箱一致。
示例
curl "https://visa.orizn.app/api/v1/visa/affiliate/stats"
响应 · 200 OK
{
  "affiliate_id": "aff_4f2a91c8",
  "active": true,
  "source": "web",
  "clicks": 1423,
  "conversions": 28,
  "referred_users": 28,
  "revenue_cents": 419800,
  "commission_rate": 0.15,
  "commission_cents": 62970,
  "this_month": { "transactions": 7, "revenue_cents": 138600, "commission_cents": 20790 },
  "by_product": {
    "orizn.visa.premium.annual":  { "transactions": 18, "commission_cents": 47100 },
    "orizn.visa.premium.monthly": { "transactions": 10, "commission_cents": 15870 }
  },
  "by_platform": { "ios": 22, "web": 6 },
  "recent_transactions": [
    { "product": "orizn.visa.premium.annual", "platform": "ios", "amount_cents": 19800, "commission_cents": 2970, "date": "2026-05-30T18: 14: 00Z" }
  ],
  "payment_method": "paypal",
  "payment_info_masked": "a***@paypal.com",
  "links": {
    "visa_app": "https://visa.orizn.app?aff=aff_4f2a91c8",
    "guide":    "https://visa.orizn.app/guide?aff=aff_4f2a91c8",
    "extension": "https://visa.orizn.app/extension?aff=aff_4f2a91c8",
    "api":      "https://visa.orizn.app/api?aff=aff_4f2a91c8"
  }
}
错误码
401无 cookie 且无 affiliate_id + email 查询参数404联盟伙伴未找到500内部错误
/visa 端点返回什么

30 项数据

每个 GET /api/v1/visa 响应最多携带 32 个字段。与某组合无关的字段会是 null、空数组或被省略 — 你可以依赖结构,但不要依赖字段一定存在。

核心字段(始终存在)
字段类型描述
passportstringISO 3166-1 alpha-3(如 FRA)
destinationstringISO 3166-1 alpha-3(如 JPN)
requirementenumvisa_free | visa_required | e_visa | visa_on_arrival | eta | no_admission
visa_free_daysint | null免签允许的天数(需要签证时为null)
visa_requiredbool需要任何签证手续时为 true
descriptionstring本地化的人类可读摘要
documents_requiredstring[]需要携带/提交的文件
processstring[]逐步申请流程
tipsstring[]旅行贴士
country_infoobject货币、语言、时区、首都
verifiedboolTrue only when an official source confirms this exact pair
sourcestring | nullWhere the value came from (e.g. official, manual)
source_urlstring | nullOfficial page this pair was read from — null until the pair has been re-sourced
last_verified_atstring | nullISO 8601 date source_url was last read — null whenever source_url is null
requirement_statusstringOnly on legally unsettled pairs. Currently the single value uncertain — key absent otherwise
requirement_status_notestring | nullPlain-English reason the regime is unsettled, safe to show to a traveler
扩展情报(可选,仅在相关时返回)
字段类型它告诉你什么
transit_visaobject过境签规则及主要枢纽的免签过境时长
passport_validity_monthsint入境时要求的护照最短有效期
visa_feeobject单次与多次入境签证费用,含币种
processing_daysobject标准 / 加急 / 特急办理时长
photo_specsobject照片尺寸(mm)、背景、眼镜与头饰规定
vaccinations_requiredstring[]强制疫苗(如 yellow_fever)
insurance_requiredobject要求的旅行保险最低保额
dual_nationality_warningsstring[]针对双重国籍者的警示(如兵役)
stamp_warningsstring[]可能导致拒绝入境的护照印章
minor_rulesobject18 岁以下旅行者的规定
overstay_penaltyobject逾期滞留的每日罚款、禁令时长、刑事责任
entry_by_modeobject空运 / 陆路 / 海路入境的不同停留期限
remote_work_visaobject数字游民签证的有无、时长、费用
extension_rulesobject能否延长停留、最长天数、费用、办理地点
reciprocity_historyobject[]两国之间的历史政策变更
safetyobject旅行警示级别(1–4),含来源和最近更新
best_apply_periodstring建议的申请时间窗口
health_requirementsobjectCOVID 检测、疫苗证明、隔离、健康筛查
embassy.your_embassy_at_destinationobject你的国家驻目的地使馆 — 用于紧急情况
embassy.visa_application_embassyobject目的地驻你国使馆 — 递交申请的地方
provenance, freshness, and what we do when the law is unclear

Data quality

Provenance — where a value came from

Every /visa response carries source_url and last_verified_at: the official page a pair was read from, and the date it was last read. Cite them in your own UI — that is what they are for.

Both fields are null on pairs that have not been re-sourced yet, and that is most of them. 56 of the 199 passport countries currently have an official source on file; the rest are answered from the consolidated dataset without a citation. A null here means we cannot show you a document, not that the answer is wrong — but if your product makes a claim a user could act on, treat a null as unverified and say so.

Coverage grows; the numbers above are a snapshot, not a ceiling. Do not branch on the count — branch on the field.

requirement_status: "uncertain" — when the law itself is unsettled

Most visa datasets answer every pair with a definite requirement, because their schema has no way to say anything else. Some pairs do not have a definite answer. When a country leaves a bloc whose freedom-of-movement treaty was the legal basis for entry, what happens at the border and what the law guarantees stop being the same thing. Burkina Faso, Mali and Niger left ECOWAS on 2025-01-29: visa-free movement between them and the remaining member states now rests on unilateral, revocable declarations rather than on a treaty.

On those pairs the response carries requirement_status: "uncertain" and a requirement_status_note you can show to a traveler verbatim. requirement itself is untouched — it stays visa_free, because that is what happens at the border today. The status says the right no longer exists; the requirement says the practice continues. Both are true, and a comparison test found no other source that reports the difference.

Because it is a separate, additive field, a client that ignores it sees no change at all — nothing breaks, you simply keep the old blind spot. The key is absent on every pair that is not affected, so test for presence, not for a value. Currently uncertain is the only value.

What /decision cannot decide

Three gaps, stated here because an endpoint you are meant to defend a decision with has to name its blind spots. They also come back inside every response, in the unknowns array, per field and per country — you never have to remember this page at runtime.

  • Transit is a dead end on most of the map. A transit rule exists for 44 of 250 destinations and is recorded per transited country, not per nationality — so even where it exists it never says whether this passport may transit. Every other destination returns status: "unknown". Confirm transit with the carrier, always.
  • residence and purpose are accepted, echoed back, and not modelled. The dataset has no residence dimension and covers short-stay tourism only. Send a residence different from the passport, or a purpose other than tourism, and you get an entry in unknowns saying exactly that — a residence permit may grant rights this endpoint cannot see.
  • Length of stay is only computed where a numeric allowance exists. visa_free_days is the one figure the dataset holds; where the permitted stay depends on the permit issued, max_stay is unknown rather than a parsed guess, and no accumulation blocker can be raised for that country.

verdict: "no_blocker_found" is worded the way it is on purpose. It means the checks that could run found nothing — not that the trip is cleared.

每一档解锁什么

套餐矩阵

功能免费hobby (legacy)starter $49pro $199business $699
每月请求数10010,00030,000250,0001,000,000
突发速率(req/s)102550100200
/visa, /visa/check✓(仅 en)✓(15 种语言)✓(15 种语言)
/visa — 扩展字段占位字段占位字段除 remote-work、reciprocity 外全部全部 32 项全部 32 项
/visa/bulk(全部目的地)
/visa/group(多护照)
/visa/decision (itinerary)
设备推送订阅
Webhooks(服务器到服务器)
团队子密钥
Score, compare, stats, live✓(公开)

Enterprise 套餐另含无限请求、自定义突发速率、私有化部署、专用 IP 和 99.95% SLA。 联系我们。

配额、突发、重置

5. 限制

Quotas reset on the 1st of each calendar month (UTC). Only the five counted endpoints — /visa, /visa/check, /visa/bulk, /visa/group /visa/decision — increment your monthly counter. Score, stats, live, devices, webhooks and team-keys management are 不计入配额.

计划价格月度限额速率亮点
Evaluation$010010 req/snon-commercial evaluation, no SLA
Commercial49$/月30,00050 req/s+ commercial use rights, all 15 languages, extended fields
Production199$/月250,000100 req/s+ uptime SLA, named contact, 1 business day support
Licensefrom $600/mo定制定制+ white-label, redistribution, dataset snapshot

超出配额后会收到 HTTP 429 并附带 X-RateLimit-Reset 标明下一个窗口何时开启。

不解析响应体也能观测

响应头

响应头出现位置
X-RateLimit-Limit你的套餐的月度配额/visa, /visa/check, /visa/bulk
X-RateLimit-Remaining本月剩余调用次数/visa, /visa/check, /visa/bulk
X-RateLimit-Reset下次重置的 ISO 时间戳(仅在 429 时发送)/visa, /visa/check, /visa/bulk
X-Plan你当前的套餐(free、starter、pro、business、enterprise)/visa, /visa/check, /visa/bulk
X-Powered-Byorizn Visa API v1所有需认证端点
X-Orizn-Upgrade升级页面的 URL(仅免费套餐)/visa, /visa/check
VaryAccept(在支持 Markdown 协商时设置)/visa, /visa/check
Cache-Controlpublic, max-age=3600 (stats) · max-age=5 (live/recent) · no-store (live)公开端点
可预期的失败

6. 错误码

错误以结构稳定的 JSON 响应体返回。用 HTTP 状态码做路由,用响应体做诊断;想确切知道每个 4xx 来自哪种条件,请看上方各端点的错误标签。

代码含义典型原因
400无效请求参数缺失或格式错误 — 非 ISO3 代码、不支持的 lang、无效请求体
401未授权缺少 x-api-key 请求头 / api_key 查询参数 / orizn_token cookie
403禁止访问密钥无效或已停用,或你的套餐不包含该端点
404未找到该组合无数据 / 资源不属于你
409冲突唯一约束竞争(联盟注册)— 可安全重试
429请求过多超出月度配额或突发速率
500内部错误后端瞬时故障 — 请用指数退避重试
{
  "error": "Monthly limit exceeded (100 req/month on free plan). Upgrade at https://visa.orizn.app",
  "plan": "free",
  "limit": 50,
  "upgrade_url": "https://visa.orizn.app/visa-api/pricing"
}
15 种语言,一个查询参数

7. 支持的语言

lang 作为查询参数传入(POST 则放在 JSON 请求体中)。默认为 en. 非英语需要 Starter 及以上套餐。

enEnglish
frFrançais
esEspañol
ptPortuguês
deDeutsch
itItaliano
ja日本語
ko한국어
zh中文
ruРусский
arالعربية
hiहिन्दी
thไทย
viTiếng Việt
tlTagalog
带类型、带重试、开箱即用

官方 SDK

手写封装 — 完整类型、自动重试、限流退避,以及结构化错误类型。同样的 30 项数据,处处一致。

npm install orizn              # JavaScript / TypeScript
pip install orizn              # Python
cargo add orizn                # Rust
npx orizn-visa-mcp             # MCP server (Claude, Cursor, Codex)
pip install langchain-orizn    # LangChain Python
npm install @orizn/langchain   # LangChain JS
更新了什么

8. 更新日志

v1.12026 年 5 月

30 项数据 + 完整端点参考

  • /visa 新增 21 个可选字段:过境、费用、照片规格、疫苗、保险、使馆、安全、逾期滞留处罚、互惠历史、远程工作签证、延期规则。
  • 新增 MCP 工具 check_transit_visa;丰富了工具描述,让智能体选对工具。
  • 文档页现已覆盖全部 28 个公开端点 — 签证数据、评分、实时、设备、webhook、团队密钥、账户、联盟。
  • SDK v1.1: [email protected] (npm), orizn==1.1.0 (PyPI), [email protected].
  • 向后兼容 — 老客户端照常工作,新字段只增不改。
v1.02026 年 5 月

发布

  • 覆盖49,750个护照/目的地对
  • 支持15种语言(en、fr、es、pt、de、it、ja、ko、zh、ru、ar、hi、th、vi、tl)
  • 端点:check、visa、bulk、changes、stats、register
  • 计划:Free(50/月)、Starter(49$)、Pro(199$)、Business(699$)、Enterprise
  • 包含使用分析、账单和交互式文档的仪表板