# RevCent MCP Guide: `CreatePendingSale`

AI/MCP-focused guide for the RevCent `CreatePendingSale` operation.

This document is meant to be read by AI agents, MCP clients, automation tools, and developers that need to understand how to create a pending Sale in RevCent and how pending Sales fit into ecommerce checkout, upsell, order-bump, and recovery workflows.

---

## Operation Summary

For broader Sale lifecycle context, see the Sales Overview: `https://revcent.com/documentation/markdown/mcp/operation/OverviewSale.md`

`CreatePendingSale` creates a new pending Sale and returns a unique `sale_id`.

A pending Sale is a Sale that is stored in RevCent but has **not yet processed payment**.

It acts like a pseudo-cart or stored checkout session for a specific customer. It can include customer details, products, shipping, tax, coupons, discounts, metadata, and optionally credit card payment information. The pending Sale can then be updated as the customer's cart or funnel changes, and payment can be processed later when the customer reaches the correct point in the flow.

The MCP operation description states that `CreatePendingSale`:

- Creates a new pending Sale.
- Issues a unique Sale ID.
- Does **not** process payment.
- Lets RevCent save a specific Sale with a customer, including payment information, without immediately processing payment.
- Was built to facilitate multi-step and upsell flows.
- Allows information and products to be added or changed before payment is processed.
- Can be updated repeatedly using `UpdatePendingSale`.
- Can be processed later using `ProcessPendingSale`.

---

## Why Pending Sales Matter

Pending Sales are extremely useful for ecommerce businesses because checkout and sales funnels are not always a single-step process.

A customer may:

- Begin checkout but not complete payment yet.
- Enter shipping and customer details before payment.
- Add an order bump before paying.
- Go through multiple upsell/downsell steps.
- Add products at different points in a funnel.
- Change shipping, tax, discounts, or products before final payment.
- Provide payment details, but wait until a later funnel step to actually process payment.
- Abandon checkout, allowing later recovery through AI, email, phone, or support.
- Be assisted by an AI Voice Agent or support rep before the Sale is processed.

`CreatePendingSale` supports this by creating a durable RevCent Sale record before payment happens.

---

## Pending Sale as a Pseudo-Cart

A pending Sale is best understood as a RevCent-hosted pseudo-cart for a specific customer.

It can store:

- Customer identity
- Billing details
- Shipping details
- Product line items
- Product-level metadata
- Shipping line items
- Shipping-level metadata
- Tax line items
- Tax-level metadata
- Coupons
- Discounts
- Sale-level metadata
- Visitor tracking metadata
- Internal order/customer IDs
- Optional credit card details for future processing

Unlike a normal cart stored only in a frontend session, a pending Sale exists in RevCent and receives a real `sale_id`. That `sale_id` can be used to update the pending Sale and later process payment.

---

## Best Use Cases

Use `CreatePendingSale` when payment should **not** be processed immediately.

Strong use cases:

| Use Case | Why Pending Sale Helps |
|---|---|
| Multi-step checkout | Save the customer/cart before payment. |
| Upsell funnels | Add products later before processing payment. |
| Order bumps | Let the cart change before the final charge. |
| Downsell flows | Modify products/discounts before payment. |
| Abandoned checkout | Store a recoverable Sale before payment is complete. |
| Payment recovery | Save customer/cart/payment context for later retry. |
| AI Assistant recovery | AI can inspect, update, or help recover the pending Sale later. |
| AI Voice Agent recovery | Voice agent can call customer and process the pending Sale live with consent. |
| Support-assisted sales | Support can update the cart before processing payment. |
| Custom storefront checkout | Backend can store checkout state in RevCent. |
| Quote-to-payment flow | Save cart/order first, process payment when approved. |

---

## Related Operations

| Operation | Purpose |
|---|---|
| `CreatePendingSale` | Create a pending Sale and receive a `sale_id`; does not process payment. |
| `UpdatePendingSale` | Update the pending Sale as many times as needed before payment. See `https://revcent.com/documentation/markdown/mcp/operation/UpdatePendingSale.md`. |
| `EstimateSale` | Estimate totals, products, shipping, tax, discounts, and coupons without processing payment. See `https://revcent.com/documentation/markdown/mcp/operation/EstimateSale.md`. |
| `ProcessPendingSale` | Process payment for the pending Sale when ready. See `https://revcent.com/documentation/markdown/mcp/operation/ProcessPendingSale.md`. |
| `GetSale` | Retrieve the pending Sale or processed Sale details. |
| `VoidSale` | Cancel a pending Sale, or fully refund a paid Sale. |
| `CreateSale` | Create a paid Sale immediately, not a pending Sale. |

