@atbas/m-mcp 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (366) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +364 -0
  3. package/dist/builder/transaction-builder.d.ts +53 -0
  4. package/dist/builder/transaction-builder.d.ts.map +1 -0
  5. package/dist/builder/transaction-builder.js +159 -0
  6. package/dist/builder/transaction-builder.js.map +1 -0
  7. package/dist/catalogue/default-catalogue.d.ts +18 -0
  8. package/dist/catalogue/default-catalogue.d.ts.map +1 -0
  9. package/dist/catalogue/default-catalogue.js +21 -0
  10. package/dist/catalogue/default-catalogue.js.map +1 -0
  11. package/dist/catalogue/endpoints.d.ts +22 -0
  12. package/dist/catalogue/endpoints.d.ts.map +1 -0
  13. package/dist/catalogue/endpoints.js +24 -0
  14. package/dist/catalogue/endpoints.js.map +1 -0
  15. package/dist/catalogue/flows.d.ts +32 -0
  16. package/dist/catalogue/flows.d.ts.map +1 -0
  17. package/dist/catalogue/flows.js +64 -0
  18. package/dist/catalogue/flows.js.map +1 -0
  19. package/dist/catalogue/hash-options.d.ts +112 -0
  20. package/dist/catalogue/hash-options.d.ts.map +1 -0
  21. package/dist/catalogue/hash-options.js +151 -0
  22. package/dist/catalogue/hash-options.js.map +1 -0
  23. package/dist/catalogue/types.d.ts +279 -0
  24. package/dist/catalogue/types.d.ts.map +1 -0
  25. package/dist/catalogue/types.js +360 -0
  26. package/dist/catalogue/types.js.map +1 -0
  27. package/dist/codegen/generate.d.ts +14 -0
  28. package/dist/codegen/generate.d.ts.map +1 -0
  29. package/dist/codegen/generate.js +490 -0
  30. package/dist/codegen/generate.js.map +1 -0
  31. package/dist/codegen/languages/node.d.ts +3 -0
  32. package/dist/codegen/languages/node.d.ts.map +1 -0
  33. package/dist/codegen/languages/node.js +32 -0
  34. package/dist/codegen/languages/node.js.map +1 -0
  35. package/dist/codegen/languages/php.d.ts +3 -0
  36. package/dist/codegen/languages/php.d.ts.map +1 -0
  37. package/dist/codegen/languages/php.js +27 -0
  38. package/dist/codegen/languages/php.js.map +1 -0
  39. package/dist/codegen/languages/python.d.ts +3 -0
  40. package/dist/codegen/languages/python.d.ts.map +1 -0
  41. package/dist/codegen/languages/python.js +27 -0
  42. package/dist/codegen/languages/python.js.map +1 -0
  43. package/dist/codegen/renderer.d.ts +24 -0
  44. package/dist/codegen/renderer.d.ts.map +1 -0
  45. package/dist/codegen/renderer.js +59 -0
  46. package/dist/codegen/renderer.js.map +1 -0
  47. package/dist/codegen/types.d.ts +50 -0
  48. package/dist/codegen/types.d.ts.map +1 -0
  49. package/dist/codegen/types.js +5 -0
  50. package/dist/codegen/types.js.map +1 -0
  51. package/dist/config/credentials.d.ts +64 -0
  52. package/dist/config/credentials.d.ts.map +1 -0
  53. package/dist/config/credentials.js +216 -0
  54. package/dist/config/credentials.js.map +1 -0
  55. package/dist/config/environment.d.ts +23 -0
  56. package/dist/config/environment.d.ts.map +1 -0
  57. package/dist/config/environment.js +54 -0
  58. package/dist/config/environment.js.map +1 -0
  59. package/dist/core/dependencies.d.ts +43 -0
  60. package/dist/core/dependencies.d.ts.map +1 -0
  61. package/dist/core/dependencies.js +2 -0
  62. package/dist/core/dependencies.js.map +1 -0
  63. package/dist/core/registry.d.ts +33 -0
  64. package/dist/core/registry.d.ts.map +1 -0
  65. package/dist/core/registry.js +13 -0
  66. package/dist/core/registry.js.map +1 -0
  67. package/dist/core/server.d.ts +61 -0
  68. package/dist/core/server.d.ts.map +1 -0
  69. package/dist/core/server.js +90 -0
  70. package/dist/core/server.js.map +1 -0
  71. package/dist/dependencies.d.ts +28 -0
  72. package/dist/dependencies.d.ts.map +1 -0
  73. package/dist/dependencies.js +2 -0
  74. package/dist/dependencies.js.map +1 -0
  75. package/dist/diagnostics/diagnose.d.ts +43 -0
  76. package/dist/diagnostics/diagnose.d.ts.map +1 -0
  77. package/dist/diagnostics/diagnose.js +121 -0
  78. package/dist/diagnostics/diagnose.js.map +1 -0
  79. package/dist/domain/amount.d.ts +157 -0
  80. package/dist/domain/amount.d.ts.map +1 -0
  81. package/dist/domain/amount.js +275 -0
  82. package/dist/domain/amount.js.map +1 -0
  83. package/dist/domain/datetime.d.ts +95 -0
  84. package/dist/domain/datetime.d.ts.map +1 -0
  85. package/dist/domain/datetime.js +211 -0
  86. package/dist/domain/datetime.js.map +1 -0
  87. package/dist/domain/response-codes.d.ts +116 -0
  88. package/dist/domain/response-codes.d.ts.map +1 -0
  89. package/dist/domain/response-codes.js +380 -0
  90. package/dist/domain/response-codes.js.map +1 -0
  91. package/dist/domain/secure-hash.d.ts +78 -0
  92. package/dist/domain/secure-hash.d.ts.map +1 -0
  93. package/dist/domain/secure-hash.js +69 -0
  94. package/dist/domain/secure-hash.js.map +1 -0
  95. package/dist/domain/signature/jazzcash.d.ts +56 -0
  96. package/dist/domain/signature/jazzcash.d.ts.map +1 -0
  97. package/dist/domain/signature/jazzcash.js +214 -0
  98. package/dist/domain/signature/jazzcash.js.map +1 -0
  99. package/dist/domain/signature/registry.d.ts +69 -0
  100. package/dist/domain/signature/registry.d.ts.map +1 -0
  101. package/dist/domain/signature/registry.js +92 -0
  102. package/dist/domain/signature/registry.js.map +1 -0
  103. package/dist/domain/signature/scheme.d.ts +349 -0
  104. package/dist/domain/signature/scheme.d.ts.map +1 -0
  105. package/dist/domain/signature/scheme.js +398 -0
  106. package/dist/domain/signature/scheme.js.map +1 -0
  107. package/dist/domain/txn-ref.d.ts +76 -0
  108. package/dist/domain/txn-ref.d.ts.map +1 -0
  109. package/dist/domain/txn-ref.js +126 -0
  110. package/dist/domain/txn-ref.js.map +1 -0
  111. package/dist/domain/types.d.ts +45 -0
  112. package/dist/domain/types.d.ts.map +1 -0
  113. package/dist/domain/types.js +70 -0
  114. package/dist/domain/types.js.map +1 -0
  115. package/dist/errors.d.ts +84 -0
  116. package/dist/errors.d.ts.map +1 -0
  117. package/dist/errors.js +87 -0
  118. package/dist/errors.js.map +1 -0
  119. package/dist/gateway/checkout-form.d.ts +16 -0
  120. package/dist/gateway/checkout-form.d.ts.map +1 -0
  121. package/dist/gateway/checkout-form.js +103 -0
  122. package/dist/gateway/checkout-form.js.map +1 -0
  123. package/dist/gateway/checkout-output.d.ts +70 -0
  124. package/dist/gateway/checkout-output.d.ts.map +1 -0
  125. package/dist/gateway/checkout-output.js +199 -0
  126. package/dist/gateway/checkout-output.js.map +1 -0
  127. package/dist/gateway/guards.d.ts +37 -0
  128. package/dist/gateway/guards.d.ts.map +1 -0
  129. package/dist/gateway/guards.js +44 -0
  130. package/dist/gateway/guards.js.map +1 -0
  131. package/dist/gateway/http-client.d.ts +42 -0
  132. package/dist/gateway/http-client.d.ts.map +1 -0
  133. package/dist/gateway/http-client.js +153 -0
  134. package/dist/gateway/http-client.js.map +1 -0
  135. package/dist/gateway/rest-client.d.ts +42 -0
  136. package/dist/gateway/rest-client.d.ts.map +1 -0
  137. package/dist/gateway/rest-client.js +241 -0
  138. package/dist/gateway/rest-client.js.map +1 -0
  139. package/dist/gateway/transport.d.ts +31 -0
  140. package/dist/gateway/transport.d.ts.map +1 -0
  141. package/dist/gateway/transport.js +73 -0
  142. package/dist/gateway/transport.js.map +1 -0
  143. package/dist/index.d.ts +3 -0
  144. package/dist/index.d.ts.map +1 -0
  145. package/dist/index.js +75 -0
  146. package/dist/index.js.map +1 -0
  147. package/dist/install/cli.d.ts +38 -0
  148. package/dist/install/cli.d.ts.map +1 -0
  149. package/dist/install/cli.js +274 -0
  150. package/dist/install/cli.js.map +1 -0
  151. package/dist/install/harnesses.d.ts +74 -0
  152. package/dist/install/harnesses.d.ts.map +1 -0
  153. package/dist/install/harnesses.js +263 -0
  154. package/dist/install/harnesses.js.map +1 -0
  155. package/dist/knowledge/corpus.d.ts +15 -0
  156. package/dist/knowledge/corpus.d.ts.map +1 -0
  157. package/dist/knowledge/corpus.js +129 -0
  158. package/dist/knowledge/corpus.js.map +1 -0
  159. package/dist/knowledge/search.d.ts +29 -0
  160. package/dist/knowledge/search.d.ts.map +1 -0
  161. package/dist/knowledge/search.js +181 -0
  162. package/dist/knowledge/search.js.map +1 -0
  163. package/dist/knowledge/source.d.ts +60 -0
  164. package/dist/knowledge/source.d.ts.map +1 -0
  165. package/dist/knowledge/source.js +91 -0
  166. package/dist/knowledge/source.js.map +1 -0
  167. package/dist/knowledge/types.d.ts +40 -0
  168. package/dist/knowledge/types.d.ts.map +1 -0
  169. package/dist/knowledge/types.js +19 -0
  170. package/dist/knowledge/types.js.map +1 -0
  171. package/dist/paths.d.ts +26 -0
  172. package/dist/paths.d.ts.map +1 -0
  173. package/dist/paths.js +106 -0
  174. package/dist/paths.js.map +1 -0
  175. package/dist/prompts/integration-walkthrough.d.ts +11 -0
  176. package/dist/prompts/integration-walkthrough.d.ts.map +1 -0
  177. package/dist/prompts/integration-walkthrough.js +52 -0
  178. package/dist/prompts/integration-walkthrough.js.map +1 -0
  179. package/dist/prompts/register.d.ts +4 -0
  180. package/dist/prompts/register.d.ts.map +1 -0
  181. package/dist/prompts/register.js +4 -0
  182. package/dist/prompts/register.js.map +1 -0
  183. package/dist/registry.d.ts +14 -0
  184. package/dist/registry.d.ts.map +1 -0
  185. package/dist/registry.js +2 -0
  186. package/dist/registry.js.map +1 -0
  187. package/dist/resources/knowledge-resources.d.ts +5 -0
  188. package/dist/resources/knowledge-resources.d.ts.map +1 -0
  189. package/dist/resources/knowledge-resources.js +121 -0
  190. package/dist/resources/knowledge-resources.js.map +1 -0
  191. package/dist/resources/register.d.ts +4 -0
  192. package/dist/resources/register.d.ts.map +1 -0
  193. package/dist/resources/register.js +8 -0
  194. package/dist/resources/register.js.map +1 -0
  195. package/dist/server.d.ts +40 -0
  196. package/dist/server.d.ts.map +1 -0
  197. package/dist/server.js +56 -0
  198. package/dist/server.js.map +1 -0
  199. package/dist/telemetry/logger.d.ts +31 -0
  200. package/dist/telemetry/logger.d.ts.map +1 -0
  201. package/dist/telemetry/logger.js +67 -0
  202. package/dist/telemetry/logger.js.map +1 -0
  203. package/dist/telemetry/redaction.d.ts +88 -0
  204. package/dist/telemetry/redaction.d.ts.map +1 -0
  205. package/dist/telemetry/redaction.js +238 -0
  206. package/dist/telemetry/redaction.js.map +1 -0
  207. package/dist/tools/build-transaction-parameters.d.ts +10 -0
  208. package/dist/tools/build-transaction-parameters.d.ts.map +1 -0
  209. package/dist/tools/build-transaction-parameters.js +154 -0
  210. package/dist/tools/build-transaction-parameters.js.map +1 -0
  211. package/dist/tools/call-context.d.ts +47 -0
  212. package/dist/tools/call-context.d.ts.map +1 -0
  213. package/dist/tools/call-context.js +15 -0
  214. package/dist/tools/call-context.js.map +1 -0
  215. package/dist/tools/codegen-tools.d.ts +4 -0
  216. package/dist/tools/codegen-tools.d.ts.map +1 -0
  217. package/dist/tools/codegen-tools.js +131 -0
  218. package/dist/tools/codegen-tools.js.map +1 -0
  219. package/dist/tools/credential-tools.d.ts +32 -0
  220. package/dist/tools/credential-tools.d.ts.map +1 -0
  221. package/dist/tools/credential-tools.js +65 -0
  222. package/dist/tools/credential-tools.js.map +1 -0
  223. package/dist/tools/descriptor.d.ts +52 -0
  224. package/dist/tools/descriptor.d.ts.map +1 -0
  225. package/dist/tools/descriptor.js +2 -0
  226. package/dist/tools/descriptor.js.map +1 -0
  227. package/dist/tools/diagnostic-tools.d.ts +3 -0
  228. package/dist/tools/diagnostic-tools.d.ts.map +1 -0
  229. package/dist/tools/diagnostic-tools.js +128 -0
  230. package/dist/tools/diagnostic-tools.js.map +1 -0
  231. package/dist/tools/gateway-tools.d.ts +6 -0
  232. package/dist/tools/gateway-tools.d.ts.map +1 -0
  233. package/dist/tools/gateway-tools.js +381 -0
  234. package/dist/tools/gateway-tools.js.map +1 -0
  235. package/dist/tools/hash-tools.d.ts +5 -0
  236. package/dist/tools/hash-tools.d.ts.map +1 -0
  237. package/dist/tools/hash-tools.js +238 -0
  238. package/dist/tools/hash-tools.js.map +1 -0
  239. package/dist/tools/knowledge-tools.d.ts +7 -0
  240. package/dist/tools/knowledge-tools.d.ts.map +1 -0
  241. package/dist/tools/knowledge-tools.js +247 -0
  242. package/dist/tools/knowledge-tools.js.map +1 -0
  243. package/dist/tools/onboarding-checklist.d.ts +3 -0
  244. package/dist/tools/onboarding-checklist.d.ts.map +1 -0
  245. package/dist/tools/onboarding-checklist.js +141 -0
  246. package/dist/tools/onboarding-checklist.js.map +1 -0
  247. package/dist/tools/register.d.ts +60 -0
  248. package/dist/tools/register.d.ts.map +1 -0
  249. package/dist/tools/register.js +145 -0
  250. package/dist/tools/register.js.map +1 -0
  251. package/dist/tools/tool-kit.d.ts +88 -0
  252. package/dist/tools/tool-kit.d.ts.map +1 -0
  253. package/dist/tools/tool-kit.js +297 -0
  254. package/dist/tools/tool-kit.js.map +1 -0
  255. package/dist/validation/payload-validator.d.ts +29 -0
  256. package/dist/validation/payload-validator.d.ts.map +1 -0
  257. package/dist/validation/payload-validator.js +79 -0
  258. package/dist/validation/payload-validator.js.map +1 -0
  259. package/dist/validation/rules/amount.d.ts +3 -0
  260. package/dist/validation/rules/amount.d.ts.map +1 -0
  261. package/dist/validation/rules/amount.js +77 -0
  262. package/dist/validation/rules/amount.js.map +1 -0
  263. package/dist/validation/rules/bill-reference.d.ts +10 -0
  264. package/dist/validation/rules/bill-reference.d.ts.map +1 -0
  265. package/dist/validation/rules/bill-reference.js +34 -0
  266. package/dist/validation/rules/bill-reference.js.map +1 -0
  267. package/dist/validation/rules/cnic.d.ts +3 -0
  268. package/dist/validation/rules/cnic.d.ts.map +1 -0
  269. package/dist/validation/rules/cnic.js +42 -0
  270. package/dist/validation/rules/cnic.js.map +1 -0
  271. package/dist/validation/rules/constants.d.ts +9 -0
  272. package/dist/validation/rules/constants.d.ts.map +1 -0
  273. package/dist/validation/rules/constants.js +28 -0
  274. package/dist/validation/rules/constants.js.map +1 -0
  275. package/dist/validation/rules/constraints.d.ts +3 -0
  276. package/dist/validation/rules/constraints.d.ts.map +1 -0
  277. package/dist/validation/rules/constraints.js +113 -0
  278. package/dist/validation/rules/constraints.js.map +1 -0
  279. package/dist/validation/rules/datetime.d.ts +3 -0
  280. package/dist/validation/rules/datetime.d.ts.map +1 -0
  281. package/dist/validation/rules/datetime.js +49 -0
  282. package/dist/validation/rules/datetime.js.map +1 -0
  283. package/dist/validation/rules/empty-string.d.ts +13 -0
  284. package/dist/validation/rules/empty-string.d.ts.map +1 -0
  285. package/dist/validation/rules/empty-string.js +32 -0
  286. package/dist/validation/rules/empty-string.js.map +1 -0
  287. package/dist/validation/rules/expiry.d.ts +3 -0
  288. package/dist/validation/rules/expiry.d.ts.map +1 -0
  289. package/dist/validation/rules/expiry.js +52 -0
  290. package/dist/validation/rules/expiry.js.map +1 -0
  291. package/dist/validation/rules/msisdn.d.ts +3 -0
  292. package/dist/validation/rules/msisdn.d.ts.map +1 -0
  293. package/dist/validation/rules/msisdn.js +45 -0
  294. package/dist/validation/rules/msisdn.js.map +1 -0
  295. package/dist/validation/rules/presence.d.ts +3 -0
  296. package/dist/validation/rules/presence.d.ts.map +1 -0
  297. package/dist/validation/rules/presence.js +90 -0
  298. package/dist/validation/rules/presence.js.map +1 -0
  299. package/dist/validation/rules/return-url.d.ts +14 -0
  300. package/dist/validation/rules/return-url.d.ts.map +1 -0
  301. package/dist/validation/rules/return-url.js +58 -0
  302. package/dist/validation/rules/return-url.js.map +1 -0
  303. package/dist/validation/rules/tool-argument.d.ts +16 -0
  304. package/dist/validation/rules/tool-argument.d.ts.map +1 -0
  305. package/dist/validation/rules/tool-argument.js +38 -0
  306. package/dist/validation/rules/tool-argument.js.map +1 -0
  307. package/dist/validation/rules/txn-ref.d.ts +3 -0
  308. package/dist/validation/rules/txn-ref.d.ts.map +1 -0
  309. package/dist/validation/rules/txn-ref.js +47 -0
  310. package/dist/validation/rules/txn-ref.js.map +1 -0
  311. package/dist/validation/rules/unknown-fields.d.ts +10 -0
  312. package/dist/validation/rules/unknown-fields.d.ts.map +1 -0
  313. package/dist/validation/rules/unknown-fields.js +29 -0
  314. package/dist/validation/rules/unknown-fields.js.map +1 -0
  315. package/dist/validation/types.d.ts +36 -0
  316. package/dist/validation/types.d.ts.map +1 -0
  317. package/dist/validation/types.js +12 -0
  318. package/dist/validation/types.js.map +1 -0
  319. package/dist/version.d.ts +23 -0
  320. package/dist/version.d.ts.map +1 -0
  321. package/dist/version.js +23 -0
  322. package/dist/version.js.map +1 -0
  323. package/knowledge/diagnostics/symptoms.json +321 -0
  324. package/knowledge/docs/bnpl-guide.md +77 -0
  325. package/knowledge/docs/card-page-redirection.md +67 -0
  326. package/knowledge/docs/card-refund.md +91 -0
  327. package/knowledge/docs/hmac-sha256-calculation.md +72 -0
  328. package/knowledge/docs/index.json +189 -0
  329. package/knowledge/docs/ipn-implementation.md +89 -0
  330. package/knowledge/docs/mwallet-recurring.md +117 -0
  331. package/knowledge/docs/mwallet-refund.md +65 -0
  332. package/knowledge/docs/mwallet-rest-v1-1.md +126 -0
  333. package/knowledge/docs/mwallet-rest-v2-0-cnic.md +113 -0
  334. package/knowledge/docs/portal-guide.md +45 -0
  335. package/knowledge/docs/shopify-guide.md +74 -0
  336. package/knowledge/docs/status-inquiry-2025-26.md +32 -0
  337. package/knowledge/docs/status-inquiry.md +111 -0
  338. package/knowledge/docs/wordpress-guide.md +49 -0
  339. package/knowledge/flow.schema.json +390 -0
  340. package/knowledge/flows/bnpl-page-redirection-v1.1.json +211 -0
  341. package/knowledge/flows/card-page-redirection-v1.1.json +211 -0
  342. package/knowledge/flows/mwallet-rest-v1.1.json +187 -0
  343. package/knowledge/flows/mwallet-rest-v2.0-cnic.json +197 -0
  344. package/knowledge/flows/mwallet-token-pay-v4.0.json +130 -0
  345. package/knowledge/flows/refund-bnpl.json +105 -0
  346. package/knowledge/flows/refund-card-v1.1.json +112 -0
  347. package/knowledge/flows/refund-card-v2.0.json +121 -0
  348. package/knowledge/flows/refund-mwallet-v1.1.json +106 -0
  349. package/knowledge/flows/status-inquiry-v1.1.json +102 -0
  350. package/knowledge/flows/status-inquiry-v2.0.json +103 -0
  351. package/knowledge/flows/token-delete-v1.json +85 -0
  352. package/knowledge/flows/token-inquiry-v1.json +85 -0
  353. package/knowledge/flows/wallet-linking-portal.json +103 -0
  354. package/knowledge/templates/node/checkout-redirect.tmpl +166 -0
  355. package/knowledge/templates/node/ipn-handler.tmpl +108 -0
  356. package/knowledge/templates/node/rest-client.tmpl +197 -0
  357. package/knowledge/templates/node/wallet-linking.tmpl +147 -0
  358. package/knowledge/templates/php/checkout-redirect.tmpl +149 -0
  359. package/knowledge/templates/php/ipn-handler.tmpl +105 -0
  360. package/knowledge/templates/php/rest-client.tmpl +191 -0
  361. package/knowledge/templates/php/wallet-linking.tmpl +137 -0
  362. package/knowledge/templates/python/checkout-redirect.tmpl +148 -0
  363. package/knowledge/templates/python/ipn-handler.tmpl +110 -0
  364. package/knowledge/templates/python/rest-client.tmpl +179 -0
  365. package/knowledge/templates/python/wallet-linking.tmpl +133 -0
  366. package/package.json +84 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-argument.d.ts","sourceRoot":"","sources":["../../../src/validation/rules/tool-argument.ts"],"names":[],"mappings":"AAAA,OAAO,EAA+B,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAE/E;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,gBAAgB,EAAE,cA4B9B,CAAC"}
