# 4. Call the Inference API

Configure the Airflux SDK to request an inference decision before displaying an interstitial ad. Based on the AI's response, you can decide whether to proceed with showing the ad. This process allows for smarter, more revenue-optimized ad delivery.

***

<figure><img src="/files/36MUXoSd2P6ZMABnOVjQ" alt=""><figcaption></figcaption></figure>

## 1. Set up the API Call and callbacks

Use the `Airflux.requestInference()` function with the `SHOW_INTERSTITIAL_AD` method to request a real-time ad decision. To ensure the AI makes an accurate decision, you must provide detailed contextual parameters and implement the appropriate callbacks.

<details>

<summary>Step 1 : Set Inference Parameters</summary>

To make an accurate decision, Airflux requires detailed **contextual parameters** related to the player state, ad type, and placement. These must be passed into the function via the `parameters` object using `AirfluxParameter.*` keys.

{% hint style="danger" %}
**Important**

All required fields must always be collected, and nullable fields should also be collected whenever available. Failure to provide these values may reduce optimization performance and lead to skewed experimental results.
{% endhint %}

<table><thead><tr><th>Name</th><th width="255.56640625">Description</th><th>Type</th><th>Required</th><th>Sample Value</th></tr></thead><tbody><tr><td><code>currency</code></td><td>The currency code for the ad revenue.(ISO 4217)</td><td>string</td><td>Required</td><td><code>“USD”</code></td></tr><tr><td><code>adType</code></td><td>The type of ad. You must use one of the pre-defined strings from the list below.<br>• <code>"interstitial_ad"</code><br>• <code>"rewarded_ad"</code><br>• <code>“other”</code></td><td>string</td><td>Required</td><td><code>“interstitial_ad”</code></td></tr><tr><td><code>adPlacementID</code></td><td>A unique identifier for the ad placement.</td><td>string</td><td>Required</td><td><code>“placement_3”</code></td></tr><tr><td><code>adPlacementType</code></td><td>The type of ad placement. You must use one of the pre-defined strings from the list below.<br>• <code>"static"</code><br>• <code>"dynamic"</code></td><td>string</td><td>Required</td><td><code>“static”</code></td></tr><tr><td><code>adPlacementPosition</code></td><td>The position of the ad placement within the game. You must use one of the pre-defined strings from the list below<br>• <code>"stage_start"</code><br>• <code>"stage_middle"</code><br>• <code>"stage_end"</code><br>• <code>"non_stage"</code></td><td>string</td><td>Nullable (if the placement is dynamic)</td><td><code>“stage_start"</code></td></tr><tr><td><code>level</code></td><td>The player's or character's current level.</td><td>int</td><td>Nullable<br>(only if no level system)</td><td><code>10</code></td></tr><tr><td><code>stage</code></td><td>The stage number where the ad was presented.<br>If not in a game, this should be the last known result.</td><td>int</td><td>Nullable (if the game has no stages)</td><td><code>10</code></td></tr><tr><td><code>stageType</code></td><td>The type of stage where the ad was presented.<br>If not in a game, this should be the last known result.<br>You must use one of the pre-defined strings from the list below.<br>• <code>"primary_stage"</code><br>• <code>"secondary_stage"</code><br>• <code>"extra_stage"</code></td><td>string</td><td>Nullable (if the game has no stages)</td><td><code>"primary_stage"</code></td></tr><tr><td><code>totalFinishedStage</code></td><td>Number of stages played so far (or play count if the game has no stages)</td><td>int</td><td>Nullable (if the information is not available)</td><td><code>10</code></td></tr><tr><td><code>stageResult</code></td><td>The result of the most recently completed stage.<br>If the ad placement occurs at the end of a stage or game, this should reflect the result of that stage. If the placement is in the middle of a stage/game or the user is not currently in gameplay, provide the result of the last finished stage.<br>You must use one of the pre-defined strings from the list below.<br>• <code>"success"</code><br>• <code>"fail"</code><br>• <code>"giveup"</code><br>• <code>"retry"</code><br>• <code>"draw"</code><br>• <code>"exhausted"</code></td><td>string</td><td>Nullable (if the game has no stages)</td><td><code>"success"</code></td></tr><tr><td><code>adCooldownSeconds</code></td><td>When a cooldown is applied to an ad placement, this key-value map shows the trigger and duration of the cooldown. The key is omitted when no cooldown is applied.<br>• <code>interstitial_ad</code> : Cooldown calculated from the last interstitial ad<br>• <code>rewarded_ad</code> : Cooldown calculated from the last rewarded ad.<br>• <code>app_open</code> : Cooldown calculated from the app open event<br>• <code>install</code> : Cooldown calculated from the app install event.<br>• <code>other</code> : Cooldown calculated from other events<br>Example: If <code>{"rewarded_ad": 120}</code> is included, it means a 2-minute cooldown is applied from the last rewarded ad.</td><td>map&#x3C;string, int></td><td>Nullable (if no cooldown is applied)</td><td><code>{”rewarded_ad”: 10, “interstitial_ad”: 20”}</code></td></tr><tr><td><code>rewardItems</code></td><td>A key-value map of items rewarded to the player. Only for rewarded ads; otherwise, null.</td><td>map&#x3C;string, int></td><td>Nullable (if the ad has no rewards)</td><td><code>{ "coin": 500, "gem": 10 }</code></td></tr></tbody></table>

