← 文档 / 指南
银行与支付导入
camt.053 对账单、Stripe CSV、PSP 结算对账以及自定义 JSON 动态数据源。
所有导入的数据都会作为银行交易(bank transactions)落入指定的银行账户(bank/accounts/create)。每笔交易都带有 externalId;重复导入相同的文件是安全的,系统会自动跳过那些 (bankAccountId, externalId) 已经存在的行,并在 skipped 计数器中进行报告。导入的交易初始状态为 new(新建),只有在完成匹配后才会过账到总账(ledger)(通过 bank/transactions/match 进行匹配,候选交易可通过 bank/transactions/suggest-matches 获取)。
Web 应用程序在银行 (Bank) → 导入文件 (Import file) 菜单下提供了相同的导入功能(支持文件上传和模板选择)。
如果匹配错误,可以通过 bank/transactions/unmatch 进行撤销(在 Web 应用的银行 (Bank) → 交易 (Transactions) 中点击取消匹配 (Unmatch))。已过账的分录绝不会被直接编辑或删除:当一笔支付被匹配到发票,或导入模板将某行分录过账到某个科目时,系统会生成一张红冲(冲销)凭证,其中所有分录的方向与原分录相反,凭证日期为 date(默认为今天,且不得早于原过账日期)。发票的已付金额和支付状态会扣减相应银行流水的金额。若某行流水关联的是支付服务商(PSP)结算,则系统只会解除该关联,因为结算过账属于整个批次。该行流水将恢复为 new 状态,以便重新进行匹配。冲销日期必须落在开放的会计期间内。
导入模板
导入模板用于指定数据源、列出该数据源提供的字段,并将涉及金额的字段映射到总账科目。模板的管理可以通过银行 (Bank) → 导入模板 (Import templates) 界面,或者使用 API 端点 bank/import-templates/create|update|delete|get|list。
POST /v1/bank/import-templates/create
{
"name": "Stripe payments export",
"type": "stripe",
"fields": [
{ "name": "id" },
{ "name": "Created date (UTC)" },
{ "name": "Amount" },
{ "name": "Fee", "accountCode": "6800" },
{ "name": "Amount Refunded" }
],
"metaFields": ["order_id"]
}
type取值必须是stripe、iso20022、bank_connection或revolut之一。- 每个字段包含一个
name和一个可选的accountCode。只有涉及金额的字段才允许指定科目:例如 Stripe 的Amount、Fee和Amount Refunded;camt.053 的Ntry/Amt;银行动态数据源的transaction_amount.amount。该科目必须在会计科目表中存在(可通过ledger/accounts/create创建)。 fields字段可以省略;如果省略,则默认采用该类型的标准字段列表:Stripe 付款 (Payments) → 导出 (Export) 文件的列名(不包含表单默认也不勾选的那 19 列Card …)、camt.053 格式对账单包含的标准元素(Stmt/Id、Stmt/Acct/Id/IBAN、Stmt/Bal/…、Ntry/Amt、Ntry/CdtDbtInd、Ntry/Sts、Ntry/BookgDt),或是 PSD2 银行动态数据源为每笔交易返回的属性。你可以根据实际文件增减条目:导入程序同时支持读取可选的 camt.053 元素,包括Ntry/ValDt、Ntry/NtryRef、Ntry/AcctSvcrRef、Ntry/AddtlNtryInf、TxDtls/Refs/EndToEndId、TxDtls/Refs/TxId、TxDtls/RltdPties/Dbtr/Nm、TxDtls/RltdPties/DbtrAcct/Id/IBAN、TxDtls/RltdPties/Cdtr/Nm、TxDtls/RltdPties/CdtrAcct/Id/IBAN、TxDtls/RmtInf/Ustrd以及TxDtls/AddtlTxInf。- Stripe 的
Customer Email(客户电子邮件)字段可以配置"createPartner": true。启用后,导入程序会针对文件中所有现有往来单位(partner)中没有的邮箱自动创建一个客户(类型为个人的往来单位,并标记为客户),使用Customer Description作为名称(若为空则使用邮箱本身),若文件中包含Card Address …列,则将其用作地址。系统会通过邮箱不区分大小写地匹配现有往来单位。响应结果中的customersCreated字段会报告创建的数量。 metaFields(仅限 Stripe)用于列出扣款(charges)所携带的元数据键名。Stripe 将每个键导出为<key> (metadata)列;此列表为自由格式,可以包含多项。invoiceItemId(仅限 Stripe,可选)指向一个目录商品。设置后,导入程序创建的每张发票和贷项通知单(credit note)行都会引用该商品(包括其过账科目以及在invoiceVatRatePercent为空时的增值税率);行文本仍取自扣款描述。companyMetaField(仅限 Stripe)用于指定上述某个键作为公司标志。当某笔扣款的该列值为true、1、yes、company、business或b2b时,为其创建的往来单位将是公司类型,而不是个人。invoiceMetaField(仅限 Stripe)用于指定其中一个键(例如订单号),invoiceVatRatePercent则指定由其创建的发票的增值税率。在导入时,每行扣款和退款记录会按该键的值进行分组:- 如果某个值与现有的销售发票匹配,即
externalRef为该值的销售订单(ecommerce/orders/create,适用于任意渠道)或fullNumber为该值的发票,则该分组会链接到该发票; - 如果某个值找不到对应发票,则会新建一张发票:往来单位取自
Customer Email(若不存在则自动创建,逻辑同createPartner),每笔扣款生成一行(以Checkout Line Item Summary或Description作为行文本,扣款金额作为含税价格,适用税率为invoiceVatRatePercent),开票日期为第一笔扣款的日期,增值税处理方式根据公司和卡片发行国家确定。该发票会立即开具并过账,同时系统会记录一个渠道为stripe且externalRef为该值的销售订单,以便后续导入时直接进行链接而不是重复创建; - 然后,将分组中的每笔扣款作为支付匹配到该发票(同时对收款进行过账);每笔退款则针对该发票按退款金额开具一张已发出的贷项通知单,并将退款与该通知单进行匹配。
API 返回的统计计数包括
invoicesCreated、invoicesLinked、creditNotesCreated和paymentsMatched;无法处理的分组(如缺少客户邮箱、包含多种币种、链接的发票仍为草稿状态或已全额付款)会列在warnings中,并保留为new状态的银行交易。请勿在同一个模板中将Amount同时映射到总账科目:匹配到发票的扣款不会被重复过账,但未匹配的扣款则会被过账。
- 如果某个值与现有的销售发票匹配,即
- 模板名称在每家公司内部必须是唯一的。
- camt.053 和银行连接(bank-connection)模板具有相同的选项,这些选项从对账单中读取,而不是从 Stripe 列中读取:
- 创建缺失的往来单位 (Create missing partners):在债务人名称行(
TxDtls/RltdPties/Dbtr/Nm,动态数据源为debtor.name)上设置createPartner,会为所有未知的资金转入付款人创建一个客户;在债权人名称行(TxDtls/RltdPties/Cdtr/Nm,动态数据源为creditor.name)上设置,会为所有未知的资金转出收款人创建一个供应商。系统首先通过 IBAN(存储在partner_bank_accounts中)识别往来单位,其次通过精确名称识别;如果名称中包含法律形式(如 UAB、MB、SIA、GmbH、Ltd 等),则新往来单位会被识别为公司,否则为个人。统计数量会通过customersCreated(文件导入)或partnersCreated(动态数据源同步)返回。 - 通过参考号链接发票 (Link invoices by reference):将
invoiceMetaField设置为附言或参考行(TxDtls/RmtInf/Ustrd、TxDtls/RmtInf/Strd/CdtrRefInf/Ref、TxDtls/Refs/EndToEndId;动态数据源为remittance_information、reference_number),系统会匹配所有参考号、附言或描述中包含未结出的已开具销售发票(资金转入)或已登记采购发票(资金转出)编号的新银行流水行,并过账相应的付款。如果付款人的 IBAN 已保存到某个往来单位中,或者付款人的名称与往来单位的名称或代码相符,则该发票必须属于该往来单位。来自未知付款人的付款,只有在金额正好等于发票剩余余额且发票编号带有系列前缀时才会进行链接,因此诸如纯金额之类的裸数字绝不会被当作参考号。大于剩余余额的付款绝不会被链接。未能通过这些检查的流水行将保持新建状态以便人工匹配,并会列在警告信息中。当设置advanceInvoices: true时,来自已知往来单位的未匹配转入款项会按invoiceVatRatePercent或invoiceItemId的税率针对该金额开具一张已发出的预收款发票(类型为advance),并将付款匹配到该发票;该往来单位必须是已知的,因此请同时勾选债务人行。 - 按交易代码设置过账规则 (Posting rules by transaction code):除了
Ntry/Amt/transaction_amount.amount之外,字段列表中还可以包含规则行,例如Ntry/BkTxCd=CHRG、=INTR、=TAXE、Ntry/CdtDbtInd=DBIT、=CRDT(动态数据源对应:bank_transaction_code=…、credit_debit_indicator=…)。流水行会过账到与其匹配的第一条规则所对应的科目:依次匹配其银行交易代码系列、收支方向,最后匹配普通的金额行。规则行本身不会与文件内容进行核对。 - 银行手续费往来单位 (Bank charges partner):在
…=CHRG规则行上设置createPartner会创建一个以银行命名的供应商(取自对账单的Stmt/Acct/Svcr/FinInstnId/Nm、连接配置中的银行名称或总账银行账户名称),并将所有手续费记账到该往来单位名下。 - 银行连接模板是通过
bank/feeds/accounts/configure(对应 App 中的银行 (Bank) → 连接 (Connections))针对每个动态数据源账户进行选择的,该端点同时还会设置syncSchedule(manual、daily、weekly、monthly):一旦过了同步周期,API 会自动按计划同步账户。模板会在每次bank/feeds/sync时应用;同步响应同时会报告posted、partnersCreated、invoicesLinked、invoicesCreated、paymentsMatched和warnings。
- 创建缺失的往来单位 (Create missing partners):在债务人名称行(
向 bank/statements/import 传递 templateId 而不是 format:模板类型决定了所使用的解析器,并且文件必须包含模板中列出的所有字段——缺少任何字段的文件将被拒绝,并返回 HTTP 422 状态码以及缺失的列或元素名称。元数据字段并非强制要求存在。银行连接模板描述的是实时的 PSD2 动态数据源,不能用于文件导入。
ISO 20022 模板同样支持读取 MT940 文件:以 {1: 或 :20: 开头的文件(或在请求中指定 "format": "mt940")会被当作 MT940 解析,并将模板的参考号匹配和过账规则应用到其行数据中。MT940 文件会跳过元素检查,且 Ntry/BkTxCd=… 规则不适用于 MT940 行,因为 MT940 不包含 ISO 20022 银行交易代码;请改用 Ntry/CdtDbtInd=… 规则。
一个银行账户只能包含一种币种。包含其他币种的对账单将被拒绝并返回 HTTP 422(对于包含同一 IBAN 下多种币种对账单的 camt.053 文件,系统仅导入与账户币种相符的对账单),向 bank/transactions/import 发送非账户币种的流水行也会被拒绝。
由带有 accountCode 的字段产生的每笔资金变动,都会在导入时作为一张平衡凭证过账:资金转入借记银行账户的总账科目并贷记映射的科目;资金转出借记映射的科目并贷记银行账户的总账科目。金额会按照变动日期的汇率折算为本位币。随后,该银行交易会与该凭证进行 matched 匹配(matchedDocumentType = journal_transaction),并不再出现在发票匹配的候选列表中。响应结果中的 posted 字段会报告过账数量。未映射字段产生的变动会保持 new 状态,并按以往方式与发票进行匹配,例如,你可以将 Fee 映射到 PSP 手续费费用科目,而将 Amount 保持未映射,这样扣款仍然可以与销售发票进行匹配。
POST /v1/bank/statements/import
{
"bankAccountId": "…",
"templateId": "…",
"content": "id,Created date (UTC),Amount,…"
}
ISO 20022 camt.053(开放银行 XML)
立陶宛的银行(如 Swedbank、SEB、Luminor、Šiaulių bankas 等)允许用户从其网上银行下载 ISO 20022 camt.053 XML 格式的账户对账单,通常在对账单导出/下载菜单下,格式选择 "ISO XML" 或 "camt.053"。PSD2 账户信息 API 返回的也是相同格式。
POST /v1/bank/statements/import
{
"bankAccountId": "…",
"format": "camt053",
"content": "<?xml version=\"1.0\"…>…"
}
- 文件可能包含多份对账单;每份对账单的 IBAN 必须与银行账户的 IBAN 相匹配(没有 IBAN 的对账单或没有 IBAN 的账户将按原样接受)。
- 分录参考号(
AcctSvcrRef/NtryRef,若无则回退使用内容哈希)将成为externalId。 - 响应会回显每份对账单的元数据:对账单 ID、期间、期初/期末余额、交易笔数。
- 系统会为每笔分录提取交易对手名称、IBAN 和付款用途以用于匹配。
反方向的付款则通过 bank/payments/export 导出为 pain.001 格式。
Revolut Business CSV
将 Revolut Business 账户的交易对账单下载为 CSV 文件,并使用内置模板 Revolut Business(templateId: "builtin-revolut")进行导入。每家公司都默认拥有此模板,无需手动创建:bank/import-templates/list-builtin 会列出它,bank/import-templates/get 可以获取它,而 bank/import-templates/update 和 bank/import-templates/delete 则会拒绝并返回 HTTP 400。在应用中,它会显示在银行 (Bank) → 导入模板 (Import templates) 的最上方;打开它可以查看其设置,保存则会创建一个你可以修改的公司自定义模板。
POST /v1/bank/statements/import
{
"bankAccountId": "…",
"templateId": "builtin-revolut",
"content": "Date started (UTC),Date completed (UTC),ID,Type,State,…"
}
- 只有
State等于COMPLETED的行才会被导入。其他行(例如PENDING)会被忽略并计入warnings中;它们将在后续导入已完成这些交易的文件时被导入。 - 每行数据会变成一笔银行交易,其日期取自
Date completed (UTC),金额取自Total amount,币种取自Payment currency,ID作为externalId,Description作为描述。 - 资金转出的交易对手为
Beneficiary name和Beneficiary IBAN;对于没有受益人的刷卡支付,交易对手为Description中的商户。资金转入的交易对手为Sender name和Sender account。 - 行数据会按账户和币种进行分组。
International account number必须与银行账户的 IBAN 相匹配,且仅导入与银行账户币种相同的行。 - 对于每一行,导入程序会检查上一行的余额加上
Total amount是否等于当前的Balance,并将所有不相等的行列在warnings中。 - 文件必须包含以下列:
Date completed (UTC)、ID、Type、State、Description、Payment currency、Total amount、Reference、Sender name和Beneficiary name。
每次导入时,内置模板会执行以下操作:
为所有未知的资金转入寄件人创建一个客户,为所有未知的资金转出受益人或刷卡商户创建一个供应商,具体逻辑如上文创建缺失的往来单位所述;
匹配所有
Reference或Description包含未结销售或采购发票编号的行,并进行付款过账,同时遵循上文通过参考号链接发票的检查规则;根据没有发票匹配的行的
Type,按照过账规则将其过账到相应科目:Type过账规则 默认科目 罗马尼亚科目表 过账方式 FEEbank.fees6800 627 借记规则对应的科目,贷记银行账户的总账科目;往来单位:以银行账户命名的供应商 CARD_PAYMENTbank.cardPayments6209 628 借记规则对应的科目,贷记银行账户的总账科目,不含增值税 TOPUPbank.topUps3010 1012 借记银行账户的总账科目,贷记规则对应的科目 其他类型(如
TRANSFER)的行将保持new状态以便后续匹配。
你可以通过 ledger/posting-rules/update 修改科目;内置模板将在下一次导入时使用新的科目。过账规则无法被关闭:如果希望导入刷卡支付或充值但不进行过账,请创建一个类型为 revolut 且不包含 Type=CARD_PAYMENT 或 Type=TOPUP 行的公司模板,并使用该模板进行导入。通过这种方式过账的刷卡支付,在随后登记供应商发票时不会与之进行匹配;两者只能过账其中之一,切勿重复过账。
类型为 revolut 的公司模板使用相同的列,并可以通过规则行 Type=FEE、Type=CARD_PAYMENT、Type=TRANSFER 和 Type=TOPUP 按类型过账行数据。若使用 "format": "revolut-csv" 且不指定模板进行导入,则仅导入行数据而不执行上述任何附加步骤。
Stripe CSV
从 Stripe 仪表板导出数据——以下两种报告均可:
- 报告 (Reports) → 余额 (Balance) → 活动明细余额变动 (Itemized balance change from activity)(推荐):包含列
balance_transaction_id, created_utc, currency, gross, fee, net, reporting_category, description。 - 付款 (Payments) → 导出 (Export):包含列
id, Created (UTC), Amount, Fee, Currency, Description, Customer Description。
POST /v1/bank/statements/import
{
"bankAccountId": "…",
"format": "stripe-csv",
"content": "balance_transaction_id,created_utc,currency,gross,fee,net,…"
}
请为 Stripe 创建一个专用的银行账户(例如命名为 "Stripe",总账科目为 2710 或其专属子科目)——Stripe 的余额表现得就像一个银行账户:扣款流入、扣除手续费、通过拨付(payout)将余额转入你的真实银行账户。
导入行为说明:
- 每笔余额交易会针对**毛额(gross)**生成一笔银行交易(
externalId= 余额交易 ID)。 - 非零的**手续费(fee)**会生成第二笔符号相反的交易(
externalId=<id>:fee,交易对手为 "Stripe")——这样可以将手续费作为费用与收入分开进行匹配/过账。退款中退回的手续费会以正数金额记入。 - **拨付(Payout)**行会作为单笔负数交易导入;请将其与你的真实银行账户对账单上的相应转入交易进行匹配。
- 金额为零的行会被跳过;日期取自
created_utc(UTC 时间)。 - 未发生资金移动的付款导出行将被跳过:
Captured = false(授权/延迟捕获)以及状态为 Failed(失败)/Canceled(已取消)的行。 - 非零的**已退款金额(Amount Refunded)**会生成第三笔负数交易(
externalId=<id>:refund),日期为Refunded date (UTC)——这样就不会丢失嵌入在付款行中的部分退款和全额退款信息。
PSP 结算对账(Stripe 拨付报告)
若要将一笔总括拨付拆分为其底层的订单、退款、手续费和拒付(chargebacks),请使用结算端点,而不是普通的对账单导入。系统支持两种 Stripe 导出格式(自动检测):
- 报告 (Reports) → 拨付 (Payouts) → 拨付明细对账 (Payout reconciliation, itemized)(报告类型为
payout_reconciliation.itemized.*或payout_reconciliation.by_id.itemized.*)——精确,每笔余额交易一行;在线上真实账户中优先推荐。 - 付款 (Payments) → 导出(统一付款)(Export (unified payments))——按扣款级别导出的报告;适用于无法进行拨付对账的测试/沙盒模式。已捕获的扣款会按
Transfer列中的拨付 ID 进行分组;未捕获/失败的行将被跳过(skippedNotSettled);非零的Amount Refunded会在该扣款的拨付批次中生成一条合成退款行——这是一种近似处理,因为退款实际上可能在随后的拨付中才结算。匹配参考号取自扣款 ID、PaymentIntent ID、Invoice Number、Client Reference ID以及所有… (metadata)列(例如元数据中的订单号)。
单个 CSV 文件可以跨越多个拨付。Stripe 下载的明细报告是按部分分文件下载的(…_charge_…、…_refund_…、…_fee_…);请将它们全部导入——只要某个拨付尚未过账,属于该拨付的行就会合并到现有的批次中(在 updated 计数器中报告),并且会重新计算批次总额。
POST /v1/bank/settlements/import
{
"bankAccountId": "…",
"provider": "stripe",
"content": "balance_transaction_id,created_utc,…,reporting_category,…,automatic_payout_id,…"
}
导入行为说明:
- 行数据会按
automatic_payout_id分组为结算批次(settlement batches)——每个拨付一个批次,包含毛额/手续费/净额总计(行net的总和 = 打入你银行账户的金额)。重新导入已存在的拨付会被跳过(skipped计数器)。尚未分配到拨付的行以及payout行本身会被跳过并单独计数。 - 每笔扣款/退款/拒付都会自动匹配到销售发票,匹配顺序依次为:电子商务订单的
externalRef(取自order_id、payment_intent_id、source_id、charge_id或任何*_metadata[...]列的值)、出现在这些列中的发票fullNumber,以及——对于退款和拒付——先前已匹配扣款的charge_id(来自同一文件或之前的导入)。 - 可通过
bank/settlements/list/bank/settlements/get进行审核;可通过bank/settlements/match { lineId, invoiceId }(或传入invoiceId: null取消匹配)修复遗留问题。
POST /v1/bank/settlements/post { id, date?, commissionPercent? } 会将整个批次作为一张平衡的总账凭证过账,并结清已匹配的发票(触发 paidAmount/paymentStatus、sale_invoice.paid Webhook):
- 借记银行账户总账科目(对应净拨付额);借记 PSP 手续费(
settlements.fees,默认 6800)对应扣除的手续费和手续费行。 - 贷记每个已匹配扣款对应的应收账款;退款和拒付则作相反处理。金额应用以每张发票的剩余金额为上限——任何超出部分都会带着警告落入暂记账户(suspense account)。
- 未匹配的扣款:如果设置了
commissionPercent,它们会被拆分为佣金收入(settlements.commissionRevenue,默认 5001)和卖家应付款(settlements.sellerPayable,默认 4499)——这适用于代收资金主要归属于卖家的市场(marketplace)业务流。如果未设置该参数,则会将其暂记在settlements.suspense(默认 4440,收到的预收款)中。 platform_earning行(Stripe Connect 应用费)过账到佣金收入;transfer行(向已连接卖家拨付)减少卖家应付款。- 所有四个科目均可按公司通过过账规则(
ledger/posting-rules)进行重写。 - 如果某行的扣款、手续费或退款已经通过 Stripe 付款导出(
bank/statements/import)导入到另一个银行账户中,则不会重复记入手续费、应收账款或暂记账户。其net金额会改为贷记到该银行账户的总账科目,从而使 Stripe 银行账户能够逐笔拨付清账。summary.clearedAmount是通过这种方式流转的总金额;如果某行金额与该账户实际持有的金额不符,则会列在warnings中。如果没有剩余需要记账的内容,批次过账时的journalTransactionId将为 null。
bank/settlements/list 和 /get 会针对每个批次返回 clearedNet、clearingDifference(拨付行减去其他银行账户为其持有的金额;一致时为零)以及 clearingOpenCount(存在差异或未过账变动的行数);/get 还会针对每行返回 clearingBankAccountId、clearingBooked、clearingDifference 和 clearingUnposted。同一笔扣款的退款行会作为一个整体进行比较,因为付款导出报告中仅包含退款总额。如果在拨付过账之后才导入 Stripe 付款导出数据,系统会跳过该拨并在 warnings 中记录该拨付名称。
佣金本身的增值税需要单独开票(向卖家开具佣金发票);拆分操作仅用于分配已收取的现金。
其他币种的拨付
凭证总是以公司本位币记账,但不同币种的拨付会自动过账——无需进行人工录入:
- 批次会按过账日期的汇率进行折算(
date,若未指定则回退到拨付日期,再回退到今天)。如果公司自身针对该币种维护的汇率(reference/exchange-rates/set)至少与官方汇率一样新,则采用公司汇率,否则采用该日期或之前最新的官方汇率。如果在该日期或之前没有可用汇率,调用将失败并返回 422 状态码,同时提示reference/exchange-rates/sync。 - 所有科目均按该批次汇率折算,唯独应收账款除外,应收账款会按照每张发票开具时的
fxRate(汇率)进行核销。这两种汇率之间的差额会作为已实现汇兑差额过账到bank.fxGain(默认 5803)或bank.fxLoss(默认 6803),从而确保凭证依然平衡。 - 响应的
summary会返回所使用的fxRate以及由此产生的exchangeDifference(汇兑差额),并且批次会保留其过账时使用的汇率。如果已匹配发票的自身币种与批次币种不同,则不会进行结算:其金额会连同警告一起转入暂记账户。 - 仍保留一条导入限制:单笔拨付的行如果混合了多种币种,将被拒绝并返回 422;同样,重新导入时币种若与该拨付已存储的批次币种不同,也会被拒绝。
手工/自定义动态数据源
任何其他数据都可以作为纯 JSON 推送:
POST /v1/bank/transactions/import
{
"bankAccountId": "…",
"transactions": [
{ "date": "2026-07-01", "amount": "-25.00", "currency": "EUR",
"counterpartyName": "…", "description": "…", "externalId": "unique-ref-1" }
]
}
请为每笔交易提供稳定的 externalId,以确保重复导入时的幂等性。