CROP

MCP Cart & Checkout API Integration

Guide for integrating Cart & Checkout APIs via MCP

Cart & Checkout API — MCP Integration

Public Swagger UI & OpenAPI URLs

ServiceSwagger UIOpenAPI JSON
Cart (cart, user carts, sync)https://cart-service-222426967009.us-east1.run.app/docshttps://cart-service-222426967009.us-east1.run.app/openapi.json
Payment (checkout carts, checkout, orders, payments, customers)https://payment-service-222426967009.us-east1.run.app/docshttps://payment-service-222426967009.us-east1.run.app/openapi.json
Search (search, AI endpoints, inventory)https://search-service-222426967009.us-east1.run.app/docshttps://search-service-222426967009.us-east1.run.app/openapi.json
Userhttps://user-service-222426967009.us-east1.run.app/docshttps://user-service-222426967009.us-east1.run.app/openapi.json

Note: API Gateway (https://api.crop-dev.app) proxies only API endpoints (/api/...), NOT Swagger UI pages (/docs). Use Cloud Run URLs directly to browse documentation.

Via API Gateway (API calls only)

Base URL: https://api.crop-dev.app

API Gateway proxies all /api/... endpoints. Swagger UI and OpenAPI JSON via gateway may be unavailable (504 timeout).

Local Development

ServiceSwagger UIOpenAPI JSON
Carthttp://localhost:3000/docshttp://localhost:3000/openapi.json
Paymenthttp://localhost:3004/docshttp://localhost:3004/openapi.json
Searchhttp://localhost:3001/docshttp://localhost:3001/openapi.json

Architecture: Two Services with Cart Functionality

CROP has two services that handle carts:

ServicePurposeEndpoints
Cart Service (port 3000)Frontend cart sync, user carts, persistent storagePOST /api/cart, GET /api/cart, GET/DELETE /api/cart/{cartId}, PUT /api/cart/sync, POST /api/cart/clear, GET/PUT/DELETE /api/cart/user/{userId}
Payment Service (port 3004)Checkout carts — save cart before payment, 24h TTLPOST /api/cart, GET /api/cart/{cartId}, DELETE /api/cart/{cartId}

Warning — Gateway routing: API Gateway (api.crop-dev.app) routes all /api/cart/* requests to Payment Service. This means:

EndpointVia GatewayDirect (Cart Service)Direct (Payment Service)
POST /api/cart✅ → payment
GET /api/cart/{cartId}✅ → payment
DELETE /api/cart/{cartId}✅ → payment
GET /api/cart (current cart)❌ 404
PUT /api/cart/sync❌ 404
POST /api/cart/clear❌ 404
GET/PUT/DELETE /api/cart/user/{userId}❌ 404

For sync, clear, user/{userId} — use the direct Cart Service URL: https://cart-service-222426967009.us-east1.run.app

For MCP integration (checkout flow) use Payment Service cart endpoints (via gateway or direct) — they are tied to cartId and ensure checkout idempotency.

Cart Service is used by the frontend for cart state synchronization. Endpoints sync, clear, user/{userId} are available only directly via Cloud Run URL.


Overall Architecture

MCP Client

  ├─ 1. Search product ─────► Search Service (GET /api/search)
  ├─ 2. Save cart ───────────► Payment Service (POST /api/cart)
  ├─ 3. Get cart ────────────► Payment Service (GET /api/cart/{cartId})
  ├─ 4. Create checkout ─────► Payment Service (POST /api/checkout/session)
  ├─ 5. [User pays on Stripe Hosted Checkout]
  ├─ 6. Check order ─────────► Payment Service (GET /api/orders/by-session/{id})
  └─ 7. Get order details ──► Payment Service (GET /api/orders/{orderId})

Step 1: Search for Product

GET https://api.crop-dev.app/api/search?q=hydraulic+filter&limit=10

Response includes productId, partNumber, title, unitPrice, manufacturer, imageUrl.

AI-optimized search (for MCP/LLM agents):

GET https://api.crop-dev.app/api/ai?q=hydraulic+filter&limit=10

Additional AI endpoints:

  • GET /api/ai/parts/{id} — part details with equipment fitment data
  • POST /api/ai/availability — batch availability check (see example below)
  • GET /api/ai/equipment — equipment ↔ parts bidirectional lookup
  • GET /api/ai/diagrams — equipment diagram images

Batch availability check:

POST https://api.crop-dev.app/api/ai/availability
Content-Type: application/json

{
  "partNumbers": ["HF-1234", "OF-5678"]
}

Required field: partNumbers (array of strings, 1–10 items). Returns results array with partNumber, found, title, price, availability, stock for each part, plus a summary object.

Step 2: Save Cart for Checkout

POST https://api.crop-dev.app/api/cart
Content-Type: application/json

{
  "cartId": "cart_1708444800_abc123xyz",
  "userId": "user_2abc...",
  "sessionId": "<uuid>",
  "items": [
    {
      "productId": "abc123",
      "partNumber": "HF-1234",
      "title": "Hydraulic Filter",
      "manufacturer": "Donaldson",
      "quantity": 2,
      "unitPrice": 45.99,
      "currency": "USD",
      "imageUrl": "https://...",
      "availability": "in_stock"
    }
  ]
}
FieldRequiredDescription
cartIdYesUnique cart ID. Format: cart_{timestamp}_{random}, min 20 chars, pattern ^[a-zA-Z0-9_-]+$
itemsYesArray of items (1–100)
userIdNoClerk user ID (for authenticated users)
sessionIdNoSession ID (for anonymous users)

Required fields per item: productId, partNumber, title, quantity, unitPrice. Optional fields per item: manufacturer, currency, imageUrl, availability.

Response:

{
  "success": true,
  "data": {
    "cartId": "cart_1708444800_abc123xyz",
    "items": [...],
    "subtotal": 91.98,
    "currency": "USD"
  }
}

Step 3: Get Cart by ID

GET https://api.crop-dev.app/api/cart/{cartId}

Response:

{
  "success": true,
  "data": {
    "cartId": "cart_1708444800_abc123xyz",
    "items": [...],
    "subtotal": 91.98,
    "currency": "USD"
  }
}

Step 4: Create Checkout Session

POST https://api.crop-dev.app/api/checkout/session
Content-Type: application/json

{
  "items": [
    {
      "productId": "abc123",
      "partNumber": "HF-1234",
      "title": "Hydraulic Filter",
      "manufacturer": "Donaldson",
      "quantity": 2,
      "unitPrice": 45.99,
      "currency": "USD"
    }
  ],
  "shippingRate": {
    "provider": "UPS",
    "serviceType": "Ground",
    "cost": 12.99,
    "estimatedDays": 5
  },
  "shippingAddress": {
    "name": "John Doe",
    "street": "123 Main St",
    "city": "Clinton",
    "state": "NY",
    "postalCode": "13323",
    "country": "US",
    "phone": "+1-315-555-0100"
  },
  "cartId": "cart_1708444800_abc123xyz",
  "customerId": "user_2abc...",
  "successUrl": "https://www.clintontractor.net/parts/checkout/success?session_id={CHECKOUT_SESSION_ID}",
  "cancelUrl": "https://www.clintontractor.net/parts/checkout/cancel"
}
FieldRequiredDescription
itemsYesArray of items (1–100)
cartIdNoCart ID for idempotency — resubmitting same cartId returns existing Stripe Session
customerIdNoClerk user ID
successUrlNoRedirect URL after successful payment (supports {CHECKOUT_SESSION_ID} placeholder)
cancelUrlNoRedirect URL if user cancels payment
shippingRateNoShipping rate object (provider, serviceType, cost, estimatedDays)
shippingAddressNoShipping address object (name, street, city, state, postalCode, country, phone)
currencyNoIgnored — server forces "usd"
metadataNoCustom key-value pairs (max 20 keys)

Response:

{
  "success": true,
  "data": {
    "sessionId": "cs_abc123def456",
    "url": "https://checkout.stripe.com/c/pay/cs_abc123def456...",
    "paymentIntentId": "pi_abc123..."
  }
}

paymentIntentId may be absent — it is not required in the response.

MCP action: return the url to the user to proceed with payment.

Step 5: Check Result After Payment

After the user returns to successUrl:

GET https://api.crop-dev.app/api/orders/by-session/cs_abc123def456

Response:

{
  "success": true,
  "data": {
    "orderId": "order_abc123",
    "orderNumber": "CTS-2026-00042",
    "status": "pending",
    "createdAt": "2026-02-20T12:05:00Z"
  }
}

Step 6: Get Order Details

GET https://api.crop-dev.app/api/orders/order_abc123
Authorization: Bearer <clerk-jwt>

Response:

{
  "success": true,
  "data": {
    "orderId": "order_abc123",
    "orderNumber": "CTS-2026-00042",
    "userId": "user_2abc...",
    "items": [
      {
        "partNumber": "HF-1234",
        "name": "Hydraulic Filter",
        "quantity": 2,
        "price": 45.99,
        "total": 91.98
      }
    ],
    "subtotal": 91.98,
    "tax": 0,
    "shipping": 12.99,
    "total": 104.97,
    "currency": "USD",
    "status": "pending",
    "paymentStatus": "paid",
    "shippingAddress": { "name": "John Doe", "street": "123 Main St", "..." : "..." },
    "createdAt": "2026-02-20T12:05:00Z"
  }
}

Key Recommendations for MCP Integration

Authentication

ScenarioMethodHeader
Guest cartSession IDX-Session-Id: <uuid>
Authenticated userClerk JWTAuthorization: Bearer <token>
Public endpoints (by-session, by-payment)Not required

Idempotency

  • Always pass cartId in POST /api/cart and POST /api/checkout/session — this guarantees idempotency
  • Format: cart_{timestamp}_{random}, minimum 20 characters, pattern ^[a-zA-Z0-9_-]+$
  • Resubmitting with the same cartId returns the same Stripe Session

Example generation:

const cartId = `cart_${Date.now()}_${crypto.randomUUID().slice(0, 8)}`;
// → "cart_1708444800000_a1b2c3d4"

Price Validation

  • Backend validates prices when creating a Checkout Session (checkoutValidationService)
  • If the price has changed, the API returns 400 VALIDATION_FAILED
  • MCP should re-fetch current prices and recreate the session

Error Handling

All APIs return errors in a standard format:

{
  "success": false,
  "error": {
    "code": "VALIDATION_FAILED",
    "message": "Price for item HF-1234 has changed from $45.99 to $47.99"
  }
}

HTTP status codes:

400 — Bad request / validation failed / prices changed
401 — Unauthorized (protected endpoints)
403 — Forbidden (accessing another user's order/cart)
404 — Cart/order not found
409 — Conflict (duplicate cartId / cannot cancel order)
500 — Internal server error
503 — Database unavailable

Order Statuses

StatusDescription
pendingOrder created, awaiting processing
processingBeing processed
shippedShipped
deliveredDelivered
cancelledCancelled

Payment Statuses

StatusDescription
pendingAwaiting payment
paidPaid
failedPayment failed
refundedRefunded
partially_refundedPartially refunded

Order Creation

Orders are created automatically via Stripe Webhook (checkout.session.completed). MCP does not create orders directly — it only creates a Checkout Session and checks the result.

Webhook Flow (for reference)

Stripe Webhook (checkout.session.completed)

  ├─ Create order in MongoDB
  ├─ Save payment record
  ├─ Publish event to Kafka
  └─ Clear cart

Cancel Order

POST https://api.crop-dev.app/api/orders/{orderId}/cancel
Authorization: Bearer <clerk-jwt>
Content-Type: application/json

{
  "reason": "requested_by_customer",
  "adminNote": "Customer changed their mind",
  "forceCancel": false
}
FieldRequiredDescription
reasonNoOne of: requested_by_customer (default), duplicate, fraudulent, other
adminNoteNoAdmin note (max 500 characters)
forceCancelNoForce cancel (default: false)

Cancellation is only possible before shipment. Cancelling automatically initiates a full refund via Stripe.


Alternative Flow: PaymentIntent (Express Checkout)

For embedded checkout (Apple Pay / Google Pay buttons directly on the site):

POST https://api.crop-dev.app/api/payment-intent
Content-Type: application/json

{
  "amount": 10498,
  "currency": "usd",
  "cartId": "cart_1708444800_abc123xyz",
  "customerId": "user_2abc..."
}

amount is in cents! $104.98 = 10498. Required fields: amount, cartId.

Response:

{
  "success": true,
  "data": {
    "clientSecret": "pi_abc123_secret_xyz...",
    "paymentIntentId": "pi_abc123..."
  }
}

clientSecret is used for stripe.confirmPayment() on the frontend.

Then verify:

GET https://api.crop-dev.app/api/payment/verify/{paymentIntentId}

Additional Endpoints (Payment Service)

Customer Management

MethodEndpointDescription
POST/api/customersCreate customer
GET/api/customers/{id}Get customer
POST/api/customers/{id}/setup-intentCreate SetupIntent to save card
GET/api/customers/{id}/payment-methodsList payment methods
DELETE/api/customers/{id}/payment-methods/{pmId}Delete payment method
PUT/api/customers/{id}/default-payment-methodSet default payment method

Admin Orders (requires X-Admin-Token header)

MethodEndpointDescription
GET/api/admin/ordersList all orders
GET/api/admin/orders/statsOrder statistics
GET/api/admin/orders/{orderId}Order details (admin)
PATCH/api/admin/orders/{orderId}Update order (admin)

Order Lookup

MethodEndpointDescription
GET/api/orders/user/{userId}User's orders
GET/api/orders/{orderId}Order details
GET/api/orders/by-payment/{paymentIntentId}Order by PaymentIntent ID
GET/api/orders/by-session/{sessionId}Order by Checkout Session ID

Cart Service Endpoints (frontend sync)

These endpoints are used by the frontend for cart state synchronization. For MCP checkout flow, use Payment Service cart endpoints.

Note: All Cart Service endpoints are available only directly via https://cart-service-222426967009.us-east1.run.app. Via API Gateway (api.crop-dev.app), only POST /api/cart, GET/DELETE /api/cart/{cartId} work — they are routed to Payment Service.

MethodEndpointDescription
POST/api/cartSave cart (duplicated in Payment Service)
GET/api/cart/{cartId}Get cart by ID (duplicated in Payment Service)
DELETE/api/cart/{cartId}Delete cart by ID (duplicated in Payment Service)
GET/api/cartCurrent cart (authenticated/anonymous)
PUT/api/cart/syncSync cart state
POST/api/cart/clearClear cart
GET/api/cart/user/{userId}Get user cart
PUT/api/cart/user/{userId}Replace user cart
DELETE/api/cart/user/{userId}Clear user cart

Cart Sync (GET /api/cart, PUT /api/cart/sync) returns: { items, total, itemCount, lastSyncedAt }. User Cart (GET/PUT /api/cart/user/{userId}) returns: { userId, items, subtotal, currency, updatedAt }.


Base URLs by Environment

EnvironmentBase URL
Production (API Gateway)https://api.crop-dev.app
Cart (Cloud Run direct)https://cart-service-222426967009.us-east1.run.app
Payment (Cloud Run direct)https://payment-service-222426967009.us-east1.run.app
Search (Cloud Run direct)https://search-service-222426967009.us-east1.run.app
Local devhttp://localhost:3000 (cart) / http://localhost:3004 (payment) / http://localhost:3001 (search)

All endpoints via Gateway use the /api/ prefix. Direct Cloud Run access also uses /api/ (configured in Hono basePath).

On this page