</details>

<details>

<summary>Step 2 : Implement the Ad Display Logic</summary>

Once the inference request is sent, the SDK will trigger one of the following callbacks. You must implement the appropriate logic in each case to ensure a smooth player experience and stable ad revenue.

| Name                | Description                                                                                                                                                                                                                       | What your app should do                                                                  | Required     |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | ------------ |
| `onShowAd`          | Triggered when the API determines the ad must be shown.                                                                                                                                                                           | Display the interstitial ad.                                                             | **Required** |
| `onSkipAd`          | Triggered when the API determines the ad must be skipped. Continue gameplay without showing ads.                                                                                                                                  | Skip the ad and continue gameplay seamlessly.                                            | **Required** |
| `onDefaultAdPolicy` | Triggered when the ad serving should not be decided by the Airflux policy. You must implement your internal logic to decide whether to show or skip the ad.                                                                       | Apply your internal ad policy logic and proceed accordingly.                             | **Required** |
| `onFailure`         | <p>Triggered when the inference request fails. This may happen if:<br>• The player's country is not supported (not in countryAllowlist)<br>• The server returns a 4XX or 5XX error<br>• The request times out after 3 seconds</p> | Use your fallback logic to decide whether to show or skip the ad. Retry is not required. | **Required** |

{% hint style="warning" %}
**Timeout and Fallback Recommendation**

Failure to handle the inference request properly may lead to degraded play experience and loss of ad revenue. To minimize potential negative effects, it is recommended to set a **3-second (default) timeout** and **implement `onFailure` code** in case the API call fails. Retry attempts upon function call failure are not required. In this case, your internal ad display logic should be included within the `onFailure` block.
{% endhint %}

</details>

#### Code Example

{% tabs %}
{% tab title="Android: Kotlin" %}

