Categorygithub.com/aliykh/appstore
modulepackage
0.0.0-20240814181023-f7f9ec3e6535
Repository: https://github.com/aliykh/appstore.git
Documentation: pkg.go.dev

# README

Apple App Store Server Golang Library

The Golang server library for the App Store Server API and App Store Server Notifications.

The App Store Server API is a REST API that you call from your server to request and provide information about your customers' in-app purchases.

The App Store Server API is independent of the app’s installation status on the customers’ devices. The App Store server returns information based on a customer’s in-app purchase history regardless of whether the customer installs, removes, or reinstalls the app on their devices.

Quick Start

Installation

go get github.com/richzw/appstore

Generate a Private Key

Log in to App Store Connect and complete the following steps:

  • Select Users and Access, and then select the Keys tab.
  • Select In-App Purchase under the Key Type.
  • Click Generate API Key or the Add (+) button.
  • Enter a name for the key. The name is for your reference only and isn’t part of the key itself. Click Generate.
  • Click Download API Key next to the new API key. And store your private key in a secure place.

Get Transaction Info

import(
	"github.com/richzw/appstore"
)

// ACCOUNTPRIVATEKEY is the key file generated from previous step
const ACCOUNTPRIVATEKEY = `
    -----BEGIN PRIVATE KEY-----
    FAKEACCOUNTKEYBASE64FORMAT
    -----END PRIVATE KEY-----
    `
func main() {
    c := &appstore.StoreConfig{
        KeyContent: []byte(ACCOUNTPRIVATEKEY),
        KeyID:      "FAKEKEYID",
        BundleID:   "fake.bundle.id",
        Issuer:     "xxxxx-xx-xx-xx-xxxxxxxxxx",
        Sandbox:    false,
    }
    transactionId := "FAKETRANSACTIONID"
    a := appstore.NewStoreClient(c)
    response, err := a.GetTransactionInfo(context.TODO(), transactionId)

    transantions, err := a.ParseSignedTransactions([]{response.SignedTransactionInfo})

    if transactions[0].TransactionId == transactionId {
        // the transaction is valid
    }
}
  • Validate the receipt
    • One option could be to validate the receipt with the App Store server through GetTransactionInfo API, and then check the transactionId in the response matches the one you are looking for.
  • 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.
  • Handle exceeded rate limits gracefully
    • If you exceed a per-hour limit, the API rejects the request with an HTTP 429 response, with a RateLimitExceededError in the body. Consider the following as you integrate the API:
      • If you periodically call the API, throttle your requests to avoid exceeding the per-hour limit for an endpoint.
      • Manage the HTTP 429 RateLimitExceededError in your error-handling process. For example, log the failure and queue the job to process it again at a later time.
      • Check the Retry-After header if you receive the HTTP 429 error. This header contains a UNIX time, in milliseconds, that informs you when you can next send a request.
  • Error handling

Look Up Order ID

import(
    "github.com/richzw/appstore"
)

// ACCOUNTPRIVATEKEY is the key file generated from previous step
const ACCOUNTPRIVATEKEY = `
    -----BEGIN PRIVATE KEY-----
    FAKEACCOUNTKEYBASE64FORMAT
    -----END PRIVATE KEY-----
    `

func main() {
    c := &appstore.StoreConfig{
        KeyContent: []byte(ACCOUNTPRIVATEKEY),
        KeyID:      "FAKEKEYID",
        BundleID:   "fake.bundle.id",
        Issuer:     "xxxxx-xx-xx-xx-xxxxxxxxxx",
        Sandbox:    false,
    }
    invoiceOrderId := "FAKEORDERID"

    a := appstore.NewStoreClient(c)
    rsp, err := a.LookupOrderID(context.TODO(), invoiceOrderId)

    orders, err := a.ParseSignedTransactions(rsp.SignedTransactions)
}

Get Transaction History

import(
    "github.com/richzw/appstore"
)

// ACCOUNTPRIVATEKEY is the key file generated from previous step
const ACCOUNTPRIVATEKEY = `
    -----BEGIN PRIVATE KEY-----
    FAKEACCOUNTKEYBASE64FORMAT
    -----END PRIVATE KEY-----
    `

func main() {
    c := &appstore.StoreConfig{
        KeyContent: []byte(ACCOUNTPRIVATEKEY),
        KeyID:      "FAKEKEYID",
        BundleID:   "fake.bundle.id",
        Issuer:     "xxxxx-xx-xx-xx-xxxxxxxxxx",
        Sandbox:    false,
    }
    originalTransactionId := "FAKEORDERID"
    a := appstore.NewStoreClient(c)
    query := &url.Values{}
    query.Set("productType", "AUTO_RENEWABLE")
    query.Set("productType", "NON_CONSUMABLE")
    gotRsp, err := a.GetTransactionHistory(context.TODO(), originalTransactionId, query)

    for _, rsp := range gotRsp {
       trans, err := a.ParseSignedTransactions(rsp.SignedTransactions)
    }
}

