mcpField
C
cardcom-payment-gateway

cardcom-payment-gateway

github.com/skills-il开发38166 次安装1 天前更新
代码仓库

关于 cardcom-payment-gateway

面向为以色列企业构建支付与开票流程的开发者,介绍 Cardcom REST API V11 集成。内容涵盖支付、令牌化、定期扣款和以色列税务凭证,并提供实现与验证指导。

主要功能

  1. 01REST API V11 支付流程
  2. 02低配置与服务器端集成模式
  3. 03令牌化和定期扣款
  4. 04以色列发票与收据生成
  5. 05支付及 Webhook 验证

适用场景

  1. 01为以色列企业应用添加 Cardcom 结账
  2. 02使用已保存卡片进行定期扣款
  3. 03在支付时开具税务凭证
  4. 04创建独立发票或收据

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/skills-il/tax-and-finance --skill cardcom-payment-gateway

安装后在 Claude Code 中输入/cardcom-payment-gateway确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

evidence.json
metadata.json
optimization-log.json
SKILL_HE.md
references/
api-endpoints.md
api-responses.md
document-types.md
domain-checklist.md
production-checklist.md
scripts/
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。

处理任何履约操作之前,以下五项必须全部满足:

  1. HTTP 状态码为 200。404 会返回 {"Message": "No HTTP resource was found..."},其中完全没有 ResponseCode,因此仅根据 ResponseCode == 0 分支会把路由错误误判为 None。
  2. 顶层 ResponseCode == 0。
  3. TranzactionInfo 不为 null。
  4. TranzactionInfo.ResponseCode == 0(其自身的说明为:“if equal zero then success , 700 and 701 success for J2 and J5 transaction”)。
  5. 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,也未说明其负载或重试计划。请将每次调用都视为不可信且可能重复的“发生了某些事情”信号:

  1. 根据其提供的 LowProfileId,在你从 LowProfile/Create 保存的 ID 中查找。未知 ID 应忽略,绝不能查询。
  2. 使用你自己的凭据调用 GetLpResult,并执行上述五项检查。绝不要从 Webhook 请求体读取金额或状态。
  3. 确保履约操作幂等(在同一事务中检查订单并将其标记为已履约),因为同一事件可能会多次到达。Cardcom 关于旧版 IndicatorUrl 接口的文档称,如果你的服务器未返回 HTTP 200,它最多会重发 7 次;应假设 V11 也可能重复发送。
  4. 先将调用记录写入持久化存储,然后返回 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默认值;使用管理面板配置
TaxInvoiceAndReceipthashbonit mas / kabalaTax Invoice + Receipt付款的 B2C 交易(最常见)
TaxInvoicehashbonit masTax InvoiceB2B 交易,单独开具收据时
ReceiptkabalaReceipt仅确认付款
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 自己的指南:

  1. 企业主在税务局个人区域进行身份验证(הזדהות),必要时先注册。
  2. 公司或 איחוד עוסקים 在那里完成 רישום פרטי תאגיד。
  3. 在 Cardcom 管理后台中,依次进入 הגדרות、מסמכים、שירות חשבוניות ישראל。生成验证码(קוד אימות);系统会将你转至税务局进行身份验证。只有企业主,或获企业主授权执行数字操作的人,才能进行此操作。
  4. 按下「בדיקת קבלת מספר הקצאה」,确认系统确实会发放编号。

验证码有效期为 三个月。过期后,开具的发票将不带编号;请重新注册,然后重新打印文档以附上编号。因此,定时开具大额发票的作业必须检查服务是否处于启用状态,不能想当然。错误 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。

  1. 在首次付款时创建 Token。 使用 Low Profile,并设置 Operation: "ChargeAndCreateToken"(或 "CreateTokenOnly")。LowProfileResult 会返回包含 Token、CardMonth、CardYear 和 TokenExDate 的 TokenInfo(即 Token 从 Cardcom 中清除的日期)。

  2. 安全地存储 Token。 保存 Token 字符串、银行卡有效期和末 4 位数字。该 Token 与你的终端绑定。

  3. 通过 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:挂起交易(延期扣款)

挂起交易会授权支付意向,但不会立即扣款:

  1. 使用 Operation: "SuspendedDeal" 创建 Low Profile 会话。
  2. LowProfileResult 会返回包含 SuspendedDealId 的 SuspendedInfo。
  3. 之后可在 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:带发票的电子商务结账

用户说:“我想在以色列的电子商务网站上收款,并自动生成税务发票。” 操作:

  1. 选择 Low Profile,并设置 DocumentTypeToCreate: "TaxInvoiceAndReceipt"。
  2. 通过 LowProfile/Create 创建 Low Profile 页面,并在 Document 对象中填写产品详情。
  3. 实现一个 WebHookUrl 处理程序,用于调用 LowProfile/GetLpResult。 结果:客户付款后,会收到自动生成的哈什博尼特马斯/卡巴拉 PDF,并通过电子邮件发送。
示例 2:SaaS 月度订阅

用户说:“我运营一个 SaaS 产品,需要每月向用户收取 149 NIS,并向他们发送发票。” 操作:

  1. 首次付款:调用 LowProfile/Create,并设置 Operation: "ChargeAndCreateToken"。
  2. 从 TokenInfo 中保存 Token、CardMonth、CardYear。
  3. 每月运行 cron:调用 Transactions/Transaction,使用该令牌、每个计费周期都重新生成的 ExternalUniqTranId,以及一个 Document 对象。 结果:自动定期扣款并按月生成发票。
示例 3:不涉及付款的独立发票

用户说:“我需要为已收到的银行转账付款开具税务发票” 操作:

  1. 使用 Documents/CreateDocument(不处理付款)。
  2. 设置 DocumentTypeToCreate: "TaxInvoice"。
  3. 包含 Name、TaxId、Products[],将 IsSendByEmail: true 设置为客户的电子邮件地址。 结果:生成税务发票并通过电子邮件发送,不涉及信用卡处理。
示例 4:使用贷项通知单处理退款

用户说:“客户想要退还订单 #5678 的款项,还需要开具贷项通知单” 操作:

  1. 使用 TransactionId 和 ApiPassword 调用 Transactions/RefundByTransactionId。
  2. 检查 ResponseCode == 0,并读取 NewTranzactionId。
  3. 调用 Documents/CreateDocument,并设置 DocumentTypeToCreate: "TaxInvoiceAndReceiptRefund" 和 DealNumbers: [{"DealNumber": <NewTranzactionId>}]。 结果:退款已处理,并生成了对应的贷项凭证。
示例 5:接受 Bit、Apple Pay 和 Google Pay

用户说:“除了信用卡,我还想让客户使用 Bit、Apple Pay 和 Google Pay 付款” 操作:

  1. 在终端上启用每种付款方式,然后照常创建 Low Profile 页面。
  2. 在银行卡表单旁显示 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。每笔交易都需单独选择是否生成单据。

评论

支持 Markdown