Documentation

In-App Purchasing

Client API

SDK API

In-App Purchasing

Comply with Apple and Google external purchase requirements

Understand your compliance responsibilities for external purchases on Apple and Google, and the SDK and webhook tools Unity provides to help you meet them.
Read time 5 minutesLast updated 3 hours ago

An external purchase sells digital content through your own web checkout (such as a payment provider) instead of Apple's or Google's in-app billing. Apple and Google allow this only in select regions and only under their own program rules, such as the External Purchase program (Apple) and the external offers programs (Google Play). Eligibility, fees, disclosures, and transaction reporting vary by platform, region, and app. In some regions, you might need little or none of these purchase requirements.
Important
Unity doesn't perform platform compliance on your behalf. You're responsible for determining your eligibility, meeting each platform's technical and policy requirements, and reporting transactions to Apple and Google where required. Consult Apple and Google directly, and review the pre-release terms, before you ship external purchases.
To help you build your own compliance flow, Unity provides SDK hooks and webhook data. This page explains the division of responsibilities, the order model your compliance steps build on, and the specific actions you can take. This page is part of the Integrate Direct to Consumer (D2C) payment providers workflow. Set up your payment provider and purchase flow before you add the compliance handling described here.

Division of responsibilities

Unity provides only technical facilitation. Your payment provider acts as merchant of record for payment processing, tax, and disputes, but it doesn't handle Apple or Google platform reporting. The platform compliance is your responsibility, and Unity doesn't enroll you in any platform program.

Unity's technical facilitation

When a Payment Providers purchase proceeds, Unity opens the checkout URL on your behalf. By default it opens in the device's external browser. If you opt into in-app presentation (
CheckoutPresentationMode.WebView
), Unity opens it in an in-app browser instead. To further understand how Unity works with orders, refer to how Unity creates and opens an order.
Unity doesn't call Apple's external-purchase notice or Google's external-link APIs for you, and Unity doesn't decide your eligibility. You invoke those platform APIs yourself, as described in your responsibilities.

Your responsibilities

Unity provides only technical facilitation. You are responsible for the following tasks:
  • Determine whether your app and region are eligible for each platform's external purchase program.
  • Run your own eligibility and disclosure checks before a purchase starts, with Apple's
    ExternalPurchaseClient
    and Google's
    ExternalBillingProgramClient
    .
  • Acquire and report any transaction tokens that Apple or Google requires, with each platform's own APIs.

How Unity creates and opens an order

You normally start a Payment Providers purchase with a single call,
PurchaseProduct(catalogListingId)
, where
catalogListingId
identifies the offer in your Remote Catalog. A purchase has two underlying steps, and you can run the first one yourself:
  • GenerateURL(catalogListingId, tokens)
    creates the order and returns its checkout URL, without opening it.
  • PurchaseProduct(catalogListingId)
    opens the checkout. If you already called
    GenerateURL
    for the same listing, it reuses that order. If you didn't, it creates the order itself, with no tokens, and then opens it.
You only need
GenerateURL
first when you need the URL up front (to disclose or render it) or when you need to attach reporting tokens to the order. Otherwise, call
PurchaseProduct
directly.

Decide what your compliance flow needs

The remaining sections are independent. Use the following table to find the steps that apply to your app and platforms:

If you need to

Do this

Section

Enforce your own eligibility rules in-appRegister a compliance callback that runs before each purchaseGate purchases with a compliance check
Show or disclose the checkout URL before the purchase opensCall
GenerateURL
to get the URL, then
PurchaseProduct
to open it
Disclose or render the checkout URL
Report external transactions to Apple or GoogleAttach tokens with
GenerateURL
, then read them back from the order webhook
Attach and report transaction tokens

Gate purchases with a compliance check

