# RevCent MCP Guide: `ProcessSalvageTransaction`

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

This document is meant to be read by AI agents, MCP clients, automation tools, and developers that need to understand how to process/recover an existing Salvage Transaction in RevCent.

It includes schema guidance, recovery workflow rules, delayed-retry best practices, no-polling guidance for external systems, and reference links from the Salvage Transactions overview.

---

## Operation Summary

`ProcessSalvageTransaction` processes an existing Salvage Transaction using the Salvage Transaction ID.

A **Salvage Transaction** is a recoverable revenue opportunity created from a declined or partially recovered payment attempt. Salvage Transactions help ecommerce businesses maximize revenue by preserving recovery opportunities that would otherwise be lost after payment failure.

Use `ProcessSalvageTransaction` when the business is ready to attempt recovery of the remaining or failed amount represented by the Salvage Transaction.

This is a consequential payment operation. It attempts to collect money.

---

## Related Documentation Links

AI/MCP clients should use these related markdown documents for broader context:

| Document | URL | Purpose |
|---|---|---|
| Salvage Transactions Overview | `https://revcent.com/documentation/markdown/mcp/operation/OverviewSalvageTransaction.md` | Explains what Salvage Transactions are, how they are created, the difference between initial Sale, subscription renewal, and trial expiration sources, recovery methods, delayed retry best practices, and no-polling external workflow guidance. |
| Payment Profile Overview | `https://revcent.com/documentation/markdown/mcp/operation/OverviewPaymentProfile.md` | Explains Payment Profiles, payment flows, gateway routing, decline handling, amount modification, and how Payment Profile behavior can create Salvage Transactions. |
| AI Assistant Overview | `https://revcent.com/documentation/markdown/mcp/operation/OverviewAIAssistant.md` | Explains AI Assistant event triggers, event delay, Thread Builder, Time Delay nodes, filters, max-runs-per-item, and wait-and-continue automation patterns useful for Salvage Transaction recovery. |
| AI Voice Agent Overview | `https://revcent.com/documentation/markdown/mcp/operation/OverviewAIVoiceAgent.md` | Explains AI Voice Agents, outbound recovery calls, identity verification, customer consent, payment update actions, and call outcome metadata. |
| Functions Overview | `https://revcent.com/documentation/markdown/mcp/operation/OverviewFunction.md` | Explains RevCent Functions, account-event triggers, outbound requests, webhook-style notifications, external integrations, and secure custom automation patterns. |

Recommended reading order:

```text
OverviewPaymentProfile.md
    ↓
OverviewSalvageTransaction.md
    ↓
OverviewAIAssistant.md
    ↓
OverviewAIVoiceAgent.md
    ↓
OverviewFunction.md
    ↓
ProcessSalvageTransaction.md
```

---

## Critical Payment Warning

`ProcessSalvageTransaction` attempts to recover money.

Do not call this operation unless:

- The Salvage Transaction exists.
- The correct `salvage_transaction_id` is known.
- `GetSalvageTransaction` has been used to inspect the record.
- The Salvage Transaction is not already salvaged.
- The Salvage Transaction has not been replaced by another active Salvage Transaction.
- The customer/card/gateway strategy is clear.
- Business retry rules allow the attempt.
- The original/latest decline reason has been reviewed.
- The decline reason does not indicate the card/payment method has no realistic chance of success, such as invalid card, stolen card, lost card, closed account, restricted card, or similar hard-decline conditions.
- Any required wait period has passed, unless immediate retry is explicitly authorized.
- The customer/user/business has authorized the recovery attempt.
- The AI/MCP client or automation is explicitly allowed to process payments in the current workflow.

---

## When to Use `ProcessSalvageTransaction`

Use `ProcessSalvageTransaction` to recover an existing Salvage Transaction when recovery is appropriate.

Good use cases:

| Use Case | Why It Fits |
|---|---|
| Recover remaining balance from partial initial Sale capture | The initial Sale partially succeeded and the remaining amount was preserved as a Salvage Transaction. |
| Recover failed subscription renewal | The renewal declined and the Salvage Transaction represents expected recurring revenue. |
| Recover failed trial expiration | The trial expiration charge failed and the Salvage Transaction represents trial-to-paid conversion revenue. |
| Recover after wait period | Customer may now have funds available or temporary issuer conditions may have cleared. |
| Manual support-assisted recovery | Support spoke with the customer and has permission to retry. |
| AI Assistant recovery | Assistant reviewed eligibility and is configured to process recovery. |
| AI Voice Agent recovery | Customer consents live on a call and payment processing is enabled. |
| External recovery workflow | External system was notified by Function, waited, re-checked eligibility, and is authorized to retry. |
| Retry with a different gateway | Business wants to use a specific RevCent gateway instead of the original gateway. |
| Retry with a different saved card | Customer has another existing card on file. |
| Retry with a new card | Customer provides a new card securely. |

---

## When Not to Use `ProcessSalvageTransaction`

Do not use this operation when:

- The Salvage Transaction is already `salvaged = true`.
- The Salvage Transaction has been replaced and should no longer be processed.
- The customer is blocked or not eligible.
- The business retry limit has been reached.
- The wait period has not passed, unless immediate retry is authorized.
- The customer has not authorized payment where authorization is required.
- The workflow is not allowed to process payments.
- The record is actually a fully declined initial Sale with no Salvage Transaction.
- The user only wants reporting or metrics.
- The user only wants to inspect the Salvage Transaction.

Use:

- `GetSalvageTransaction` to inspect one Salvage Transaction.
- `BigQueryRunQuery` for reporting and metrics.
- pending Sale/Sale recovery workflows for fully declined initial Sales that remain pending.

---

## Schema Summary

Operation:

```text
name: ProcessSalvageTransaction
title: Process A Salvage Transaction
description: Process an existing salvage transaction using the salvage transaction ID.
input type: object
additionalProperties: false
```

Required top-level fields:

```text
salvage_transaction_id
```

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

---

## Full Input Schema

| Field | Type | Required | Description |
|---|---:|---:|---|
| `salvage_transaction_id` | string | Yes | 20-character Salvage Transaction ID. |
| `gateway` | string | No | 20-character RevCent Gateway ID. If provided, processes the Salvage Transaction on this specific gateway. If omitted, uses the Salvage Transaction's original gateway. |
| `customer_card_id` | string | No | 20-character RevCent Customer Card ID. If provided, attempts the Salvage Transaction using a non-default existing card associated with the Salvage Transaction customer. If omitted, uses the customer default card. |
| `payment` | object | No | New credit card payment information to use for the recovery attempt. If omitted, the existing default payment method associated with the related customer is used. |
| `bill_to` | object | No | Billing information to use when providing a new credit card with separate billing information. |

---

## 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. |
| `salvage_transaction_id` | string | 20-character Salvage Transaction ID. |
| `result` | string | Result message. |

The operation output is intentionally small. If updated recovery details are needed, use `GetSalvageTransaction` after processing.

---

## Default Processing Behavior

If only `salvage_transaction_id` is provided, RevCent attempts to process the Salvage Transaction using:

```text
original gateway + related customer's default payment method
```

Example:

```json
{
  "salvage_transaction_id": "XXXXXXXXXXXXXXXXXXXX"
}
```

Use this when:

- The original gateway should be retried.
- The customer's default card should be retried.
- No new card or alternate saved card was provided.
- Business retry policy allows default retry.

---

## Processing With a Specific Gateway

Use `gateway` when the recovery attempt should process on a specific RevCent Gateway ID.

Example:

```json
{
  "salvage_transaction_id": "XXXXXXXXXXXXXXXXXXXX",
  "gateway": "YYYYYYYYYYYYYYYYYYYY"
}
```

Use this when:

- The original gateway had issues.
- Gateway routing strategy recommends a different gateway.
- Payment Profile or recovery analytics suggest better success elsewhere.
- A manual user selected a gateway intentionally.
- An AI/external workflow has explicit gateway-routing rules.

Do not guess gateway IDs.

If `gateway` is omitted, RevCent uses the Salvage Transaction's original gateway.

---

## Processing With a Non-Default Existing Customer Card

Use `customer_card_id` when the customer has an existing saved card that is not the default card and the recovery attempt should use that card.

Example:

```json
{
  "salvage_transaction_id": "XXXXXXXXXXXXXXXXXXXX",
  "customer_card_id": "YYYYYYYYYYYYYYYYYYYY"
}
```

Use this when:

- The default card has failed.
- The customer has another valid card on file.
- The customer or support user selected a specific saved card.
- A recovery workflow is configured to retry a non-default card.

Do not guess customer card IDs.

If `customer_card_id` is omitted and no new payment is provided, RevCent uses the related customer's default payment method.

---

## Processing With a New Credit Card

Use `payment.credit_card` when the customer provides a new card to recover the Salvage Transaction.

Example:

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

Credit card data is sensitive.

AI/MCP clients must only pass credit card data through secure, approved payment collection workflows. Do not ask customers to paste full card details into insecure contexts.

---

## `payment` Object Schema

`payment` has:

```text
additionalProperties: false
required:
  - credit_card
```

| Field | Type | Required | Description |
|---|---:|---:|---|
| `credit_card` | object | Yes | New credit card to use for the Salvage Transaction processing attempt. |

---

## `payment.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, digits only. |
| `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 code as a string, digits only. Length can vary by card type. |

---

## Processing With New Credit Card and Separate Billing Information

Use `bill_to` when a new card is provided and the billing details are different or need to be explicitly supplied.

Example:

```json
{
  "salvage_transaction_id": "XXXXXXXXXXXXXXXXXXXX",
  "payment": {
    "credit_card": {
      "card_number": "<CARD_NUMBER_COLLECTED_SECURELY>",
      "exp_month": 12,
      "exp_year": 29,
      "card_code": "<CARD_CODE_COLLECTED_SECURELY>"
    }
  },
  "bill_to": {
    "first_name": "Jane",
    "last_name": "Customer",
    "email": "jane@example.com",
    "address_line_1": "123 Main St",
    "city": "New York",
    "state": "NY",
    "zip": "10001",
    "country": "USA"
  }
}
```

---

## `bill_to` Object Schema

`bill_to` has:

```text
additionalProperties: false
required:
  - 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. |

---

## Best Practice: Always Inspect First With `GetSalvageTransaction`

Before calling `ProcessSalvageTransaction`, use `GetSalvageTransaction` to inspect the record.

Input:

```json
{
  "salvage_transaction_id": "XXXXXXXXXXXXXXXXXXXX"
}
```

Important fields to inspect:

| Field | Why It Matters |
|---|---|
| `salvaged` | If true, the Salvage Transaction has already been successfully recovered and processing again will error. |
| `amount_to_salvage` | Current recoverable amount. |
| `amount_original_total` | Original amount intended to be charged. |
| `amount_charged` | Amount actually charged in the origin attempt. |
| `num_retries` | Number of recovery attempts already made. |
| `latest_retry_transaction` | Most recent retry attempt result. Review decline phrase/raw response before retrying. |
| `latest_transaction` | Most recent related transaction. Review gateway result phrase/raw response to understand whether retry has a realistic chance of success. |
| `success_transaction_id` | Successful recovery transaction, if already recovered. |
| `is_replacement` | Whether this Salvage Transaction replaced another. |
| `has_replacement` | Whether this Salvage Transaction was replaced by another. |
| `salvage_transaction_replaced_by` | Replacement Salvage Transaction ID. |
| `customer.blocked` | Whether the customer is blocked. |
| `customer.enabled` | Whether the customer is enabled. |
| `is_subscription_renewal` | Whether recovery relates to a subscription renewal. |
| `is_trial_expiration` | Whether recovery relates to a trial expiration. |
| `sale_initial` | Whether recovery relates to an initial Sale partial amount. |
| `payment_profile` | Payment Profile context for the original attempt. |
| `gateway_id` / `gateway_name` | Original gateway context. |
| `metadata` | Prior workflow/recovery metadata. |

Do not process blindly.