Recommended flow:

```text
CreatePendingSale
    ↓
UpdatePendingSale as cart/funnel changes
    ↓
EstimateSale if totals need to be shown
    ↓
ProcessPendingSale when payment should be processed
```

---

## Related Documentation Links

AI/MCP clients should use these related markdown documents for broader Sale lifecycle context and pending Sale workflow continuity:

| Document | URL | Purpose |
|---|---|---|
| Sales Overview | `https://revcent.com/documentation/markdown/mcp/operation/OverviewSale.md` | Explains the overall Sale object, Sale lifecycle, Product Sales, shipments, tax, discounts, refunds, subscriptions, trials, fulfillment, events, AI workflows, and reporting rules. |
| Update Pending Sale | `https://revcent.com/documentation/markdown/mcp/operation/UpdatePendingSale.md` | Explains how to modify an existing pending Sale before payment is processed. Use after `CreatePendingSale` when the cart, products, shipping, tax, discounts, customer details, or payment information changes. |
| Estimate Sale | `https://revcent.com/documentation/markdown/mcp/operation/EstimateSale.md` | Explains how to estimate Sale totals, products, shipping, tax, coupons, and discounts before payment is processed. Useful before `ProcessPendingSale` to show totals or validate pricing. |
| Process Pending Sale | `https://revcent.com/documentation/markdown/mcp/operation/ProcessPendingSale.md` | Explains how to process payment for a pending Sale when the customer/cart/funnel is ready to be charged. Use after `CreatePendingSale` and any needed `UpdatePendingSale` calls. |

Recommended pending Sale reading order:

```text
OverviewSale.md
    ↓
CreatePendingSale.md
    ↓
UpdatePendingSale.md
    ↓
EstimateSale.md
    ↓
ProcessPendingSale.md
```

---

## `CreatePendingSale` vs `CreateSale`

| Operation | Payment Processed Immediately? | Best For |
|---|---:|---|
| `CreatePendingSale` | No | Stored cart, checkout session, upsell funnel, order bump, delayed payment, recovery. |
| `CreateSale` | Yes | Immediate paid Sale attempt. |

Use `CreatePendingSale` when the Sale may change before payment or when payment should happen later.

Use `CreateSale` when the customer/system is ready to process payment immediately.

---

## Schema Summary

Operation:

```text
name: CreatePendingSale
title: Create A Pending Sale
description: Create a pending Sale without processing payment.
input type: object
additionalProperties: false
```

Required top-level fields:

```text
campaign
customer
product
ip_address
```

The input schema does **not** allow unknown top-level fields.

---

## Full Top-Level Input Schema

| Field | Type | Required | Description |
|---|---:|---:|---|
| `campaign` | string | Yes | 20-character Campaign ID. |
| `iso_currency` | string | No | Three-character ISO 4217 currency code. |
| `ip_address` | string | Yes | Customer IP address. |
| `credit_card` | object | No | Optional credit card payment information to save for later processing. |
| `customer` | object | Yes | Customer details. Receives first priority when creating a new customer. |
| `bill_to` | object | No | Billing information. If not present, `customer` is used. Useful when adding credit card details with separate billing information. |
| `ship_to` | object | No | Shipping destination. If not present, `customer` or `bill_to` is used in priority order. |
| `product` | array<object> | Yes | Products to include in the pending Sale. |
| `shipping` | array<object> | No | Shipping entries to include in the pending Sale. |
| `tax` | array<object> | No | Tax entries to include in the pending Sale. |
| `coupon` | array<object> | No | Coupon codes to automatically apply discounts to the pending Sale. |
| `discount` | array<object> | No | Static discount entries to apply to the pending Sale. |
| `internal_sale_id` | string | No | Optional internal Sale ID, such as a third-party order ID. |
| `internal_customer_id` | string | No | Optional internal Customer ID, such as a third-party customer ID. |
| `metadata` | array<object> | No | Sale-level metadata passed down to items created from the Sale, including customer, product sales, shipping, and tax. |

---

## Output Schema

Successful output can include:

| Field | Type | Description |
|---|---:|---|
| `api_call_id` | string | 20-character API call ID. |
| `api_call_unix` | integer | Unix timestamp when the API call was initiated. |
| `code` | integer | API response code. `1` indicates success. |
| `campaign_id` | string | 20-character Campaign ID. |
| `customer_id` | string | 20-character Customer ID. |
| `sale_id` | string | 20-character Sale ID for the newly created pending Sale. |
| `result` | string | Result message. |

The returned `sale_id` is critical. It is used to update and process the same pending Sale later.

---

## Payment Behavior

`CreatePendingSale` does **not** process payment.

Even if credit card information is included, the operation only stores the pending Sale and payment information for later processing.

Payment happens later through `ProcessPendingSale`.

This distinction is critical for AI/MCP clients:

```text
CreatePendingSale = save the Sale/cart/customer/payment context
ProcessPendingSale = actually process payment
```

Do not tell the user that payment has been processed after `CreatePendingSale`.

---

## Credit Card Information

`credit_card` is optional.

Use it when the business wants to store credit card payment information on the pending Sale so it can be used when processing the pending Sale later.

The schema states:

```text
If you wish to add credit card payment information to the pending sale, which will be used when processing the pending sale for payment.
```

Credit card data is sensitive. AI/MCP clients should only collect or pass card details through secure, approved payment collection workflows.

---

## `credit_card` Object Schema

`credit_card` has:

```text
additionalProperties: false
required:
  - card_number
  - exp_month
  - exp_year
```

| Field | Type | Required | Description |
|---|---:|---:|---|
| `card_number` | string | Yes | Full credit card number. |
| `exp_month` | integer | Yes | Credit card expiration month as one or two digit integer, e.g. `1` or `12`. |
| `exp_year` | integer | Yes | Credit card expiration year as two digit integer, e.g. `29`. |
| `card_code` | string | No | Credit card security code. Depending on card type, length can vary. |
| `three_ds` | object | No | Optional 3DS values to pass to the processor later. |

Example:

```json
{
  "credit_card": {
    "card_number": "<CARD_NUMBER_COLLECTED_SECURELY>",
    "exp_month": 12,
    "exp_year": 29,
    "card_code": "<CARD_CODE_COLLECTED_SECURELY>"
  }
}
```

---

## `credit_card.three_ds` Object Schema

`three_ds` is optional and has:

```text
additionalProperties: false
```

Use it when 3DS is used during checkout and RevCent should parse/send those 3DS values when payment is processed.

| Field | Type | Description |
|---|---:|---|
| `enabled` | boolean | Must be true if using 3DS values. Default is false. |
| `version` | string | 3DS version, such as `2.1.0` or `2.2.0`. |
| `eci` | string | eCommerce indicator. |
| `cavv` | string | Cardholder Authentication Verification Value. |
| `xid` | string | Transaction identifier from authentication processing. |
| `directory_server_id` | string | Directory server transaction identifier. |
| `authentication_response` | string | Describes whether customer was successfully verified or attempted. |
| `acs_transaction_id` | string | Access Control Server transaction identifier. |
| `algorithm` | string | 3DS algorithm used. |
| `directory_response` | string | 3DS directory server response. |
| `enrollment_response` | string | Verify enrollment response/status. |
| `three_ds_server_transaction_id` | string | 3DS server transaction ID. |

Do not invent 3DS values. They must come from the real 3DS checkout/authentication flow.

---

## `customer` Object Schema

`customer` is required for `CreatePendingSale`.

The customer object receives first priority when creating a new customer.

`customer` has:

```text
additionalProperties: false
required:
  - first_name
  - last_name
  - email
```

| Field | Type | Required | Description |
|---|---:|---:|---|
| `first_name` | string | Yes | Customer first name. |
| `last_name` | string | Yes | Customer last name. |
| `email` | string/email | Yes | Customer email. |
| `address_line_1` | string | No | Customer first address line. |
| `address_line_2` | string | No | Customer second address line. |
| `city` | string | No | Customer city. |
| `state` | string | No | Customer state. |
| `zip` | string | No | Customer ZIP/postal code. |
| `country` | string | No | Customer country in three-letter ISO 3166-1 alpha-3 format. |
| `company` | string | No | Customer company. |
| `phone` | string | No | Customer phone. |

Example:

```json
{
  "customer": {
    "first_name": "Jane",
    "last_name": "Customer",
    "email": "jane@example.com",
    "phone": "555-555-5555",
    "address_line_1": "123 Main St",
    "city": "New York",
    "state": "NY",
    "zip": "10001",
    "country": "USA"
  }
}
```

---

## `bill_to` Object Schema

Use `bill_to` when billing information differs from customer information.

If not present, the `customer` object is used.

`bill_to` has:

```text
additionalProperties: false
required when object is provided:
  - first_name
  - last_name
  - email
```

| Field | Type | Required | Description |
|---|---:|---:|---|
| `first_name` | string | Yes | Bill-to first name. |
| `last_name` | string | Yes | Bill-to last name. |
| `email` | string/email | Yes | Bill-to email. |
| `address_line_1` | string | No | Bill-to first address line. |
| `address_line_2` | string | No | Bill-to second address line. |
| `city` | string | No | Bill-to city. |
| `state` | string | No | Bill-to state. |
| `zip` | string | No | Bill-to ZIP/postal code. |
| `country` | string | No | Bill-to country in three-letter ISO 3166-1 alpha-3 format. |
| `company` | string | No | Bill-to company. |
| `phone` | string | No | Bill-to phone. |

---

## `ship_to` Object Schema

Use `ship_to` when the shipping destination differs from customer or billing information.

If not present, the `customer` object or `bill_to` object is used in priority order.

`ship_to` has:

```text
additionalProperties: false
required when object is provided:
  - first_name
  - last_name
  - email
```

| Field | Type | Required | Description |
|---|---:|---:|---|
| `first_name` | string | Yes | Shipping first name. |
| `last_name` | string | Yes | Shipping last name. |
| `email` | string/email | Yes | Shipping email. |
| `address_line_1` | string | No | Shipping first address line. |
| `address_line_2` | string | No | Shipping second address line. |
| `city` | string | No | Shipping city. |
| `state` | string | No | Shipping state. |
| `zip` | string | No | Shipping ZIP/postal code. |
| `country` | string | No | Shipping country in three-letter ISO 3166-1 alpha-3 format. |
| `company` | string | No | Shipping company. |
| `phone` | string | No | Shipping phone. |

---

## `product` Array Schema

`product` is required.

Each product object has:

```text
additionalProperties: false
required:
  - id
```

| Field | Type | Required | Description |
|---|---:|---:|---|
| `id` | string | Yes | 20-character Product ID. |
| `quantity` | integer | No | Quantity being purchased. Default is 1. |
| `price` | number | No | Price to charge if different from the product default price in RevCent. |
| `metadata` | array<object> | No | Product-level metadata passed to the eventual Product Sale. |

### Product-Level Metadata

Product-level metadata is extremely important for funnels.

The schema states that metadata provided for an individual product is passed to the eventual Product Sale for that product.

This is useful for metrics such as:

- Upsells
- Downsells
- Order bumps
- Funnel step
- Bundle component
- Offer variation
- Funnel source
- Post-purchase offer tracking

Example:

```json
{
  "id": "XXXXXXXXXXXXXXXXXXXX",
  "quantity": 1,
  "metadata": [
    {
      "name": "is_upsell",
      "value": "true"
    },
    {
      "name": "funnel_step",
      "value": "upsell_1"
    }
  ]
}
```

This allows product-level BigQuery reports on upsells by filtering for metadata such as:

```text
is_upsell = true
```

---

## `shipping` Array Schema

`shipping` is optional.

Each shipping object has:

```text
additionalProperties: false
required:
  - amount
```

| Field | Type | Required | Description |
|---|---:|---:|---|
| `amount` | number | Yes | Amount to charge for the shipping entry. Can be 0. |
| `provider` | string | No | Shipping provider. Used when creating shipment at a fulfillment center. |
| `provider_method` | string | No | Shipping provider method corresponding to the provider. |
| `name` | string | No | Optional shipping entry name. |
| `description` | string | No | Optional shipping entry description. |
| `metadata` | array<object> | No | Shipping-level metadata passed to the eventual shipping item. |

Example:

```json
{
  "shipping": [
    {
      "amount": 6.95,
      "provider": "usps",
      "provider_method": "priority",
      "name": "USPS Priority",
      "metadata": [
        {
          "name": "shipping_offer",
          "value": "standard_checkout"
        }
      ]
    }
  ]
}
```

---

## `tax` Array Schema

`tax` is optional.

Each tax object has:

```text
additionalProperties: false
required:
  - amount
```

| Field | Type | Required | Description |
|---|---:|---:|---|
| `amount` | number | Yes | Amount to charge for the tax entry. |
| `name` | string | No | Optional tax entry name. |
| `description` | string | No | Optional tax entry description. |
| `metadata` | array<object> | No | Tax-level metadata passed to the eventual tax item. |

Example:

```json
{
  "tax": [
    {
      "amount": 3.25,
      "name": "Sales Tax",
      "metadata": [
        {
          "name": "tax_region",
          "value": "NY"
        }
      ]
    }
  ]
}
```

---

## `coupon` Array Schema

`coupon` is optional.

Each coupon object has:

```text
additionalProperties: false
required:
  - coupon_code
```

| Field | Type | Required | Description |
|---|---:|---:|---|
| `coupon_code` | string | Yes | Coupon code that exists in RevCent. |

Example:

```json
{
  "coupon": [
    {
      "coupon_code": "SPRING20"
    }
  ]
}
```

Use `EstimateSale` if the user wants to preview coupon effects before processing payment.

---

## `discount` Array Schema

`discount` is optional.

Each discount object has:

```text
additionalProperties: false
required:
  - discount_value
  - discount_type
```

| Field | Type | Required | Description |
|---|---:|---:|---|
| `discount_value` | number | Yes | Discount value relative to `discount_type`. |
| `discount_type` | string enum | Yes | Either `percent` or `amount`. |
| `name` | string | No | Optional discount name. |
| `description` | string | No | Optional discount description. |
| `apply_to_product` | boolean | No | Whether to apply discount to products purchased. Default is true. |
| `apply_to_shipping` | boolean | No | Whether to apply discount to shipping. Default is true. |

Allowed `discount_type` values:

```json
[
  "percent",
  "amount"
]
```

Example:

```json
{
  "discount": [
    {
      "discount_value": 10,
      "discount_type": "percent",
      "name": "10 Percent Funnel Discount",
      "apply_to_product": true,
      "apply_to_shipping": false
    }
  ]
}
```

---

## Metadata Object Schema

Metadata appears in several places:

- Sale-level `metadata`
- Product-level `product[].metadata`
- Shipping-level `shipping[].metadata`
- Tax-level `tax[].metadata`

Each metadata object has:

```text
additionalProperties: false
required:
  - name
  - value
```

| Field | Type | Required | Limit |
|---|---:|---:|---|
| `name` | string | Yes | 1 to 100 characters. |
| `value` | string | Yes | 1 to 255 characters. |

---

## Sale-Level Metadata

Sale-level metadata is optional but very important.

The schema states that Sale-level metadata is passed down to all items created as a result of the Sale, including:

- Customer
- Product Sales
- Shipping
- Tax

Use Sale-level metadata for attribution and lifecycle dimensions that should apply broadly to the entire pending Sale.

Examples:

```json
{
  "metadata": [
    {
      "name": "utm_source",
      "value": "google"
    },
    {
      "name": "utm_campaign",
      "value": "spring_sale"
    },
    {
      "name": "funnel_id",
      "value": "main_funnel"
    },
    {
      "name": "checkout_step",
      "value": "initial_cart"
    }
  ]
}
```

---

## Visitor Tracking Metadata Requirement

If the pending Sale took place on a website and tracking-domain DNS is set up in RevCent for that website, the Sale metadata must include the following values from the visitor/session cookie:

```json
[
  {
    "name": "revcent_track_id",
    "value": "[the value of visitor/session cookie.revcent_track_id]"
  },
  {
    "name": "revcent_entry_id",
    "value": "[the value of visitor cookie.revcent_entry_id]"
  }
]
```

These values connect the pending Sale to RevCent tracking and conversion attribution.

This is important because a pending Sale may later be processed into a paid Sale, recovered by AI, recovered by phone, or updated through a funnel. Tracking metadata allows the business to understand the origin and lifecycle of that Sale.

---

## Offline Payment Third-Party Metadata Requirement

If the pending Sale involves an offline payment with a third-party processor, the schema requires these three metadata entries to ensure proper association:

```json
[
  {
    "name": "offline_payment_third_party",
    "value": "sezzle | afterpay | klarna | affirm | amazon_pay"
  },
  {
    "name": "offline_payment_third_party_transaction_id",
    "value": "[the transaction ID from the third party]"
  },
  {
    "name": "offline_payment_third_party_integration_id",
    "value": "[the RevCent ID of the third party integration within your account for the third party processor]"
  }
]
```

Supported values shown in the schema:

```text
sezzle
afterpay
klarna
affirm
amazon_pay
```

Do not omit these fields for third-party offline payment pending Sales.

---

## Internal IDs

### `internal_sale_id`

Use `internal_sale_id` for a third-party order ID or external cart/session/order reference.

Examples:

- Custom storefront cart ID
- Funnel order ID
- CRM opportunity ID
- Internal order ID
- External checkout session ID

### `internal_customer_id`

Use `internal_customer_id` for a third-party customer ID.

Examples:

- Custom storefront customer ID
- CRM customer ID
- External account ID
- Internal customer reference

Internal IDs are useful for syncing pending Sales back to external systems and matching later payment/recovery outcomes.

---

## Minimal Pending Sale Example

```json
{
  "campaign": "XXXXXXXXXXXXXXXXXXXX",
  "ip_address": "203.0.113.10",
  "customer": {
    "first_name": "Jane",
    "last_name": "Customer",
    "email": "jane@example.com"
  },
  "product": [
    {
      "id": "XXXXXXXXXXXXXXXXXXXX"
    }
  ]
}
```

This creates a pending Sale but does not process payment.

---

## Pending Sale With Credit Card Stored for Later Processing

```json
{
  "campaign": "XXXXXXXXXXXXXXXXXXXX",
  "iso_currency": "USD",
  "ip_address": "203.0.113.10",
  "customer": {
    "first_name": "Jane",
    "last_name": "Customer",
    "email": "jane@example.com"
  },
  "credit_card": {
    "card_number": "<CARD_NUMBER_COLLECTED_SECURELY>",
    "exp_month": 12,
    "exp_year": 29,
    "card_code": "<CARD_CODE_COLLECTED_SECURELY>"
  },
  "product": [
    {
      "id": "XXXXXXXXXXXXXXXXXXXX",
      "quantity": 1
    }
  ]
}
```

This stores the pending Sale and payment information, but payment is not processed until `ProcessPendingSale`.

---

## Upsell / Order Bump Funnel Example

```json
{
  "campaign": "XXXXXXXXXXXXXXXXXXXX",
  "iso_currency": "USD",
  "ip_address": "203.0.113.10",
  "customer": {
    "first_name": "Jane",
    "last_name": "Customer",
    "email": "jane@example.com",
    "phone": "555-555-5555"
  },
  "product": [
    {
      "id": "BASE_PRODUCT_IDXXXX",
      "quantity": 1,
      "metadata": [
        {
          "name": "funnel_item_type",
          "value": "main_offer"
        }
      ]
    },
    {
      "id": "ORDER_BUMP_PRODUCT",
      "quantity": 1,
      "metadata": [
        {
          "name": "funnel_item_type",
          "value": "order_bump"
        },
        {
          "name": "is_order_bump",
          "value": "true"
        }
      ]
    }
  ],
  "metadata": [
    {
      "name": "funnel_id",
      "value": "spring_main_funnel"
    },
    {
      "name": "checkout_stage",
      "value": "pre_payment"
    }
  ]
}
```

Later, `UpdatePendingSale` can add more upsell/downsell products before `ProcessPendingSale`.

---

## Full Pending Sale Example With Tracking Metadata

```json
{
  "campaign": "XXXXXXXXXXXXXXXXXXXX",
  "iso_currency": "USD",
  "ip_address": "203.0.113.10",
  "customer": {
    "first_name": "Jane",
    "last_name": "Customer",
    "email": "jane@example.com",
    "phone": "555-555-5555",
    "address_line_1": "123 Main St",
    "city": "New York",
    "state": "NY",
    "zip": "10001",
    "country": "USA"
  },
  "bill_to": {
    "first_name": "Jane",
    "last_name": "Billing",
    "email": "billing@example.com",
    "address_line_1": "456 Billing Ave",
    "city": "New York",
    "state": "NY",
    "zip": "10002",
    "country": "USA"
  },
  "ship_to": {
    "first_name": "Jane",
    "last_name": "Shipping",
    "email": "shipping@example.com",
    "address_line_1": "789 Shipping Rd",
    "city": "Brooklyn",
    "state": "NY",
    "zip": "11201",
    "country": "USA"
  },
  "credit_card": {
    "card_number": "<CARD_NUMBER_COLLECTED_SECURELY>",
    "exp_month": 12,
    "exp_year": 29,
    "card_code": "<CARD_CODE_COLLECTED_SECURELY>"
  },
  "product": [
    {
      "id": "XXXXXXXXXXXXXXXXXXXX",
      "quantity": 1,
      "metadata": [
        {
          "name": "funnel_item_type",
          "value": "main_offer"
        }
      ]
    }
  ],
  "shipping": [
    {
      "amount": 6.95,
      "provider": "usps",
      "provider_method": "priority",
      "name": "USPS Priority",
      "metadata": [
        {
          "name": "shipping_offer",
          "value": "standard"
        }
      ]
    }
  ],
  "tax": [
    {
      "amount": 3.25,
      "name": "Sales Tax",
      "metadata": [
        {
          "name": "tax_region",
          "value": "NY"
        }
      ]
    }
  ],
  "coupon": [
    {
      "coupon_code": "SPRING20"
    }
  ],
  "discount": [
    {
      "discount_value": 5.00,
      "discount_type": "amount",
      "name": "Pre-Payment Funnel Discount",
      "apply_to_product": true,
      "apply_to_shipping": false
    }
  ],
  "internal_sale_id": "FUNNEL_SESSION_12345",
  "internal_customer_id": "EXT_CUSTOMER_98765",
  "metadata": [
    {
      "name": "revcent_track_id",
      "value": "visitor-session-track-id"
    },
    {
      "name": "revcent_entry_id",
      "value": "visitor-entry-id"
    },
    {
      "name": "utm_source",
      "value": "google"
    },
    {
      "name": "utm_campaign",
      "value": "spring_sale"
    },
    {
      "name": "funnel_id",
      "value": "spring_main_funnel"
    },
    {
      "name": "checkout_stage",
      "value": "pre_payment"
    }
  ]
}
```

---

## Lifecycle Chart

```text
CreatePendingSale
├─ Stores customer
├─ Stores cart/product line items
│  ├─ Product-level metadata can identify main offer, upsell, downsell, order bump
│  └─ Product Sales are created later when payment is processed
├─ Stores shipping/tax/discount/coupon context
├─ Stores optional payment information for later processing
├─ Stores sale-level attribution and tracking metadata
├─ Returns sale_id
│
├─ UpdatePendingSale can modify the pending Sale repeatedly
│  ├─ Add/remove/change products
│  ├─ Add upsells/order bumps
│  ├─ Change shipping/tax/discounts
│  └─ Update customer/payment details
│
├─ EstimateSale can preview totals without payment
│
└─ ProcessPendingSale processes payment when ready
   ├─ Creates paid Sale outcome
   ├─ Creates Product Sales
   ├─ Creates shipments/tax/discounts as applicable
   ├─ Creates subscriptions/trials if products are configured that way
   ├─ Triggers events/email/AI/functions as configured
   └─ Makes reporting possible with BigQueryRunQuery
```

---

## AI/MCP Workflow Guidance

### Multi-Step Checkout

Use `CreatePendingSale` at the point where the customer has entered enough information to store a cart but should not yet be charged.

Then use `UpdatePendingSale` as the customer moves through later checkout steps.

Use `ProcessPendingSale` only when the customer reaches the final payment point and authorizes payment.

### Upsell / Order Bump Funnel

Use product-level metadata to identify funnel context.

Examples:

```json
{
  "name": "is_upsell",
  "value": "true"
}
```

```json
{
  "name": "is_order_bump",
  "value": "true"
}
```

This allows later reporting on:

- Main offer conversion
- Order bump conversion
- Upsell revenue
- Downsell revenue
- Funnel-step product performance
- Refunds by funnel step
- Subscription/trial creation by funnel offer

### Abandoned Checkout Recovery

A pending Sale is ideal for abandoned checkout recovery because it stores the customer's cart and context.

Recovery workflows can include:

- Email Template follow-up
- AI Assistant review and recovery
- AI Voice Agent outbound recovery call
- Support-assisted completion
- Discount/coupon adjustment
- Payment retry or completion

