@agenzo/token-cli 0.3.0 → 0.3.2

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.
package/dist/index.js CHANGED
@@ -270,10 +270,6 @@ var ApiClient = class {
270
270
  const headers = {
271
271
  "User-Agent": `agenzo-admin-cli/${getCurrentVersion()}`
272
272
  };
273
- const traceparent = process.env.TRACEPARENT;
274
- if (traceparent) {
275
- headers["traceparent"] = traceparent;
276
- }
277
273
  if (auth.type === "bearer") {
278
274
  headers["Authorization"] = `Bearer ${auth.token}`;
279
275
  } else if (auth.type === "api-key") {
@@ -696,17 +692,11 @@ async function renderWithContext(result, opts, configManager) {
696
692
  render({ ...result, data: payload }, opts);
697
693
  }
698
694
  var PromptEngine = class {
699
- /** Return flagValue if provided, else env fallback, else prompt interactively */
695
+ /** Return flagValue directly if provided, otherwise prompt interactively */
700
696
  static async resolveInput(flagValue, config) {
701
697
  if (flagValue !== void 0) {
702
698
  return flagValue;
703
699
  }
704
- if (config.envVar) {
705
- const envValue = process.env[config.envVar];
706
- if (envValue !== void 0 && envValue !== "") {
707
- return envValue;
708
- }
709
- }
710
700
  if (config.type === "password") {
711
701
  return password({ message: config.message, mask: "*" });
712
702
  }
@@ -753,363 +743,232 @@ async function collectPaymentMethodParams(type, flags) {
753
743
  return params;
754
744
  }
755
745
 
756
- // src/verb-schema.ts
757
- var CLI_NAME = "agenzo-token-cli";
758
- function wantsJsonSchema(argv = process.argv) {
759
- for (let i = 0; i < argv.length; i++) {
760
- const a = argv[i];
761
- if (a === "--format=json") return true;
762
- if (a === "--format" && argv[i + 1] === "json") return true;
763
- }
764
- return false;
765
- }
766
- function emitSchema(schema) {
767
- console.log(JSON.stringify(schema, null, 2));
768
- }
769
- function attachSchemaHelp(cmd, schema) {
770
- const baseHelp = cmd.helpInformation.bind(cmd);
771
- cmd.helpInformation = (context) => {
772
- if (!wantsJsonSchema()) return baseHelp(context);
773
- emitSchema(schema);
774
- return "";
775
- };
776
- return cmd;
777
- }
778
- var pmAddSchema = {
779
- cli: CLI_NAME,
780
- noun: "payment-methods",
781
- verb: "add",
782
- description: "Add a payment method (card binding + 3DS verification)",
783
- flags: {
784
- "card-number": { type: "string", required: true, description: "Card number (PAN)" },
785
- "exp-month": { type: "string", required: true, description: "Expiration month (MM)" },
786
- "exp-year": { type: "string", required: true, description: "Expiration year (YY or YYYY)" },
787
- "cardholder-name": { type: "string", required: true, description: "Name on the card" },
788
- "member-id": { type: "string", required: false, description: "Member ID to associate the card with" },
789
- "api-key": { type: "string", required: true, description: "API Key for authentication", source: "config" }
790
- },
791
- response: {
792
- id: { type: "string", description: "Payment method ID" },
793
- status: { type: "string", description: "PENDING / ACTIVE / FAILED" },
794
- card_brand: { type: "string", description: "visa / mastercard / ..." },
795
- last_four: { type: "string", description: "Last 4 digits of card" },
796
- verification_url: { type: "string|null", description: "3DS verification URL (when PENDING)" }
797
- },
798
- example: {
799
- command: 'agenzo-token-cli payment-methods add --card-number 4111111111111111 --exp-month 12 --exp-year 2027 --cardholder-name "Alice Test"',
800
- output_summary: "Returns payment method ID and 3DS verification URL. Complete 3DS to activate."
801
- },
802
- error_recovery: {
803
- INVALID_CARD: "Card number failed Luhn check or is not supported. Verify and retry.",
804
- EVO_ERROR: "Upstream payment processor error. Retry after a short delay."
805
- }
806
- };
807
- var pmListSchema = {
808
- cli: CLI_NAME,
809
- noun: "payment-methods",
810
- verb: "list",
811
- description: "List payment methods for the authenticated developer",
812
- flags: {
813
- "member": { type: "string", required: false, description: "Filter by member ID" },
814
- "api-key": { type: "string", required: true, description: "API Key for authentication", source: "config" }
815
- },
816
- response: {
817
- payment_methods: {
818
- type: "array",
819
- description: "List of payment methods",
820
- items: {
821
- id: { type: "string", description: "Payment method ID" },
822
- status: { type: "string", description: "PENDING / ACTIVE / DISABLED" },
823
- card_brand: { type: "string", description: "Card brand" },
824
- last_four: { type: "string", description: "Last 4 digits" },
825
- created_at: { type: "string", description: "Creation time (ISO 8601)" }
826
- }
827
- }
828
- },
829
- example: {
830
- command: "agenzo-token-cli payment-methods list",
831
- output_summary: "Returns array of payment methods with status and card info."
832
- }
833
- };
834
- var pmGetSchema = {
835
- cli: CLI_NAME,
836
- noun: "payment-methods",
837
- verb: "get",
838
- description: "Get a payment method by ID",
839
- flags: {
840
- "pm-id": { type: "string", required: true, description: "Payment method ID" },
841
- "api-key": { type: "string", required: true, description: "API Key for authentication", source: "config" }
842
- },
843
- response: {
844
- id: { type: "string", description: "Payment method ID" },
845
- status: { type: "string", description: "PENDING / ACTIVE / DISABLED / FAILED / EXPIRED" },
846
- card_brand: { type: "string", description: "Card brand" },
847
- last_four: { type: "string", description: "Last 4 digits" },
848
- member_id: { type: "string|null", description: "Associated member ID" },
849
- created_at: { type: "string", description: "Creation time" }
850
- },
851
- example: {
852
- command: "agenzo-token-cli payment-methods get pm_01HZXD...",
853
- output_summary: "Returns full payment method details including 3DS verification status."
854
- }
855
- };
856
- var pmDisableSchema = {
857
- cli: CLI_NAME,
858
- noun: "payment-methods",
859
- verb: "disable",
860
- description: "Disable a payment method (cascades revoke on active payment tokens)",
861
- flags: {
862
- "pm-id": { type: "string", required: true, description: "Payment method ID to disable" },
863
- "api-key": { type: "string", required: true, description: "API Key for authentication", source: "config" }
864
- },
865
- response: {
866
- id: { type: "string", description: "Disabled payment method ID" },
867
- status: { type: "string", description: "DISABLED" },
868
- revoked_tokens_count: { type: "int", description: "Number of payment tokens revoked by cascade" }
869
- },
870
- example: {
871
- command: "agenzo-token-cli payment-methods disable pm_01HZXD...",
872
- output_summary: "Disables the payment method and revokes any active tokens bound to it."
873
- }
874
- };
875
- var ptCreateSchema = {
876
- cli: CLI_NAME,
877
- noun: "payment-tokens",
878
- verb: "create",
879
- description: "Create a payment token (VCN, Network Token cryptogram, or x402 USDC signature)",
880
- flags: {
881
- "type": { type: "string", required: true, description: "Token type: vcn / network_token / x402", constraints: "vcn | network_token | x402" },
882
- "payment-method-id": { type: "string", required: true, description: "Source payment method ID (must be ACTIVE)" },
883
- "amount": { type: "string", required: "conditional", description: "Amount in minor units (required for vcn and x402)" },
884
- "currency": { type: "string", required: false, default: "USD", description: "ISO 4217 currency code" },
885
- "member-id": { type: "string", required: false, description: "Member ID" },
886
- "external-transaction-id": { type: "string", required: false, description: "External reference for reconciliation" },
887
- "pay-to": { type: "string", required: "conditional", description: "Recipient address (required for x402)" },
888
- "nonce": { type: "string", required: "conditional", description: "Nonce bytes32 hex (required for x402)" },
889
- "network": { type: "string", required: "conditional", description: "Chain network (required for x402, e.g. base-sepolia)" },
890
- "deadline": { type: "int", required: "conditional", description: "Epoch seconds deadline (required for x402)" },
891
- "api-key": { type: "string", required: true, description: "API Key for authentication", source: "config" }
892
- },
893
- response: {
894
- id: { type: "string", description: "Payment token ID" },
895
- type: { type: "string", description: "vcn / network_token / x402" },
896
- status: { type: "string", description: "ACTIVE / REVOKED / EXPIRED" },
897
- token_data: { type: "object", description: "Type-specific token payload (cryptogram / VCN number / x402 signature)" },
898
- expires_at: { type: "string|null", description: "Expiration time (ISO 8601)" }
899
- },
900
- example: {
901
- command: "agenzo-token-cli payment-tokens create --type network_token --payment-method-id pm_01HZXD...",
902
- output_summary: "Returns token ID and cryptogram/VCN/signature data for payment execution."
903
- },
904
- error_recovery: {
905
- INVALID_PAYMENT_METHOD: "Payment method is not ACTIVE or not found. Verify status with payment-methods get.",
906
- UNSUPPORTED_TOKEN_TYPE: "Use vcn, network_token, or x402."
907
- }
908
- };
909
- var ptListSchema = {
910
- cli: CLI_NAME,
911
- noun: "payment-tokens",
912
- verb: "list",
913
- description: "List payment tokens for the authenticated developer",
914
- flags: {
915
- "type": { type: "string", required: false, description: "Filter by token type (vcn / network_token / x402)" },
916
- "member-id": { type: "string", required: false, description: "Filter by member ID" },
917
- "payment-method-id": { type: "string", required: false, description: "Filter by source payment method" },
918
- "api-key": { type: "string", required: true, description: "API Key for authentication", source: "config" }
919
- },
920
- response: {
921
- payment_tokens: {
922
- type: "array",
923
- description: "List of payment tokens",
924
- items: {
925
- id: { type: "string", description: "Token ID" },
926
- type: { type: "string", description: "Token type" },
927
- status: { type: "string", description: "ACTIVE / REVOKED / EXPIRED" },
928
- payment_method_id: { type: "string", description: "Source payment method" },
929
- created_at: { type: "string", description: "Creation time" }
930
- }
931
- }
932
- },
933
- example: {
934
- command: "agenzo-token-cli payment-tokens list --type network_token",
935
- output_summary: "Returns array of payment tokens filtered by type."
936
- }
937
- };
938
- var ptGetSchema = {
939
- cli: CLI_NAME,
940
- noun: "payment-tokens",
941
- verb: "get",
942
- description: "Get a payment token by ID",
943
- flags: {
944
- "payment-token-id": { type: "string", required: true, description: "Payment token ID" },
945
- "api-key": { type: "string", required: true, description: "API Key for authentication", source: "config" }
946
- },
947
- response: {
948
- id: { type: "string", description: "Token ID" },
949
- type: { type: "string", description: "Token type" },
950
- status: { type: "string", description: "ACTIVE / REVOKED / EXPIRED" },
951
- token_data: { type: "object", description: "Type-specific payload" },
952
- payment_method_id: { type: "string", description: "Source payment method" },
953
- created_at: { type: "string", description: "Creation time" },
954
- expires_at: { type: "string|null", description: "Expiration time" }
955
- },
956
- example: {
957
- command: "agenzo-token-cli payment-tokens get pt_01HZXD...",
958
- output_summary: "Returns full token details including token_data payload."
959
- }
960
- };
961
- var ptRevokeSchema = {
962
- cli: CLI_NAME,
963
- noun: "payment-tokens",
964
- verb: "revoke",
965
- description: "Revoke an active payment token",
966
- flags: {
967
- "payment-token-id": { type: "string", required: true, description: "Payment token ID to revoke" },
968
- "api-key": { type: "string", required: true, description: "API Key for authentication", source: "config" }
969
- },
970
- response: {
971
- id: { type: "string", description: "Revoked token ID" },
972
- status: { type: "string", description: "REVOKED" }
973
- },
974
- example: {
975
- command: "agenzo-token-cli payment-tokens revoke pt_01HZXD...",
976
- output_summary: "Marks the token as REVOKED. Cannot be undone."
977
- }
978
- };
979
-
980
746
  // src/payment-methods/add.ts
981
- var POLL_INTERVAL_MS = 3e3;
982
- var POLL_TIMEOUT_MS = 15 * 60 * 1e3;
747
+ var MANUAL_POLL_INTERVAL_MS = 3e3;
748
+ var MANUAL_POLL_TIMEOUT_MS = 15 * 60 * 1e3;
749
+ var DROPIN_POLL_INTERVAL_MS = 5e3;
750
+ var DROPIN_POLL_TIMEOUT_MS = 30 * 60 * 1e3;
751
+ var TERMINAL_STATUSES = /* @__PURE__ */ new Set(["ACTIVE", "FAILED", "EXPIRED"]);
983
752
  function registerAddCommand(parent, deps) {
984
- const cmd = parent.command("add").description("Add a payment method (card binding + 3DS)").option("--api-key <key>", "API Key for authentication").option("--type <type>", "Payment method type (default: card)", "card").option("--email <email>", "Email for 3DS verification").option("--card-number <number>", "Card number").option("--expiry <mmyy>", "Expiry date (MMYY format)").option("--cvv <cvv>", "Card CVV").option(
753
+ const cmd = parent.command("add").description("Add a payment method (manual 3DS or Drop-in session)").option("--api-key <key>", "API Key for authentication").option("--type <type>", "Payment method type (default: card)", "card").option(
754
+ "--mode <mode>",
755
+ 'Add mode: "manual" (default; CLI collects card details and polls 3DS) or "dropin" (mint a Drop-in session and poll until the user finishes adding the payment method in the browser)',
756
+ "manual"
757
+ ).option(
758
+ "--email <email>",
759
+ "Manual mode: email for 3DS verification. Dropin mode: email used as the Drop-in session reference."
760
+ ).option("--card-number <number>", "Card number (manual mode only)").option("--expiry <mmyy>", "Expiry date (MMYY format) (manual mode only)").option("--cvv <cvv>", "Card CVV (manual mode only)").option(
985
761
  "--idempotency-key <key>",
986
- "Idempotency key forwarded verbatim as the Idempotency-Key header"
762
+ "Idempotency key forwarded verbatim as the Idempotency-Key header (manual mode only)"
987
763
  );
988
- attachSchemaHelp(cmd, pmAddSchema);
989
764
  cmd.action(async () => {
990
765
  const opts = cmd.optsWithGlobals();
991
766
  const format = resolveFormat(opts.format);
992
767
  const isYes = Boolean(opts.yes);
993
- const apiKey = await PromptEngine.resolveInput(opts.apiKey, {
994
- message: "API Key:",
995
- type: "password",
996
- envVar: "AGENZO_API_KEY"
997
- });
998
- const type = opts.type || "card";
999
- const flags = {
1000
- email: opts.email,
1001
- cardNumber: opts.cardNumber,
1002
- expiry: opts.expiry,
1003
- cvv: opts.cvv
1004
- };
1005
- const params = await collectPaymentMethodParams(type, flags);
1006
- let idempotencyKey = opts.idempotencyKey;
1007
- if (!idempotencyKey) {
1008
- if (isYes) {
1009
- throw new IdempotencyKeyRequiredError("payment-methods add");
1010
- }
1011
- idempotencyKey = await PromptEngine.resolveInput(void 0, {
1012
- message: "Idempotency key (unique per write, for safe retry):",
1013
- validate: (v) => v.trim().length > 0 || "Idempotency key is required"
1014
- });
768
+ const mode = String(opts.mode ?? "manual").toLowerCase();
769
+ if (mode !== "manual" && mode !== "dropin") {
770
+ throw new CliError(
771
+ "PARAM_INVALID",
772
+ `Unknown --mode "${opts.mode}". Expected "manual" or "dropin".`
773
+ );
1015
774
  }
1016
- const extraHeaders = {
1017
- "Idempotency-Key": idempotencyKey
1018
- };
1019
- const result = await deps.apiClient.post(
1020
- "/payment-methods/create",
1021
- { type: "api-key", key: apiKey },
1022
- params,
1023
- extraHeaders
1024
- );
1025
- if (!result.success) {
1026
- throw CliError.fromApi(result, { auth: "api-key" });
775
+ if (mode === "dropin") {
776
+ await handleDropinMode(deps, opts, format);
777
+ return;
1027
778
  }
1028
- const pm = result.data;
1029
- notify(format, "success", "Payment method created");
1030
- const createdResult = {
1031
- data: pm,
1032
- text: () => {
1033
- const lines = [
1034
- ["ID", pm.id],
1035
- ["Type", pm.type],
1036
- ["Status", pm.status]
1037
- ];
1038
- if (pm.brand) lines.push(["Brand", pm.brand]);
1039
- if (pm.first6) lines.push(["First 6", pm.first6]);
1040
- if (pm.last4) lines.push(["Last 4", pm.last4]);
1041
- return Formatter.keyValue(lines);
1042
- }
1043
- };
1044
- const configManager = new ConfigManager();
1045
- await renderWithContext(createdResult, { format }, configManager);
1046
- notify(format, "info", "Complete 3DS verification via email to activate");
1047
- if (type === "card" && pm.status === "PENDING") {
1048
- const finalStatus = await poll3dsVerification(
1049
- deps.apiClient,
1050
- apiKey,
1051
- pm.id,
1052
- format
779
+ await handleManualMode(deps, opts, format, isYes);
780
+ });
781
+ }
782
+ async function handleManualMode(deps, opts, format, isYes) {
783
+ const apiKey = await PromptEngine.resolveInput(opts.apiKey, {
784
+ message: "API Key:",
785
+ type: "password"
786
+ });
787
+ const type = opts.type || "card";
788
+ const flags = {
789
+ email: opts.email,
790
+ cardNumber: opts.cardNumber,
791
+ expiry: opts.expiry,
792
+ cvv: opts.cvv
793
+ };
794
+ const params = await collectPaymentMethodParams(type, flags);
795
+ let idempotencyKey = opts.idempotencyKey;
796
+ if (!idempotencyKey) {
797
+ if (isYes) {
798
+ throw new IdempotencyKeyRequiredError("payment-methods add");
799
+ }
800
+ idempotencyKey = await PromptEngine.resolveInput(void 0, {
801
+ message: "Idempotency key (unique per write, for safe retry):",
802
+ validate: (v) => v.trim().length > 0 || "Idempotency key is required"
803
+ });
804
+ }
805
+ const extraHeaders = {
806
+ "Idempotency-Key": idempotencyKey
807
+ };
808
+ const result = await deps.apiClient.post(
809
+ "/payment-methods/create",
810
+ { type: "api-key", key: apiKey },
811
+ params,
812
+ extraHeaders
813
+ );
814
+ if (!result.success) {
815
+ throw CliError.fromApi(result, { auth: "api-key" });
816
+ }
817
+ const pm = result.data;
818
+ notify(format, "success", "Payment method created");
819
+ const createdResult = {
820
+ data: pm,
821
+ text: () => {
822
+ const lines = [
823
+ ["ID", pm.id],
824
+ ["Type", pm.type],
825
+ ["Status", pm.status]
826
+ ];
827
+ if (pm.brand) lines.push(["Brand", pm.brand]);
828
+ if (pm.first6) lines.push(["First 6", pm.first6]);
829
+ if (pm.last4) lines.push(["Last 4", pm.last4]);
830
+ return Formatter.keyValue(lines);
831
+ }
832
+ };
833
+ const configManager = new ConfigManager();
834
+ await renderWithContext(createdResult, { format }, configManager);
835
+ notify(format, "info", "Complete 3DS verification via email to activate");
836
+ if (type === "card" && pm.status === "PENDING") {
837
+ const finalStatus = await poll3dsVerification(deps.apiClient, apiKey, pm.id, format);
838
+ if (finalStatus === "ACTIVE") {
839
+ const getResult = await deps.apiClient.get(
840
+ `/payment-methods/${pm.id}`,
841
+ { type: "api-key", key: apiKey }
1053
842
  );
1054
- if (finalStatus === "ACTIVE") {
1055
- const getResult = await deps.apiClient.get(
1056
- `/payment-methods/${pm.id}`,
1057
- { type: "api-key", key: apiKey }
1058
- );
1059
- if (getResult.success) {
1060
- const activatedPm = getResult.data;
1061
- notify(format, "success", "Payment method activated");
1062
- const activatedResult = {
1063
- data: activatedPm,
1064
- text: () => {
1065
- const lines = [
1066
- ["ID", activatedPm.id],
1067
- ["Type", activatedPm.type],
1068
- ["Status", activatedPm.status]
1069
- ];
1070
- if (activatedPm.brand) lines.push(["Brand", activatedPm.brand]);
1071
- if (activatedPm.first6) lines.push(["First 6", activatedPm.first6]);
1072
- if (activatedPm.last4) lines.push(["Last 4", activatedPm.last4]);
1073
- return Formatter.keyValue(lines);
1074
- }
1075
- };
1076
- await renderWithContext(activatedResult, { format }, configManager);
1077
- } else {
1078
- notify(format, "success", "Payment method activated");
1079
- const degraded = { ...pm, status: "ACTIVE" };
1080
- const degradedResult = {
1081
- data: degraded,
1082
- text: () => {
1083
- const lines = [
1084
- ["ID", degraded.id],
1085
- ["Type", degraded.type],
1086
- ["Status", degraded.status]
1087
- ];
1088
- if (degraded.brand) lines.push(["Brand", degraded.brand]);
1089
- if (degraded.first6) lines.push(["First 6", degraded.first6]);
1090
- if (degraded.last4) lines.push(["Last 4", degraded.last4]);
1091
- return Formatter.keyValue(lines);
1092
- }
1093
- };
1094
- await renderWithContext(degradedResult, { format }, configManager);
1095
- }
1096
- } else if (finalStatus === "FAILED") {
1097
- notify(format, "error", "3DS verification failed");
1098
- } else if (finalStatus === "TIMEOUT") {
1099
- notify(
1100
- format,
1101
- "info",
1102
- `Verification timed out (15 min). Check status with: agenzo-token-cli payment-methods get ${pm.id} --api-key <your_key>`
1103
- );
843
+ if (getResult.success) {
844
+ const activatedPm = getResult.data;
845
+ notify(format, "success", "Payment method activated");
846
+ const activatedResult = {
847
+ data: activatedPm,
848
+ text: () => {
849
+ const lines = [
850
+ ["ID", activatedPm.id],
851
+ ["Type", activatedPm.type],
852
+ ["Status", activatedPm.status]
853
+ ];
854
+ if (activatedPm.brand) lines.push(["Brand", activatedPm.brand]);
855
+ if (activatedPm.first6) lines.push(["First 6", activatedPm.first6]);
856
+ if (activatedPm.last4) lines.push(["Last 4", activatedPm.last4]);
857
+ return Formatter.keyValue(lines);
858
+ }
859
+ };
860
+ await renderWithContext(activatedResult, { format }, configManager);
861
+ } else {
862
+ notify(format, "success", "Payment method activated");
863
+ const degraded = { ...pm, status: "ACTIVE" };
864
+ const degradedResult = {
865
+ data: degraded,
866
+ text: () => {
867
+ const lines = [
868
+ ["ID", degraded.id],
869
+ ["Type", degraded.type],
870
+ ["Status", degraded.status]
871
+ ];
872
+ if (degraded.brand) lines.push(["Brand", degraded.brand]);
873
+ if (degraded.first6) lines.push(["First 6", degraded.first6]);
874
+ if (degraded.last4) lines.push(["Last 4", degraded.last4]);
875
+ return Formatter.keyValue(lines);
876
+ }
877
+ };
878
+ await renderWithContext(degradedResult, { format }, configManager);
1104
879
  }
880
+ } else if (finalStatus === "FAILED") {
881
+ notify(format, "error", "3DS verification failed");
882
+ } else if (finalStatus === "TIMEOUT") {
883
+ notify(
884
+ format,
885
+ "info",
886
+ `Verification timed out (15 min). Check status with: agenzo-token-cli payment-methods get ${pm.id} --api-key <your_key>`
887
+ );
1105
888
  }
889
+ }
890
+ }
891
+ async function handleDropinMode(deps, opts, format) {
892
+ const apiKey = await PromptEngine.resolveInput(opts.apiKey, {
893
+ message: "API Key:",
894
+ type: "password"
1106
895
  });
896
+ const email = await PromptEngine.resolveInput(opts.email, {
897
+ message: "Email:"
898
+ });
899
+ const configManager = new ConfigManager();
900
+ const sessionResult = await deps.apiClient.post(
901
+ "/payment-methods/dropin/create",
902
+ { type: "api-key", key: apiKey },
903
+ { email }
904
+ );
905
+ if (!sessionResult.success) {
906
+ throw CliError.fromApi(sessionResult, { auth: "api-key" });
907
+ }
908
+ const session = sessionResult.data;
909
+ const pmId = session.id;
910
+ notify(format, "success", "Drop-in session created");
911
+ const createdResult = {
912
+ data: session,
913
+ text: () => Formatter.keyValue([["Session ID", session.session_id || "-"]])
914
+ };
915
+ await renderWithContext(createdResult, { format }, configManager);
916
+ notify(
917
+ format,
918
+ "info",
919
+ "Use the Session ID to add the payment method in the browser via the Drop-in SDK"
920
+ );
921
+ const finalPm = await pollVerificationStatus(deps.apiClient, apiKey, pmId, {
922
+ intervalMs: DROPIN_POLL_INTERVAL_MS,
923
+ timeoutMs: DROPIN_POLL_TIMEOUT_MS
924
+ });
925
+ if (finalPm.status === "ACTIVE") {
926
+ notify(format, "success", "Payment method activated");
927
+ const activated = {
928
+ data: finalPm,
929
+ text: () => Formatter.keyValue([
930
+ ["PM ID", finalPm.id],
931
+ ["Brand", finalPm.brand ?? "-"],
932
+ ["First 6", finalPm.first6 ?? "-"],
933
+ ["Last 4", finalPm.last4 ?? "-"],
934
+ ["Status", finalPm.status]
935
+ ])
936
+ };
937
+ await renderWithContext(activated, { format }, configManager);
938
+ return;
939
+ }
940
+ if (finalPm.status === "FAILED") {
941
+ notify(format, "error", "Failed to add payment method");
942
+ await renderPmId(finalPm.id, format, configManager);
943
+ process.exitCode = 1;
944
+ return;
945
+ }
946
+ if (finalPm.status === "EXPIRED") {
947
+ notify(format, "error", "Session expired before the payment method was added");
948
+ await renderPmId(finalPm.id, format, configManager);
949
+ process.exitCode = 1;
950
+ return;
951
+ }
952
+ notify(
953
+ format,
954
+ "error",
955
+ "Adding payment method did not complete within 30 minutes. Re-run with the same email to resume."
956
+ );
957
+ await renderPmId(pmId, format, configManager);
958
+ process.exitCode = 1;
959
+ }
960
+ async function renderPmId(id, format, configManager) {
961
+ const result = {
962
+ data: { id },
963
+ text: () => Formatter.keyValue([["PM ID", id]])
964
+ };
965
+ await renderWithContext(result, { format }, configManager);
1107
966
  }
1108
967
  async function poll3dsVerification(apiClient, apiKey, paymentMethodId, format) {
1109
968
  const startTime = Date.now();
1110
969
  notify(format, "info", "Waiting for 3DS verification...");
1111
- while (Date.now() - startTime < POLL_TIMEOUT_MS) {
1112
- await sleep(POLL_INTERVAL_MS);
970
+ while (Date.now() - startTime < MANUAL_POLL_TIMEOUT_MS) {
971
+ await sleep(MANUAL_POLL_INTERVAL_MS);
1113
972
  const result = await apiClient.get(
1114
973
  "/payment-methods/verification/status",
1115
974
  { type: "api-key", key: apiKey },
@@ -1127,6 +986,21 @@ async function poll3dsVerification(apiClient, apiKey, paymentMethodId, format) {
1127
986
  }
1128
987
  return "TIMEOUT";
1129
988
  }
989
+ async function pollVerificationStatus(apiClient, apiKey, pmId, options) {
990
+ const startTime = Date.now();
991
+ while (Date.now() - startTime < options.timeoutMs) {
992
+ const result = await apiClient.get(
993
+ "/payment-methods/verification/status",
994
+ { type: "api-key", key: apiKey },
995
+ { payment_method_id: pmId }
996
+ );
997
+ if (result.success && TERMINAL_STATUSES.has(result.data.status)) {
998
+ return result.data;
999
+ }
1000
+ await sleep(options.intervalMs);
1001
+ }
1002
+ return { id: pmId, status: "PENDING" };
1003
+ }
1130
1004
  function sleep(ms) {
1131
1005
  return new Promise((resolve) => setTimeout(resolve, ms));
1132
1006
  }
@@ -1134,14 +1008,12 @@ function sleep(ms) {
1134
1008
  // src/payment-methods/list.ts
1135
1009
  function registerListCommand(parent, deps) {
1136
1010
  const cmd = parent.command("list").description("List payment methods").option("--api-key <key>", "API Key for authentication").option("--member <member_id>", "Filter by member ID");
1137
- attachSchemaHelp(cmd, pmListSchema);
1138
1011
  cmd.action(async () => {
1139
1012
  const opts = cmd.optsWithGlobals();
1140
1013
  const format = resolveFormat(opts.format);
1141
1014
  const apiKey = await PromptEngine.resolveInput(opts.apiKey, {
1142
1015
  message: "API Key:",
1143
- type: "password",
1144
- envVar: "AGENZO_API_KEY"
1016
+ type: "password"
1145
1017
  });
1146
1018
  const params = {};
1147
1019
  if (opts.member) {
@@ -1182,14 +1054,12 @@ function registerListCommand(parent, deps) {
1182
1054
  // src/payment-methods/get.ts
1183
1055
  function registerGetCommand(parent, deps) {
1184
1056
  const cmd = parent.command("get <pm_id>").description("Get a payment method by ID").option("--api-key <key>", "API key for authentication");
1185
- attachSchemaHelp(cmd, pmGetSchema);
1186
1057
  cmd.action(async (pmId) => {
1187
1058
  const opts = cmd.optsWithGlobals();
1188
1059
  const format = resolveFormat(opts.format);
1189
1060
  const apiKey = await PromptEngine.resolveInput(opts.apiKey, {
1190
1061
  message: "API Key:",
1191
- type: "password",
1192
- envVar: "AGENZO_API_KEY"
1062
+ type: "password"
1193
1063
  });
1194
1064
  const result = await deps.apiClient.get(
1195
1065
  `/payment-methods/${pmId}`,
@@ -1229,14 +1099,12 @@ function registerDisableCommand(parent, deps) {
1229
1099
  "--idempotency-key <key>",
1230
1100
  "Idempotency key forwarded verbatim as the Idempotency-Key header"
1231
1101
  );
1232
- attachSchemaHelp(cmd, pmDisableSchema);
1233
1102
  cmd.action(async (pmId) => {
1234
1103
  const opts = cmd.optsWithGlobals();
1235
1104
  const format = resolveFormat(opts.format);
1236
1105
  const apiKey = await PromptEngine.resolveInput(opts.apiKey, {
1237
1106
  message: "API Key:",
1238
- type: "password",
1239
- envVar: "AGENZO_API_KEY"
1107
+ type: "password"
1240
1108
  });
1241
1109
  let idempotencyKey = opts.idempotencyKey;
1242
1110
  if (!idempotencyKey) {
@@ -1387,15 +1255,13 @@ function registerCreateCommand(parent, deps) {
1387
1255
  "--idempotency-key <key>",
1388
1256
  "Idempotency key forwarded verbatim as the Idempotency-Key header"
1389
1257
  );
1390
- attachSchemaHelp(cmd, ptCreateSchema);
1391
1258
  cmd.action(async () => {
1392
1259
  const opts = cmd.optsWithGlobals();
1393
1260
  const format = resolveFormat(opts.format);
1394
1261
  const isYes = Boolean(opts.yes);
1395
1262
  const apiKey = await PromptEngine.resolveInput(opts.apiKey, {
1396
1263
  message: "API Key:",
1397
- type: "password",
1398
- envVar: "AGENZO_API_KEY"
1264
+ type: "password"
1399
1265
  });
1400
1266
  const cliType = await PromptEngine.resolveInput(opts.type, {
1401
1267
  message: "Token type:",
@@ -1534,7 +1400,7 @@ function registerCreateCommand(parent, deps) {
1534
1400
  body.member_id = member;
1535
1401
  }
1536
1402
  if (opts.externalTxId) {
1537
- body.external_transaction_id = opts.externalTxId;
1403
+ body.external_tx_id = opts.externalTxId;
1538
1404
  }
1539
1405
  const extraHeaders = {
1540
1406
  "Idempotency-Key": idempotencyKey
@@ -1620,14 +1486,12 @@ function getSummary(token) {
1620
1486
  }
1621
1487
  function registerListCommand2(parent, deps) {
1622
1488
  const cmd = parent.command("list").description("List payment tokens").option("--api-key <key>", "API Key for authentication").option("--type <type>", "Filter by token type").option("--member <member_id>", "Filter by member ID");
1623
- attachSchemaHelp(cmd, ptListSchema);
1624
1489
  cmd.action(async () => {
1625
1490
  const opts = cmd.optsWithGlobals();
1626
1491
  const format = resolveFormat(opts.format);
1627
1492
  const apiKey = await PromptEngine.resolveInput(opts.apiKey, {
1628
1493
  message: "API Key:",
1629
- type: "password",
1630
- envVar: "AGENZO_API_KEY"
1494
+ type: "password"
1631
1495
  });
1632
1496
  const params = {};
1633
1497
  if (opts.type) {
@@ -1758,14 +1622,12 @@ function formatCentsPlain(cents) {
1758
1622
  }
1759
1623
  function registerGetCommand2(parent, deps) {
1760
1624
  const cmd = parent.command("get <payment_token_id>").description("Get a payment token by ID").option("--api-key <key>", "API key for authentication").option("--reveal", "Reveal full VCN card number and CVC in the output");
1761
- attachSchemaHelp(cmd, ptGetSchema);
1762
1625
  cmd.action(async (paymentTokenId) => {
1763
1626
  const opts = cmd.optsWithGlobals();
1764
1627
  const format = resolveFormat(opts.format);
1765
1628
  const apiKey = await PromptEngine.resolveInput(opts.apiKey, {
1766
1629
  message: "API Key:",
1767
- type: "password",
1768
- envVar: "AGENZO_API_KEY"
1630
+ type: "password"
1769
1631
  });
1770
1632
  const result = await deps.apiClient.get(
1771
1633
  `/payment-tokens/${paymentTokenId}`,
@@ -1791,14 +1653,12 @@ function registerRevokeCommand(parent, deps) {
1791
1653
  "--idempotency-key <key>",
1792
1654
  "Idempotency key forwarded verbatim as the Idempotency-Key header"
1793
1655
  );
1794
- attachSchemaHelp(cmd, ptRevokeSchema);
1795
1656
  cmd.action(async (paymentTokenId) => {
1796
1657
  const opts = cmd.optsWithGlobals();
1797
1658
  const format = resolveFormat(opts.format);
1798
1659
  const apiKey = await PromptEngine.resolveInput(opts.apiKey, {
1799
1660
  message: "API Key:",
1800
- type: "password",
1801
- envVar: "AGENZO_API_KEY"
1661
+ type: "password"
1802
1662
  });
1803
1663
  let idempotencyKey = opts.idempotencyKey;
1804
1664
  if (!idempotencyKey) {
@@ -1867,7 +1727,7 @@ async function main() {
1867
1727
  const program = new Command();
1868
1728
  programRef = program;
1869
1729
  program.name("agenzo-token-cli").version(getCurrentVersion()).description(
1870
- "Agenzo token plane: payment methods (card binding + 3DS) and payment tokens (VCN / Network Token / X402)"
1730
+ "Agenzo token plane: payment methods (add payment method + 3DS) and payment tokens (VCN / Network Token / X402)"
1871
1731
  ).option("--verbose", "Show verbose logs").option("--yes", "Skip confirmation prompts (for automation/AI Agents)").option(
1872
1732
  "--format <format>",
1873
1733
  "Output format: json | table (default: table; or set AGENZO_FORMAT)"
@@ -1886,54 +1746,6 @@ async function main() {
1886
1746
  registerListCommand2(ptCmd, deps);
1887
1747
  registerGetCommand2(ptCmd, deps);
1888
1748
  registerRevokeCommand(ptCmd, deps);
1889
- const svcCmd = program.command("services").description("Token service discovery");
1890
- svcCmd.command("list").description("List available token services from platform catalog").option("--api-key <key>", "API Key for authentication").action(async () => {
1891
- const opts = svcCmd.parent.optsWithGlobals();
1892
- const format = resolveFormat(opts.format);
1893
- const apiKey = await PromptEngine.resolveInput(opts.apiKey, {
1894
- message: "API Key:",
1895
- type: "password",
1896
- envVar: "AGENZO_API_KEY"
1897
- });
1898
- const host = (await configManager.load()).api_host || "http://localhost:8001";
1899
- const discoveryClient = new ApiClient({ baseUrl: `${host}/api/discovery/v1` });
1900
- const result = await discoveryClient.get(
1901
- "/catalog",
1902
- { type: "api-key", key: apiKey },
1903
- { category: "payment" }
1904
- );
1905
- if (!result.success) {
1906
- throw CliError.fromApi(result, { auth: "api-key" });
1907
- }
1908
- const cmdResult = {
1909
- text: () => JSON.stringify(result.data, null, 2),
1910
- data: result.data
1911
- };
1912
- await renderWithContext(cmdResult, { format }, configManager);
1913
- });
1914
- svcCmd.command("get <service_id>").description("Get a token service capability by ID").option("--api-key <key>", "API Key for authentication").action(async (serviceId) => {
1915
- const opts = svcCmd.parent.optsWithGlobals();
1916
- const format = resolveFormat(opts.format);
1917
- const apiKey = await PromptEngine.resolveInput(opts.apiKey, {
1918
- message: "API Key:",
1919
- type: "password",
1920
- envVar: "AGENZO_API_KEY"
1921
- });
1922
- const host2 = (await configManager.load()).api_host || "http://localhost:8001";
1923
- const discoveryClient2 = new ApiClient({ baseUrl: `${host2}/api/discovery/v1` });
1924
- const result = await discoveryClient2.get(
1925
- `/catalog/${serviceId}`,
1926
- { type: "api-key", key: apiKey }
1927
- );
1928
- if (!result.success) {
1929
- throw CliError.fromApi(result, { auth: "api-key" });
1930
- }
1931
- const cmdResult = {
1932
- text: () => JSON.stringify(result.data, null, 2),
1933
- data: result.data
1934
- };
1935
- await renderWithContext(cmdResult, { format }, configManager);
1936
- });
1937
1749
  await program.parseAsync(process.argv);
1938
1750
  }
1939
1751
  function resolveActiveFormat() {