关于 didit-proof-of-address
面向需要核验个人地址的应用,介绍 Didit 的地址证明文件验证 API。它提取文件信息、检查真实性信号,并可将提取结果与预期数据比对。
主要功能
- 01分类地址证明文件并提取信息
- 02解析地址并进行地理编码
- 03核对日期、姓名、地址和国家
- 04检查 PDF 与 EXIF 篡改信号
- 05检测二维码和条形码
适用场景
- 01在用户注册时核验地址文件
- 02将提交文件与预期身份信息比对
- 03检查文件日期及潜在篡改
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ didit-protocol/ skills --skill didit-proof-of-address安装后在 Claude Code 中输入/didit-proof-of-address确认已加载。
附带文件scripts/verify_address.py
详细介绍
Didit 地址证明 API
概述
只需一次调用即可验证地址证明文件(图片或 PDF)。系统会对文件进行分类(类型和子类型),提取签发方、日期、持有人姓名和地址,解析地址并进行地理编码,通过 PDF/EXIF 取证检测篡改,并交叉核对可选的 expected_* 值。结果为 Approved 或 Declined,并附带 warnings 列表,说明发现的所有问题。
**定价:**每次调用 $0.20(每个 200 响应都会计费,无论结果是 Approved 还是 Declined;单独调用没有免费额度)。这些是截至 2026 年 11 月 1 日的标价,届时 Didit 将调整定价,每月 500 次免费检查将改为每月 $10 的免费额度。当前价格请查看 didit.me/pricing。
主要限制:
- 格式:JPG、JPEG、PNG、TIFF、PDF、WEBP。支持多页 PDF。加密 PDF 需要提供
document_password。 - 最大上传大小:PDF 为 50 MB,图片为 6 MB(超过限制的文件会返回
400) - 延迟:通常为 5-15 s,多页 PDF 最长约 30 s。客户端超时时间应设置为至少 45 s,且在调用完成前不要重试。
- 按类型划分的文件最大期限(默认值):公共事业账单和银行对账单为 3 个月,政府签发文件及其他文件为 12 个月。1 个月按 30 天计算。可通过
poa_document_age_months(1-120,或 -1 表示不进行期限检查)逐次请求修改。已过期的打印到期日也会使文件失效。 - 拍摄指南:使用全彩,确保所有边角和页面完整可见,且未经过数字编辑。
**功能:**文件分类、基于大模型的提取、地址解析和地理编码(纬度/经度)、语言检测、签发日期和期限检查、姓名/地址/国家交叉核对、PDF 和 EXIF 篡改取证、银行详细信息提取、二维码和条形码检测。
接受的文件类型(document_type):
| 类型 | 示例(document_subtype) |
|---|---|
UTILITY_BILL | 电费、水费、燃气费、网费、电话费、综合公共事业账单 |
BANK_STATEMENT | 账户对账单、信用卡对账单、抵押贷款或贷款对账单 |
GOVERNMENT_ISSUED_DOCUMENT | 税务评估文件、居住证明、选民登记卡 |
OTHER_POA_DOCUMENT | 租赁协议、保险单、雇主证明信 |
无法分类的文件会获得 document_type: "UNKNOWN",并因 INVALID_DOCUMENT_TYPE 被拒绝。
API 参考: https://docs.didit.me/standalone-apis/proof-of-address 功能指南: https://docs.didit.me/core-technology/proof-of-address/overview 警告: https://docs.didit.me/core-technology/proof-of-address/warnings-proof-of-address
身份验证
每个请求都需要 x-api-key 标头。使用 Didit Business Console 中 Developers > API keys 下的应用 API 密钥,或者以编程方式创建账户和密钥(参见入门指南)。具有自定义访问权限的命名密钥需要 Sessions 写入权限才能运行独立检查;仅限特定工作流或仅限已批准会话的密钥无法运行这些检查。
入门指南(尚无账户?)
如果你没有 Didit API 密钥,只需调用 2 次 API 即可创建:
- **注册:**使用
{"email": "[email protected]", "password": "MyStr0ng!Pass"}调用POST https://apx.didit.me/auth/v2/programmatic/register/ - 检查邮箱,获取 6 位验证码
- **验证:**使用
{"email": "[email protected]", "code": "A3K9F2"}调用POST https://apx.didit.me/auth/v2/programmatic/verify-email/。密钥位于响应的application.api_key中。
**添加额度:**调用 GET /v3/billing/balance/ 查询余额;使用 {"amount_in_dollars": 50} 调用 POST /v3/billing/top-up/ 获取 Stripe 结账链接。
完整的平台管理说明(工作流、会话、用户、账单)请参阅 didit-verification-management 技能。
端点
POST https://verification.didit.me/v3/poa/
请求头
| 请求头 | 值 | 必填 |
|---|---|---|
x-api-key | 你的 API 密钥 | 是 |
Content-Type | multipart/form-data | 是 |
请求参数(multipart/form-data)
| 参数 | 类型 | 必填 | 默认值 | 描述 |
|---|---|---|---|---|
document | 文件 | 是 | - | PoA 文档:tiff、jpg、jpeg、png、pdf 或 webp。PDF 最大 50 MB,图像最大 6 MB |
document_password | 字符串 | 否 | - | 加密 PDF 的密码。未提供密码或密码错误时返回 400 |
expected_address | 字符串 | 否 | - | 要核对的地址。系统会对地址进行地理编码,并与文档中的地址进行比较;如果不匹配,或无法验证预期地址,则会添加 ADDRESS_MISMATCH_WITH_PROVIDED |
expected_country | 字符串 | 否 | - | ISO 3166-1 alpha-2 或 alpha-3 代码(ES 或 ESP)。文档中的国家/地区不同,则会添加 POA_COUNTRY_MISMATCH_WITH_PROVIDED |
expected_first_name | 字符串 | 否 | - | 要与 name_on_document 核对的名字(支持模糊匹配和转写)。请与 expected_last_name 一起发送:只有两者都已设置时才会执行姓名核对 |
expected_last_name | 字符串 | 否 | - | 同一核对中的姓氏。得分低于 86(0-100)时会添加 NAME_MISMATCH_WITH_PROVIDED |
poa_languages_allowed | 字符串 | 否 | 全部 51 种受支持语言 | 以逗号分隔的 ISO 639-1 代码,例如 en,es。如果是其他语言,则会添加 UNSUPPORTED_DOCUMENT_LANGUAGE;如果代码未知,则返回 400 和受支持语言列表 |
poa_document_age_months | 字符串 | 否 | utility_bill:3,bank_statement:3,government_issued_document:12,other_poa_document:12 | 使用 key:value 对设置每种类型的最大有效期限。值为 1-120,或使用 -1 表示不检查有效期限。**发送此参数时,请列出你接受的所有类型:**未列出的类型将视为不接受(添加信息性提示 POA_DOCUMENT_NOT_SUPPORTED_FOR_APPLICATION),且不检查有效期限 |
poa_address_mismatch_action | DECLINE / NO_ACTION | 否 | DECLINE | 适用于 ADDRESS_MISMATCH_WITH_PROVIDED、NAME_MISMATCH_WITH_PROVIDED 和 POA_COUNTRY_MISMATCH_WITH_PROVIDED |
poa_document_issues_action | DECLINE / NO_ACTION | 否 | DECLINE | 适用于 DOCUMENT_METADATA_MISMATCH |
poa_document_authenticity_action | DECLINE / NO_ACTION | 否 | DECLINE | 适用于 SUSPECTED_DOCUMENT_MANIPULATION |
poa_unsupported_language_action | DECLINE / NO_ACTION | 否 | DECLINE | 适用于 UNSUPPORTED_DOCUMENT_LANGUAGE |
poa_issuer_not_identified_action | DECLINE / NO_ACTION | 否 | DECLINE | 适用于 ISSUER_NOT_IDENTIFIED |
poa_name_mismatch_action | DECLINE / NO_ACTION | 否 | DECLINE | 接受此参数,但不会应用:姓名不匹配时会遵循 poa_address_mismatch_action |
save_api_request | 布尔值 | 否 | true | true:将请求保存为会话(可在 Business Console 中查看;使用返回的 request_id 调用 GET /v3/session/{sessionId}/decision/;发送 status.updated webhook)。false:不保存任何内容,且无法查询 request_id |
vendor_data | 字符串 | 否 | - | 你的用户标识符,会在响应中返回并保存到会话中 |
metadata | JSON 字符串 | 否 | - | 以字符串字段形式发送的 JSON 对象,例如 {"flow":"onboarding"}。会在响应中返回并保存 |
**沙盒:**沙盒 API 密钥会跳过处理和计费。请求验证后(无效输入仍会返回 400),系统会返回固定的 Approved 模拟响应,且不保存任何内容。
示例
import requests
with open("bill.pdf", "rb") as f:
response = requests.post(
"https://verification.didit.me/v3/poa/",
headers={"x-api-key": "YOUR_API_KEY"},
files={"document": ("bill.pdf", f, "application/pdf")},
data={
"expected_first_name": "Jane",
"expected_last_name": "Doe",
"expected_country": "ESP",
"poa_languages_allowed": "en,es",
"vendor_data": "user-123",
},
timeout=60, # extraction takes 5-15 s, up to ~30 s for multi-page PDFs
)
response.raise_for_status()
poa = response.json()["poa"]
print(poa["status"], poa["poa_formatted_address"], [w["risk"] for w in poa["warnings"]])
const formData = new FormData();
formData.append("document", documentFile); // File or Blob
formData.append("expected_first_name", "Jane");
formData.append("expected_last_name", "Doe");
formData.append("expected_country", "ESP");
formData.append("vendor_data", "user-123");
const response = await fetch("https://verification.didit.me/v3/poa/", {
method: "POST",
headers: { "x-api-key": "YOUR_API_KEY" },
body: formData,
signal: AbortSignal.timeout(60_000),
});
if (!response.ok) throw new Error(`PoA failed: ${response.status} ${await response.text()}`);
const { poa } = await response.json();
console.log(poa.status, poa.warnings.map((w: { risk: string }) => w.risk));
响应(200 OK)
{
"request_id": "4b523a8d-ed32-45e4-8aa8-a89eda459d88",
"poa": {
"issuing_state": "ESP",
"document_type": "UTILITY_BILL",
"document_subtype": "ELECTRICITY_BILL",
"document_language": "es",
"issuer": "Acme Energy",
"issue_date": "2026-09-15",
"expiration_date": null,
"poa_address": "C/ Mayor 10, 2B, 28013 Madrid",
"poa_formatted_address": "Calle Mayor 10, 2B, 28013 Madrid, Spain",
"poa_parsed_address": {
"street_1": "Calle Mayor 10",
"street_2": "2B",
"city": "Madrid",
"region": "Comunidad de Madrid",
"country": "ES",
"postal_code": "28013",
"document_location": {"latitude": 40.4155, "longitude": -3.7074}
},
"expected_details_address": null,
"expected_details_formatted_address": null,
"expected_details_parsed_address": null,
"name_on_document": "JANE DOE",
"extra_fields": {
"bank_account_number": null,
"bank_iban": null,
"bank_sort_code": null,
"bank_routing_number": null,
"bank_swift_bic": null,
"bank_branch_name": null,
"bank_branch_address": null,
"document_phone_number": null,
"additional_names": []
},
"detected_codes": [],
"status": "Approved",
"warnings": []
},
"vendor_data": "user-123",
"metadata": null,
"created_at": "2026-10-12T09:30:00.000000+00:00"
}
即使文档被拒绝,仍会返回 200。以下是账单超出允许有效期限时的警告示例:
{
"risk": "POA_DOCUMENT_EXPIRED",
"feature": "PROOF_OF_ADDRESS",
"additional_data": {
"expiration_reason": "age_window",
"max_age_months": 3,
"document_subtype": "ELECTRICITY_BILL",
"document_type": "UTILITY_BILL",
"issue_date": "2026-02-10"
},
"log_type": "error",
"short_description": "Document expired",
"long_description": "The submitted document is older than the maximum accepted age of 3 months from its issue date, which exceeds the acceptable time period for validity."
}
响应不包含文档文件或取证元数据。设置 save_api_request=true 时,GET /v3/session/{request_id}/decision/ 会在 poa_verifications[] 中返回这些内容(document_file 是临时 URL,约 4 小时后过期)。
状态值及处理方式
| 状态 | 含义 | 操作 |
|---|---|---|
"Approved" | 没有任何警告导致拒绝 | 使用解析出的地址;仍可能存在 information 警告 |
"Declined" | 至少有一条警告的 log_type: "error" | 查看 warnings[].risk,并要求提供另一份文件或修正 expected_* 输入 |
此端点不会返回 In Review 或 Not Finished。请务必读取 poa.status 和 poa.warnings,而不只是 HTTP 状态码。
错误响应
| 代码 | 含义 | 操作 |
|---|---|---|
400 | 请求无效 | 查看响应正文中的字段错误 |
401 | API 密钥已过期 | 轮换密钥,或在 开发者 > API 密钥 中创建新密钥 |
403 | 缺少、错误或已撤销的 API 密钥;无权访问此端点的受限密钥;请求来自密钥 IP 允许列表之外;或额度不足 | 查看 detail 或 error 中的消息:修正 x-api-key 标头或密钥的访问权限,或充值 |
429 | 速率限制:每个密钥每分钟允许 300 个 POST/PATCH/DELETE 请求和 600 个 GET 请求 | 等待 Retry-After 指定的秒数,然后重试 |
此端点产生 400 的原因:没有 document、扩展名不在允许列表中、PDF 超过 50 MB 或图像超过 6 MB、加密 PDF 未提供 document_password 或密码错误、poa_languages_allowed 中包含未知代码、poa_document_age_months 配对错误,或无法处理提取内容的文件({"error": ["Error extracting POA information"]})。额度检查会在任何处理之前进行;额度不足时,403 正文为 {"error": "You don't have enough credits to perform this request. ..."}。
响应字段参考
| 字段 | 类型 | 描述 |
|---|---|---|
request_id | uuid | 当 save_api_request=true 时为会话 ID;否则为一次性关联 ID |
poa.status | string | "Approved" 或 "Declined" |
poa.issuing_state | string/null | 文档所属国家/地区,通常采用 ISO 3166-1 alpha-3(ESP) |
poa.document_type | string | UTILITY_BILL、BANK_STATEMENT、GOVERNMENT_ISSUED_DOCUMENT、OTHER_POA_DOCUMENT 或 UNKNOWN |
poa.document_subtype | string | 例如 ELECTRICITY_BILL、WATER_BILL、ACCOUNT_STATEMENT、CREDIT_CARD_STATEMENT、TAX_ASSESSMENT;无法确定时为 UNKNOWN |
poa.document_language | string/null | ISO 639-1 代码 |
poa.issuer | string/null | 签发公司或组织;null 会添加 ISSUER_NOT_IDENTIFIED |
poa.issue_date | date/null | YYYY-MM-DD;null 会因 UNABLE_TO_EXTRACT_ISSUE_DATE 而拒绝 |
poa.expiration_date | date/null | 文档上印制的到期日期(如有) |
poa.poa_address | string/null | 文档上印制的地址;null 会因 MISSING_ADDRESS_INFORMATION 而拒绝 |
poa.poa_formatted_address | string/null | 地理编码后的标准化地址 |
poa.poa_parsed_address | object/null | {street_1, street_2, city, region, country, postal_code, document_location};country 为 ISO alpha-2 |
poa.poa_parsed_address.document_location | object/null | 文档地址的 {latitude, longitude} |
poa.expected_details_address | string/null | 回显 expected_address |
poa.expected_details_formatted_address | string/null | 地理编码后的 expected_address |
poa.expected_details_parsed_address | object/null | expected_address 的地理编码结果,包含 is_verified 标志 |
poa.name_on_document | string/null | 主要持有人姓名;null 会因 POA_NAME_NOT_DETECTED 而拒绝 |
poa.extra_fields | object | bank_account_number、bank_iban、bank_sort_code、bank_routing_number、bank_swift_bic、bank_branch_name、bank_branch_address、document_phone_number(缺失时为 null)、additional_names(数组) |
poa.detected_codes | array | QR 码和条形码:type、page_number、position、x、y、width、height、page_width、page_height、raw_payload(base64)、parsed_payload(无法解码时为 null) |
poa.warnings | array | {risk, feature, additional_data, log_type, short_description, long_description};feature 始终为 PROOF_OF_ADDRESS |
vendor_data | string/null | 回显你的 vendor_data |
metadata | object/null | 回显你的 metadata |
created_at | string | ISO 8601 UTC 时间戳 |
警告标签
log_type 为 error(设置为 Declined)或 information(无影响)。此端点不会生成 warning。
始终拒绝
| 标签 | 原因 |
|---|---|
MISSING_ADDRESS_INFORMATION | 无法提取地址 |
POA_DOCUMENT_EXPIRED | 文档已超过其类型允许的期限,或文档上印制的到期日期已过。additional_data:expiration_reason(age_window 或 printed_expiration)、document_type、document_subtype、issue_date,以及 max_age_months 或 expiration_date |
INVALID_DOCUMENT_TYPE | 无法归类为 PoA 文档(document_type: "UNKNOWN") |
UNABLE_TO_VALIDATE_DOCUMENT_AGE | 文档有效期检查本身失败 |
UNABLE_TO_EXTRACT_ISSUE_DATE | 未找到签发日期(此端点不支持配置) |
POA_NAME_NOT_DETECTED | 未找到持有人姓名(此端点不支持配置) |
可配置(默认值为 DECLINE,NO_ACTION 会将其设为 information)
| 标签 | 原因 | 选项 |
|---|---|---|
NAME_MISMATCH_WITH_PROVIDED | name_on_document 与 expected_first_name + expected_last_name 不匹配 | poa_address_mismatch_action |
ADDRESS_MISMATCH_WITH_PROVIDED | 文档地址与 expected_address 不同,或无法验证其中一个地址 | poa_address_mismatch_action |
POA_COUNTRY_MISMATCH_WITH_PROVIDED | 文档国家/地区与 expected_country 不同。additional_data:expected_country、extracted_country | poa_address_mismatch_action |
DOCUMENT_METADATA_MISMATCH | 文件为空、文件元数据无法读取,或 EXIF 日期格式错误 | poa_document_issues_action |
SUSPECTED_DOCUMENT_MANIPULATION | 取证发现编辑痕迹:数字签名后修改、叠加文本篡改、使用已知 PDF 编辑器、EXIF 日期不一致或可疑的重新导出。additional_data:reason、detection_method | poa_document_authenticity_action |
UNSUPPORTED_DOCUMENT_LANGUAGE | 语言不在 poa_languages_allowed 中 | poa_unsupported_language_action |
ISSUER_NOT_IDENTIFIED | 未找到签发机构 | poa_issuer_not_identified_action |
此端点上的提示信息(绝不会拒绝)
| 标签 | 原因 |
|---|---|
POA_DOCUMENT_NOT_SUPPORTED_FOR_APPLICATION | 检测到的类型未包含在 poa_document_age_months 中 |
UNPARSABLE_OR_INVALID_ADDRESS | 已读取地址,但无法解析并进行地理编码以获得有效的居住地址 |
此端点绝不会生成 FUTURE_ISSUE_DATE、POOR_DOCUMENT_QUALITY、NAME_MISMATCH_ID_VERIFICATION、POA_NAME_MISMATCH_BETWEEN_DOCUMENTS 和 POA_MAX_ATTEMPTS_EXCEEDED(这些属于工作流会话)。此处不会自动拒绝日期为未来的文档。
常见工作流
基本地址验证
1. POST /v3/poa/ with the document (client timeout >= 45 s)
2. "Approved" -> store poa_formatted_address / poa_parsed_address
"Declined" -> branch on warnings[].risk:
POA_DOCUMENT_EXPIRED -> ask for a more recent document
MISSING_ADDRESS_INFORMATION -> ask for a clearer, complete document
INVALID_DOCUMENT_TYPE -> ask for a utility bill, bank statement or official letter
UNABLE_TO_EXTRACT_ISSUE_DATE -> ask for a document with a visible issue date
SUSPECTED_DOCUMENT_MANIPULATION -> do not accept; ask for the original file
地址与身份交叉核验
独立调用不会与 ID 检查关联,因此请传入您已信任的数据:
1. POST /v3/id-verification/ -> read id_verification.first_name, last_name, issuing_state
(see the didit-id-document-verification skill)
2. POST /v3/poa/ with expected_first_name, expected_last_name, expected_country
(and expected_address if the user typed one)
3. NAME_MISMATCH_WITH_PROVIDED / ADDRESS_MISMATCH_WITH_PROVIDED / POA_COUNTRY_MISMATCH_WITH_PROVIDED
-> Declined by default; send poa_address_mismatch_action=NO_ACTION to only flag them
检索或更正已存储的结果
1. Call with save_api_request=true (default); keep request_id
2. GET /v3/session/{request_id}/decision/ -> poa_verifications[] with document_file and forensics
3. To fix extracted fields after a manual review, PATCH /v3/session/{sessionId}/update-poa-data/
(documented in the didit-verification-management skill)
实用脚本
verify_address.py:通过命令行验证地址证明文档。打印 JSON 响应,然后显示状态、地址和警告风险。
# Requires: pip install requests
export DIDIT_API_KEY="your_api_key"
python scripts/verify_address.py utility_bill.pdf
python scripts/verify_address.py bank_statement.jpg --vendor-data user-123
python scripts/verify_address.py bill.pdf --first-name Jane --last-name Doe --country ESP
python scripts/verify_address.py bill.pdf --expected-address "Calle Mayor 10, 28013 Madrid" --languages en,es
python scripts/verify_address.py bill.pdf --document-age utility_bill:6,bank_statement:6,government_issued_document:12,other_poa_document:12
python scripts/verify_address.py locked.pdf --password "pdf-password" --no-save