Get Refund History

import(
    "github.com/richzw/appstore"
)

// ACCOUNTPRIVATEKEY is the key file generated from previous step
const ACCOUNTPRIVATEKEY = `
    -----BEGIN PRIVATE KEY-----
    FAKEACCOUNTKEYBASE64FORMAT
    -----END PRIVATE KEY-----
    `

func main() {
    c := &appstore.StoreConfig{
        KeyContent: []byte(ACCOUNTPRIVATEKEY),
        KeyID:      "FAKEKEYID",
        BundleID:   "fake.bundle.id",
        Issuer:     "xxxxx-xx-xx-xx-xxxxxxxxxx",
        Sandbox:    false,
    }
    originalTransactionId := "FAKEORDERID"
    a := appstore.NewStoreClient(c)
    gotRsp, err := a.GetRefundHistory(context.TODO(), originalTransactionId)

    for _, rsp := range gotRsp {
       trans, err := a.ParseSignedTransactions(rsp.SignedTransactions)
    }
}

Parse Notification from App Store

import (
    "github.com/richzw/appstore"
    "github.com/golang-jwt/jwt/v4"
)

func main() {
    c := &appstore.StoreConfig{
        KeyContent: []byte(ACCOUNTPRIVATEKEY),
        KeyID:      "FAKEKEYID",
        BundleID:   "fake.bundle.id",
        Issuer:     "xxxxx-xx-xx-xx-xxxxxxxxxx",
        Sandbox:    false,
    }
    tokenStr := "SignedRenewalInfo Encode String" // or SignedTransactionInfo string
    a := appstore.NewStoreClient(c)
    token, err := a.ParseNotificationV2(tokenStr)

    claims, ok := token.Claims.(jwt.MapClaims)
    for key, val := range claims {
        fmt.Printf("Key: %v, value: %v\n", key, val) // key value of TransactionInfo
    }
}
import (
    "github.com/richzw/appstore"
    "github.com/golang-jwt/jwt/v4"
)

func main() {
    c := &appstore.StoreConfig{
        KeyContent: []byte(ACCOUNTPRIVATEKEY),
        KeyID:      "FAKEKEYID",
        BundleID:   "fake.bundle.id",
        Issuer:     "xxxxx-xx-xx-xx-xxxxxxxxxx",
        Sandbox:    false,
    }
    tokenStr := "JWSTransactionDecodedPayload Encode String"
    a := appstore.NewStoreClient(c)

    jws, err := a.ParseNotificationV2WithClaim(tokenStr)
    // access the fields of JWSTransactionDecodedPayload from jws directly
}

Support

App Store Server API 1.12+

License

appstore is licensed under the MIT.

# Functions

No description provided by the author
NewStoreClient create a appstore server api client.
NewStoreClientWithHTTPClient creates a appstore server api client with a custom http client.
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author

# Constants

No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
list of notificationType https://developer.apple.com/documentation/appstoreservernotifications/notificationtype.
list of notificationType https://developer.apple.com/documentation/appstoreservernotifications/notificationtype.
list of notificationType https://developer.apple.com/documentation/appstoreservernotifications/notificationtype.
list of notificationType https://developer.apple.com/documentation/appstoreservernotifications/notificationtype.
list of notificationType https://developer.apple.com/documentation/appstoreservernotifications/notificationtype.
list of notificationType https://developer.apple.com/documentation/appstoreservernotifications/notificationtype.
list of notificationType https://developer.apple.com/documentation/appstoreservernotifications/notificationtype.
list of notificationType https://developer.apple.com/documentation/appstoreservernotifications/notificationtype.
list of notificationType https://developer.apple.com/documentation/appstoreservernotifications/notificationtype.
list of notificationType https://developer.apple.com/documentation/appstoreservernotifications/notificationtype.
list of notificationType https://developer.apple.com/documentation/appstoreservernotifications/notificationtype.
list of notificationType https://developer.apple.com/documentation/appstoreservernotifications/notificationtype.
list of notificationType https://developer.apple.com/documentation/appstoreservernotifications/notificationtype.
list of notificationType https://developer.apple.com/documentation/appstoreservernotifications/notificationtype.
list of notificationType https://developer.apple.com/documentation/appstoreservernotifications/notificationtype.
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
Environment https://developer.apple.com/documentation/appstoreserverapi/environment.
Environment https://developer.apple.com/documentation/appstoreserverapi/environment.
No description provided by the author
list of subtypes https://developer.apple.com/documentation/appstoreservernotifications/subtype.
list of subtypes https://developer.apple.com/documentation/appstoreservernotifications/subtype.
list of subtypes https://developer.apple.com/documentation/appstoreservernotifications/subtype.
list of subtypes https://developer.apple.com/documentation/appstoreservernotifications/subtype.
list of subtypes https://developer.apple.com/documentation/appstoreservernotifications/subtype.
list of subtypes https://developer.apple.com/documentation/appstoreservernotifications/subtype.
list of subtypes https://developer.apple.com/documentation/appstoreservernotifications/subtype.
list of subtypes https://developer.apple.com/documentation/appstoreservernotifications/subtype.
list of subtypes https://developer.apple.com/documentation/appstoreservernotifications/subtype.
list of subtypes https://developer.apple.com/documentation/appstoreservernotifications/subtype.
list of subtypes https://developer.apple.com/documentation/appstoreservernotifications/subtype.
list of subtypes https://developer.apple.com/documentation/appstoreservernotifications/subtype.
list of subtypes https://developer.apple.com/documentation/appstoreservernotifications/subtype.
No description provided by the author
No description provided by the author
No description provided by the author

# Variables

Errors.
Retryable errors.
No description provided by the author
No description provided by the author
Authorize Tokens For App Store Server API Request Doc: https://developer.apple.com/documentation/appstoreserverapi/generating_tokens_for_api_requests.
Authorize Tokens For App Store Server API Request Doc: https://developer.apple.com/documentation/appstoreserverapi/generating_tokens_for_api_requests.
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
Notification test and history errors.
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author

# Structs

No description provided by the author
ConsumptionRequestBody https://developer.apple.com/documentation/appstoreserverapi/consumptionrequest.
No description provided by the author
ExtendRenewalDateRequest https://developer.apple.com/documentation/appstoreserverapi/extendrenewaldaterequest.
HistoryResponse https://developer.apple.com/documentation/appstoreserverapi/historyresponse.
No description provided by the author
JWSDecodedHeader https://developer.apple.com/documentation/appstoreserverapi/jwsdecodedheader.
JWSRenewalInfoDecodedPayload https://developer.apple.com/documentation/appstoreserverapi/jwsrenewalinfodecodedpayload.
JWSTransaction https://developer.apple.com/documentation/appstoreserverapi/jwstransaction.
No description provided by the author
MassExtendRenewalDateRequest https://developer.apple.com/documentation/appstoreserverapi/massextendrenewaldaterequest.
MassExtendRenewalDateStatusResponse https://developer.apple.com/documentation/appstoreserverapi/massextendrenewaldatestatusresponse.
Notification Data.
NotificationHistoryRequest https://developer.apple.com/documentation/appstoreserverapi/notificationhistoryrequest.
NotificationHistoryResponseItem https://developer.apple.com/documentation/appstoreserverapi/notificationhistoryresponseitem.
NotificationHistoryResponses https://developer.apple.com/documentation/appstoreserverapi/notificationhistoryresponse.
Notification signed payload.
No description provided by the author
OrderLookupResponse https://developer.apple.com/documentation/appstoreserverapi/orderlookupresponse.
RefundLookupResponse same as the RefundHistoryResponse https://developer.apple.com/documentation/appstoreserverapi/refundhistoryresponse.
Notification Renewal Info.
SendAttemptItem https://developer.apple.com/documentation/appstoreserverapi/sendattemptitem.
SendTestNotificationResponse https://developer.apple.com/documentation/appstoreserverapi/sendtestnotificationresponse.
StatusResponse https://developer.apple.com/documentation/appstoreserverapi/get_all_subscription_statuses.
No description provided by the author
No description provided by the author
No description provided by the author
Token represents an Apple Provider Authentication Token (JSON Web Token).
Notification Transaction Info.
TransactionInfoResponse https://developer.apple.com/documentation/appstoreserverapi/transactioninforesponse.

# Interfaces

No description provided by the author
No description provided by the author

# Type aliases

No description provided by the author
No description provided by the author
https://developer.apple.com/documentation/appstoreserverapi/extendreasoncode.
https://developer.apple.com/documentation/appstoreserverapi/firstsendattemptresult.
IAPType https://developer.apple.com/documentation/appstoreserverapi/type.
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
SubtypeV2 is type.
TransactionReason indicates the cause of a purchase transaction, https://developer.apple.com/documentation/appstoreservernotifications/transactionreason.
No description provided by the author