> For the complete documentation index, see [llms.txt](https://docs.allout.game/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.allout.game/core-engine-concepts/purchasing-product-apis.md).

# Purchasing/Product APIs

Players can buy products (game passes + consumables) for Sparks in your game. When a purchase happens, All Out calls your **purchase handler** so you can grant the item or feature.

{% hint style="info" %}
For creating products and viewing analytics, see [In Game Products](/monetization/in-game-products.md).
{% endhint %}

### Product types (quick overview)

* **Game passes**: one-time, persistent unlocks (admin pass, permanent ability, house ownership)
* **Consumables**: can be bought multiple times (potion, temporary buff, one-time coin pack)

Product types are configured in the creator portal. See [In Game Products](/monetization/in-game-products.md).

### Purchasing API reference

```go
Product :: struct {
    id: string;
    name: string;
    description: string;
    price: s64;
    consumable: bool;
    icon: Texture_Asset;
}

Purchasing :: struct {
    prompt_purchase :: proc(player: Player, id: string);
    owns_product    :: proc(player: Player, id: string) -> bool;
    get_product     :: proc(id: string) -> Product;
}
```

### Prompting a purchase

To start the purchase flow, call `Purchasing.prompt_purchase` with a product ID.

```go
BUY_DOUBLE_JUMP_ID :: "prod_double_jump";

try_prompt_double_jump :: proc(player: Player) {
    Purchasing.prompt_purchase(player, BUY_DOUBLE_JUMP_ID);
}
```

{% hint style="info" %}
The product ID is shown in the monetization/products page in the creator portal (you can click to copy it). See [In Game Products](/monetization/in-game-products.md).
{% endhint %}

### Checking if a player owns a product (game passes)

For game passes, you can gate gameplay features by checking ownership.

```go
ADMIN_PASS_ID :: "prod_admin";

is_admin :: proc(player: Player) -> bool {
    return Purchasing.owns_product(player, ADMIN_PASS_ID);
}
```

{% hint style="info" %}
Consumables can be bought multiple times, owns\_product shouldn't be used to award them. Consumables are usually granted in your purchase handler (coins, items, buffs, etc).
{% endhint %}

### Reading product info (name/price/icon)

If you want to show a “Buy” UI or log product info, fetch the product definition by ID:

```go
product := Purchasing.get_product("prod_double_jump");
log_info("Product % costs % sparks", {product.name, product.price});
```

### The purchase handler (granting)

When a player buys a product in your game, All Out calls:

```go
ao_purchase_handler :: proc(player: Player, id: string) -> bool
```

If your game does not define `ao_purchase_handler`, non-consumable products are granted automatically so they work with `Purchasing.owns_product`. Consumable products still require a handler and are marked as grant failures without one.

You should:

* Switch on the product ID
* Grant the item/feature
* Return `true` if the grant succeeded
* Return `false` if the grant failed (inventory full, missing prerequisite, etc)

```go
COIN_PACK_ID :: "prod_coin_pack_small";
DOUBLE_JUMP_ID :: "prod_double_jump";

ao_purchase_handler :: proc(player: Player, id: string) -> bool {
    switch id {
        case COIN_PACK_ID: {
            // Example: grant coins (consumable)
            Economy.deposit_currency(player, "Coins", 500);
            Notifier.notify(player, "Thanks! +500 coins");
            return true;
        }
        case DOUBLE_JUMP_ID: {
            // Example: game pass unlock (persistent)
            // You typically just enable it via owns_product() checks elsewhere.
            // Still return true so the purchase is considered granted.
            Notifier.notify(player, "Double Jump unlocked!");
            return true;
        }
    }

    // Unknown ID
    return false;
}
```

### Grant failures & retries

If your purchase handler returns `false`, the purchase is marked as a **grant failure**.

* Grant failures are shown in the creator portal
* They're automatically retried when the player joins until they succeed
* You can manually re-run a purchase handler by marking a purchase as “ungranted” in the player data UI

See:

* [In Game Products](/monetization/in-game-products.md) (“Purchase Handlers / Grant Failures”)
* [Editing/Viewing Player Data](/data-and-persistence/editing-viewing-player-data.md) (“Purchases” section)

### Cross-game (hub + minigames)

If you use game parenting, purchases can be shared across your games. See [Cross-Game Products/Data](/data-and-persistence/cross-game-products-data.md).


---

# 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://docs.allout.game/core-engine-concepts/purchasing-product-apis.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.