### AI Voice Agent Recovery

An AI Voice Agent can retrieve a pending Sale, verify the customer, answer questions, and process the pending Sale only if the customer clearly consents and the voice agent is configured with the correct system actions.

### AI Assistant Recovery

An AI Assistant can review a pending Sale, determine if recovery is appropriate, send an email, update metadata/notes, or trigger another workflow. Payment processing should only occur when the assistant has explicit tool access, instructions, and authorization rules.

---

## Reporting and Metrics

Do not use operational listing endpoints for reporting.

Use `BigQueryRunQuery` for:

- Pending Sale creation rate
- Pending-to-paid conversion rate
- Abandoned checkout rate
- Recovery rate
- Upsell conversion
- Order bump conversion
- Funnel revenue
- Product-level upsell reports
- Metadata attribution
- Payment recovery performance
- AI recovery performance
- AI Voice Agent recovery performance
- Refunds by funnel step
- Trial/subscription creation from pending Sales

Product-level metadata is especially valuable for funnel reporting because it flows to the eventual Product Sale.

Sale-level metadata is valuable because it passes down to customer, product sales, shipping, and tax.

---

## Refund Implications

`CreatePendingSale` does not process payment, so there is nothing to refund until payment has been processed.

After `ProcessPendingSale` creates a paid Sale outcome, refund routing follows normal Sale refund rules:

| Refund Intent | Correct Operation |
|---|---|
| Refund one product line item | `RefundProductSale` |
| Refund part of one product line item | `RefundProductSale` with `amount` |
| Refund shipping | `RefundShipment` |
| Refund part of shipping | `RefundShipment` with `amount` |
| Refund tax | `RefundTax` |
| Refund part of tax | `RefundTax` with `amount` |
| Refund the entire Sale | `VoidSale` |

Use `VoidSale` to cancel a pending Sale if it should not be processed.

---

## Validation Checklist Before Calling `CreatePendingSale`

Before calling `CreatePendingSale`, verify:

- The flow should create a pending Sale, not process payment immediately.
- Campaign ID is valid.
- Customer first name, last name, and email are present.
- Product IDs are valid.
- Product quantities and price overrides are intentional.
- Product-level metadata is included for upsells/order bumps/funnel reporting.
- Shipping entries are correct if provided.
- Tax entries are correct if provided.
- Coupon codes and discounts are intentional.
- Credit card data, if included, was collected securely.
- Visitor tracking metadata is included when RevCent tracking-domain DNS is configured.
- Offline third-party metadata is included when using a third-party offline payment processor.
- Internal Sale ID and internal Customer ID are included when integrating with a custom storefront or external system.
- The resulting `sale_id` will be stored for future `UpdatePendingSale` and `ProcessPendingSale` calls.

---

## Common Mistakes to Avoid

Do not:

- Tell the user payment was processed after `CreatePendingSale`.
- Use `CreatePendingSale` when the user wants an immediate charge; use `CreateSale`.
- Lose the returned `sale_id`.
- Forget to use `UpdatePendingSale` for later cart/funnel changes.
- Forget to use `ProcessPendingSale` when ready to charge.
- Omit required `customer`, `campaign`, `product`, or `ip_address`.
- Guess Product IDs or Campaign IDs.
- Store upsell/order-bump context only in vague Sale-level metadata when product-level metadata is needed.
- Omit `revcent_track_id` or `revcent_entry_id` for tracked website Sales.
- Omit third-party offline payment metadata when applicable.
- Use non-descriptive metadata names.
- Collect credit card data through an insecure workflow.
- Use listing operations for metrics instead of `BigQueryRunQuery`.

---

## Final AI/MCP Instruction

Use `CreatePendingSale` when the business needs RevCent to store a customer-specific pseudo-cart or checkout state before payment is processed.

This is best for multi-step checkout, upsell funnels, order bumps, abandoned checkout recovery, delayed payment, AI recovery, AI Voice Agent recovery, and other sales funnels where customer/cart/payment information should be stored but payment should occur later.

Use `UpdatePendingSale` to change the pending Sale, `EstimateSale` to preview totals, and `ProcessPendingSale` to process payment when the Sale is ready.


---
Document Parent Directory
* [Operations](https://revcent.com/documentation/markdown/mcp/operation/index.md) - AI/MCP details and overviews for operations available within the RevCent MCP.