@@ -0,0 +1,38 @@
1
+ import { issue } from '../types.js';
2
+ /**
3
+ * A parameter the flow marks `neverAcceptAsToolArgument` must not appear at all.
4
+ *
5
+ * Card flows carry the PAN, the expiry and the CVV. `safeHandler` scrubs tool
6
+ * OUTPUTS, not inputs, so a value supplied here was written to the conversation
7
+ * transcript — and to whatever the harness persists of it — before any server
8
+ * code ran. By the time this rule fires the disclosure has already happened, so
9
+ * the issue says so plainly instead of offering a correction that would repeat
10
+ * it: the only safe next step is to route the value around this server and to
11
+ * treat the one already sent as compromised.
12
+ *
13
+ * The value is never echoed back, for the same reason.
14
+ */
15
+ export const toolArgumentRule = (context) => {
16
+ const issues = [];
17
+ for (const parameter of context.flow.parameters) {
18
+ if (!parameter.neverAcceptAsToolArgument) {
19
+ continue;
20
+ }
21
+ // Absent is the expected state, and an empty string carries nothing: the
22
+ // presence rule deliberately leaves such a parameter alone rather than
23
+ // asking the merchant to supply one, so neither case is a disclosure.
24
+ const value = context.parameters[parameter.name];
25
+ if (value === undefined || value === '') {
26
+ continue;
27
+ }
28
+ issues.push(issue(context, {
29
+ code: 'tool-argument.forbidden',
30
+ severity: 'error',
31
+ field: parameter.name,
32
+ message: `${parameter.name} must never be sent through this server. ${context.flow.title} declares it as data that cannot cross the tool boundary, and the value supplied here was already recorded in the conversation before validation ran.`,
33
+ fix: `Remove "${parameter.name}" from the payload and let your own server, or the provider's hosted field, supply it directly to the gateway. Treat the value already sent as compromised.`,
34
+ }));
35
+ }
36
+ return issues;
37
+ };
38
+ //# sourceMappingURL=tool-argument.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-argument.js","sourceRoot":"","sources":["../../../src/validation/rules/tool-argument.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAA6C,MAAM,aAAa,CAAC;AAE/E;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAmB,CAAC,OAAO,EAA8B,EAAE;IACtF,MAAM,MAAM,GAAsB,EAAE,CAAC;IAErC,KAAK,MAAM,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;QAChD,IAAI,CAAC,SAAS,CAAC,yBAAyB,EAAE,CAAC;YACzC,SAAS;QACX,CAAC;QAED,yEAAyE;QACzE,uEAAuE;QACvE,sEAAsE;QACtE,MAAM,KAAK,GAAG,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACjD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;YACxC,SAAS;QACX,CAAC;QAED,MAAM,CAAC,IAAI,CACT,KAAK,CAAC,OAAO,EAAE;YACb,IAAI,EAAE,yBAAyB;YAC/B,QAAQ,EAAE,OAAO;YACjB,KAAK,EAAE,SAAS,CAAC,IAAI;YACrB,OAAO,EAAE,GAAG,SAAS,CAAC,IAAI,4CAA4C,OAAO,CAAC,IAAI,CAAC,KAAK,uJAAuJ;YAC/O,GAAG,EAAE,WAAW,SAAS,CAAC,IAAI,6JAA6J;SAC5L,CAAC,CACH,CAAC;IACJ,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { type ValidationRule } from '../types.js';
2
+ export declare const txnRefRule: ValidationRule;
3
+ //# sourceMappingURL=txn-ref.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"txn-ref.d.ts","sourceRoot":"","sources":["../../../src/validation/rules/txn-ref.ts"],"names":[],"mappings":"AACA,OAAO,EAA+B,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAY/E,eAAO,MAAM,UAAU,EAAE,cA8CxB,CAAC"}
@@ -0,0 +1,47 @@
1
+ import { MAX_TXN_REF_LENGTH, validateRequestId, validateTxnRefNo } from '../../domain/txn-ref.js';
2
+ import { issue } from '../types.js';
3
+ /**
4
+ * `pp_TxnRefNo` and `pp_RequestID` must be unique alphanumeric identifiers.
5
+ *
6
+ * Uniqueness cannot be checked from a single payload, so it is surfaced as a
7
+ * standing reminder whenever the value looks like it could have been reused —
8
+ * specifically when it carries no time component.
9
+ */
10
+ const CONTAINS_TIMESTAMP = /\d{14}/;
11
+ export const txnRefRule = (context) => {
12
+ const issues = [];
13
+ for (const parameter of context.flow.parameters) {
14
+ if (parameter.valueType !== 'txn-ref' && parameter.valueType !== 'request-id') {
15
+ continue;
16
+ }
17
+ const value = context.parameters[parameter.name];
18
+ if (value === undefined || value === '') {
19
+ continue;
20
+ }
21
+ // The flow's own declared maximum wins over the documented default, so a
22
+ // correction from JazzCash stays a data change rather than a code change.
23
+ const check = parameter.valueType === 'txn-ref'
24
+ ? validateTxnRefNo(value, parameter.maxLength)
25
+ : validateRequestId(value, parameter.maxLength);
26
+ for (const problem of check.issues) {
27
+ issues.push(issue(context, {
28
+ code: 'txn-ref.invalid',
29
+ severity: 'error',
30
+ field: parameter.name,
31
+ message: problem.replace(/^pp_\w+/, parameter.name),
32
+ fix: `Use up to ${String(parameter.maxLength ?? MAX_TXN_REF_LENGTH)} letters and digits. The documented shape is a three-letter merchant prefix followed by YYYYMMDDHHMMSS, for example "Goo20230208115409".`,
33
+ }));
34
+ }
35
+ if (check.valid && !CONTAINS_TIMESTAMP.test(value)) {
36
+ issues.push(issue(context, {
37
+ code: 'txn-ref.uniqueness-unverifiable',
38
+ severity: 'warning',
39
+ field: parameter.name,
40
+ message: `${parameter.name} ("${value}") carries no timestamp, so uniqueness across transactions cannot be inferred. The gateway rejects a reference it has already seen.`,
41
+ fix: 'Append a YYYYMMDDHHMMSS stamp, plus a few random alphanumeric characters if you may create more than one transaction per second. A clock alone cannot separate two references generated in the same instant.',
42
+ }));
43
+ }
44
+ }
45
+ return issues;
46
+ };
47
+ //# sourceMappingURL=txn-ref.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"txn-ref.js","sourceRoot":"","sources":["../../../src/validation/rules/txn-ref.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAClG,OAAO,EAAE,KAAK,EAA6C,MAAM,aAAa,CAAC;AAE/E;;;;;;GAMG;AAEH,MAAM,kBAAkB,GAAG,QAAQ,CAAC;AAEpC,MAAM,CAAC,MAAM,UAAU,GAAmB,CAAC,OAAO,EAA8B,EAAE;IAChF,MAAM,MAAM,GAAsB,EAAE,CAAC;IAErC,KAAK,MAAM,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;QAChD,IAAI,SAAS,CAAC,SAAS,KAAK,SAAS,IAAI,SAAS,CAAC,SAAS,KAAK,YAAY,EAAE,CAAC;YAC9E,SAAS;QACX,CAAC;QAED,MAAM,KAAK,GAAG,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACjD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;YACxC,SAAS;QACX,CAAC;QAED,yEAAyE;QACzE,0EAA0E;QAC1E,MAAM,KAAK,GACT,SAAS,CAAC,SAAS,KAAK,SAAS;YAC/B,CAAC,CAAC,gBAAgB,CAAC,KAAK,EAAE,SAAS,CAAC,SAAS,CAAC;YAC9C,CAAC,CAAC,iBAAiB,CAAC,KAAK,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;QAEpD,KAAK,MAAM,OAAO,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;YACnC,MAAM,CAAC,IAAI,CACT,KAAK,CAAC,OAAO,EAAE;gBACb,IAAI,EAAE,iBAAiB;gBACvB,QAAQ,EAAE,OAAO;gBACjB,KAAK,EAAE,SAAS,CAAC,IAAI;gBACrB,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,SAAS,EAAE,SAAS,CAAC,IAAI,CAAC;gBACnD,GAAG,EAAE,aAAa,MAAM,CAAC,SAAS,CAAC,SAAS,IAAI,kBAAkB,CAAC,0IAA0I;aAC9M,CAAC,CACH,CAAC;QACJ,CAAC;QAED,IAAI,KAAK,CAAC,KAAK,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YACnD,MAAM,CAAC,IAAI,CACT,KAAK,CAAC,OAAO,EAAE;gBACb,IAAI,EAAE,iCAAiC;gBACvC,QAAQ,EAAE,SAAS;gBACnB,KAAK,EAAE,SAAS,CAAC,IAAI;gBACrB,OAAO,EAAE,GAAG,SAAS,CAAC,IAAI,MAAM,KAAK,qIAAqI;gBAC1K,GAAG,EAAE,8MAA8M;aACpN,CAAC,CACH,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { type ValidationRule } from '../types.js';
2
+ /**
3
+ * No parameter may be added that the flow does not declare.
4
+ *
5
+ * "No parameters may be added or removed from the request payload." An extra
6
+ * field with a non-empty value silently changes the secure hash, which surfaces
7
+ * to the merchant as an unexplained mismatch rather than as a rejected field.
8
+ */
9
+ export declare const unknownFieldsRule: ValidationRule;
10
+ //# sourceMappingURL=unknown-fields.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unknown-fields.d.ts","sourceRoot":"","sources":["../../../src/validation/rules/unknown-fields.ts"],"names":[],"mappings":"AACA,OAAO,EAA+B,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAE/E;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,EAAE,cA2B/B,CAAC"}
@@ -0,0 +1,29 @@
1
+ import { parameterNames } from '../../catalogue/types.js';
2
+ import { issue } from '../types.js';
3
+ /**
4
+ * No parameter may be added that the flow does not declare.
5
+ *
6
+ * "No parameters may be added or removed from the request payload." An extra
7
+ * field with a non-empty value silently changes the secure hash, which surfaces
8
+ * to the merchant as an unexplained mismatch rather than as a rejected field.
9
+ */
10
+ export const unknownFieldsRule = (context) => {
11
+ const declared = new Set(parameterNames(context.flow));
12
+ const issues = [];
13
+ for (const name of Object.keys(context.parameters)) {
14
+ if (declared.has(name)) {
15
+ continue;
16
+ }
17
+ const value = context.parameters[name] ?? '';
18
+ const affectsHash = value !== '' && context.flow.hash.includeFieldPrefixes.some((prefix) => name.startsWith(prefix));
19
+ issues.push(issue(context, {
20
+ code: 'unknown-fields.not-declared',
21
+ severity: 'error',
22
+ field: name,
23
+ message: `${name} is not part of ${context.flow.title}.${affectsHash ? ' It is non-empty and matches a hashed prefix, so it is also corrupting your secure hash.' : ''}`,
24
+ fix: `Remove "${name}" from the payload. The documented field set for this flow is: ${parameterNames(context.flow).join(', ')}.`,
25
+ }));
26
+ }
27
+ return issues;
28
+ };
29
+ //# sourceMappingURL=unknown-fields.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unknown-fields.js","sourceRoot":"","sources":["../../../src/validation/rules/unknown-fields.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,KAAK,EAA6C,MAAM,aAAa,CAAC;AAE/E;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAmB,CAAC,OAAO,EAA8B,EAAE;IACvF,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IACvD,MAAM,MAAM,GAAsB,EAAE,CAAC;IAErC,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;QACnD,IAAI,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACvB,SAAS;QACX,CAAC;QAED,MAAM,KAAK,GAAG,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QAC7C,MAAM,WAAW,GACf,KAAK,KAAK,EAAE,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;QAEnG,MAAM,CAAC,IAAI,CACT,KAAK,CAAC,OAAO,EAAE;YACb,IAAI,EAAE,6BAA6B;YACnC,QAAQ,EAAE,OAAO;YACjB,KAAK,EAAE,IAAI;YACX,OAAO,EAAE,GAAG,IAAI,mBAAmB,OAAO,CAAC,IAAI,CAAC,KAAK,IACnD,WAAW,CAAC,CAAC,CAAC,0FAA0F,CAAC,CAAC,CAAC,EAC7G,EAAE;YACF,GAAG,EAAE,WAAW,IAAI,kEAAkE,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;SACjI,CAAC,CACH,CAAC;IACJ,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC"}
@@ -0,0 +1,36 @@
1
+ import type { IntegrationFlow } from '../catalogue/types.js';
2
+ import type { NormalisedParameters } from '../domain/types.js';
3
+ import type { DocRef } from '../errors.js';
4
+ /**
5
+ * Validation vocabulary.
6
+ *
7
+ * Every issue is structured rather than a bare string, so a tool result can be
8
+ * rendered for a human and consumed by a model without re-parsing prose. The
9
+ * `fix` field is mandatory: an error that does not say what to do instead is an
10
+ * error the merchant will bring straight back to a support engineer.
11
+ */
12
+ export type IssueSeverity = 'error' | 'warning';
13
+ export interface ValidationIssue {
14
+ /** Stable machine-readable identifier, e.g. `amount.not-minor-units`. */
15
+ readonly code: string;
16
+ readonly severity: IssueSeverity;
17
+ /** Parameter this concerns, or `undefined` for payload-level issues. */
18
+ readonly field: string | undefined;
19
+ readonly message: string;
20
+ readonly fix: string;
21
+ readonly docRefs: readonly DocRef[];
22
+ }
23
+ export interface RuleContext {
24
+ readonly flow: IntegrationFlow;
25
+ readonly parameters: NormalisedParameters;
26
+ /** The `pp_ReturnURL` registered against the merchant profile, when known. */
27
+ readonly registeredReturnUrl: string | undefined;
28
+ /** Injectable clock so plausibility checks are deterministic under test. */
29
+ readonly now: Date;
30
+ }
31
+ export type ValidationRule = (context: RuleContext) => readonly ValidationIssue[];
32
+ /** Build an issue, defaulting the citations to the flow's own documentation. */
33
+ export declare function issue(context: RuleContext, partial: Omit<ValidationIssue, 'docRefs'> & {
34
+ docRefs?: readonly DocRef[];
35
+ }): ValidationIssue;
36
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/validation/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAE3C;;;;;;;GAOG;AAEH,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,SAAS,CAAC;AAEhD,MAAM,WAAW,eAAe;IAC9B,yEAAyE;IACzE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;IACjC,wEAAwE;IACxE,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;IAC/B,QAAQ,CAAC,UAAU,EAAE,oBAAoB,CAAC;IAC1C,8EAA8E;IAC9E,QAAQ,CAAC,mBAAmB,EAAE,MAAM,GAAG,SAAS,CAAC;IACjD,4EAA4E;IAC5E,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC;CACpB;AAED,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,EAAE,WAAW,KAAK,SAAS,eAAe,EAAE,CAAC;AAElF,gFAAgF;AAChF,wBAAgB,KAAK,CACnB,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE,IAAI,CAAC,eAAe,EAAE,SAAS,CAAC,GAAG;IAAE,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GAC1E,eAAe,CASjB"}
@@ -0,0 +1,12 @@
1
+ /** Build an issue, defaulting the citations to the flow's own documentation. */
2
+ export function issue(context, partial) {
3
+ return {
4
+ code: partial.code,
5
+ severity: partial.severity,
6
+ field: partial.field,
7
+ message: partial.message,
8
+ fix: partial.fix,
9
+ docRefs: partial.docRefs ?? context.flow.docRefs,
10
+ };
11
+ }
12
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/validation/types.ts"],"names":[],"mappings":"AAqCA,gFAAgF;AAChF,MAAM,UAAU,KAAK,CACnB,OAAoB,EACpB,OAA2E;IAE3E,OAAO;QACL,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO;KACjD,CAAC;AACJ,CAAC"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Server name and version reported to MCP clients.
3
+ *
4
+ * Kept as source rather than imported from `package.json`, which lives outside
5
+ * `rootDir`. `tests/version.test.ts` asserts the two stay in step, so this
6
+ * cannot drift silently.
7
+ *
8
+ * The npm package is scoped — `@atbas/m-mcp` — and this is deliberately not.
9
+ * It is also the key an install writes into a harness config file, and a scope
10
+ * there buys nothing while costing a quoted TOML key and a `/` in every
11
+ * merchant's configuration. The parity test compares this against the package
12
+ * name with its scope removed, so the two still cannot drift apart.
13
+ */
14
+ export declare const SERVER_NAME = "m-mcp";
15
+ export declare const SERVER_VERSION = "0.1.0";
16
+ /**
17
+ * Version stamp of the JazzCash documentation corpus this build encodes.
18
+ *
19
+ * Every guide under `docs/integration_documents/` is marked "VERSION: 2026".
20
+ * When a newer set of guides arrives, regenerate the corpus and bump this.
21
+ */
22
+ export declare const CORPUS_VERSION = "2026";
23
+ //# sourceMappingURL=version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,WAAW,UAAU,CAAC;AAEnC,eAAO,MAAM,cAAc,UAAU,CAAC;AAEtC;;;;;GAKG;AACH,eAAO,MAAM,cAAc,SAAS,CAAC"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Server name and version reported to MCP clients.
3
+ *
4
+ * Kept as source rather than imported from `package.json`, which lives outside
5
+ * `rootDir`. `tests/version.test.ts` asserts the two stay in step, so this
6
+ * cannot drift silently.
7
+ *
8
+ * The npm package is scoped — `@atbas/m-mcp` — and this is deliberately not.
9
+ * It is also the key an install writes into a harness config file, and a scope
10
+ * there buys nothing while costing a quoted TOML key and a `/` in every
11
+ * merchant's configuration. The parity test compares this against the package
12
+ * name with its scope removed, so the two still cannot drift apart.
13
+ */
14
+ export const SERVER_NAME = 'm-mcp';
15
+ export const SERVER_VERSION = '0.1.0';
16
+ /**
17
+ * Version stamp of the JazzCash documentation corpus this build encodes.
18
+ *
19
+ * Every guide under `docs/integration_documents/` is marked "VERSION: 2026".
20
+ * When a newer set of guides arrives, regenerate the corpus and bump this.
21
+ */
22
+ export const CORPUS_VERSION = '2026';
23
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,OAAO,CAAC;AAEnC,MAAM,CAAC,MAAM,cAAc,GAAG,OAAO,CAAC;AAEtC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,MAAM,CAAC"}
@@ -0,0 +1,321 @@
1
+ {
2
+ "version": "2026",
3
+ "note": "Symptom knowledge base. Every entry is traceable to the 2026 guides or to a defect found in their own samples. Causes are ordered most-likely-first.",
4
+ "symptoms": [
5
+ {
6
+ "id": "hash-mismatch",
7
+ "title": "Secure hash mismatch (HASH_MISMATCH)",
8
+ "keywords": ["hash", "mismatch", "securehash", "signature", "invalid hash", "hash_mismatch", "integrity"],
9
+ "causes": [
10
+ {
11
+ "cause": "The Integrity Salt is prepended to the message AND used as the HMAC key. One of the two is usually missing.",
12
+ "check": "Print the exact string you hash. It must start with your salt followed by '&'.",
13
+ "fix": "Build `salt & value1 & value2 …` and pass the same salt as the HMAC key.",
14
+ "docRefs": [{ "docId": "hmac-sha256-calculation", "sectionId": "how-is-hmac-sha256-calculated" }]
15
+ },
16
+ {
17
+ "cause": "Empty parameters were included in the hash string.",
18
+ "check": "Count the values in your hash string against the non-empty fields in your payload.",
19
+ "fix": "Skip values that are the empty string when hashing. Keep sending those fields as \"\".",
20
+ "docRefs": [{ "docId": "hmac-sha256-calculation", "sectionId": "rules-that-are-easy-to-miss" }]
21
+ },
22
+ {
23
+ "cause": "Parameters were not sorted by name, or were sorted with a locale-aware comparator.",
24
+ "check": "Confirm the sort is a plain ASCII comparison of the raw parameter names.",
25
+ "fix": "In PHP use `ksort($params, SORT_STRING)`. In JavaScript use `.sort()` without `localeCompare`.",
26
+ "docRefs": [{ "docId": "hmac-sha256-calculation", "sectionId": "php-sample-divergences" }]
27
+ },
28
+ {
29
+ "cause": "A stale pp_SecureHash was left in the payload and fed back into its own calculation.",
30
+ "check": "Confirm pp_SecureHash is removed before hashing, particularly on a retry.",
31
+ "fix": "Delete pp_SecureHash from the parameter set, hash, then add the result back.",
32
+ "docRefs": [{ "docId": "hmac-sha256-calculation", "sectionId": "rules-that-are-easy-to-miss" }]
33
+ },
34
+ {
35
+ "cause": "ppmpf_* fields were excluded from the hash while carrying values (assumption A1).",
36
+ "check": "If any ppmpf_1..5 is non-empty, confirm it participates in the hash.",
37
+ "fix": "Include non-empty ppmpf_* fields, matching the official PHP samples. Note that the official JavaScript sample disagrees; JazzCash has not resolved this.",
38
+ "docRefs": [{ "docId": "mwallet-rest-v1-1", "sectionId": "common-failures" }]
39
+ },
40
+ {
41
+ "cause": "The payload was modified after the hash was computed.",
42
+ "check": "Confirm nothing regenerates a timestamp or reference between hashing and sending.",
43
+ "fix": "Compute the hash as the last step, from exactly the map you transmit.",
44
+ "docRefs": [{ "docId": "hmac-sha256-calculation", "sectionId": "common-failures" }]
45
+ },
46
+ {
47
+ "cause": "The salt belongs to a different environment or merchant.",
48
+ "check": "Re-copy the Integrity Salt from Integration > Credentials for the environment you are calling.",
49
+ "fix": "Confirm the salt and the Merchant ID come from the same portal account.",
50
+ "docRefs": [{ "docId": "portal-guide", "sectionId": "credentials" }]
51
+ }
52
+ ]
53
+ },
54
+ {
55
+ "id": "return-url-validation-failure",
56
+ "title": "Request rejected although the data looks correct",
57
+ "keywords": ["return url", "returnurl", "validation failed", "authentication", "rejected", "callback url"],
58
+ "causes": [
59
+ {
60
+ "cause": "pp_ReturnURL differs from the URL registered against the merchant profile.",
61
+ "check": "Compare the transmitted URL with the registered one character by character, including any trailing slash.",
62
+ "fix": "Send the registered URL exactly, or update it under Integration > Credentials. It is part of merchant authentication, so any difference fails validation.",
63
+ "docRefs": [{ "docId": "card-page-redirection", "sectionId": "important-notes" }]
64
+ },
65
+ {
66
+ "cause": "A parameter was added to or removed from the documented field set.",
67
+ "check": "Compare your payload against the flow specification.",
68
+ "fix": "Send exactly the documented fields: no additions, no removals, unused ones as \"\".",
69
+ "docRefs": [{ "docId": "mwallet-rest-v1-1", "sectionId": "request-payload-rules" }]
70
+ },
71
+ {
72
+ "cause": "A field was sent as JSON null rather than an empty string.",
73
+ "check": "Search the payload for null values.",
74
+ "fix": "Replace every null with \"\".",
75
+ "docRefs": [{ "docId": "mwallet-rest-v1-1", "sectionId": "request-payload-rules" }]
76
+ }
77
+ ]
78
+ },
79
+ {
80
+ "id": "wrong-amount",
81
+ "title": "Customer charged the wrong amount",
82
+ "keywords": ["amount", "wrong amount", "100 times", "minor units", "decimal", "too much", "too little"],
83
+ "causes": [
84
+ {
85
+ "cause": "pp_Amount was sent in major units rather than minor units.",
86
+ "check": "PKR 100.00 must be transmitted as \"10000\".",
87
+ "fix": "Multiply by 100 before sending and divide by 100 when reading a response. Use integer or decimal arithmetic, never floating point.",
88
+ "docRefs": [{ "docId": "mwallet-rest-v1-1", "sectionId": "currency-and-amount-handling" }]
89
+ },
90
+ {
91
+ "cause": "A refund amount was converted differently from the payment amount.",
92
+ "check": "Confirm the refund path applies the same ×100 conversion.",
93
+ "fix": "Share one conversion helper between payment and refund code.",
94
+ "docRefs": [{ "docId": "card-refund", "sectionId": "common-failures" }]
95
+ }
96
+ ]
97
+ },
98
+ {
99
+ "id": "duplicate-transaction-reference",
100
+ "title": "Transaction rejected as a duplicate",
101
+ "keywords": ["duplicate", "txnrefno", "already exists", "reference", "unique"],
102
+ "causes": [
103
+ {
104
+ "cause": "pp_TxnRefNo was reused.",
105
+ "check": "Confirm a fresh reference is generated for every attempt, including retries.",
106
+ "fix": "Use a prefix plus YYYYMMDDHHMMSS plus milliseconds, so two orders in the same second cannot collide.",
107
+ "docRefs": [{ "docId": "mwallet-rest-v1-1", "sectionId": "transaction-reference-requirements" }]
108
+ },
109
+ {
110
+ "cause": "A failed request was retried with the same reference.",
111
+ "check": "Confirm the retry path resolves the outcome before resending.",
112
+ "fix": "Call Status Inquiry to establish whether the first attempt succeeded, rather than resending blindly.",
113
+ "docRefs": [{ "docId": "status-inquiry", "sectionId": "introduction" }]
114
+ }
115
+ ]
116
+ },
117
+ {
118
+ "id": "bill-reference-rejected",
119
+ "title": "pp_BillReference rejected",
120
+ "keywords": ["billreference", "bill reference", "alphanumeric", "special character", "order number"],
121
+ "causes": [
122
+ {
123
+ "cause": "The value contains spaces or punctuation.",
124
+ "check": "pp_BillReference must contain only A-Z, a-z and 0-9.",
125
+ "fix": "Strip punctuation from your order number, e.g. ORD-1024/A becomes ORD1024A. The value may repeat across transactions.",
126
+ "docRefs": [{ "docId": "mwallet-rest-v1-1", "sectionId": "transaction-reference-requirements" }]
127
+ }
128
+ ]
129
+ },
130
+ {
131
+ "id": "timestamp-rejected",
132
+ "title": "Timestamp or expiry rejected",
133
+ "keywords": ["timestamp", "datetime", "expiry", "expired", "timezone", "txndatetime", "pkt"],
134
+ "causes": [
135
+ {
136
+ "cause": "The timestamp was generated in the host time zone rather than Pakistan Standard Time.",
137
+ "check": "Compare your stamp against the current time in Asia/Karachi.",
138
+ "fix": "Set the time zone explicitly: `date_default_timezone_set('Asia/Karachi')`, `ZoneInfo('Asia/Karachi')`, or an Intl formatter with `timeZone: 'Asia/Karachi'`.",
139
+ "docRefs": [{ "docId": "mwallet-rest-v1-1", "sectionId": "date-and-time-parameters" }]
140
+ },
141
+ {
142
+ "cause": "pp_TxnExpiryDateTime is not one day after pp_TxnDateTime.",
143
+ "check": "Confirm the expiry follows the transaction by one day.",
144
+ "fix": "Derive the expiry from the transaction time rather than computing it separately. Note that the token payment sample in the recurring guide has an expiry two months BEFORE its transaction time; do not copy it.",
145
+ "docRefs": [{ "docId": "mwallet-recurring", "sectionId": "mwallet-pay-via-token" }]
146
+ }
147
+ ]
148
+ },
149
+ {
150
+ "id": "ipn-not-received",
151
+ "title": "IPN notifications never arrive",
152
+ "keywords": ["ipn", "webhook", "notification", "callback", "not received", "never arrives"],
153
+ "causes": [
154
+ {
155
+ "cause": "The IPN URL is not registered.",
156
+ "check": "Open Integration > Credentials and confirm the IPN field is populated.",
157
+ "fix": "Register the public URL of your listener. For WooCommerce the path is {base}/jazzcash_ipn_v2.",
158
+ "docRefs": [{ "docId": "wordpress-guide", "sectionId": "return-and-ipn-urls" }]
159
+ },
160
+ {
161
+ "cause": "The listener is not reachable from the internet, or does not answer within 60 seconds.",
162
+ "check": "Post a sample notification to your own URL from outside your network.",
163
+ "fix": "Acknowledge first and process asynchronously. JazzCash retries twice, then stops.",
164
+ "docRefs": [{ "docId": "ipn-implementation", "sectionId": "retry-behaviour" }]
165
+ },
166
+ {
167
+ "cause": "The listener returns a non-000 response, so JazzCash treats delivery as failed.",
168
+ "check": "Confirm the handler returns pp_ResponseCode \"000\" on success.",
169
+ "fix": "Return the documented acknowledgement body, including your own pp_SecureHash.",
170
+ "docRefs": [{ "docId": "ipn-implementation", "sectionId": "expected-ipn-response" }]
171
+ }
172
+ ]
173
+ },
174
+ {
175
+ "id": "orders-fulfilled-twice",
176
+ "title": "Orders fulfilled or counted twice",
177
+ "keywords": ["duplicate order", "twice", "retry", "idempotent", "double", "fulfilled twice"],
178
+ "causes": [
179
+ {
180
+ "cause": "The IPN handler is not idempotent and JazzCash retried.",
181
+ "check": "A failed or slow acknowledgement causes two more deliveries of the same notification.",
182
+ "fix": "Key on pp_TxnRefNo. If the order is already paid, acknowledge and stop.",
183
+ "docRefs": [{ "docId": "ipn-implementation", "sectionId": "retry-behaviour" }]
184
+ }
185
+ ]
186
+ },
187
+ {
188
+ "id": "refund-fails",
189
+ "title": "Refund is rejected",
190
+ "keywords": ["refund", "mpin", "reversal", "refund failed", "cannot refund"],
191
+ "causes": [
192
+ {
193
+ "cause": "The Merchant MPIN is not saved in the merchant portal.",
194
+ "check": "Sending the MPIN in the request is not sufficient: it must also be stored in the portal.",
195
+ "fix": "Save the MPIN in the merchant portal, then retry.",
196
+ "docRefs": [{ "docId": "shopify-guide", "sectionId": "step-8-refunds" }]
197
+ },
198
+ {
199
+ "cause": "The original transaction did not complete.",
200
+ "check": "Run Status Inquiry against the original pp_TxnRefNo and confirm pp_PaymentResponseCode is 121.",
201
+ "fix": "Only completed transactions can be refunded.",
202
+ "docRefs": [{ "docId": "status-inquiry", "sectionId": "reading-the-codes" }]
203
+ },
204
+ {
205
+ "cause": "A new pp_TxnRefNo was generated instead of referencing the original transaction.",
206
+ "check": "The refund payload must carry the ORIGINAL transaction's reference.",
207
+ "fix": "Send the reference of the transaction being refunded.",
208
+ "docRefs": [{ "docId": "mwallet-refund", "sectionId": "sample-request" }]
209
+ },
210
+ {
211
+ "cause": "Cumulative refunds would exceed the original amount.",
212
+ "check": "Compare TotalRefundAmount from the previous refund against the original amount.",
213
+ "fix": "Track the cumulative total before issuing another partial refund.",
214
+ "docRefs": [{ "docId": "card-refund", "sectionId": "unprefixed-response-fields" }]
215
+ }
216
+ ]
217
+ },
218
+ {
219
+ "id": "response-fields-not-found",
220
+ "title": "Response fields are missing or undefined",
221
+ "keywords": ["undefined", "missing field", "responsecode", "securehash", "not found", "null response"],
222
+ "causes": [
223
+ {
224
+ "cause": "Card and BNPL refund responses use unprefixed field names.",
225
+ "check": "Those responses carry ResponseCode, ResponseMessage and SecureHash, with no pp_ prefix.",
226
+ "fix": "Read both spellings, or branch on the flow.",
227
+ "docRefs": [{ "docId": "card-refund", "sectionId": "unprefixed-response-fields" }]
228
+ },
229
+ {
230
+ "cause": "The retrieval reference is spelled differently across APIs.",
231
+ "check": "MWallet payment responses return pp_RetreivalReferenceNo; Status Inquiry returns pp_RetrievalReferenceNo.",
232
+ "fix": "Match the gateway's spelling for the API you called.",
233
+ "docRefs": [{ "docId": "status-inquiry", "sectionId": "reading-the-codes" }]
234
+ }
235
+ ]
236
+ },
237
+ {
238
+ "id": "payment-method-missing",
239
+ "title": "The payment method does not appear",
240
+ "keywords": ["not showing", "missing method", "not enabled", "no option", "payment method"],
241
+ "causes": [
242
+ {
243
+ "cause": "JazzCash has not enabled the payment option against your Merchant ID.",
244
+ "check": "Every guide asks you to share your Merchant ID so the team can enable the option.",
245
+ "fix": "Send your Merchant ID to JazzCash and ask for the specific method to be enabled.",
246
+ "docRefs": [{ "docId": "card-page-redirection", "sectionId": "create-a-sandbox-account" }]
247
+ },
248
+ {
249
+ "cause": "In Shopify, the old JazzCash payment method is still active.",
250
+ "check": "Settings > Payments may show two JazzCash methods.",
251
+ "fix": "Deactivate the old method, but do not uninstall the old app until outstanding transactions are settled.",
252
+ "docRefs": [{ "docId": "shopify-guide", "sectionId": "step-1-deactivate" }]
253
+ }
254
+ ]
255
+ },
256
+ {
257
+ "id": "unknown-response-code",
258
+ "title": "An unrecognised response code",
259
+ "keywords": ["unknown code", "response code", "what does", "undocumented", "157", "124"],
260
+ "causes": [
261
+ {
262
+ "cause": "The 2026 corpus documents only 000, 121, 199 and 999.",
263
+ "check": "Read the accompanying message field, which carries the gateway's own description.",
264
+ "fix": "Treat the transaction as UNRESOLVED, not failed. Run Status Inquiry, and escalate to JazzCash with the pp_TxnRefNo and retrieval reference if it stays unclear. Do not refund or re-charge on an unrecognised code.",
265
+ "docRefs": [{ "docId": "status-inquiry", "sectionId": "reading-the-codes" }]
266
+ }
267
+ ]
268
+ },
269
+ {
270
+ "id": "paid-but-not-marked-paid",
271
+ "title": "Money was taken but the order is not marked paid",
272
+ "keywords": ["not marked paid", "money taken", "debited", "pending order", "stuck pending"],
273
+ "causes": [
274
+ {
275
+ "cause": "pp_ResponseCode 000 was read as proof of payment on a Status Inquiry.",
276
+ "check": "On Status Inquiry, 000 means only that the enquiry itself worked.",
277
+ "fix": "Read pp_PaymentResponseCode: 121 means the money moved.",
278
+ "docRefs": [{ "docId": "status-inquiry", "sectionId": "introduction" }]
279
+ },
280
+ {
281
+ "cause": "The IPN did not arrive and no reconciliation runs.",
282
+ "check": "Look for transactions with no terminal state older than ten minutes.",
283
+ "fix": "Run Status Inquiry on a schedule for any transaction without a terminal outcome. Status Inquiry is a mandatory integration precisely for this.",
284
+ "docRefs": [{ "docId": "status-inquiry", "sectionId": "introduction" }]
285
+ }
286
+ ]
287
+ },
288
+ {
289
+ "id": "credentials-exposed",
290
+ "title": "Integrity Salt or credentials exposed",
291
+ "keywords": ["salt", "exposed", "browser", "client side", "leak", "public", "javascript"],
292
+ "causes": [
293
+ {
294
+ "cause": "The hash is computed in browser JavaScript, as the official wallet-linking sample does.",
295
+ "check": "View source on your linking or checkout page and search for the salt.",
296
+ "fix": "Compute pp_SecureHash on your server and render only the finished hash. The salt is the HMAC key: anyone who has it can forge a valid request for your merchant account. Rotate the salt with JazzCash if it has been published.",
297
+ "docRefs": [{ "docId": "mwallet-recurring", "sectionId": "sample-defects" }]
298
+ },
299
+ {
300
+ "cause": "Credentials are committed to version control.",
301
+ "check": "Search your repository history for the Merchant ID, password and salt.",
302
+ "fix": "Move them to environment variables, gitignore the file, and ask JazzCash to rotate anything that was committed.",
303
+ "docRefs": [{ "docId": "portal-guide", "sectionId": "credentials" }]
304
+ }
305
+ ]
306
+ },
307
+ {
308
+ "id": "wrong-environment",
309
+ "title": "Unsure which environment a request reached",
310
+ "keywords": ["environment", "sandbox", "production", "live", "which endpoint", "same url"],
311
+ "causes": [
312
+ {
313
+ "cause": "Sandbox and production use identical URLs in every documented flow.",
314
+ "check": "The endpoint tells you nothing. Only the credentials decide which environment you reached.",
315
+ "fix": "Track the environment alongside the credentials, log which profile was loaded, and treat going live as a credential swap rather than a URL change.",
316
+ "docRefs": [{ "docId": "card-page-redirection", "sectionId": "endpoint" }]
317
+ }
318
+ ]
319
+ }
320
+ ]
321
+ }