Skip to content

Step 5. Deliver products

For Steam, the actual charge is completed in the app server's receipt verification step. When verification succeeds, the app server delivers the product to the user, and the app client closes the order by finalizing the purchase and then saves the product delivery result. The hiveAxylTransactionId that the app client uses in this step is the value that the app server received in the receipt verification response and passed on.

1. Deliver products

After checking the receipt verification result, the app server delivers the product to the user who paid. Your app implements product delivery, and the delivery method can differ from app to app.

Finalize the purchase only after the app server finishes delivering the product. Retrieving undelivered orders finds only orders that are not closed, so if you close an order by finalizing the purchase before delivery, you cannot find that order again if the app stops during delivery.

2. Finalize the purchase

Perform the final purchase finalization for the Steam payment. This step closes the payment status and updates the related data, and it does not make any additional charge.

Method

FinalizePurchaseAsync

To implement purchase finalization, call FinalizePurchaseAsync() provided by the Hive Axyl SDK. It performs the final purchase finalization of the Steam payment, closes the payment status, and updates the related data. The actual charge is completed in the preceding receipt verification step.

Call parameters

Field name Type Required Description
request PurchaseFinalizeRequest Required Request data for purchase finalization.
context ApiCallContext Optional Per-call settings object that specifies the idempotency key, cancellation token, and request policy. If omitted, the default values are used.

PurchaseFinalizeRequest

Field name Type Required Description
AxylReceipt string Required Pass Data.AxylReceipt from the payment session initialization response exactly as is. For a purchase recovered through Restore purchases, pass the AxylReceipt from that response. It is the same value as the sealed receipt that you passed when you requested receipt verification from the app server. The server decrypts this value to find the order to finalize, so if you modify the value, the request is rejected.
ProviderId PurchaseFinalizeRequestProviderId Required Market identifier. Because this request is only for Steam purchase finalization, specify only Steam.

Call example

Check the success result of PaymentsFinalizePurchaseResult and the domain-specific results (Outcome) defined by this method in the example below and in the response status. For the result model and handling principles of common failures (Failure) that prevent the request from being performed, see Common error handling.

using Hive.Axyl.Payments;
using Hive.Axyl.Core;

// payments: IPaymentsService registered during initialization (for how to retrieve it, see [Install and initialize the module](../init.md))
IPaymentsService payments = HiveCore.Resolve<IPaymentsService>();

var request = new PurchaseFinalizeRequest
{
    AxylReceipt = axylReceipt, // AxylReceipt from the payment session initialization response. The same value you passed when requesting verification from the app server
    ProviderId = PurchaseFinalizeRequestProviderId.Steam
};

PaymentsFinalizePurchaseResult result = await payments.FinalizePurchaseAsync(request);

switch (result)
{
    case PaymentsFinalizePurchaseResult.Success success:
        // Purchase finalized. Check the order number and the store transaction ID
        Debug.Log($"orderId: {success.Data.OrderId}, storeTransactionId: {success.Data.StoreTransactionId}");
        break;

    case PaymentsFinalizePurchaseResult.PaymentBadRequest:
        // The request cannot be processed. Check the request values and call conditions
        break;

    case PaymentsFinalizePurchaseResult.PaymentInvalidParameter:
        // Invalid parameter. Check the request values
        break;

    // Handle common Failure
    case PaymentsFinalizePurchaseResult.Failure failure:
        HiveError err = failure.Problem;
        Debug.LogError($"[{err.Code}] {err.Message} (trace: {err.TraceId})");
        break;

    // Safety net: unhandled results and unknown new results (UnknownOutcome)
    default:
        Debug.LogWarning($"Unhandled result: {result.GetType().Name}");
        break;
}

Response data

On success, the result is contained in Data (PurchaseFinalizeResponseData) of PaymentsFinalizePurchaseResult.Success.

Field name Type Required Description
Data.OrderId string Optional Steam order number.
Data.StoreTransactionId string Optional Steam transaction ID (transid).
Data.Meta string? Optional Response meta information.

Response example

// Example of success.Data in the Success branch
// success.Data.OrderId = "2026010100001"
// success.Data.StoreTransactionId = "3390549843"

Response status

The table below summarizes the success result of PaymentsFinalizePurchaseResult and the domain-specific results (Outcome) defined by this method. For the result model and handling principles of common failures (Failure) that prevent the request from being performed, see Common error handling.

Response case Description App client handling
Success The payment status has changed to completed. Check the order number and transaction ID, and then proceed to the next step
PaymentBadRequest The request cannot be processed. Check the request values and call conditions
PaymentInvalidParameter Invalid parameter (for example, a required value is missing). Check and correct the required field values
PaymentResourceNotFound The payment information cannot be found. Check the receipt, order number, and payment status
UnknownOutcome A domain-specific result that the SDK does not recognize. Treat it as a failure and log the result code
Failure Common Failure. See Common error handling. Handle it according to the common error handling guidelines

3. Save product delivery results

After the app server completes product delivery, record the delivery result, such as success or cancellation, in the Hive Axyl server.

Method

ItemResultAsync

