Skip to content

feat(shopping): add Order Management API commands - #253

Open
sswaminathan-godaddy wants to merge 14 commits into
mainfrom
shopping-apis-EP-96684
Open

feat(shopping): add Order Management API commands#253
sswaminathan-godaddy wants to merge 14 commits into
mainfrom
shopping-apis-EP-96684

Conversation

@sswaminathan-godaddy

@sswaminathan-godaddy sswaminathan-godaddy commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator

Objective

Expose the Shopping API through gddy so agents and customers can browse the catalog, create and complete checkouts, and retrieve completed orders.

Shopping requests use the selected environment's standard GoDaddy API front door and obtain the complete lifecycle OAuth scope bundle in one consent flow. PAT support requires Shopping scopes to be made available in the Developer Portal and is tracked separately.

What changed

  • Added a gddy shopping command group:
    • catalog search, catalog lookup, catalog get
    • checkout create, checkout get, checkout update, checkout complete
    • order get
  • Added the complete Shopping OAuth scope bundle to every Shopping command:
    • shopping.catalog:read
    • shopping.checkout:execute
    • shopping.order:read
  • Added simple catalog inputs for search, lookup, and product retrieval, with --body / --file retained for advanced requests.
  • Added simple checkout inputs for common create, optional update, and completion workflows, with JSON retained for advanced nested fields.
  • Enforced a maximum of one payment instrument on checkout requests.
  • Added ISO-4217 currency validation, normalization, and minor-unit formatting.
  • Added generated UUID idempotency keys for completion when one is not supplied; callers can provide a stable non-empty key instead.
  • Completion makes one purchase attempt only. It does not retry or wait for order visibility; shopping order get <order-id> --wait owns bounded eventual-consistency polling.
  • Added safe cross-platform structured next actions and percent-encoded dynamic URL path segments.
  • Added customer-facing no-saved-payment-method guidance using the selected environment's account URL.
  • Added human-readable Shopping responses and preserved raw API responses in JSON output.
  • Added the Shopping guide and standard command schemas/help metadata.

Validation

Executed from rust/:

cargo check --workspace
cargo clippy --workspace -- -D warnings
cargo test --workspace
cargo fmt --check
./scripts/check-module-size.sh
git diff --check

All checks passed. cargo test --workspace passed with 819 tests across the workspace, plus 17 ignored tests and no failures.

Also verified the deployed Test Shopping API through the standard front door for catalog discovery, checkout creation/completion, and order retrieval. A GBP end-to-end purchase produced a GBP order with expected final totals.

Pending / follow-up

  • Make the three shopping.* scopes available to Personal Access Token creation in the Developer Portal, then add Shopping PAT support.
  • Investigate the upstream completion response's inconsistent USD currency field; the final Test order correctly reported GBP and expected GBP totals.

🤖 Generated with Claude Code

Add Shopping catalog, checkout, and order commands backed by the direct Order Management Katana service.

- Add configurable Shopping service URL resolution.
- Request the full Shopping OAuth scope bundle in one consent flow.
- Add catalog search/lookup/get and checkout create/get/update/complete.
- Require idempotency keys for completion and avoid automatic replays.
- Add bounded order-read polling for eventual consistency.
- Document the completed-checkout read limitation and direct-service setup.
- Add client, resolver, scope, command discovery, and dry-run coverage.

Pending:
- Register shopping.catalog:read, shopping.checkout:execute, and shopping.order:read for the CLI OAuth client.
- Run authenticated Test-tier catalog and checkout checks.
- Authorize and execute a real Test-tier completion smoke only when needed.
- Switch to front-door routing/PAT exchange when available.

Co-Authored-By: Claude <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings September 9, 2026 00:06

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The new Shopping HTTP client currently emits transport debug logs that can capture sensitive customer/order payloads, and the top-level help text is slightly misleading about supported env-var overrides.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR introduces a new gddy shopping module that talks directly to the Order Management Shopping API (Katana endpoint) so agents/users can browse the catalog and run checkout → order flows from the CLI while Shopping is not yet front-doored.