---

## Best Practice: Review Decline Reason Before Processing

Before attempting to process a Salvage Transaction, review the original decline reason and latest retry decline reason, if any.

The goal is to avoid unnecessary retry attempts and avoid decline fees when the Salvage Transaction has little or no chance of recovery.

Not every Salvage Transaction should be processed automatically. Some decline reasons suggest a temporary issue, while others suggest the payment method is invalid, blocked, stolen, closed, or otherwise not recoverable with the same card.

### Decline Reasons That May Be Recoverable

These decline reasons may be worth retrying after a wait period or after customer outreach, depending on business policy:

- Insufficient funds
- Temporary issuer unavailable
- Processor timeout
- Generic soft decline
- Do not honor, depending on merchant policy and history
- Transaction limit exceeded
- Velocity/temporary card limit
- Temporary gateway or processor issue
- Authentication or 3DS issue that can be retried correctly
- Customer says funds will be available later
- Customer provides a new card

### Decline Reasons That Should Usually Block Automatic Retry

These decline reasons may indicate the Salvage Transaction has little or no chance of recovery using the same payment method.

AI/MCP clients, AI Assistants, manual users, and external systems should consider blocking automatic processing when the decline reason indicates:

- Invalid card number
- Invalid expiration date
- Stolen card
- Lost card
- Closed account
- Pick up card
- Restricted card
- Card reported fraudulent
- Account not found
- Transaction not permitted to cardholder
- Transaction not permitted to terminal/merchant
- Hard processor decline
- Fraud detected
- Card permanently blocked
- Customer blocked or disabled
- Issuer says do not retry
- Any gateway response that clearly indicates the same card should not be retried

This logic should be driven by the actual gateway response fields and business rules, not guesswork.

### Fields to Review

Use `GetSalvageTransaction` and inspect:

| Field | Why It Matters |
|---|---|
| `request_origin` | Origin transaction that created the Salvage Transaction. |
| `latest_transaction.gateway_result_phrase` | Latest known gateway result phrase. |
| `latest_transaction.gateway_raw_response` | Raw gateway response, useful for exact decline code parsing. |
| `latest_transaction.code` | Latest transaction response code. |
| `latest_retry_transaction.gateway_result_phrase` | Most recent recovery-attempt gateway result phrase. |
| `latest_retry_transaction.gateway_raw_response` | Raw retry response for exact retry decline code. |
| `latest_retry_transaction.code` | Most recent retry transaction response code. |
| `customer.blocked` | Blocked customers should not be retried without review. |
| `customer.enabled` | Disabled customers should not be retried without review. |
| `metadata` | May contain prior recovery decision, decline classification, or business-specific retry flags. |

### AI/MCP Decision Rule

Before processing:

```text
GetSalvageTransaction
    ↓
Read origin/latest decline reason
    ↓
Classify decline as recoverable, uncertain, or not recoverable
    ↓
If not recoverable: do not process automatically
    ↓
If uncertain: route to manual review or customer outreach
    ↓
If recoverable: wait X days, re-check, then process if authorized
```

The purpose is to avoid spending money on decline fees for retries that are very unlikely to succeed.

---

## AI Assistant Decline-Reason Logic

AI Assistants can analyze the source decline reason before processing a Salvage Transaction.

There are two recommended places to add this logic.

### Option 1: AI Assistant Filter Function

Use a filter Function to prevent the AI Assistant from running when the Salvage Transaction is clearly not recoverable.

Example filter concept:

```javascript
// Filter Function concept for a salvage transaction.
// Return "pass" only if the decline appears recoverable.

const item = event.data.item_details || {};
const latest = item.latest_retry_transaction || item.latest_transaction || {};
const phrase = String(latest.gateway_result_phrase || "").toLowerCase();
const raw = String(latest.gateway_raw_response || "").toLowerCase();

const hardDeclinePatterns = [
  "invalid card",
  "invalid card number",
  "invalid expiration",
  "stolen",
  "lost card",
  "pick up card",
  "closed account",
  "restricted card",
  "account not found",
  "fraud",
  "do not retry",
  "card blocked"
];

const isHardDecline = hardDeclinePatterns.some(pattern => {
  return phrase.includes(pattern) || raw.includes(pattern);
});

if (item.salvaged === true || item.has_replacement === true) {
  callback(null, "fail");
  return;
}

if (item.customer && (item.customer.blocked === true || item.customer.enabled === false)) {
  callback(null, "fail");
  return;
}

if (isHardDecline) {
  callback(null, "fail");
  return;
}

callback(null, "pass");
```