To implement saving consumable product delivery results, call ItemResultAsync() provided by the Hive Axyl SDK. It records the result in the Hive Axyl server after product delivery is complete. This method does not confirm the payment or decide whether to deliver the product.

Call parameters

Field name Type Required Description
request ItemResultBody Required Request data object for saving consumable product delivery results.
context ApiCallContext Optional Per-call settings object that specifies the idempotency key, cancellation token, and request policy. If omitted, the default values are used.

ItemResultBody

Field name Type Required Description
AxylTransactionId string Required Hive Axyl payment transaction ID (the prefix identifies the market). Use the hiveAxylTransactionId value that the app server received in the receipt verification response and passed on.
Status int Required Delivery result status. 1: delivery succeeded, 2: canceled without reclaiming the product, 3: canceled and the product reclaimed. Any other value is invalid.
Assets IReadOnlyList<ItemResultAsset> Optional List of products actually delivered. If there are no items to record, omit this field.
ProjectPayloadInfo string Optional App-specific free-form JSON data (JSON string)

ItemResultAsset

Field name Type Required Description
AssetId string Optional Unique ID of the product in the app
AssetName string Optional Name of the product in the app
Quantity int Optional Delivery quantity. If you specify it, it must be 1 or more.

Call example

Check the success result of PaymentsItemResultResult and the domain-specific results (Outcome) defined by this method in the example below and in the response status. For the result model and handling principles of common failures (Failure) that prevent the request from being performed, see Common error handling.

using Hive.Axyl.Payments;
using Hive.Axyl.Core;

// payments: IPaymentsService registered during initialization (for how to retrieve it, see [Install and initialize the module](../init.md))
IPaymentsService payments = HiveCore.Resolve<IPaymentsService>();

// After product delivery is complete, create the request object with the delivery result
var request = new ItemResultBody
{
    AxylTransactionId = axylTransactionId, // hiveAxylTransactionId from the receipt verification response passed by the app server
    Status = 1, // 1: Delivery succeeded
    Assets = new[]
    {
        new ItemResultAsset { AssetId = "item_gold_100", AssetName = "골드 100개", Quantity = 1 }
    },
    ProjectPayloadInfo = "{\"serverId\":\"server01\"}" // (Optional) App-specific free-form JSON data
};

PaymentsItemResultResult result = await payments.ItemResultAsync(request);

switch (result)
{
    case PaymentsItemResultResult.Success success:
        // Delivery result recorded. You can check success.Data.Meta.
        break;

    // Problem with request values — check the required values, quantity, and status value
    case PaymentsItemResultResult.PaymentInvalidParameter:
    case PaymentsItemResultResult.PaymentBadRequest:
        Debug.LogError("Check the request parameters.");
        break;

    // Handle common Failure
    case PaymentsItemResultResult.Failure failure:
        HiveError err = failure.Problem;
        Debug.LogError($"[{err.Code}] {err.Message} (trace: {err.TraceId})");
        break;

    // Safety net: unhandled results and unknown new results (UnknownOutcome)
    default:
        Debug.LogWarning($"Unhandled result: {result.GetType().Name}");
        break;
}

Response data

On success, the response meta information is contained in Data (SuccessResponseData) of PaymentsItemResultResult.Success.

Field name Type Required Description
Data.Meta string? Optional Response meta information.

Response example

// You can check success.Data.Meta in the Success branch.

Response status

The table below summarizes the success result of PaymentsItemResultResult and the domain-specific results (Outcome) defined by this method. For the result model and handling principles of common failures (Failure) that prevent the request from being performed, see Common error handling.

Response case Description App client handling
Success Delivery result recorded successfully Proceed with the next payment processing
InvalidQuantity The delivery quantity is invalid. Check the delivery quantity
InvalidStatus The delivery result status value is invalid. Check the Status value
PaymentBadRequest The request cannot be processed. Check the request values and call conditions
PaymentInvalidParameter When a parameter is invalid (for example, AxylTransactionId is missing) Check the required parameter settings
PaymentResourceNotFound The payment information cannot be found. Check the receipt, order number, and payment status
UnknownOutcome A domain-specific result that the SDK does not recognize. Treat it as a failure and log the result code
Failure Common Failure. See Common error handling. Handle it according to the common error handling guidelines

4. Optional: Stop receiving Steam callbacks

When the payment flow has fully ended and you no longer need to receive Steam payment approval callbacks, call StopCallbackListenerAsync() to release the callback listener.

using Hive.Axyl.Core;
using Hive.Axyl.Payments.Addon.Steam;

if (HiveCore.TryResolve<ISteamMicrotransactionsPlugin>(out var steamPlugin))
{
    var stopResult = await steamPlugin.StopCallbackListenerAsync();
    switch (stopResult)
    {
        case SteamMicrotransactionsServiceStopCallbackListenerResult.Success:
            // Stopped receiving callbacks
            break;

        default:
            Debug.LogWarning($"Failed to stop receiving callbacks: {stopResult.GetType().Name}");
            break;
    }
}
Note

StopCallbackListenerAsync() is idempotent. Calling it again after the listener has already been released does not cause an error.

Learn more

If a product could not be delivered because of a network error or a similar problem during the payment process, implement Restore purchases.