Changes:

  • Added the shopping command group with catalog, checkout, and order read commands plus guide/help metadata.
  • Implemented a dedicated Shopping HTTP client and shared helpers (JSON body/file parsing, idempotency-key validation, bounded polling for eventual consistency).
  • Added Shopping API base-URL resolution via <ENV>_SHOPPING_URL, SHOPPING_URL, and shopping_url in the environments TOML, plus registered new OAuth scopes.
File summaries
File Description
rust/src/shopping/order/mod.rs Adds the shopping order command group wiring.
rust/src/shopping/order/get.rs Implements shopping order get with optional bounded polling.
rust/src/shopping/mod.rs Registers the Shopping module, scopes bundle, and top-level help text.
rust/src/shopping/guides/shopping.md Documents configuration, auth scopes, and recommended workflow.
rust/src/shopping/common.rs Shared helpers for client creation, JSON input, idempotency, and polling.
rust/src/shopping/client.rs New reqwest-based Shopping API client and error mapping.
rust/src/shopping/checkout/update.rs Implements full-replacement checkout update with --body/--file and dry-run.
rust/src/shopping/checkout/mod.rs Adds the shopping checkout command group wiring.
rust/src/shopping/checkout/get.rs Implements shopping checkout get (with guidance not to use post-completion).
rust/src/shopping/checkout/create.rs Implements shopping checkout create with raw JSON input and dry-run.
rust/src/shopping/checkout/complete.rs Implements shopping checkout complete (idempotency required, optional wait-for-order).
rust/src/shopping/catalog/search.rs Implements shopping catalog search with JSON input.
rust/src/shopping/catalog/mod.rs Adds the shopping catalog command group wiring.
rust/src/shopping/catalog/lookup.rs Implements shopping catalog lookup with JSON input.
rust/src/shopping/catalog/get.rs Implements shopping catalog get (product details) with JSON input.
rust/src/scopes.rs Registers Shopping OAuth scopes in the global scope registry.
rust/src/main.rs Wires the Shopping module into the CLI module list.
rust/src/environments/shopping.rs Adds Shopping base-URL resolver with env var precedence + tests.
rust/src/environments/mod.rs Exposes shopping_url resolver from environments module.
rust/src/environments/config.rs Adds shopping_url to environment TOML config struct and defaults.
Review details

Suppressed comments (1)

rust/src/shopping/client.rs:98

  • --debug transport logging of raw response bytes can leak customer/order details (and potentially payment-related fields) when interacting with Shopping. If transport logging is needed, prefer logging only status/headers or implementing explicit redaction for sensitive JSON fields.
        let bytes = response.bytes().await?;
        cli_engine::transport::debug_log_reqwest_response(status, &headers, &bytes);

  • Files reviewed: 20/20 changed files
  • Comments generated: 2
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread rust/src/shopping/client.rs Outdated
Comment thread rust/src/shopping/mod.rs Outdated
sswaminathan-godaddy and others added 10 commits September 8, 2026 21:45
…d per returned product, including more sensible next steps
Co-Authored-By: Claude <noreply@anthropic.com>
Clarify customer-facing Shopping API terminology, checkout request guidance, completion safety, and order retrieval behavior. Remove endpoint-override setup from the Shopping guide while retaining its actionable runtime configuration error.

Co-Authored-By: Claude <noreply@anthropic.com>
Add catalog currency selection and currency-aware display, preserve full API data for JSON output, and streamline checkout creation through completion. Keep completion single-shot with generated idempotency keys and move order visibility polling to order retrieval.

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Dry-run metadata, retry error handling, generated commands, URL construction, and advertised behavior have unresolved correctness issues.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (2)

