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.
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
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.
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
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.