Skip to content
/ go-iap Public

go-iap verifies the purchase receipt via AppStore, GooglePlayStore, AmazonAppStore and Huawei HMS.

License

Notifications You must be signed in to change notification settings

awa/go-iap

Folders and files

NameName
Last commit message
Last commit date

Latest commit

370f33b · Mar 14, 2025
Jan 19, 2025
May 23, 2024
Mar 14, 2025
Jan 27, 2024
Feb 5, 2025
Jan 31, 2025
Apr 5, 2021
Feb 8, 2018
Jan 24, 2022
Feb 12, 2025
Jan 31, 2025
Jan 31, 2025

Repository files navigation

go-iap

unit test

go-iap verifies the purchase receipt via AppStore, GooglePlayStore, Amazon AppStore, HMS or MicrosoftStore.

Current API Documents:

  • AppStore: GoDoc
  • AppStore Server API: GoDoc
  • GooglePlay: GoDoc
  • Amazon AppStore: GoDoc
  • Huawei HMS: GoDoc
  • Microsoft Store: GoDoc

Installation

go get github.com/awa/go-iap/appstore
go get github.com/awa/go-iap/playstore
go get github.com/awa/go-iap/amazon
go get github.com/awa/go-iap/hms
go get github.com/awa/go-iap/microsoftstore

Quick Start

In App Purchase (via App Store)

import(
    "github.com/awa/go-iap/appstore"
)

func main() {
	client := appstore.New()
	req := appstore.IAPRequest{
		ReceiptData: "your receipt data encoded by base64",
	}
	resp := &appstore.IAPResponse{}
	ctx := context.Background()
	err := client.Verify(ctx, req, resp)
}

Note: The verifyReceipt API has been deprecated as of 5 Jun 2023. Please use App Store Server API instead.

In App Billing (via GooglePlay)

import(
    "github.com/awa/go-iap/playstore"
)

func main() {
	// You need to prepare a public key for your Android app's in app billing
	// at https://console.developers.google.com.
	jsonKey, err := ioutil.ReadFile("jsonKey.json")
	if err != nil {
		log.Fatal(err)
	}

	client := playstore.New(jsonKey)
	ctx := context.Background()
	resp, err := client.VerifySubscription(ctx, "package", "subscriptionID", "purchaseToken")
}

In App Purchase (via Amazon App Store)

import(
    "github.com/awa/go-iap/amazon"
)

func main() {
	client := amazon.New("developerSecret")

	ctx := context.Background()
	resp, err := client.Verify(ctx, "userID", "receiptID")
}

In App Purchase (via Huawei Mobile Services)

import(
    "github.com/awa/go-iap/hms"
)

func main() {
	// If "orderSiteURL" and/or "subscriptionSiteURL" are empty,
	// they will be default to AppTouch German.
	// Please refer to https://developer.huawei.com/consumer/en/doc/HMSCore-References-V5/api-common-statement-0000001050986127-V5 for details.
	client := hms.New("clientID", "clientSecret", "orderSiteURL", "subscriptionSiteURL")
	ctx := context.Background()
	resp, err := client.VerifySubscription(ctx, "purchaseToken", "subscriptionID", 1)
}

In App Store Server API

Note

  • The App Store Server API differentiates between a sandbox and a production environment based on the base URL:

  • If you're unsure about the environment, follow these steps:

    • Initiate a call to the endpoint using the production URL. If the call is successful, the transaction identifier is associated with the production environment.
    • If you encounter an error code 4040010, indicating a TransactionIdNotFoundError, make a call to the endpoint using the sandbox URL.
    • If this call is successful, the transaction identifier is associated with the sandbox environment. If the call fails with the same error code, the transaction identifier doesn't exist in either environment.
  • GetTransactionInfo

import(
	"github.com/awa/go-iap/appstore/api"
)

//  For generate key file and download it, please refer to https://developer.apple.com/documentation/appstoreserverapi/creating_api_keys_to_use_with_the_app_store_server_api
const ACCOUNTPRIVATEKEY = `
    -----BEGIN PRIVATE KEY-----
    FAKEACCOUNTKEYBASE64FORMAT
    -----END PRIVATE KEY-----
    `
func main() {
	c := &api.StoreConfig{
		KeyContent: []byte(ACCOUNTPRIVATEKEY),  // Loads a .p8 certificate
		KeyID:      "FAKEKEYID",                // Your private key ID from App Store Connect (Ex: 2X9R4HXF34)
		BundleID:   "fake.bundle.id",           // Your app’s bundle ID
		Issuer:     "xxxxx-xx-xx-xx-xxxxxxxxxx",// Your issuer ID from the Keys page in App Store Connect (Ex: "57246542-96fe-1a63-e053-0824d011072a")
		Sandbox:    false,                      // default is Production
	}
	transactionId := "FAKETRANSACTIONID"
	a := api.NewStoreClient(c)
	ctx := context.Background()
	response, err := a.GetTransactionInfo(ctx, transactionId)

	transantion, err := a.ParseSignedTransaction(response.SignedTransactionInfo)
	if err != nil {
	    // error handling
	}

	if transaction.TransactionId == transactionId {
		// the transaction is valid
	}
}
  • GetTransactionHistory
import(
	"github.com/awa/go-iap/appstore/api"
)

//  For generate key file and download it, please refer to https://developer.apple.com/documentation/appstoreserverapi/creating_api_keys_to_use_with_the_app_store_server_api
const ACCOUNTPRIVATEKEY = `
    -----BEGIN PRIVATE KEY-----
    FAKEACCOUNTKEYBASE64FORMAT
    -----END PRIVATE KEY-----
    `
func main() {
	c := &api.StoreConfig{
		KeyContent: []byte(ACCOUNTPRIVATEKEY),  // Loads a .p8 certificate
		KeyID:      "FAKEKEYID",                // Your private key ID from App Store Connect (Ex: 2X9R4HXF34)
		BundleID:   "fake.bundle.id",           // Your app’s bundle ID
		Issuer:     "xxxxx-xx-xx-xx-xxxxxxxxxx",// Your issuer ID from App Store Connect (Users and Access > Integrations > In-App Purchase)(Ex: "57246542-96fe-1a63-e053-0824d011072a")
		Sandbox:    false,                      // default is Production
	}
	originalTransactionId := "FAKETRANSACTIONID"
	a := api.NewStoreClient(c)
	query := &url.Values{}
	query.Set("productType", "AUTO_RENEWABLE")
	query.Set("productType", "NON_CONSUMABLE")
	ctx := context.Background()
	responses, err := a.GetTransactionHistory(ctx, originalTransactionId, query)

	for _, response := range responses {
		transantions, err := a.ParseSignedTransactions(response.SignedTransactions)
	}
}

Parse Notification from App Store

import (
	"github.com/awa/go-iap/appstore"
	"github.com/golang-jwt/jwt/v5"
)

func main() {
	tokenStr := "SignedRenewalInfo Encode String" // or SignedTransactionInfo string
	token := jwt.Token{}
	client := appstore.New()
	err := client.ParseNotificationV2(tokenStr, &token)

	claims, ok := token.Claims.(jwt.MapClaims)
	for key, val := range claims {
		fmt.Printf("Key: %v, value: %v\n", key, val) // key value of SignedRenewalInfo
	}
}

ToDo

  • Validator for In App Purchase Receipt (AppStore)
  • Validator for Subscription token (GooglePlay)
  • Validator for Purchase Product token (GooglePlay)
  • More Tests

Support

In App Purchase

This validator supports the receipt type for iOS7 or above.

In App Billing

This validator uses Version 3 API.

In App Purchase (Amazon)

This validator uses RVS for IAP v2.0.

In App Purchase (HMS)

This validator uses Version 2 API.

In App Store Server API

This validator uses Version 1.0+

In App Purchase (Microsoft Store)

This validator uses Version 1.0

License

go-iap is licensed under the MIT.