rust/src/shopping/checkout/complete.rs:117

  • This command does not expose the --wait-for-order option advertised in the PR description, and the handler never calls wait_for_order after completion. Either implement the bounded completion polling flow or update the PR description so users do not expect this flag.
                "Places a real order. Use --payment-instrument for one saved payment instrument, \
                 or --body/--file for advanced payment or billing-address fields. Use --idempotency-key \
                 to control retries, or omit it to let gddy generate and return one. The CLI never retries \
                 completion automatically. Read the resulting order with `shopping order get <order-id> --wait`.",

rust/src/shopping/catalog/search.rs:412

  • Values such as --query and --cursor are user/API-controlled and are interpolated inside single quotes without escaping. A query like O'Reilly produces an invalid next-page command; use structured next-action parameters or a cross-shell-safe quoting helper.
fn append_search_flag(command: &mut String, name: &str, value: Option<&Value>) {
    if let Some(value) = value.and_then(Value::as_str) {
        command.push_str(&format!(" --{name} '{value}'"));
    }
  • Files reviewed: 18/18 changed files
  • Comments generated: 8
  • Review effort level: Balanced

Comment thread rust/src/shopping/catalog/search.rs Outdated
Comment thread rust/src/shopping/checkout/complete.rs
Comment thread rust/src/shopping/checkout/complete.rs Outdated
Comment thread rust/src/shopping/checkout/create.rs
Comment thread rust/src/shopping/checkout/update.rs
Comment thread rust/src/shopping/client.rs Outdated
Comment thread rust/src/shopping/common.rs Outdated
Comment thread rust/src/shopping/checkout/complete.rs Outdated
- Render safe cross-platform structured next actions in human output\n- Mark checkout dry runs and preserve non-404 order-read failures\n- Encode dynamic checkout/order path segments\n- Show concise catalog lookup and bounded payment method choices\n- Render final totals only when response currency is available\n- Document the updated checkout experience

Co-Authored-By: Claude <noreply@anthropic.com>
Add httpmock coverage for catalog, checkout, and order routes, request metadata, encoded identifiers, empty successes, and HTTP error handling. Also move two existing test modules to the ends of their files to satisfy Clippy's items-after-test-module lint.

Co-Authored-By: Claude <noreply@anthropic.com>
Comment thread rust/src/shopping/mod.rs Outdated
.with_long(
"Browse GoDaddy products, create/update/complete checkout, and view completed orders.\n\
\n\
Shopping commands request the required OAuth permissions together so you can \

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this mean? That it requests all permissions no matter what you do? I am not sure users would understand this text.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense... Probably unnecessary.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the customer-facing permission and scope explanation; required scopes remain internal command metadata.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest soft line breaks, not hard. That's because the markdown renderer takes care of line wrapping based on the terminal width. With explicit hard line breaks, the text is breaking exactly where it is in the markdown file instead, which will not work as well for narrower terminals.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will do.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rewrote guide prose using soft wraps; explicit continuations remain only in shell examples.

Comment thread rust/src/shopping/guides/shopping.md Outdated
Comment on lines +5 to +7
# Shopping API

`gddy shopping` integrates with the Shopping API.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CLI is an abstraction over APIs; we should be focused on telling customers what they can do, not which APIs are being called.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# Shopping API
`gddy shopping` integrates with the Shopping API.
# Shopping for GoDaddy Products
Use `gddy shopping` commands to purchase GoDaddy's products and review your past purchases.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will update

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reworked the guide around customer outcomes: discover products, manage a cart, place an order, and review purchases.

Comment thread rust/src/shopping/guides/shopping.md Outdated
Comment on lines +9 to +31
## Authentication

Every Shopping command requests these OAuth scopes together, so the first command
can take the customer through one consent flow for the complete lifecycle:

```text
shopping.catalog:read
shopping.checkout:execute
shopping.order:read
```

You can authenticate before running a workflow:

```bash
gddy auth login \
--scope shopping.catalog:read \
--scope shopping.checkout:execute \
--scope shopping.order:read
```

Shopping requests use the selected environment's standard API front door. OAuth requests the
complete lifecycle scope bundle above in one consent flow. PAT support requires those Shopping
scopes to be available on the Developer Portal and is tracked separately.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is any of this something a user needs to know? Users aren't going to have any environments besides prod and in edge cases OTE. They're not going to know what "front door" means. This "is tracked separately" doesn't make sense for users either...

I think this entire guide needs a rewrite so it is geared toward users of the CLI. My suggested outline:

  1. Introduction, what this guide teaches you (how to buy GoDaddy products)
  2. Concepts (what's in a catalog, the cart, payment methods, etc. I am writing this before reviewing the whole thing, so whatever concepts the CLI exposes, not the ones I'm speculating on)
  3. How to accomplish specific tasks (command sequence, explain anything non-obvious)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SOunds good. Will take another stab at it.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rewrote the guide as a customer-focused catalog-to-cart-to-order journey and removed internal environment/front-door material.

}

fn next_actions(response: &Value, env: &str) -> Vec<cli_engine::NextAction> {
let Some(product) = response.get("product") else {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we have a spec, I highly recommend generating code (using progenitor like we did for domains) so that we have strong types instead of working with typeless JSON. That should avoid potential bugs in JSON traversal and make the code less verbose with all the type conversions.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, will look into this

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a generated shopping-client crate backed by the authoritative Shopping OpenAPI contract and Progenitor builders.


const PAYMENT_INSTRUMENT_LIMIT: usize = 5;

fn available_payment_instruments(checkout: &Value, show_all: bool) -> Vec<Value> {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should have a separate command for listing payment instruments.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, but it's a bit complicated.. Applicable payment methods are really specific to the checkout context. For instance, if the currency were to change, it could potentially change the available payment options - this is how FOS works as well (and perhaps why UCP doesn't have a separate way to get available payments).

If anything, let's defer explicit commands for this for first release. I will try to make the guide better to help users understand the flow easily.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we want, I can expose a command that lists available payments in a checkout session.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deferred a standalone payment-method command for this release: eligible methods are cart-specific. Cart create/get exposes the contextual choices and IDs.

Comment thread rust/src/shopping/guides/shopping.md Outdated
saved instrument for selection at completion.

A stored payment instrument normally supplies its saved billing address automatically. Use a
JSON document when you need an address override or other advanced nested fields:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure a sample JSON document makes sense. If JSON is being used, that would be something an AI agent would probably need to do for the human, and the AI agent should have a schema so it knows the shape of the JSON. Same for all these other advanced options.

I'd suggest either omitting these JSON/file parameters or at least having the guide link agents to where they can get the JSON schema.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, maybe just stick to simple inputs all the way through then... at least for now... will address

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed raw JSON walkthroughs from the guide; the main journey now uses only simple command inputs. Advanced inputs remain available for exceptional use.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use the progenitor pattern here instead of manually traversing JSON and risking mismatch with the spec?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good (I personally had no idea there's such a thing - just went with Claude's impl as long as the testing achieved the outcome)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Migrated Shopping transport and request modeling to a generated Progenitor client; dynamic JSON remains only at the CLI projection/compatibility boundary.

Comment thread rust/src/shopping/money.rs Outdated
@@ -0,0 +1,107 @@
use serde_json::Value;

/// Shopping amounts are ISO-4217 minor units. Their decimal scale derives from the returned

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sure we're not duplicating the currency formatting we already have for domains. If it's the same standard, we're using a library that understands the standard.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will address

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consolidated ISO-4217 minor-unit formatting on the existing Domains implementation; Shopping retains only its response-shape extraction.

Comment thread rust/src/next_action.rs Outdated
Comment on lines +29 to +30
/// Mirrors cli-engine placeholder substitution for custom human views. The
/// structured template and parameters remain in the output envelope.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude... why do you keep "mirroring" functionality (duplicating) instead of reusing what we already have? We already have a standard output envelope to include these actions in a standard way. If we really need to duplicate code, we need a better explanation on why that is necessary.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed! will have it take a closer look.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed project-local next-action display/substitution logic. cli-engine now renders standard structured next-action footers for custom views.

Co-Authored-By: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants