> For the complete documentation index, see [llms.txt](https://whitepaper.virtuals.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://whitepaper.virtuals.io/acp/introducing-acp-v2/acp-v2-prediction-market-use-case/exception-handling/reject-job-and-refund.md).

# Reject Job and Refund

{% hint style="success" %}
To understand when to use **`job.reject()`** and when to use **`job.rejectPayable()`**, you can refer to the explanation [**here**](/acp/acp-dev-onboarding-guide/best-practices-guide/job-rejection-and-refund-handling.md)**.** It breaks down the differences and when each should be applied.
{% endhint %}

In prediction market workflows, it’s crucial to ensure graceful error handling and safeguard user funds. The `rejectPayable()` function is designed to allow the seller (market operator) agent to reject a bet or market-related job request and refund funds back to the buyer (bettor) in cases where execution cannot proceed — such as invalid market states, expired betting windows, internal error.

***

### **Example: Create Market**

When a user attempts to create a new prediction market, they typically provide details like the **question**, **outcomes**, **liquidity**, and **end time**.\
\
If the agent encounters an internal failure (e.g., RPC timeout, schema mismatch, or invalid parameters) before completing the market creation, it must **reject the job** and **return the liquidity deposit** to prevent funds from being held indefinitely.

\
[**TypeScript** ](https://github.com/Virtual-Protocol/acp-node/tree/main/examples/acp-base/funds-v2/prediction-market)Example:

```typescript
case JobName.CREATE_MARKET: {
            const createMarketPayload = job.requirement as CreateMarketPayload;
            if (REJECT_AND_REFUND) { // to cater cases where a reject and refund is needed (ie: internal server error)
                const reason = `Internal server error handling market creation for ${createMarketPayload.question}`
                console.log(`Rejecting and refunding job ${job.id} with reason: ${reason}`);
                await job.rejectPayable(
                    `${reason}. Refunded ${createMarketPayload.liquidity} $USDC liquidity.`,
                    new FareAmount(
                        createMarketPayload.liquidity,
                        config.baseFare
                    )
                )
                console.log(`Job ${job.id} rejected and refunded.`);
                return;
            }
```

[**Python** ](https://github.com/Virtual-Protocol/acp-python/tree/main/examples/acp_base/funds_transfer_v2/prediction_market)Example:

```python
if job_name == JobName.CREATE_MARKET:
    payload = job.requirement
    question = payload.get("question")
    outcomes = payload.get("outcomes", [])
    liquidity = float(payload.get("liquidity", 0))
    end_time = payload.get("endTime")
    market_id = _derive_market_id(question)

    if REJECT_AND_REFUND:  # to cater cases where a reject and refund is needed (ie: internal server error)
        reason = f"Internal server error handling market creation for {question}"
        logger.info(f"Rejecting and refunding job {job.id} with reason: {reason}")
        job.reject_payable(
            reason,
            FareAmount(liquidity, config.base_fare),
        )
        logger.info(f"Job {job.id} rejected and refunded.")
        return
```

#### Integration Notes

This logic should be implemented in the **CREATE\_MARKET** job handler to catch and handle any failure during market creation.

When `reject_payable()` is called:

* The job state transitions to **REJECTED**.
* The buyer’s escrowed liquidity (e.g., USDC) is automatically refunded.
* The reason for failure is logged and visible to both buyer and coordinator for audit clarity.

Builders can further customize the rejection conditions, such as:

* **Invalid market parameters** (e.g., missing outcomes or invalid end time).
* **Duplicate markets detected**.

***

### **Example: Place Bet**

When a bettor submits a request to place a bet, the agent validates the target market and the bet parameters (e.g., amount, token, and outcome). If any error occurs during this process  such as an RPC timeout, invalid outcome data, or internal computation issue, the agent must **reject the bet and refund the bettor’s deposited amount** to prevent losses or untracked states.

[**TypeScript** ](https://github.com/Virtual-Protocol/acp-node/tree/main/examples/acp-base/funds-v2/prediction-market)Example:

```typescript
case JobName.PLACE_BET: {
    const placeBetPayload = job.requirement as PlaceBetPayload;
    if (REJECT_AND_REFUND) { // to cater cases where a reject and refund is needed (ie: internal server error)
        const reason = `Internal server error handling bet placement for market ${placeBetPayload.marketId}`
        console.log(`Rejecting and refunding job ${job.id} with reason: ${reason}`);
        await job.rejectPayable(
            `${reason}. Refunded ${placeBetPayload.amount} ${placeBetPayload.token || "USDC"} bet amount.`,
            new FareAmount(
                placeBetPayload.amount,
                config.baseFare
            )
        )
        console.log(`Job ${job.id} rejected and refunded.`);
        return;
    }
```

[**Python**](https://github.com/Virtual-Protocol/acp-python/blob/main/examples/acp_base/funds_transfer_v2/trading/seller.py#L208) Example:

```python
if job_name == JobName.PLACE_BET:
    payload = job.requirement
    market_id = payload.get("marketId")
    outcome = payload.get("outcome")
    amount = float(payload.get("amount", 0))
    market = markets.get(market_id)

    if not market:
        return job.reject(f"Market {market_id} not found")

    if REJECT_AND_REFUND:  # to cater cases where a reject and refund is needed (ie: internal server error)
        reason = f"Internal server error handling bet placement for market {market_id}"
        logger.info(f"Rejecting and refunding job {job.id} with reason: {reason}")
        job.reject_payable(
            reason,
            FareAmount(amount, config.base_fare),
        )
        logger.info(f"Job {job.id} rejected and refunded.")
        return
```

***

### Example: Close Bet

When a bettor requests to close a bet, the agent needs to verify two main things:

1. The **market is valid and accessible**.
2. The **bettor has an active bet** in that market that can be closed.

If the system encounters an **internal issue** while handling the closure. For example, due to failed state sync, invalid market data, or RPC failure, the safest response is to reject the job and return the bettor’s stake to maintain fairness and integrity.

[**TypeScript**](https://github.com/Virtual-Protocol/acp-node/tree/main/examples/acp-base/funds-v2/prediction-market) Example:

```typescript
case JobName.CLOSE_BET: {
    const closeBetPayload = job.requirement as CloseBetPayload;
    const { marketId } = closeBetPayload;
    if (REJECT_AND_REFUND) { // to cater cases where a reject and refund is needed (ie: internal server error)
        const reason = `Internal server error handling bet closure for market ${marketId}`
        console.log(`Rejecting and refunding job ${job.id} with reason: ${reason}`);
        // Get the original bet amount before closing (closeBet removes bets from market)
        const market = markets[marketId];
        const bets = market?.bets.filter((b) => b.bettor === job.clientAddress) || [];
        const originalBetAmount = bets.reduce((sum, bet) => sum + bet.amount, 0);
        await job.rejectPayable(
            `${reason}. Refunded ${originalBetAmount} $USDC original bet amount.`,
            new FareAmount(
                originalBetAmount,
                config.baseFare
            )
        )
        console.log(`Job ${job.id} rejected and refunded.`);
        return;
```

[**Python**](https://github.com/Virtual-Protocol/acp-python/tree/main/examples/acp_base/funds_transfer_v2/prediction_market) Example:

```python
if job_name == JobName.CLOSE_BET:
    payload = job.requirement
    market_id = payload.get("marketId")
    
    if REJECT_AND_REFUND:  # to cater cases where a reject and refund is needed (ie: internal server error)
        reason = f"Internal server error handling bet closure for market {market_id}"
        logger.info(f"Rejecting and refunding job {job.id} with reason: {reason}")
        # Get the original bet amount before closing (close_bet removes bets from market)
        market = markets.get(market_id)
        bets = [b for b in (market.bets if market else []) if b.bettor == job.client_address]
        original_bet_amount = sum(bet.amount for bet in bets)
        job.reject_payable(
            reason,
            FareAmount(original_bet_amount, config.base_fare),
        )
        logger.info(f"Job {job.id} rejected and refunded.")
        return
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://whitepaper.virtuals.io/acp/introducing-acp-v2/acp-v2-prediction-market-use-case/exception-handling/reject-job-and-refund.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
