go-iap

repository·master·Indexed 21 days ago

https://github.com/awa/go-iap

A Go library for verifying in-app purchase receipts and subscriptions across multiple platforms, including the App Store (via legacy verifyReceipt and the App Store Server API), Google Play, Amazon App Store, Huawei HMS, and Microsoft Store.

Tokens
2.9K
Snippets
10
Records
12
Agent score
77%

What's inside go-iap

  1. Use the App Store Server API

    master

    The App Store Server API is the recommended way to interact with Apple's purchase data.

    Environment Selection

    • Production: https://api.storekit.itunes.apple.com/
    • Sandbox: https://api.storekit-sandbox.itunes.apple.com/

    Tip: If you are unsure which environment a transactionId belongs to, try the production URL first. If you receive error code 4040010 (TransactionIdNotFoundError), retry using the sandbox URL.

  2. Install go-iap packages

    master

    Install the specific provider package you need using go get. You can install multiple providers if your application supports multiple stores.

    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
  3. Verify Huawei HMS subscriptions

    master

    Use the hms package to verify subscriptions. If orderSiteURL or subscriptionSiteURL are left empty, they default to AppTouch German.

    import(
        "github.com/awa/go-iap/hms"
    )
    
    func main() {
    	// If "orderSiteURL" and/or "subscriptionSiteURL" are empty,
    	// they will be default to AppTouch German.
    	client := hms.New("clientID", "clientSecret", "orderSiteURL", "subscriptionSiteURL")
    	ctx := context.Background()
    	resp, err := client.VerifySubscription(ctx, "purchaseToken", "subscriptionID", 1)
    }
  4. Get transaction info via App Store Server API

    master

    Use api.NewStoreClient with a StoreConfig to retrieve transaction details. You must provide your .p8 certificate content, Key ID, Bundle ID, and Issuer ID.

    import(
    	"github.com/awa/go-iap/appstore/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
    		BundleID:   "fake.bundle.id",           // Your app’s bundle ID
    		Issuer:     "xxxxx-xx-xx-xxxxxxxxxx",// Your issuer ID from App Store Connect
    		Sandbox:    false,                      // default is Production
    	}
    	transactionId := "FAKETRANSACTIONID"
    	a := api.NewStoreClient(c)
    	ctx := context.Background()
    	response, err := a.GetTransactionInfo(ctx, transactionId)
    
    	transaction, err := a.ParseSignedTransaction(response.SignedTransactionInfo)
    	if err != nil {
    	    // error handling
    	}
    
    	if transaction.TransactionID == transactionId {
    		// the transaction is valid
    	}
    }
  5. Verify Google Play subscriptions

    master

    Use the playstore package to verify subscriptions. You must provide a JSON key file obtained from the Google Play Console.

    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")
    }
  6. Verify Amazon App Store purchases

    master

    Use the amazon package to verify purchases using a developer secret.

    import(
        "github.com/awa/go-iap/amazon"
    )
    
    func main() {
    	client := amazon.New("developerSecret")
    
    	ctx := context.Background()
    	resp, err := client.Verify(ctx, "userID", "receiptID")
    }
  7. Verify App Store receipts (Legacy)

    master

    Use the appstore package to verify receipts.

    Warning: The verifyReceipt API has been deprecated by Apple as of June 5, 2023. It is recommended to use the App Store Server API instead.

    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)
    }
  8. Parse App Store Notifications

    master

    Use client.ParseNotificationV2 to decode signed strings like SignedRenewalInfo or SignedTransactionInfo into JWT claims.

    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
    	}
    }
  9. Get transaction history via App Store Server API

    master

    Retrieve a history of transactions for an original transaction ID. You can filter by productType using a URL query (e.g., AUTO_RENEWABLE or NON_CONSUMABLE).

    import(
    	"github.com/awa/go-iap/appstore/api"
    )
    
    const ACCOUNTPRIVATEKEY = `
        -----BEGIN PRIVATE KEY-----
        FAKEACCOUNTKEYBASE64FORMAT
        -----END PRIVATE KEY-----
        `
    func main() {
    	c := &api.StoreConfig{
    		KeyContent: []byte(ACCOUNTPRIVATEKEY),
    		KeyID:      "FAKEKEYID",
    		BundleID:   "fake.bundle.id",
    		Issuer:     "xxxxx-xx-xx-xxxxxxxxxx",
    		Sandbox:    false,
    	}
    	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 {
    		transactions, err := a.ParseSignedTransactions(response.SignedTransactions)
    	}
    }
  10. Get Application Access Token Header

    master

    The GetApplicationAccessTokenHeader method retrieves the OAuth AccessToken from HMS and returns it as a formatted Basic authentication header string.

    To optimize performance and comply with HMS rate limits (1000 requests per 5 minutes), the client caches the token internally. A new token is only requested from the HMS OAuth API when the current cached token is near expiration (using a 60-second grace period).

    header, err := client.GetApplicationAccessTokenHeader()
    if err != nil {
        // handle error
    }
    // Use 'header' in your HTTP requests to HMS services
  11. Initialize a Huawei HMS Client

    master

    Use hms.New to create a new client instance for verifying in-app purchases and subscriptions. You must provide your clientID and clientSecret obtained from the HMS API Console.

    Optional parameters orderSiteURL and subscriptionSiteURL allow you to specify custom site URLs for IAP services. If these are not provided or do not start with http, the client defaults to the AppTouch Germany sites:

    • Order Site: https://orders-at-dre.iap.dbankcloud.com
    • Subscription Site: https://subscr-at-dre.iap.dbankcloud.com
    import "awa/awa/go-iap/hms"
    
    // Initialize with credentials and custom site URLs
    client := hms.New("YOUR_CLIENT_ID", "YOUR_CLIENT_SECRET", "https://orders-at-dre.iap.dbankcloud.com", "https://subscr-at-dre.iap.dbankcloud.com")
    
    // Or initialize with defaults
    client := hms.New("YOUR_CLIENT_ID", "YOUR_CLIENT_SECRET", "", "")
  12. Handle Huawei HMS API Errors

    master

    The hms package provides several exported error variables to help you identify specific failure scenarios returned by the HMS API. You can check for these errors using errors.Is().

    Common error types include:

    • hms.ErrorResponseInvalidParameter: The parameter passed to the API is invalid or permissions are missing.
    • hms.ErrorResponseCritical: A critical error occurred during API operations.
    • hms.ErrorResponseProductNotBelongToUser: The user does not own the product they are trying to consume/confirm.
    • hms.ErrorResponseConsumedProduct: The product has already been consumed or confirmed.
    • hms.ErrorResponseAbnormalUserAccount: The user account is abnormal (e.g., deregistered).
    • hms.ErrorResponseUnknown: An undocumented error occurred.