```kotlin
import ai.airflux.Airflux
import ai.airflux.AirfluxInference
import ai.airflux.AirfluxParameter
import android.util.Log

Airflux.requestInference(
    inference = AirfluxInference.SHOW_INTERSTITIAL_AD(
        parameters = mapOf(
            AirfluxParameter.AD_TYPE to "interstitial_ad",
	    AirfluxParameter.AD_PLACEMENT_ID to "placement_3", 
            AirfluxParameter.AD_PLACEMENT_TYPE to "static",
            AirfluxParameter.AD_PLACEMENT_POSITION to "stage_start", 
            AirfluxParameter.STAGE to 10,
            AirfluxParameter.STAGE_TYPE to "primary_stage",
            AirfluxParameter.TOTAL_FINISHED_STAGE to 10, 
            AirfluxParameter.STAGE_RESULT to "success",
            AirfluxParameter.AD_COOLDOWN_SECONDS to mapOf( 
                "rewarded_ad" to 10,
                "interstitial_ad" to 20
            ),
            AirfluxParameter.REWARD_ITEMS to mapOf( 
                "coin" to 500,
                "gem" to 10
            ),
            AirfluxParameter.FORCE_RESPONSE to mapOf( 
                "action" to "showAd",
                "parameters" to mapOf<String, Any>() 
            )
        ),
        onShowAd = {
            // AI determined to show the ad. Implement your logic here.
            Log.d("Airflux", "AI decided to show ad.")
            // Your function to display the interstitial ad
        },
        onSkipAd = {
            // AI determined to skip the ad. Implement your logic here.
            Log.d("Airflux", "AI decided to skip ad.")
            // Your function to continue gameplay without showing ads
        },
        onDefaultAdPolicy = {
            // Implement your internal logic to decide whether to show or skip the ad.
            Log.d("Airflux", "AI returned default policy. Implementing internal logic.")
            // Your function for default ad decision logic
        },
        onFailure = { error ->
            // Inference request failed. Implement your internal logic to handle the error
            // and decide whether to show or skip the ad based on your game's policy.
            Log.e("Airflux", "Inference request failed: ${error.message}. Falling back to default policy.")
            // Your function for default ad decision logic on error
        }
    )
)

```

{% endtab %}

{% tab title="Android: Java" %}

```java
import ai.airflux.Airflux;
import ai.airflux.AirfluxInference;
import ai.airflux.AirfluxParameter;
import android.util.Log;

Airflux.requestInference(
    AirfluxInference.SHOW_INTERSTITIAL_AD(
        new HashMap<String, Object>() {{
            put(AirfluxParameter.AD_TYPE, "interstitial_ad");
            put(AirfluxParameter.AD_PLACEMENT_ID, "placement_3");
            put(AirfluxParameter.AD_PLACEMENT_TYPE, "static");
            put(AirfluxParameter.AD_PLACEMENT_POSITION, "stage_start");
            put(AirfluxParameter.STAGE, 10);
            put(AirfluxParameter.STAGE_TYPE, "primary_stage");
            put(AirfluxParameter.TOTAL_FINISHED_STAGE, 10);
            put(AirfluxParameter.STAGE_RESULT, "success");
            put(AirfluxParameter.AD_COOLDOWN_SECONDS, new HashMap<String, Integer>() {{
                put("rewarded_ad", 10);
                put("interstitial_ad", 20);
            }});
            put(AirfluxParameter.REWARD_ITEMS, new HashMap<String, Integer>() {{
                put("coin", 500);
                put("gem", 10);
            }});
            put(AirfluxParameter.FORCE_RESPONSE, new HashMap<String, Object>() {{
                put("action", "showAd");
                put("parameters", new HashMap<String, Object>());
            }});
        }},
        () -> {
            // AI determined to show the ad. Implement your logic here.
            Log.d("Airflux", "AI decided to show ad.");
            // Your function to display the interstitial ad
        },
        () -> {
            // AI determined to skip the ad. Implement your logic here.
            Log.d("Airflux", "AI decided to skip ad.");
            // Your function to continue gameplay without showing ads
        },
        () -> {
            // Implement your internal logic to decide whether to show or skip the ad.
            Log.d("Airflux", "AI returned default policy. Implementing internal logic.");
            // Your function for default ad decision logic
        },
        airfluxError -> {
            // Inference request failed. Implement your internal logic to handle the error
            // and decide whether to show or skip the ad based on your game's policy.
            Log.e("Airflux", String.format("Inference request failed: %s. Falling back to default policy.", airfluxError.getMessage()));
            // Your function for default ad decision logic on error
        }
    )
);

```

{% endtab %}
{% endtabs %}

#### **Verification**

<details>

<summary>Testing with Force responses</summary>

Ensure that your app correctly calls the inference API at each interstitial placement and follows the returned decision reliably.

**What to test**

1. The inference request includes all required parameters.
2. Exactly one of the decision callbacks is triggered per request.

**Testing with Force responses**

To simulate various responses during development or QA, you can use the `AirfluxParameter.FORCE_RESPONSE` parameter in your inference request:

{% hint style="info" %}
It’s **recommended to implement handling for all four cases** to ensure consistent ad delivery across various environments and edge cases.
{% endhint %}

| Simulated value     | Callback triggered    | Purpose                                      | Expected Behavior                   |
| ------------------- | --------------------- | -------------------------------------------- | ----------------------------------- |
| `“showAd”`          | `onShowAd()`          | Test ad display flow                         | Ad is displayed to the player       |
| `“skipAd”`          | `onSkipAd()`          | Test ad skip behavior                        | Ad is skipped and gameplay resumes  |
| `“defaultAdPolicy”` | `onDefaultAdPolicy()` | Test your ad decision logic                  | Your ad decision logic is executed  |
| `“failure”`         | `onFailure(error)`    | Test fallback handling for failure scenarios | Custom policy determines ad display |

```kotlin
[AirfluxParameter.FORCE_RESPONSE]: {
    "action": "showAd",
    "parameters": {}
}
```

{% hint style="info" %}
The `FORCE_RESPONSE` parameter is intended for testing purposes only and **must be removed from production builds**. If left active, it may cause ads to be **always shown or always skipped**, regardless of actual inference decisions.
{% endhint %}

**Code Example**

{% code title="Android: Kotlin" %}

```kotlin
AirfluxParameter.FORCE_RESPONSE to mapOf(
    "action" to "showAd",
    "parameters" to mapOf<String, Any>()
)
```

{% endcode %}

{% code title="Android: Java" %}

```java
put(AirfluxParameter.FORCE_RESPONSE, new HashMap<String, Object>() {{
    put("action", "showAd");
    put("parameters", new HashMap<String, Object>());
}});
```

{% endcode %}

</details>

***

## 2. Deploy the app

After completing sufficient QA and crash testing, deploy your gaming app. To ensure proper integration with Airflux, make sure the deployment follows the timeline coordinated with the Growth Manager.

<details>

<summary>Where can I get guidance for the app store review?</summary>

Click [here](https://docs.airflux.ai/airflux-reference/preparing-for-the-app-store-review) for guidance on preparing for the Google Play and App Store reviews.

</details>

***

## Next steps

Congratulations! If you have completed the steps above, you are all set to optimize your in-game advertising with Airflux. Click [here](https://docs.airflux.ai/reporting) to learn how to receive your optimization results.

***

## Frequently Asked Questions

<details>

<summary>What is the difference between <code>onSkipAd()</code> and <code>onFailure()</code> callbacks?</summary>

* The `onSkipAd()` callback function is triggered when the API call is successful, and the inference result from the Airflux AI model indicates that an ad should not be displayed to enhance the play experience and maximize ad revenue.
* The `onFailure()` callback function is triggered when the API call fails. This includes situations such as the device's country not being in the allowlist (`countryAllowlist`), network issues, server errors, or request validation failures, where no response is received.

</details>

<details>

<summary>What is the response time of the API by country?</summary>

Airflux aims to deliver reliable service to users worldwide and typically maintains quick response times in most regions. However, minor delays may arise based on the network environment.

</details>


---

# Agent Instructions: 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:

```
GET https://docs.airflux.ai/airflux-onboarding/airflux-integration-android/4.-call-the-inference-api.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
