简介《K3 Cloud WebAPI接口说明书_V4.0》面向金蝶K3 Cloud金蝶云星空开发者、云计算应用开发者及第三方系统集成人员用于解决企业云端应用与ERP系统对接时接口不明确、调试成本高的问题。说明书从接口目标、适用对象和整体架构讲起重点介绍Kingdee.BOS.WebApi.FormService.dll、ServicesStub.dll、Client.dll三个核心组件的作用与调用方式并给出Visual Studio、.NET Framework、K3 Cloud SDK等开发工具建议。接口部分完整覆盖登录验证、查看、保存、批量保存、提交、审核、反审核、删除表单数据等常用操作每个接口均包含定义、参数与返回值说明同时针对调用失败、错误信息处理、性能优化等常见问题给出解决策略。资源包为单个docx文件共34页体积仅101KB内容紧凑但体系完整。发布以来已有1167人学习下载适合需要在K3 Cloud平台上进行二次开发和系统集成的工程师作为手边参考。1. 拿到 K3 Cloud WebAPI 说明书 V4.0 后先别急着读文档K3 Cloud WebAPI 接口说明书_V4.0 这份文档通常不是躺在资料库里吃灰的——项目上需要把 K3 Cloud 的物料、供应商、销售订单推给 MES、WMS 或自研中台时它就是那本唯一的“对接字典”。V4.0 意味着接口版本已经迭代了几轮认证方式、业务对象操作、查询接口都形成了稳定范式。但大多数第一次拿到这本说明书的人翻开目录后反而更懵章节不少示例代码片段零散连先调哪个接口都摸不着头脑。这篇笔记不打算替你把说明书念一遍而是按一线对接的顺序把它拆成“环境通、认证通、业务通、查询通”四个关卡每关给出最小可跑的请求、参数表、以及文档没写明白的边界。适合手里已经有 K3 Cloud 环境、要接第三方系统的实施或开发也适合刚接手这类集成、想判断这个方案值不值得投入的人。先立住一个结论K3 Cloud WebAPI 的核心就一个令牌、两类服务、三种操作——后面所有接口都绕不开这个架子。2. 从说明书里找三样东西再走通认证拿 Token2.1 先定位端点、账套标识、接口版本三要素K3 Cloud WebAPI 的本质是一组部署在 K3 Cloud 服务器 IIS 站点下的 HTTP 服务所有请求都是 POST JSON返回也是 JSON。翻开说明书 V4.0第一件事不是看接口列表而是先确认三个基础信息服务端点地址、账套标识、当前接口版本。端点地址也就是 WebAPI 的根路径常见部署格式是http://K3服务器IP/K3Cloud/所有服务请求都是在根路径后面拼具体服务名。账套标识acct_id是数据中心在管理中心里对应的 ID不是数据库名也不是账套显示名称——这个最容易搞混。在 K3 Cloud 管理中心的数据中心列表页面每行记录里能看到“数据中心ID”通常是一串大写字母和数字的混合值。接口版本在说明书封面或前言里写明了 V4.0对应到实际请求里一般不显式传版本号靠服务路径区分。我一般会先在浏览器里访问http://服务器IP/K3Cloud/能看到 IIS 默认页或 K3 的登录跳转页面说明 WebAPI 站点已经发布。如果这一步不通后面对接全是白费。注意K3 的 WebAPI 服务默认要求本机或局域网内可达跨网段对接要先确认防火墙端口是否放行以及 IIS 站点绑定的域名或 IP 是否允许访问。提示确认 acct_id 时不要从数据库里查直接在管理中心界面取最稳妥。曾经有人直接查数据库表取出来的是内码导致后续所有请求都报“无效的账套”。2.2 认证先行走通用表单请求换 Token 的最小复现K3 Cloud WebAPI 的认证流程是用用户名密码换取一个 Token后续所有业务请求都带着这个 Token 走。说明书 V4.0 里认证接口的路径是固定的示例请求如下curl -X POST http://服务器IP/K3Cloud/Kingdee.BOS.WebApi.ServicesStub.AuthService.ValidateUser \ -H Content-Type: application/x-www-form-urlencoded \ -d acct_id你的账套IDusername对接用户password对接密码lcid2052这个请求返回的 JSON 结构里面LoginResultType等于 1 表示认证成功Data字段里就是 Token 字符串。可能你已经注意到了认证接口用的是表单格式不是 JSON。这是 K3 WebAPI 的一个特例很多第一次对接的人在这里翻车——明明说明书里全是 JSON 示例到了认证却要换成表单。认证通过后Token 在 K3 服务端默认有有效期。说明书里通常不详细写过期策略实测和生产环境经验是Token 有效期可能从几十分钟到几小时不等跟服务器配置有关。更稳妥的做法不是每次都重新认证而是把 Token 缓存起来调用业务接口时发现 401 或特定错误码再重新认证重试一次。用 Python 的 requests 库做完整认证和调用封装时代码逻辑一般是import requests def get_token(server_url, acct_id, username, password): auth_url f{server_url}/Kingdee.BOS.WebApi.ServicesStub.AuthService.ValidateUser payload { acct_id: acct_id, username: username, password: password, lcid: 2052 } resp requests.post(auth_url, datapayload, timeout15) result resp.json() if result.get(LoginResultType) ! 1: raise RuntimeError(f认证失败: {result}) return result[Data]认证这部分有几个参数要特别注意。lcid是语言区域标识2052 表示简体中文如果对接方需要繁体或英文环境这个值要跟着变。password明文传输所以生产环境务必走 HTTPS 或内网专线不要在外网裸奔。timeout建议设 10 到 15 秒K3 服务在账套启动或负载高时认证响应可能慢到让人误以为服务挂了。Token 拿到后每个业务请求都要在 Header 里带上Content-Type: application/json、Cookie: kdservice-sessionid你的Token。对Cookie 这个名字是固定的不是自定义 Header说明书里一般会写在某个不起眼的角落网上很多老版本示例直接把这个漏了。3. 三类高频接口的调用套路保存、操作、查询3.1 保存业务对象从物料到销售订单的通用格式K3 Cloud WebAPI 的业务对象操作统一走一个服务入口Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.Execute。不管是保存物料、保存供应商、保存销售订单还是保存其他单据路径都一样靠请求体里的formid区分对象靠op区分操作。保存物料的最小请求体如下import requests def save_bd_material(token, server_url, material_data): endpoint f{server_url}/Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.Execute headers { Content-Type: application/json, Cookie: fkdservice-sessionid{token} } payload { formid: BD_MATERIAL, op: Save, data: { NeedReturnFields: [FNumber, FName, FID], Model: material_data } } resp requests.post(endpoint, jsonpayload, headersheaders, timeout30) return resp.json()请求体里关键是formid和data.Model。formid是业务对象的表单标识物料是BD_MATERIAL销售订单是SAL_SALEORDER供应商是BD_SUPPLIER这些标识在 K3 的 BOS 设计器里可以查到说明书里也列出了常用表单标识。data.Model里放的是业务字段键是字段标识值是具体值。作为物料至少要传FName物料名称编码FNumber通常不传由编码规则自动生成如果强制传需要在编码规则允许范围内否则会报编码冲突。这里有个新手最容易掉的坑K3 Cloud 的基础资料字段比如计量单位、物料分组、税分类在 WebAPI 里不能直接传中文名称要传对应的内码或标识。比如计量单位传FUnitId但这个字段在请求里通常接收的是一个对象形如{FNumber: PCS}或直接传内码数字。具体格式要看字段类型说明书里字段说明列有“WebAPI格式”一列这块要认真核对我在第 4 章再细讲。3.2 单据操作Submit、Audit 的顺序不能乱K3 Cloud 单据在系统里的生命周期是保存暂存→ 提交 → 审核。WebAPI 把这三个阶段拆成了三个独立操作都走Execute入口。刚对接时最容易犯的错是保存完直接调审核跳过了提交系统会返回类似“当前单据状态不允许审核”的错误。销售订单从创建到审核的完整调用序列如下def execute_op(token, server_url, formid, op, data): endpoint f{server_url}/Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.Execute headers { Content-Type: application/json, Cookie: fkdservice-sessionid{token} } payload { formid: formid, op: op, data: data } resp requests.post(endpoint, jsonpayload, headersheaders, timeout30) return resp.json() # 1) 保存返回单据内码 FID save_result execute_op(token, server_url, SAL_SALEORDER, Save, { NeedReturnFields: [FID], Model: {FBillNo: , FSaleOrgId: {FNumber: 100}, FCustomerId: {FNumber: CUST001}} }) # 2) 提交传入一张或多张单据的 FID fid save_result[Data][0][FID] submit_result execute_op(token, server_url, SAL_SALEORDER, Submit, { Ids: str(fid), IgnoreWarning: True }) # 3) 审核 execute_op(token, server_url, SAL_SALEORDER, Audit, { Ids: str(fid), IgnoreWarning: True })这个例子里有进一步值得注意的参数。Ids传的是 FID 字符串多个 ID 用逗号拼接实际提交时通常是一次提交一批所以Ids拼接一长串。IgnoreWarning这个参数很重要K3 在提交或审核时如果遇到业务警告比如库存不足、信用额度超限默认会中断并返回提示IgnoreWarning设为True表示跳过这些警告继续执行但生产环境要慎用——有些警告其实是业务上不能忽略的要结合场景决定不要在代码里写死。还有收款单、付款单这一类单据提交前可能要先执行“保存并提交”这个联合操作但 WebAPI 说明书里通常明确建议拆成两步原因很简单联合操作一旦中间环节出错排查链路很长拆开后哪一步失败看哪一步的错误信息。3.3 查询接口ExecuteBillQuery 的分页与过滤条件查询走的是同一个Execute入口op换成ExecuteBillQuery。这个是使用最频繁、也最容易用错的接口。最小查询示例如下def query_data(token, server_url, formid, field_keys, filter_string): endpoint f{server_url}/Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.Execute headers { Content-Type: application/json, Cookie: fkdservice-sessionid{token} } payload { formid: formid, op: ExecuteBillQuery, data: { FieldKeys: field_keys, FilterString: filter_string, OrderString: FID ASC, TopRowCount: 100, Limit: 100, StartRow: 0 } } resp requests.post(endpoint, jsonpayload, headersheaders, timeout60) return resp.json()[Data]返回结果Data是一个二维数组第一行是字段名后面每行是数据值。这个格式和传统 API 返回 JSON 对象数组很不一样——你不能用result[FName]直接取字段必须先读第一行的字段名列表再用索引定位列。说明书里对返回格式的说明就在某个不起眼的段落很多初接触的人在这里反复踩坑。查询接口的FilterString是查询条件语法是 K3 的过滤表达式形如FCreateDate2024-01-01 and FStatusA。字段值多数要用单引号包裹日期格式要注意服务器时区。TopRowCount和Limit都控制返回行数但实际分页建议用Limit StartRow组合。K3 的查询默认有单次最大行数限制常见是 100 或 500跟服务器配置有关所以大数据量导出时不能只调高TopRowCount要按页循环拉取。OrderString在分页查询时一定要传否则页与页之间可能出现数据重复或遗漏。4. 说明书没明说的参数细节字段格式、分页、日期与数值4.1 字段标识用内码还是列表Format 参数的两个值这是 K3 WebAPI 对接中最隐蔽的一个参数。在Execute的请求体里data可以额外携带一个Format参数它控制基础资料字段的返回格式。Format为 1 时返回的是内码数据库里的 FID为 2 时返回的是列表值也就是我们界面上看到的编码或名称。举例说明查询销售订单时带上客户字段FCustomerId如果Format不传默认返回的是内码数字传了Format: 2返回的就是客户编码或客户名称。这个参数一旦不匹配就会出现“查询出来了但数据对不上”的情况——比如你拿内码去和 MES 系统的客户编码匹配怎么都对不上其实是返回格式不同。payload { formid: SAL_SALEORDER, op: ExecuteBillQuery, data: { FieldKeys: [FID, FBillNo, FCustomerId, FSaleOrgId], FilterString: FID 0, Format: 2, # 关键让基础资料字段返回编码/名称 } }这个参数在说明书里可能只有一句话但实际影响面非常大。保存接口同样受影响当你在Model里给基础资料字段赋值时如果服务端期望的是内码数字你传了编码字符串保存会失败或静默写入错误值。4.2 分页参数Limit、StartRow 和 TopRowCount 的关系K3 Cloud WebAPI 的分页参数有三个作用各不相同参数作用实际建议TopRowCount限制本次最大返回行数单次查询建议不超过服务器上限Limit本次要返回的行数分页时的页大小常用 50~200StartRow从第几行开始取下一页 当前 StartRow Limit如果只设TopRowCount那它等效于单页行数但循环翻页时没有偏移量只能用StartRow控制。这里有个经验K3 的ExecuteBillQuery并不适合一次拉几十万行服务端容易超时或内存暴涨。生产上稳妥的做法是每次拉 200 到 500 行等上一页处理完再拉下一页。即便服务器配置很高也尽量按这个思路来——因为接口超时重试的成本远比多循环几次高。另外分页查询的结果并不保证顺序稳定所以OrderString必须指定排序字段否则可能出现同一批数据在不同页里重复或漏掉。排序字段用主键如 FID是最稳的不要只按业务日期排序业务日期在一天内可能大量重复。4.3 数值与日期字段的类型陷阱K3 WebAPI 对数值和日期的 JSON 序列化有自己的习惯。数值字段在保存时直接传数字比如数量FQty: 10这没问题但如果字段是百分比或精度位数不同的数值需要按数据库字段精度来不要用 float 无脑传。比如数量字段精度是 2 位小数你传了10.999K3 可能会四舍五入成11.00也可能是直接报错取决于字段校验设置。日期字段则是最容易踩的坑。K3 的日期在 JSON 响应里有时是标准字符串2024-06-01 00:00:00有时却是/Date(1717171200000)/这种微软格式视字段类型和服务器版本而定。保存时日期字段建议统一传2024-06-01 00:00:00字符串这是兼容性最好的格式。如果你在查询返回里看到/Date(...)/自己写个正则解析成标准字符串再往下游走不要直接把这个字符串丢给 MySQL 或别的系统。注意不同单据的日期字段要求不同。比如单据日期FDate可以只传年月日但时间戳字段FModifyDate不接受省略时分秒。对接前先在 BOS 设计器里看字段的“格式类型”或在测试账套用一条假数据探一遍比翻说明书效率高。5. K3 Cloud WebAPI 对接避坑五个高频翻车现场5.1 发布 WebAPI 站点后接口返回 404我刚接触 K3 Cloud 集成时把 WebAPI 服务发布到 IIS 后浏览器访问根路径有响应但 POST 到AuthService.ValidateUser一直 404。排查了很久最后发现是 IIS 应用程序池的 .NET 版本没选对——K3 Cloud 的 WebAPI 站点要求 .NET CLR 版本 v4.0且托管管道模式为“集成”。如果应用池用了 v2.0 或经典模式路由根本不会生效。解决步骤IIS 管理器 → 应用程序池 → 找到 K3Cloud 对应的池 → 右键高级设置 → 把“.NET CLR 版本”改为 v4.0“托管管道模式”改为集成然后回收应用池再试。这个坑在说明书里不会写因为部署环节通常由 K3 实施方负责但很多二开或自主对接的团队是自己发布站点就容易绕远路。5.2 Token 认证成功但业务请求返回 401现象是认证接口明明返回了 Token复制到业务请求里却被拒。原因有两类一是 Token 已经过期二是请求 Header 里的 Cookie 名称写错。K3 WebAPI 的 Token 在 Header 里不是在 Authorization 里而是模拟 Session 的Cookie: kdservice-sessionidxxx。本地用 Postman 测试时很多人习惯把 Token 放在 Authorization 或自定义 Header就会一直 401。解决方式认证成功后把 Token 缓存到内存变量或 Redis业务请求统一从缓存取取到 Token 后先打印请求头确认Cookie字段拼写无误。如果确认无误还 401重新调一次认证接口换新 Token 再重试。5.3 保存销售订单成功但提交时报“当前单据状态不可提交”现象是 Save 返回了 FID说明单据已保存但紧接着 Submit 报状态错误。原因通常是单据有工作流或审核流保存后直接提交时服务端校验发现单据还处于“暂存”以外的状态需要先走完其他前置操作。另一个常见原因是单据上有必录字段在保存时没校验保存被允许但提交时触发完整校验失败。我在实际项目里遇到过一种情况销售订单的分录行数量字段没有传保存时是预估模式提交时系统需要真实数量而拒绝。解决思路是先把单据完整录一遍用界面提交成功后再用 WebAPI 复现整个流程对比缺少了哪些字段或参数。5.4 ExecuteBillQuery 返回的字段顺序和请求不一致这是查询接口最隐蔽的问题。返回的Data第一行明明是字段名但遍历时发现某些字段值对不上列名。原因不是 K3 乱了序而是查询接口对某些特殊字段如基础资料、多选基础资料在返回时会额外展开导致列数比 FieldKeys 多。曾经踩过请求了 7 个字段返回了 9 列前面对得上后面错位。解决方式不要用硬编码的索引取列值而是动态读取返回的第一行做映射找到每个字段名对应的索引后再取数据。脚本里写个通用的“行转字典”函数先把二维数组转成[{字段名: 值}, ...]再往下游处理。这样即便 K3 在后续升级里增加了返回列也不会让整个脚本崩溃。5.5 大批量同步时数据库连接池被占满用 WebAPI 同步数据时如果每次调用都新建连接而不复用上游系统会在大量请求时把 K3 服务器的数据库连接池打满导致后续请求超时或报“连接数已满”。这个现象在说明书里完全不会提但实际项目中非常常见。解决方式是控制并发度。同步任务不要用多线程同时发几十个请求Serial 执行或限制并发 3~5 个即可且每个线程复用同一个 Session同一个 Token。再进一步可以在请求重试逻辑里加入退避策略遇到连接问题等 1~2 秒再重试而不是无脑立刻重发。K3 WebAPI 的吞吐量本身有限单账套下并发 20 个请求已经是很大的压力了。6. 从说明书到可持续运行把调用封装成带日志的联调工具对接到了联调阶段最需要的是一个能记录每次请求和返回的封装层而不是在脚本里零散地写requests.post。我在项目里通常把 K3 的调用抽成一个小的类核心逻辑是统一处理 Token 获取与过期重试、统一打印请求返回摘要、统一把二维数组转成字典列表。import time import requests class K3Client: def __init__(self, server_url, acct_id, username, password): self.server_url server_url self.auth_payload { acct_id: acct_id, username: username, password: password, lcid: 2052 } self.token None self.expire_at 0 def _ensure_token(self): if self.token and time.time() self.expire_at: return resp requests.post( f{self.server_url}/Kingdee.BOS.WebApi.ServicesStub.AuthService.ValidateUser, dataself.auth_payload, timeout15 ).json() if resp.get(LoginResultType) ! 1: raise RuntimeError(f认证失败: {resp}) self.token resp[Data] # 本地把 Token 有效期保守设为 50 分钟 self.expire_at time.time() 3000 def execute(self, formid, op, data, retries3): self._ensure_token() url f{self.server_url}/Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.Execute headers { Content-Type: application/json, Cookie: fkdservice-sessionid{self.token} } payload {formid: formid, op: op, data: data} for attempt in range(retries): try: resp requests.post(url, jsonpayload, headersheaders, timeout60) result resp.json() # 记录请求状态方便回看问题 print(f[K3] {formid}.{op} status{result.get(Status)} fmsg{result.get(Message, )[:80]}) return result except requests.Timeout: print(f[K3] timeout, retry {attempt 1}/{retries}) time.sleep(2 * (attempt 1)) raise RuntimeError(f{formid}.{op} 重试 {retries} 次仍超时)这个封装里有两个值得注意的设计。一是 Token 不放到调用方手里而是由客户端类自动管理时钟按 50 分钟刷新一次避免每次调用都重新认证增加服务端压力。二是超时重试采用递增退避第一次超时等 2 秒第二次等 4 秒第三次等 6 秒重试 3 次仍失败就抛异常方便上层任务捕获告警。实际运维时我会再追加一步把每个请求的formid、op、响应耗时、错误信息都打到日志文件流量异常时靠这份日志回溯比在 K3 服务器端查 BOS 日志快得多。联调验证时拿同一个业务场景在界面手动做一遍再让脚本跑一遍对比两边的字段值、状态流和时间线。K3 WebAPI 这种依赖单据状态的接口最怕的就是调用方和服务端各自理解的状态机不一致。我自己吃过亏的地方是以为提交操作返回成功就万事大吉后来发现工作流配置了多级审批提交只是进了第一步。所以在生产任务里我会在提交后主动查询一次单据状态确认符合预期再往下走。这是从“接口调通”到“业务可靠”之间最关键的一步希望帮到你。本文还有配套的精品资源点击获取