This step is optional. Add it only if you enforce your own eligibility rules in-app. Register a compliance callback to apply your own eligibility rules before a purchase proceeds. When you call
PurchaseProduct
(or
Purchase
), Unity runs your callback first and passes a
PaymentProviderComplianceContext
that exposes the
Cart
being purchased. If the callback returns
false
(or throws), the purchase fails with
PurchasingUnavailable
and no order is created.
  1. Define a function that returns a
    Task<bool>
    indicating whether the player passed your compliance check:
    Task<bool> RunComplianceCheckAsync(PaymentProviderComplianceContext context){ const bool allow = true; return Task.FromResult(allow);}
  2. Register the function on the Payment Providers purchase service so Unity calls the function when a purchase begins:
    m_PurchasingService.PaymentProviders?.SetComplianceCheck(RunComplianceCheckAsync);
  3. Use the platform clients inside your check to call the APIs each platform requires for compliance:
    • Apple: use
      ExternalPurchaseClient
      to access Apple's external purchase APIs.
    • Google: use
      ExternalBillingProgramClient
      to access Google's external billing APIs.
Note
The compliance callback runs only for
PurchaseProduct
and
Purchase
.
GenerateURL
isn't gated by it and creates the order immediately, so if you call
GenerateURL
(for disclosure or tokens), run your eligibility checks before that call.

Disclose or render the checkout URL

A platform might require you to display or disclose the external purchase URL before the player proceeds, or you might want to render the checkout in your own web view. In either case, call
GenerateURL
to get the URL without opening it:
string url = await m_PurchasingService.PaymentProviders.GenerateURL(catalogListingId);// Display or disclose the URL, then call PurchaseProduct to open the checkout.
PurchaseProduct(catalogListingId)
then reuses the order
GenerateURL
already created instead of creating a duplicate.
Note
Don't call
GenerateURL
only to prepare a purchase in advance. If you don't need the URL or tokens, call
PurchaseProduct
directly. It creates and opens the order for you. A redundant
GenerateURL
(especially with a forgotten
await
) only adds a race window.

Attach and report transaction tokens

This step is required when Apple or Google requires you to report external transactions (this varies by program and region). Apple and Google require you to report each external transaction back to them through their server APIs. You get an opaque transaction token from the platform, attach it to the Unity order, and receive it back in the order webhook so you can file your report. You generate the tokens yourself: Apple tokens come from
ExternalPurchaseClient
, and the Google token comes from
ExternalBillingProgramClient
.
PurchaseProduct
doesn't accept tokens, so a purchase that creates its own order attaches no tokens. To get your tokens onto the order, call
GenerateURL(catalogListingId, tokens)
first. The subsequent
PurchaseProduct
for the same listing then adopts that token-bearing order:
await m_PurchasingService.PaymentProviders.GenerateURL(catalogListingId, tokenList);m_PurchasingService.PurchaseProduct(catalogListingId);
Unity stores the tokens with the order without inspecting or validating them, and surfaces them in order webhooks. They're not returned in the order API response.
Note
If you attach reporting tokens, the order webhook is the only place Unity returns the tokens. Refer to Configure a webhook or Cloud Code module for purchase fulfillment.

Tokens in the webhook payload

Order webhooks include an
externalTransactionTokens
array under
data
. Each entry carries the token and the store it targets:
{ "eventType": "order.paid", "data": { "id": "...", "playerId": "...", "status": "paid", "externalTransactionTokens": [ { "store": "apple", "token": "opaque-apple-transaction-token", "type": "acquisition" }, { "store": "google", "token": "opaque-google-transaction-token" } ] }}

store

string
required
The app store the token targets. One of
apple
or
google
. Determines where you report the transaction.

token

string
required
The external purchase or transaction token. Unity stores and forwards it without inspecting it.

type

string
The Apple-only token category. One of
acquisition
,
services
, or
linkOut
. Omitted for Google.
Note
You can supply up to two tokens per order, because a single Apple external purchase can require two token types depending on the region, such as an
acquisition
token (EU) and a
linkOut
token (Japan). Report each token according to the relevant program. Unity doesn't act on the
type
.
Use these tokens to self-report the transaction through Apple's External Purchase Server API or Google's
externalTransactions
API, as required by each program.

Next steps

This page is part of a workflow to set up D2C payment providers with IAP. To continue this workflow, choose one of the following options: