关于 cardcom-payment-gateway
面向为以色列企业构建支付与开票流程的开发者,介绍 Cardcom REST API V11 集成。内容涵盖支付、令牌化、定期扣款和以色列税务凭证,并提供实现与验证指导。
主要功能
- 01REST API V11 支付流程
- 02低配置与服务器端集成模式
- 03令牌化和定期扣款
- 04以色列发票与收据生成
- 05支付及 Webhook 验证
适用场景
- 01为以色列企业应用添加 Cardcom 结账
- 02使用已保存卡片进行定期扣款
- 03在支付时开具税务凭证
- 04创建独立发票或收据
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ skills-il/ tax-and-finance --skill cardcom-payment-gateway安装后在 Claude Code 中输入/cardcom-payment-gateway确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
evidence.jsonmetadata.jsonoptimization-log.jsonSKILL_HE.mdreferences/api-endpoints.mdapi-responses.mddocument-types.mddomain-checklist.mdproduction-checklist.mdscripts/validate_cardcom_response.py详细介绍
Cardcom 支付网关
法律声明
这是一份由 AI 模型运营的免费技术集成指南,说明如何调用 Cardcom API,以及以色列的开票规则与之有何关联。本指南的所有输出均由 AI 模型自动生成,未经税务顾问、会计师或律师参与、审核或批准。本文内容不构成税务意见或专业建议,AI 模型也可能出错、遗漏信息或给出错误结论。
此集成生成的文件属于税务文件。你有责任正确开具这些文件、进行申报并缴纳税款;具有约束力的计算结果以税务局为准;只有法律允许的人员才能在税务局面前代理。特定发票是否需要分配编号,以及能否抵扣进项增值税,应由你的会计师根据你的实际情况作出判断。正式上线前,请税务顾问或会计师审核开票配置,并按照 PCI DSS 处理持卡人数据。使用本技能输出所产生的一切责任均由用户独自承担。
概述
Cardcom 是一家以色列支付处理商,其独特优势在于可集成符合以色列税法的发票和收据生成功能。其他以色列支付网关只处理付款,而 Cardcom 可在支付流程中自动生成税务发票(hashbonit mas)和收据(kabala);以色列企业依法必须开具这两类文件。
本技能涵盖 Cardcom V11 REST API 的支付、令牌化、定期扣款和文件生成功能。端点和字段名称均取自官方 V11 OpenAPI 规范。
官方文档: https://secure.cardcom.solutions/Api/v11/Docs(包含完整 OpenAPI 架构的交互式 API 参考)。截至 2026 年,V11 是当前版本;目前没有公开的 V12。
支持中心: https://support.cardcom.solutions
Cardcom 在以色列市场中的定位: 与 Tranzila 等其他以色列支付网关竞争。Cardcom 公布的起步费率约为 1.2%,且会随交易量增加而下降;这只是最低费率,并非报价,因此应让用户向 Cardcom 索取实际报价。其鲜明特色仍是内置税务文件生成功能。如需集成 Tranzila,请改用 tranzila-payment-gateway 技能。
说明
第 1 步:选择集成模式
| 模式 | 卡数据处理方式 | 适用场景 |
|---|---|---|
| Low Profile(iframe/重定向) | Cardcom 负责处理卡信息输入 | 大多数集成场景,PCI 范围最小(SAQ-A) |
| Transaction(服务器到服务器) | 原始卡数据或令牌 | 扣款使用已存储的令牌、定期扣款 |
| CreateDocument(服务器到服务器) | 不涉及卡数据 | 单独生成发票/收据 |
大多数以色列商户会在首次付款时使用 Low Profile,同时创建令牌;随后使用已存储的令牌,通过 Transaction 端点进行定期扣款。所有支付流程都可以通过附加 Document 对象自动生成发票。
步骤 2:设置身份验证
Cardcom API V11 凭据:
TerminalNumber(整数)——终端 ID(1000是 Cardcom 的测试终端,见下文)ApiName(字符串)——API 用户名ApiPassword(字符串)——API 密码。一般来说:读取或操作公司范围数据的操作需要它;仅对单张卡片扣款的操作则不需要。Transactions/ListTransactions、RefundByTransactionId、SpecialTransactions、Documents/CreateDocument、CancelDoc和Financial/*报表等操作都需要它。它不是LowProfile/Create或Transactions/Transaction的顶层字段,因此不要在这些操作中发送。不同版本的规范中,要求提供此字段的架构会有变化(见注意事项),因此请检查 V11 OpenAPI 规范中端点请求架构的required数组,而不要依赖列表。
测试环境(Cardcom 自有的开发者测试页面):
- 终端
1000。该终端的 API 用户名和密码未公开,请向 Cardcom 支持团队索取。 - 以色列测试卡
4580280000000008(支持分期付款和信用交易);游客测试卡4580000000000000(不支持分期付款或信用交易)。到期日期可填任意未来日期,CVV 填123,身份证号可填任意号码。 - 使用测试卡时,金额低于 5,000 NIS 会模拟成功,高于 5,000 NIS 会模拟失败,因此大额测试扣款失败属于预期情况,并非错误。
- 测试终端交易会走完整的清算流程,但不会实际扣款。使用真实卡在测试终端上操作时不会扣款,但会冻结相应金额的信用额度(מסגרת),为期三天,因此切勿使用客户的卡进行测试。
请将 ApiName、ApiPassword 和所有已存储的令牌视为机密。 Transactions/Transaction 只需要 TerminalNumber、ApiName 和 Amount,因此仅凭 ApiName 和令牌就能对已保存的卡片扣款。请将它们存储在仅供服务器访问的环境变量中(在 Next.js 中,切勿使用 NEXT_PUBLIC_*),仅从服务器端代码调用 Cardcom,并且绝不要记录完整响应(其中包含令牌和持卡人的身份证号)。
步骤 3:实现支付流程
低配置集成(推荐)
这是一个两步流程。
步骤 3a:创建支付页面
POST https://secure.cardcom.solutions/api/v11/LowProfile/Create
Content-Type: application/json
{
"TerminalNumber": 1000,
"ApiName": "your-api-name",
"Operation": "ChargeAndCreateToken",
"ReturnValue": "unique-order-id",
"Amount": 100.00,
"SuccessRedirectUrl": "https://example.com/success",
"FailedRedirectUrl": "https://example.com/failed",
"WebHookUrl": "https://example.com/webhook",
"ISOCoinId": 1,
"Language": "he",
"Document": {
"DocumentTypeToCreate": "TaxInvoiceAndReceipt",
"Name": "Customer Name",
"Email": "[email protected]",
"Products": [
{ "Description": "Product name", "UnitCost": 100.00, "Quantity": 1 }
]
}
}
响应为 CreateLowProfileResponse:检查 ResponseCode == 0(成功),失败时读取 Description。成功时会返回 LowProfileId(请保存)和 Url(将客户重定向到该网址,或将其嵌入 iframe)。如果你的终端启用了这些支付方式,也会返回 UrlToBit 和 UrlToPayPal。
Operation 字段控制行为:ChargeOnly(默认)、ChargeAndCreateToken、CreateTokenOnly、SuspendedDeal、Do3DSAndSubmit。
Document 中各行的金额总和必须与 Amount 完全相等(Cardcom:“יש לדאוג שסה"כ שורות החשבונית שווה לסכום החיוב”),因此行项目价格应填写客户实际支付的金额,含增值税。如果金额不匹配,可能会出现已扣款但未开具发票的情况,因为 Cardcom 会优先处理扣款。
步骤 3b:获取结果
支付完成后,Cardcom 会调用你的 WebHookUrl,或者你可以查询:
POST https://secure.cardcom.solutions/api/v11/LowProfile/GetLpResult
{
"TerminalNumber": 1000,
"ApiName": "your-api-name",
"LowProfileId": "id-from-step-3a"
}
响应为 LowProfileResult,其顶层 ResponseCode 并非支付结果。规范将其描述为“if equel zero then success , else , a develper error”——它只能说明请求格式正确,除此之外不能说明任何情况。银行卡交易结果位于嵌套的 TranzactionInfo 中;规范称其“Will no be null at operations: ChargeOnly, ChargeAndCreateToken”,也就是说,持卡人放弃页面时它为 null。
处理任何履约操作之前,以下五项必须全部满足:
- HTTP 状态码为 200。404 会返回
{"Message": "No HTTP resource was found..."},其中完全没有ResponseCode,因此仅根据ResponseCode == 0分支会把路由错误误判为None。 - 顶层
ResponseCode == 0。 TranzactionInfo不为 null。TranzactionInfo.ResponseCode == 0(其自身的说明为:“if equal zero then success , 700 and 701 success for J2 and J5 transaction”)。TranzactionInfo.Amount等于你预期的金额,且ReturnValue与你自己的订单 ID 匹配。
还要检查 TranzactionInfo.IsRefund / DealType:退款也是成功交易,会通过简单的 ResponseCode == 0 检查。如果你要求开具单据,DocumentInfo 也必须不为 null——如果扣款成功但 DocumentInfo: null,就意味着你收了款却没有开具税务发票(发票开具失败时,Cardcom 会优先处理扣款)。scripts/validate_cardcom_response.py --expect charge --amount <n> --return-value <order-id> --with-document 会执行上述全部检查,并在无法确认时拒绝通过。
切勿在浏览器跳转到由客户控制的 SuccessRedirectUrl 时履约,也不要依据原始 Webhook 请求体履约。TokenInfo 包含存储的 Token 以及 CardMonth/CardYear;SuspendedInfo 用于挂起的交易。
**Webhook 处理程序(WebHookUrl 是 LowProfile/Create 的必填项):**V11 规范未定义其签名、共享密钥或 HMAC,也未说明其负载或重试计划。请将每次调用都视为不可信且可能重复的“发生了某些事情”信号:
- 根据其提供的
LowProfileId,在你从LowProfile/Create保存的 ID 中查找。未知 ID 应忽略,绝不能查询。 - 使用你自己的凭据调用
GetLpResult,并执行上述五项检查。绝不要从 Webhook 请求体读取金额或状态。 - 确保履约操作幂等(在同一事务中检查订单并将其标记为已履约),因为同一事件可能会多次到达。Cardcom 关于旧版
IndicatorUrl接口的文档称,如果你的服务器未返回 HTTP 200,它最多会重发 7 次;应假设 V11 也可能重复发送。 - 先将调用记录写入持久化存储,然后返回 HTTP 200(返回 200 会停止 Cardcom 重发)。同时,使用
GetLpResult扫描待处理订单,不要等待可能永远不会到来的 Webhook;支付页面代码会在创建 24 小时后过期。更多信息请参阅references/production-checklist.md。
替代支付方式
LowProfile/Create 响应中的 UrlToBit 和 UrlToPayPal 是单独的 URL,可与银行卡表单一同显示;在终端上启用 Google Pay 和 Apple Pay 后,它们会作为钱包按钮显示在托管页面中。Apple Pay 不支持保存令牌或定期订单(Cardcom:按钮可能会显示在定期订单页面上,但无法完成付款),因此不能用它支付 ChargeAndCreateToken 订阅页面;在 iframe 中使用时,还需要通过 Cardcom 支持将你的域名注册到 Apple。详情请参阅:references/api-endpoints.md。
第 4 步:生成以色列税务单据
使用 DocumentTypeToCreate 字段设置单据类型。该字段是字符串枚举(不是整数)。常见值:
| 值 | 希伯来语 | 英语 | 适用场景 |
|---|---|---|---|
Auto | --- | Auto | 默认值;使用管理面板配置 |
TaxInvoiceAndReceipt | hashbonit mas / kabala | Tax Invoice + Receipt | 付款的 B2C 交易(最常见) |
TaxInvoice | hashbonit mas | Tax Invoice | B2B 交易,单独开具收据时 |
Receipt | kabala | Receipt | 仅确认付款 |
TaxInvoiceAndReceiptRefund | --- | Tax Invoice + Receipt Refund | 冲销 TaxInvoiceAndReceipt |
TaxInvoiceRefund | --- | Tax Invoice Refund | 冲销 TaxInvoice |
完整的 DocumentToCreate 枚举包含 25 个值,详见 references/document-types.md。其中没有 QuoteRefund 或 OrderRefund,因此不要通过追加 Refund 来杜撰退款变体。
在支付流程中包含单据:
将 Document 对象添加到 Low Profile Create 或 Transaction 请求中。付款成功后,Cardcom 会自动生成单据。
单独创建单据:
POST https://secure.cardcom.solutions/api/v11/Documents/CreateDocument
{
"ApiName": "your-api-name",
"ApiPassword": "your-api-password",
"Document": {
"DocumentTypeToCreate": "TaxInvoice",
"Name": "Customer Ltd",
"TaxId": "123456789",
"Email": "[email protected]",
"IsSendByEmail": true,
"Languge": "he",
"ISOCoinID": 1,
"Products": [
{ "Description": "Web development services", "UnitCost": 5000.00, "Quantity": 1 }
]
}
}
响应为 DocumentInfo:检查 ResponseCode == 0,然后读取 DocumentType、DocumentNumber、AccountId 和 DocumentUrl(PDF 链接)。
三个单据对象中的字段拼写有所不同(Languge 与 Language;而 ISOCoinID 仅存在于此独立 Document 中,不存在于 Low Profile 或 Transaction 单据中);完整字段列表请参阅注意事项和 references/document-types.md。TaxId 取代了旧字段 VAT_Number,IsSendByEmail 取代了 SendByEmail。
第 4.5 步:税务发票上的分配编号(Mispar Haktzaa)
**不要在文档 API 中查找分配编号字段。那里没有这个字段,而且这并非遗漏。**Cardcom 的文档系统已连接税务局,开具超过门槛的税务发票时会直接向税务局申请编号。CreateDocument 请求和 DocumentInfo 响应中都不包含该编号;编号会印在文档上,标题为「מספר הקצאה:」,因此请从 DocumentUrl 处的 PDF 中读取。
**只有完成会过期的注册后,这项功能才会生效。**没有编号时,客户无法抵扣超过门槛的发票上的进项增值税。Cardcom 自己的指南:
- 企业主在税务局个人区域进行身份验证(הזדהות),必要时先注册。
- 公司或 איחוד עוסקים 在那里完成 רישום פרטי תאגיד。
- 在 Cardcom 管理后台中,依次进入 הגדרות、מסמכים、שירות חשבוניות ישראל。生成验证码(קוד אימות);系统会将你转至税务局进行身份验证。只有企业主,或获企业主授权执行数字操作的人,才能进行此操作。
- 按下「בדיקת קבלת מספר הקצאה」,确认系统确实会发放编号。
验证码有效期为 三个月。过期后,开具的发票将不带编号;请重新注册,然后重新打印文档以附上编号。因此,定时开具大额发票的作业必须检查服务是否处于启用状态,不能想当然。错误 Not Acceptable (406) 表示完成身份验证的用户没有该企业的税务局授权:企业主需在「הרשאות לפעולות דיגיטליות」下授予授权,并选择两个事项:「חשבוניות ישראל – אימות מספר הקצאה בחשבונית ספק」和「חשבוניות ישראל – בקשת מספר הקצאה עבור חשבונית ללקוח」。
Cardcom 还说明,以下情况下不会发放编号:缺少客户 ID/公司编号(TaxId);供应商与客户的公司编号相同;或税务发票兼收据不含增值税。
门槛安排(不含增值税;法规措辞为 עולה על,即“超过”):
| 生效日期 | 门槛 |
|---|---|
| 2024 年 5 月 | 25,000 NIS |
| 2025 年 1 月 | 20,000 NIS |
| 2026 年 1 月 1 日 | 10,000 NIS |
| 2026 年 6 月 1 日 | 5,000 NIS(当前生效) |
门槛取决于每份文档自身的日期;较早的文档、osek patur 和零税率发票请参阅 references/document-types.md。即使所有设置都已完成,编号仍可能被拒发:根据 s.47(a2)(3),主管可在有合理理由怀疑发票不合规时决定不分配编号(作出预先决定,即 החלטה מקדמית,并须在两个工作日内举行听证);s.47(a2)(4) 则允许交易方在开具发票后申请编号。请先确认文档上已显示编号,再依赖该编号。
第 4.6 步:幂等性,以及授权与扣款
每次调用 Transactions/Transaction 时都要发送 ExternalUniqTranId。 这是你为这笔扣款设置的唯一 ID,规范明确指出:“发送你的唯一交易 ID 以防止交易重复。如果发送相同的 ExternalUniqTranId,你将收到错误代码 608”。如果不发送,某个 cron 的 HTTP 调用在 Cardcom 扣款后超时,重试时就会向客户重复扣款。
608 表示“此 ID 已收到有效的银行卡响应”,而不是“支付失败”。 Cardcom 的令牌扣款指南指出,调用收到扣款(0)、J2(701)或 J5(700)响应后,该 ID 就会被使用,因此 608 并不能证明已扣款。切勿改用新 ID 重试:出现 608、超时或结果不明确时,调用 POST /api/v11/Transactions/GetTransactionByExternalUniqTran,并根据该记录的 ResponseCode 作出处理(0 = 已扣款;700/701 = 仅已验证或已预授权)。扣款被拒不会占用该 ID,因此可以使用相同 ID 重试;重新发送前,请等待响应(最多 7 秒)。扣款操作要使用自己的 ID,不能使用预授权的 ID。
J2 和 J5 并非一回事,700/701 也不代表客户完全没有受到影响。 JValidateType 适用于 CreateTokenOnly 和 SuspendedDeal 操作,用于选择 J2(简单的银行卡验证,不会预留金额)或 J5(授权,会占用持卡人的信用额度)。在 LowProfile/Create 中,其默认值为 5,因此 CreateTokenOnly 页面会对 Amount 进行 J5 预授权,除非你发送 AdvancedDefinition.JValidateType: 2。要完成 J5 扣款,需使用该令牌进行扣款,并将 Advanced.ApprovalNumber 设为你收到的 TokenInfo.TokenApprovalNumber(规范:“capture an J5 (authoriz) request”)。如果授权一直未扣款,客户的资金会被冻结,直到授权过期;因此,使用 J5 时必须设置扣款步骤和解除预授权的流程(Cardcom 文档说明可使用 MTI=420 和预授权的交易编号;测试终端无法执行 J5,参见 references/production-checklist.md)。
步骤 5:实现基于 Token 的定期付款
对于订阅和定期账单(hora'ot keva),Cardcom 支持两种方式:
- 基于银行卡的定期付款:按计划向已存储的信用卡
Token收费。本步骤将介绍此方式。 - MASAV 银行定期付款指令:直接从客户的以色列银行账户扣款。通过
RecuringPayments端点(RecuringPayments/GetRecurringPayment、GetRecurringPaymentHistory、IsBankNumberValid)进行管理。客户倾向于银行扣款而非银行卡扣款,或无法使用银行卡时,请使用此方式。底层指令由 Cardcom 控制面板配置。
对于基于银行卡的定期付款,首先确认商家已启用 Cardcom 的 tokens 模块,并且使用的终端不要求 CVV(在要求 CVV 的终端上,每次 Token 扣款都需要一次性 J5 批准编号)。如果未启用该模块,Cardcom 仅会保留 Token 6 个月。有关退款的信息,请参阅 references/production-checklist.md。
-
在首次付款时创建 Token。 使用 Low Profile,并设置
Operation: "ChargeAndCreateToken"(或"CreateTokenOnly")。LowProfileResult会返回包含Token、CardMonth、CardYear和TokenExDate的TokenInfo(即 Token 从 Cardcom 中清除的日期)。 -
安全地存储 Token。 保存
Token字符串、银行卡有效期和末 4 位数字。该 Token 与你的终端绑定。 -
通过 Transaction 端点扣款:
POST https://secure.cardcom.solutions/api/v11/Transactions/Transaction
{
"TerminalNumber": 1000,
"ApiName": "your-api-name",
"Token": "token-uuid",
"CardExpirationMMYY": "1227",
"Amount": 99.00,
"ISOCoinId": 1,
"ExternalUniqTranId": "sub-8841-2026-10",
"Document": {
"DocumentTypeToCreate": "TaxInvoiceAndReceipt",
"Name": "Subscriber Name",
"Email": "[email protected]",
"IsSendByEmail": true,
"Products": [
{ "Description": "Monthly subscription", "UnitCost": 99.00, "Quantity": 1 }
]
}
}
ExternalUniqTranId 应为每位订阅者的每个计费周期设置一个唯一 ID,因此重试同一周期会被阻止(608),而下个月的扣款则可以正常进行。响应为 TransactionInfo:只有 ResponseCode == 0 才表示扣款成功(700/701 是 J2/J5 验证结果,不会扣款)。随后读取 TranzactionId、Token、DocumentNumber 和 DocumentUrl。每次 Token 扣款都可以在附加 Document 对象时自动生成并发送发票。如果缺少 DocumentNumber,说明银行卡已扣款,但尚未开具发票;此时应使用 CreateDocument 开具发票,而不是再次扣款。
步骤 6:处理退款
通过 Cardcom 交易 ID 退款:
POST https://secure.cardcom.solutions/api/v11/Transactions/RefundByTransactionId
{
"ApiName": "your-api-name",
"ApiPassword": "your-api-password",
"TransactionId": 219282004,
"PartialSum": 100.00,
"CancelOnly": false,
"AllowMultipleRefunds": false
}
退款必须提供 ApiPassword。PartialSum 用于退还部分交易金额(省略该参数则退还全额)。CancelOnly: true 会在交易存入前将其作废。响应为 RefundByTransactionIdResp:检查 ResponseCode == 0,然后读取 NewTranzactionId(退款交易的 ID)。
要开具相应的贷项凭证,请调用 Documents/CreateDocument,并设置退款凭证类型,例如 TaxInvoiceAndReceiptRefund 或 TaxInvoiceRefund,再通过 DealNumbers: [{"DealNumber": <NewTranzactionId>}] 将其关联到退款交易,而不是原始扣款。Cardcom 较早版本界面的退款指南对此有明确说明:退款后,需要再次调用凭证 API,并将凭证关联到退款交易。对于同一笔退款,也不要调用 Documents/CancelDoc:其规范摘要为“取消凭证并退还信用卡款项”,需要提供 ApiName、ApiPassword、DocumentNumber 和 INTEGER 类型的 DocumentType,并返回 NewDocumentNumber。同时使用它和 RefundByTransactionId 有造成重复退款的风险。对于已有凭证的销售进行全额退款时,可以单独使用 CancelDoc 作为与凭证关联的替代方式;AllowMultipleRefunds(默认值为 false)可防止对同一笔交易重复退款。
步骤 6.5:查询交易以用于报告
要提取某个日期范围内的交易(对账、月度报告、仪表板):
POST https://secure.cardcom.solutions/api/v11/Transactions/ListTransactions
{
"ApiName": "your-api-name",
"ApiPassword": "your-api-password",
"FromDate": "01062026",
"ToDate": "30062026",
"TranStatus": "Success",
"Page": 1,
"Page_size": 100
}
ApiPassword、FromDate、ToDate(DDMMYYYY 格式的字符串,因此 01062026 表示 2026 年 6 月 1 日)、Page(从 1 开始)和 Page_size(10 到 2000)均为必填项。没有 TerminalNumber 字段;要限定到某个终端,请使用 LimitForTerminal。
响应是 GetTranzactionsResp:检查 ResponseCode == 0,然后读取 Tranzactions(TransactionInfo 数组)以及回显的 Page 和 Page_size。继续请求下一页,直到某页返回的行数少于 Page_size。
Transactions/SpecialTransactions 尽管名称如此,却是一个只读端点(参见 references/api-endpoints.md)。
步骤 7:挂起交易(延期扣款)
挂起交易会授权支付意向,但不会立即扣款:
- 使用
Operation: "SuspendedDeal"创建 Low Profile 会话。 LowProfileResult会返回包含SuspendedDealId的SuspendedInfo。- 之后可在 Cardcom 管理面板中扣款,也可使用
POST /api/v11/SuspendedDeals/Charge扣款;该端点只有TerminalNumber、ApiName和SuspendedDealID这几个字段(均为必填项,additionalProperties: false)。**注意大小写:**结果对象中的字段拼写为SuspendedDealId,请求中的字段拼写为SuspendedDealID;请使用请求中的拼写。SuspendedDeals/Cancel和GetSuspendedDealInfo使用相同的三个字段;该组还包含GetSuspendedDeals和UpdateSuspendedDealInfo。
适用于预授权以及交付后收费的服务。这里也适用 JValidateType;在 LowProfile/Create 中,该参数默认为 5(J5),因此挂起交易通常会冻结卡上的金额:请取消不打算扣款的交易。
步骤 8:处理错误
此技能使用的每个端点都会返回一个 ResponseCode 整数和一个 Description 字符串(少数其他端点,例如 GetTransactionInfoById 和 CompanyOperations 查询,会直接返回数组或布尔值)。ResponseCode == 0 表示成功;任何非零值都表示开发者或交易错误,Description 中包含面向用户的原因说明。
import requests
BASE = "https://secure.cardcom.solutions/api/v11"
payload["ExternalUniqTranId"] = order_id # same id on every retry of THIS charge
try:
r = requests.post(f"{BASE}/Transactions/Transaction", json=payload, timeout=30)
except requests.RequestException:
r = None # outcome unknown: the card MAY have been charged
if r is None or r.status_code != 200:
# Never re-charge blind. Ask Cardcom whether the charge went through.
q = requests.post(f"{BASE}/Transactions/GetTransactionByExternalUniqTran",
json={"TerminalNumber": payload["TerminalNumber"],
"ApiName": payload["ApiName"],
"ExternalUniqTranId": order_id}, timeout=30)
resp = q.json() if q.status_code == 200 else None
else:
resp = r.json()
code = resp.get("ResponseCode") if resp else None
if code == 0:
deal_id = resp["TranzactionId"]
elif code == 608:
mark_for_lookup(order_id) # id already answered: look the record up, never re-charge
else:
log_error(f"Cardcom error {code}: {resp.get('Description') if resp else 'no response'}")
务必同时检查 HTTP 状态(200 表示请求已收到)和 ResponseCode(0 表示操作成功)。仅在服务端保存 ApiName/ApiPassword;这些调用都不能从浏览器 JavaScript 中运行。完整的数字错误参考请查阅官方文档 https://secure.cardcom.solutions/Api/v11/Docs;不要将错误代码硬编码为消息映射,而应读取 Description。处理模式请参见 references/api-responses.md。
示例
示例 1:带发票的电子商务结账
用户说:“我想在以色列的电子商务网站上收款,并自动生成税务发票。” 操作:
- 选择 Low Profile,并设置
DocumentTypeToCreate: "TaxInvoiceAndReceipt"。 - 通过
LowProfile/Create创建 Low Profile 页面,并在Document对象中填写产品详情。 - 实现一个
WebHookUrl处理程序,用于调用LowProfile/GetLpResult。 结果:客户付款后,会收到自动生成的哈什博尼特马斯/卡巴拉 PDF,并通过电子邮件发送。
示例 2:SaaS 月度订阅
用户说:“我运营一个 SaaS 产品,需要每月向用户收取 149 NIS,并向他们发送发票。” 操作:
- 首次付款:调用
LowProfile/Create,并设置Operation: "ChargeAndCreateToken"。 - 从
TokenInfo中保存Token、CardMonth、CardYear。 - 每月运行 cron:调用
Transactions/Transaction,使用该令牌、每个计费周期都重新生成的ExternalUniqTranId,以及一个Document对象。 结果:自动定期扣款并按月生成发票。
示例 3:不涉及付款的独立发票
用户说:“我需要为已收到的银行转账付款开具税务发票” 操作:
- 使用
Documents/CreateDocument(不处理付款)。 - 设置
DocumentTypeToCreate: "TaxInvoice"。 - 包含
Name、TaxId、Products[],将IsSendByEmail: true设置为客户的电子邮件地址。 结果:生成税务发票并通过电子邮件发送,不涉及信用卡处理。
示例 4:使用贷项通知单处理退款
用户说:“客户想要退还订单 #5678 的款项,还需要开具贷项通知单” 操作:
- 使用
TransactionId和ApiPassword调用Transactions/RefundByTransactionId。 - 检查
ResponseCode == 0,并读取NewTranzactionId。 - 调用
Documents/CreateDocument,并设置DocumentTypeToCreate: "TaxInvoiceAndReceiptRefund"和DealNumbers: [{"DealNumber": <NewTranzactionId>}]。 结果:退款已处理,并生成了对应的贷项凭证。
示例 5:接受 Bit、Apple Pay 和 Google Pay
用户说:“除了信用卡,我还想让客户使用 Bit、Apple Pay 和 Google Pay 付款” 操作:
- 在终端上启用每种付款方式,然后照常创建 Low Profile 页面。
- 在银行卡表单旁显示
UrlToBit;Apple Pay 和 Google Pay 会显示在页面中(Apple Pay 仅适用于一次性收费,不适用于创建令牌的页面)。 结果:客户可以选择付款方式;Webhook 流程不变。
社区库
- @tsdiapi/cardcom(TypeScript/Node.js)——社区维护的 V11 客户端,未经我们审核。
npm install @tsdiapi/cardcom - CardCom/OpenFields-FrontEnd-React 和 CardCom/OpenFields-Backend-Node ——Cardcom 官方 OpenFields 示例(见下方链接)。
参考链接
| 资源 | URL |
|---|---|
| V11 API 文档(OpenAPI 参考) | https://secure.cardcom.solutions/Api/v11/Docs |
| Cardcom 支持中心 | https://support.cardcom.solutions |
| OpenFields React 示例 | https://github.com/CardCom/OpenFields-FrontEnd-React |
| OpenFields Node.js 示例 | https://github.com/CardCom/OpenFields-Backend-Node |
捆绑资源
参考资料
references/api-endpoints.md——Cardcom REST API V11 端点参考:LowProfile、Transactions、Documents、RecuringPayments、Financial 和 CompanyOperations 路径及其关键请求/响应字段。构建 API 集成时请查阅。references/api-responses.md——V11 的ResponseCode+Description响应模式、各操作的响应对象,以及推荐的错误处理流程。调试失败的 API 调用时请查阅。references/document-types.md——DocumentTypeToCreate字符串枚举、Document对象字段列表,以及根据以色列税法处理 VAT 的方式。确定要生成哪种单据时请查阅。references/production-checklist.md——订阅前提条件、单据总额、J5 释放、Webhook 状态、幂等性和密钥。上线前请阅读。references/domain-checklist.md——本技能接受审核时依据的覆盖范围检查清单。
脚本
scripts/validate_cardcom_response.py——验证 Cardcom V11 API 响应,可以是LowProfileResult,也可以是扁平响应(Transaction、CreateDocument、RefundByTransactionId)。如果缺少预期结果,--expect {charge,token,document,refund,validation}会以失败关闭;--amount和--return-value会与订单进行核对;--with-document会将未开具发票的收费判定为失败。只有ResponseCode为 0 才算成功;除非传入--validation-only,否则 700/701 会被拒绝,因为它们表示 J2/J5 卡片检查通过,但没有发生扣款。608 会报告为重复请求被拦截。运行:python scripts/validate_cardcom_response.py --help
注意事项
- V11 的成功检查条件是
ResponseCode == 0,而不是DealResponse == 0。V11 中不存在DealResponse;受旧版 Cardcom 示例训练的 Agent 会凭空编造这个字段。此技能中的端点会返回ResponseCode和Description字符串。 Document对象中的DocumentTypeToCreate和CreateDocumentUrl中的DocumentType是字符串枚举("TaxInvoiceAndReceipt"、"TaxInvoice"……)。但若干 V11 文档端点使用整数类型:CancelDoc.DocumentType、SendAllDocumentsToEmail.DocumentType、GetReport.DocType和CrossDocument字段。规范未公布整数与名称之间的映射,因此应从 Cardcom 或已有的文档中获取该值,不要猜测。TerminalNumber必须以整数而非字符串形式发送。Agent 经常会把它加上引号。- **不同版本的规范中,
ApiPassword列表会有变化,因此绝不要凭记忆作答。**此技能曾写明Documents/ExternalShopCreateDocument不需要ApiPassword;当前规范要求该字段,而且它引用的TapTransactions路径已不存在。请阅读端点的 schema。反过来说,ApiPassword不是LowProfile/Create或Transactions/Transaction的顶层字段,但如果设置IsRefund/IsRefundDeal(没有原始TransactionId时使用令牌或卡片退款路径),则必须在Advanced/AdvancedDefinition中填写该字段。 - Webhook 未经过身份验证。
LowProfile/Create中没有任何签名或密钥字段,而WebHookUrl是必填字段,并非可选字段。任何知道该 URL 的人都能向其发送 POST 请求,因此它只能触发对你创建的LowProfileId的GetLpResult查询(步骤 3b)。 - 报表端点
ListTransactions和SpecialTransactions不接受TerminalNumber,其 schema 也未列出该字段(两者均标记为additionalProperties: false),因此不要发送该字段。对于ListTransactions,使用LimitForTerminal将查询范围限定到某个终端。日期格式为DDMMYYYY字符串;此外,ListTransactions还要求提供Page,且Page_size必须介于 10 和 2000 之间。 - 留意 V11 中字段的实际拼写:
ISOCoinID/ISOCoinId、IsSendByEmail(而不是SendByEmail)、TaxId(而不是VAT_Number)。**语言字段在不同文档对象中的拼写不同,而且每个 schema 只列出各自的拼写(additionalProperties: false),因此另一种拼写顶多会被忽略:**独立CreateDocument中的Document和Transaction中的DocumentTran使用拼写错误的Languge;而附加到LowProfile/Create的文档DocumentLP使用正确拼写Language。到处都使用Languge会导致 Low Profile 文档语言未按预期设置。 - 当前以色列增值税税率为 18%(自 2025 年 1 月起生效;此前为 17%,因此,重新开具较早时期的文档时,必须采用其日期当时生效的税率)。Cardcom 在服务器端计算增值税,因此文档金额会根据
IsVatFree标志处理。 - PCI 范围:托管式 Low Profile 可让你保持在 SAQ-A 范围内。使用原始
CardNumber/CVV2进行服务器到服务器的Transaction会进入 SAQ-D 范围。当前标准为 PCI DSS v4.0.1;其中 51 项未来生效要求已于 2025 年 3 月 31 日起生效。除非确有理由处理原始卡数据,否则优先使用 Low Profile 或令牌。 - 结算时间由终端配置,而非按请求配置,且无法通过 API 设置。Cardcom 提供按月、按周和每半月结算的周期(日期见
references/api-endpoints.md);在承诺具体日期前,请确认商户终端配置的结算周期。
故障排除
错误:LowProfile/Create 返回非零 ResponseCode
原因:请求存在验证或身份验证问题。
解决方案:读取响应中的 Description 字符串,其中会说明具体问题。确认 TerminalNumber 是整数,且 ApiName 正确。完整的数字错误代码参考见 https://secure.cardcom.solutions/Api/v11/Docs。
错误:“Low Profile 页面已加载,但付款失败”
原因:在测试终端上,超过 5,000 NIS 的测试卡金额会被模拟为失败(Cardcom 的测试页面)。其他情况下,卡片结果会显示在 TranzactionInfo.Description 中;此工具尚未验证其他原因。
解决方案:测试金额低于 5,000 NIS,然后读取 GetLpResult 中的 TranzactionInfo.ResponseCode 和 Description。Cardcom 的文档要求重定向和通知 URL 使用外部(非 localhost)HTTPS 地址,因此开发时请使用隧道。
错误:“退款返回非零 ResponseCode”
原因:缺少 ApiPassword,或交易已入账,但你发送了 CancelOnly: true。
解决方案:每个退款请求都要包含 ApiPassword。仅在入账前使用 CancelOnly: true;入账后,请发送实际退款(省略 CancelOnly 或将其设为 false)。
错误:“发票已创建,但未发送邮件”
原因:IsSendByEmail 被显式设为 false(其默认值为 true),或者缺少 Email 或其无效。
解决方案:将 IsSendByEmail 保持为 true,并在 Document 对象中包含有效的 Email。请检查垃圾邮件文件夹;Cardcom 会使用自己的域名发送邮件。
错误:令牌扣款时 ResponseCode 为 608
原因:某次获得有效卡片响应的调用已使用过相同的 ExternalUniqTranId,该调用可能是扣款,也可能是 J2/J5 检查(规范:“如果再次发送相同的 ExternalUniqTranId,你将收到错误代码 608”)。
解决方案:不要使用新 ID 再次扣款。调用 Transactions/GetTransactionByExternalUniqTran,并根据记录中的 ResponseCode 进行处理:0 表示已向客户扣款,700/701 表示之前的调用仅进行了 J2/J5 检查。
错误:“令牌扣款成功,但没有发票”
原因:Transaction 请求中缺少 Document 对象。
解决方案:每次令牌扣款都要包含完整的 Document 对象,其中包含 DocumentTypeToCreate、Name 和 Products。每笔交易都需单独选择是否生成单据。