The filter Function should be customized for the actual gateway response values the business sees in RevCent.

### Option 2: AI Assistant Thread Step

The assistant can also perform decline-reason analysis inside a normal Thread Step.

Example Thread Step instruction:

```text
Retrieve the Salvage Transaction details. Review the original and latest retry gateway response phrase and raw response. Classify the decline as recoverable, uncertain, or not recoverable. If the response indicates invalid card, stolen card, lost card, closed account, restricted card, fraud, do-not-retry, or similar hard-decline conditions, do not call ProcessSalvageTransaction. Instead create a note or metadata explaining why recovery was skipped. If the decline appears recoverable, continue with the configured wait/retry policy.
```

Use a Thread Step when more nuanced AI reasoning is useful.

Use a filter Function when the goal is to save AI cost and prevent the assistant from running on clearly unrecoverable records.

---

## External System Decline-Reason Logic

External systems should analyze the decline reason before calling `ProcessSalvageTransaction`.

The external system should receive the initial Function notification, store the `salvage_transaction_id`, wait according to policy, then call `GetSalvageTransaction` and inspect the gateway response fields before attempting processing.

Correct external flow:

```text
Function notification received
    ↓
Store salvage_transaction_id
    ↓
Wait X days
    ↓
GetSalvageTransaction
    ↓
Analyze request_origin / latest_transaction / latest_retry_transaction decline reason
    ↓
If hard decline: do not call ProcessSalvageTransaction
    ↓
If soft decline: process only if eligible and authorized
```

External systems should maintain a configurable denylist of hard-decline codes and phrases based on actual gateway responses.

Examples:

```text
invalid_card
stolen_card
lost_card
closed_account
restricted_card
pickup_card
account_not_found
fraud_detected
do_not_retry
```

The external system should record skip outcomes, such as:

```json
{
  "recovery_skipped": "true",
  "recovery_skip_reason": "hard_decline_invalid_card",
  "recovery_decline_source": "latest_transaction.gateway_result_phrase"
}
```

This creates useful BigQuery reporting dimensions for measuring avoided retry costs and prevented decline fees.

---

## Best Practice: Wait Before Processing

The Salvage Transactions overview recommends waiting before processing/retrying a Salvage Transaction.

Do **not** immediately retry every Salvage Transaction as soon as it is created.

A wait period gives the customer time for funds to become available, card limits to reset, bank holds to clear, or temporary issuer/gateway conditions to resolve. Immediate retries often repeat the same decline condition.

Recommended pattern:

```text
Salvage Transaction created
    ↓
Wait X days according to business policy
    ↓
GetSalvageTransaction
    ↓
Re-check eligibility
    ↓
ProcessSalvageTransaction only if appropriate and authorized
```

The exact wait period should be determined by the business.

Example wait strategies:

| Scenario | Example Wait Strategy |
|---|---|
| Insufficient funds / soft decline | Wait 1 to 3 days. |
| Subscription renewal failure | Wait according to subscription retry policy. |
| Trial expiration failure | Wait a few days before retry or outreach. |
| Partial initial Sale remaining balance | Wait before attempting to recover the remaining amount. |
| Customer promised payment later | Wait until the customer-provided date or expected funding window. |
| High-value recovery | Consider manual review or customer outreach before retry. |

AI/MCP clients should not hard-code a universal wait period. Use account policy, product type, customer lifecycle, decline context, and recovery strategy.

---

## AI Assistant Recovery Guidance

A Salvage Transaction can be recovered by an AI Assistant, commonly triggered by:

```text
salvage_transaction.created
```

Best practice:

- Use an initial event delay before the assistant runs, or
- Use a Time Delay node inside the assistant thread.

AI Assistant flow:

```text
salvage_transaction.created
    ↓
Initial event delay or immediate AI evaluation
    ↓
GetSalvageTransaction
    ↓
Branch by source:
    - initial Sale partial remaining
    - subscription renewal
    - trial expiration
    ↓
Wait X days if not already waited
    ↓
Re-check Salvage Transaction
    ↓
ProcessSalvageTransaction only if allowed and authorized
    ↓
Record outcome with metadata/note/AI thread
```

AI safeguards:

- Use filters.
- Use max-runs-per-item.
- Use retry limits.
- Avoid retry loops.
- Re-check eligibility after waiting.
- Record outcomes with notes/metadata.
- Use BigQuery for recovery reporting.
- Do not automatically process unless the assistant is explicitly configured and authorized.

Reference:

```text
https://revcent.com/documentation/markdown/mcp/operation/OverviewAIAssistant.md
```

---

## AI Voice Agent Recovery Guidance

AI Voice Agents can help recover Salvage Transactions when a live customer conversation is useful.

A voice agent may:

- Call the customer after a wait period.
- Explain the failed or partially recovered payment.
- Verify the customer.
- Ask if the customer wants to complete payment.
- Help add or update a card if allowed.
- Trigger a Function or external workflow if needed.
- Record call outcome metadata.
- Process the Salvage Transaction only when the customer clearly consents and the action is enabled.

Best practice:

```text
Wait X days
    ↓
AI Voice Agent calls customer
    ↓
Verify identity
    ↓
Explain payment issue
    ↓
Get clear consent
    ↓
Use secure card update/collection if needed
    ↓
ProcessSalvageTransaction only when authorized
```

Reference:

```text
https://revcent.com/documentation/markdown/mcp/operation/OverviewAIVoiceAgent.md
```

---

## External System Guidance: Do Not Poll

External systems should **never** poll `GetSalvageTransactions` to discover new Salvage Transactions.

Use RevCent Functions instead.

Correct pattern:

```text
salvage_transaction.create account event
    ↓
RevCent Function triggered
    ↓
Function sends salvage_transaction_id to external system
    ↓
External system stores event_id and salvage_transaction_id
    ↓
External system waits X days
    ↓
External system calls GetSalvageTransaction
    ↓
External system calls ProcessSalvageTransaction only if eligible and authorized
```

Why not poll:

- `GetSalvageTransactions` is operational lookup, not an event feed.
- Polling creates unnecessary API load.
- Polling can miss records due to timing, filters, date windows, or pagination.
- Event-driven Functions are more reliable and scalable.
- External systems should receive exact IDs from RevCent events.

Reference:

```text
https://revcent.com/documentation/markdown/mcp/operation/OverviewFunction.md
```

---

## Manual Recovery Guidance

Manual users can process Salvage Transactions from an operational workflow.

Recommended manual process:

```text
GetSalvageTransaction
    ↓
Review amount_to_salvage, source, customer, retries, latest response
    ↓
Confirm wait period has passed or immediate retry is authorized
    ↓
Decide payment method:
    - default card
    - non-default saved customer card
    - new card
    ↓
Decide gateway:
    - original gateway
    - specific gateway
    ↓
ProcessSalvageTransaction
    ↓
GetSalvageTransaction to verify updated state if needed
```

Manual processing is best for:

- High-value recovery.
- Customer-requested retry.
- New card provided by customer.
- Specific gateway choice.
- AI Assistant escalated to manual review.
- Ambiguous decline reasons.
- Customer service recovery.

---

## Source-Aware Processing Guidance

The Salvage Transactions overview explains that source matters.

### Initial Sale Partial Remaining

For initial Sales, a Salvage Transaction is created only when a partial amount was captured and a remaining amount exists.

```text
Full initial Sale amount attempted
    ↓
Decline occurs
    ↓
Payment Profile reduces amount
    ↓
Reduced amount succeeds
    ↓
Salvage Transaction created for remaining amount
```

`ProcessSalvageTransaction` recovers the remaining amount.

A fully declined initial Sale does **not** create a Salvage Transaction. It remains pending and should be recovered through pending Sale/Sale retry workflows, not `ProcessSalvageTransaction`.

### Subscription Renewal

Subscription renewal Salvage Transactions can be created on full decline or partial recovery.

`ProcessSalvageTransaction` attempts to recover the failed or remaining renewal amount.

Check:

- `is_subscription_renewal`
- `subscription_renewals`
- `subscriptions`
- customer status
- subscription status
- retry count

### Trial Expiration

Trial expiration Salvage Transactions can be created on full decline or partial recovery.

`ProcessSalvageTransaction` attempts to recover failed or remaining trial expiration revenue.

Check:

- `is_trial_expiration`
- `trials`
- customer status
- trial status
- retry count

---

## Processing Examples

### Example 1: Default Recovery

Uses original gateway and customer's default payment method.

```json
{
  "salvage_transaction_id": "XXXXXXXXXXXXXXXXXXXX"
}
```

### Example 2: Specific Gateway

```json
{
  "salvage_transaction_id": "XXXXXXXXXXXXXXXXXXXX",
  "gateway": "YYYYYYYYYYYYYYYYYYYY"
}
```

### Example 3: Non-Default Saved Customer Card

```json
{
  "salvage_transaction_id": "XXXXXXXXXXXXXXXXXXXX",
  "customer_card_id": "YYYYYYYYYYYYYYYYYYYY"
}
```

### Example 4: New Card

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

### Example 5: Specific Gateway + New Card + Billing Info

```json
{
  "salvage_transaction_id": "XXXXXXXXXXXXXXXXXXXX",
  "gateway": "YYYYYYYYYYYYYYYYYYYY",
  "payment": {
    "credit_card": {
      "card_number": "<CARD_NUMBER_COLLECTED_SECURELY>",
      "exp_month": 12,
      "exp_year": 29,
      "card_code": "<CARD_CODE_COLLECTED_SECURELY>"
    }
  },
  "bill_to": {
    "first_name": "Jane",
    "last_name": "Customer",
    "email": "jane@example.com",
    "address_line_1": "123 Main St",
    "city": "New York",
    "state": "NY",
    "zip": "10001",
    "country": "USA"
  }
}
```

---

## Recommended Recovery Lifecycle

```text
Salvage Transaction created
├─ AI Assistant, Function, or manual user becomes aware of record
├─ Do not immediately process by default
├─ Wait X days according to business policy
├─ GetSalvageTransaction
│  ├─ Confirm salvaged = false
│  ├─ Confirm no active replacement
│  ├─ Confirm amount_to_salvage
│  ├─ Check source: initial Sale / subscription renewal / trial expiration
│  ├─ Check customer status
│  ├─ Check retry count
│  └─ Check latest retry/transaction result
├─ Choose processing strategy
│  ├─ default card + original gateway
│  ├─ specific gateway
│  ├─ non-default saved card
│  └─ new card
├─ ProcessSalvageTransaction
├─ GetSalvageTransaction if updated status is needed
└─ Record/report outcome through metadata, notes, AI thread, external system, or BigQuery
```

---

## BigQuery Reporting Guidance

Do not use `GetSalvageTransactions` for reporting, aggregation, data mining, or bulk retrieval.

Use `BigQueryRunQuery` for:

- Salvage recovery rate.
- Salvaged revenue.
- Amount to salvage by date.
- Recovery success by source.
- Initial Sale partial recovery reporting.
- Subscription renewal recovery reporting.
- Trial expiration recovery reporting.
- Recovery success by gateway.
- Recovery success by Payment Profile.
- AI Assistant recovery performance.
- AI Voice Agent recovery performance.
- Manual vs automated recovery performance.
- Recovery outcomes by wait period.
- Recovery outcomes by customer segment.
- Retry counts before success.
- Decline reason analysis.
- Hard-decline skip reporting.
- Avoided retry/decline-fee analysis.
- Product/campaign/shop attribution.

Use metadata such as:

- `recovery_channel`
- `recovery_wait_days`
- `recovery_attempt_number`
- `ai_assistant_id`
- `ai_voice_agent_id`
- `external_workflow_id`
- `manual_user_id`
- `payment_authorization_source`
- `recovery_outcome`
- `decline_reason_classification`
- `recovery_skipped`
- `recovery_skip_reason`
- `hard_decline_detected`

to make reporting granular.

---

## Validation Checklist Before Calling `ProcessSalvageTransaction`

Before calling `ProcessSalvageTransaction`, verify:

- `salvage_transaction_id` is known and correct.
- `GetSalvageTransaction` has been used to inspect the record.
- `salvaged` is false.
- The Salvage Transaction has not been replaced by another active record.
- `amount_to_salvage` is expected.
- Source type is understood:
  - initial Sale partial remaining
  - subscription renewal
  - trial expiration
- For fully declined initial Sales, confirm this is actually a Salvage Transaction and not a pending Sale recovery case.
- Customer is correct and eligible.
- Customer is not blocked.
- Customer payment method strategy is clear.
- Gateway strategy is clear.
- Retry count is within business limits.
- Business-defined wait period has passed unless immediate retry is explicitly authorized.
- Latest transaction/retry result has been reviewed.
- Original/latest decline reason has been reviewed and classified.
- Hard-decline business logic does not indicate the recovery attempt is unlikely to succeed.
- The recovery attempt will not likely create avoidable decline fees with no realistic chance of success.
- New credit card data, if provided, was collected securely.
- Billing details are provided if needed.
- AI/autonomous workflows have explicit permission and safeguards.
- External workflows received the ID by Function/event notification, not polling.
- The recovery attempt is authorized by the business/user/customer context.
- Follow-up reporting/metadata/notes plan is clear.

---

## Common Mistakes to Avoid

Do not:

- Process without first using `GetSalvageTransaction`.
- Process a Salvage Transaction that is already `salvaged = true`.
- Process a Salvage Transaction that has been replaced.
- Retry immediately without a business reason or customer authorization.
- Retry before the wait period has passed.
- Retry endlessly without limits.
- Use `GetSalvageTransactions` for metrics or external polling.
- Poll from an external system to discover new Salvage Transactions.
- Guess Salvage Transaction IDs.
- Guess gateway IDs.
- Guess customer card IDs.
- Confuse `amount_charged` with `amount_to_salvage`.
- Treat a fully declined initial Sale as a Salvage Transaction.
- Ask customers for card data in insecure contexts.
- Automatically process from AI without explicit configuration and safeguards.
- Ignore subscription/trial state when source is renewal or trial expiration.
- Ignore customer blocked/enabled status.
- Ignore latest decline/retry result.
- Retry cards with hard-decline reasons such as invalid, stolen, lost, closed, restricted, fraud, or do-not-retry responses.
- Create avoidable decline fees by retrying Salvage Transactions with no realistic chance of success.
- Skip decline-reason analysis in AI Assistant filters, AI steps, external systems, or manual review workflows.
- Ignore replacement fields.
- Assume output fields that are not documented.
- Use listing operations for reporting instead of `BigQueryRunQuery`.

---

## Final AI/MCP Instruction

Use `ProcessSalvageTransaction` only when an existing Salvage Transaction is ready for an authorized recovery attempt.

Always inspect the record first with `GetSalvageTransaction`, review the original/latest decline reason, avoid processing records with hard-decline reasons that have no realistic chance of success, wait X days according to business policy unless immediate retry is authorized, re-check eligibility, then choose the correct recovery strategy: original gateway/default card, specific gateway, non-default saved customer card, or new card.

For AI and external workflows, use event-driven patterns and safeguards. AI Assistants should use event delays or Time Delay nodes and can add hard-decline logic in a filter Function or Thread Step. External systems should be notified through RevCent Functions, must not poll `GetSalvageTransactions`, and should analyze decline reasons before calling `ProcessSalvageTransaction`.

Use `BigQueryRunQuery` for all Salvage Transaction reporting and recovery metrics.


---
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.