### Install App Store Server Golang Library Source: https://github.com/richzw/appstore/blob/master/README.md Install the library using the go get command. ```shell go get github.com/richzw/appstore ``` -------------------------------- ### Basic Setup Source: https://github.com/richzw/appstore/blob/master/_autodocs/00-START-HERE.md Demonstrates how to initialize the App Store client with configuration details. ```APIDOC ## Basic Setup ### Description Initializes the App Store client with necessary configuration. ### Method `appstore.NewStoreClient` ### Parameters #### Configuration (`appstore.StoreConfig`) - **KeyContent** ([]byte) - Required - The content of your App Store Connect API key. - **KeyID** (string) - Required - The ID of your App Store Connect API key. - **BundleID** (string) - Required - The bundle identifier of your app. - **Issuer** (string) - Required - The issuer ID from your App Store Connect API key. - **Sandbox** (bool) - Optional - Set to `true` for sandbox environment, `false` for production. ### Request Example ```go config := &appstore.StoreConfig{ KeyContent: []byte(keyContent), KeyID: "2X9R4HXF34", BundleID: "com.example.app", Issuer: "57246542-96fe-1a63-e053-0824d011072a", Sandbox: false, // Production } client := appstore.NewStoreClient(config) ``` ``` -------------------------------- ### Configuration and Setup Source: https://github.com/richzw/appstore/blob/master/_autodocs/MANIFEST.txt Details on setting up the App Store API client, including credentials and environment configuration. ```APIDOC ## Configuration and Setup ### Description This section provides guidance on configuring the App Store Server API client, managing credentials, and selecting the appropriate environment. ### Configuration Options - `StoreConfig`: Details all available configuration parameters. - **Environment Selection**: Options for `Sandbox` vs `Production` environments. - **HTTP Client Customization**: How to customize the underlying HTTP client. - **Security Best Practices**: Recommendations for secure credential management. - **Credential Management**: Procedures for handling API keys and other authentication credentials. ``` -------------------------------- ### JitterBackoff Example Source: https://github.com/richzw/appstore/blob/master/_autodocs/api-reference/backoff.md Shows how to configure and use JitterBackoff for exponential backoff with jitter and a maximum limit, suitable for production API requests. ```go backoff := &appstore.JitterBackoff{ Initial: 100 * time.Millisecond, Max: 30 * time.Second, Multiplier: 2.0, } client := appstore.SetRetry( http.DefaultClient, backoff, appstore.ShouldRetryDefault, ) ``` -------------------------------- ### SetInitializer Source: https://github.com/richzw/appstore/blob/master/_autodocs/api-reference/http-utilities.md Runs initialization logic before each request. Useful for token generation and authentication setup. ```APIDOC ## SetInitializer ### Description Runs initialization logic before each request. Useful for token generation and authentication setup. ### Method func SetInitializer(c HTTPClient, init Initializer) DoFunc ### Parameters #### Path Parameters - **c** (HTTPClient) - Required - The HTTP client to wrap - **init** (Initializer) - Required - Function that initializes and wraps the client ### Returns `DoFunc` - Wrapped HTTP client ### Example ```go // Token generation initializer initializer := func(c appstore.HTTPClient) (appstore.DoFunc, error) { token, err := generateToken() if err != nil { return nil, err } return appstore.AddHeader(c, "Authorization", "Bearer "+token), nil } client := appstore.SetInitializer(http.DefaultClient, initializer) ``` ``` -------------------------------- ### OneSecondBackoff Example Source: https://github.com/richzw/appstore/blob/master/_autodocs/api-reference/backoff.md Demonstrates using a fixed 1-second delay for retries. Useful for simple retry scenarios or testing. ```go backoff := &appstore.OneSecondBackoff{} client := appstore.SetRetry(http.DefaultClient, backoff, appstore.ShouldRetryDefault) ``` -------------------------------- ### Development (Sandbox) Configuration Source: https://github.com/richzw/appstore/blob/master/_autodocs/configuration.md Provides a configuration example for the App Store client in a development or sandbox environment. It uses environment variables for sensitive key information and sets the Sandbox flag to true. ```go config := &appstore.StoreConfig{ KeyContent: []byte(os.Getenv("DEV_KEY")), KeyID: os.Getenv("DEV_KEY_ID"), BundleID: "com.example.app.dev", Issuer: os.Getenv("DEV_ISSUER"), Sandbox: true, } client := appstore.NewStoreClient(config) ``` -------------------------------- ### Setup App Store Connect Client Source: https://github.com/richzw/appstore/blob/master/_autodocs/00-START-HERE.md Configure and initialize the App Store Connect client with your credentials. Ensure you use the correct KeyID, BundleID, and Issuer ID. Set Sandbox to true for testing against the sandbox environment. ```go config := &appstore.StoreConfig{ KeyContent: []byte(keyContent), KeyID: "2X9R4HXF34", BundleID: "com.example.app", Issuer: "57246542-96fe-1a63-e053-0824d011072a", Sandbox: false, // Production } client := appstore.NewStoreClient(config) ``` -------------------------------- ### AddHeader Middleware Example Source: https://github.com/richzw/appstore/blob/master/_autodocs/api-reference/http-utilities.md Wraps an HTTP client to add header values, appending them to any existing values for the same header key. Use this to include multiple values for a header. ```go client := http.DefaultClient client = appstore.AddHeader(client, "Accept", "application/json") client = appstore.AddHeader(client, "Accept", "text/plain") // Appends ``` -------------------------------- ### SetHeader Middleware Example Source: https://github.com/richzw/appstore/blob/master/_autodocs/api-reference/http-utilities.md Wraps an HTTP client to set specific header values, replacing any existing ones. Use this to ensure a header has a precise value. ```go client := http.DefaultClient client = appstore.SetHeader(client, "User-Agent", "MyApp/1.0") client = appstore.SetHeader(client, "X-Custom", "value1", "value2") req, _ := http.NewRequest("GET", "https://example.com", nil) resp, _ := client.Do(req) ``` -------------------------------- ### SetInitializer Middleware Source: https://github.com/richzw/appstore/blob/master/_autodocs/api-reference/http-utilities.md Wraps an HTTP client to run initialization logic before each request. Useful for dynamic token generation and authentication setup. ```go // Token generation initializer initializer := func(c appstore.HTTPClient) (appstore.DoFunc, error) { token, err := generateToken() if err != nil { return nil, err } return appstore.AddHeader(c, "Authorization", "Bearer "+token), nil } client := appstore.SetInitializer(http.DefaultClient, initializer) ``` -------------------------------- ### Debug Backoff Behavior with Logging Source: https://github.com/richzw/appstore/blob/master/_autodocs/api-reference/backoff.md Add logging to understand backoff behavior during retries. This example demonstrates how to use JitterBackoff and print the waiting duration for each retry attempt. ```go backoff := &appstore.JitterBackoff{ Initial: 100 * time.Millisecond, Max: 5 * time.Second, Multiplier: 2.0, } for i := 0; i < 10; i++ { pause := backoff.Pause() if pause < 0 { fmt.Println("Max retries exceeded") break } fmt.Printf("Retry %d: Waiting %v\n", i+1, pause) time.Sleep(pause) } ``` -------------------------------- ### Initializer Type Definition Source: https://github.com/richzw/appstore/blob/master/_autodocs/api-reference/http-utilities.md Defines the function signature for initializing HTTP clients, allowing for setup of authentication tokens or other pre-request logic. ```go type Initializer func(HTTPClient) (DoFunc, error) ``` -------------------------------- ### Get Transaction Info Source: https://github.com/richzw/appstore/blob/master/_autodocs/MANIFEST.txt Retrieve details for a specific transaction using its unique identifier. Ensure the client is properly initialized. ```go transaction, err := client.GetTransactionInfo(ctx, "transaction-id") if err != nil { // Handle error } // Parse response info, err := store.ParseTransactionInfoResponse(transaction) if err != nil { // Handle error } ``` -------------------------------- ### Token Generation with Custom Timing Source: https://github.com/richzw/appstore/blob/master/_autodocs/api-reference/token.md Example of generating an App Store Connect API token, overriding the default timing functions for IssuedAt and ExpiredAt for custom behavior or testing. ```go token := &appstore.Token{ KeyContent: keyBytes, KeyID: "2X9R4HXF34", BundleID: "com.example.app", Issuer: "57246542-96fe-1a63-e053-0824d011072a", IssuedAtFunc: func() int64 { return time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC).Unix() }, ExpiredAtFunc: func() int64 { return time.Date(2024, 1, 1, 1, 0, 0, 0, time.UTC).Unix() }, } err := token.Generate() ``` -------------------------------- ### Get Transaction Information with App Store Client Source: https://github.com/richzw/appstore/blob/master/_autodocs/README.md Initializes the App Store client and retrieves detailed information for a specific transaction ID. Handles potential errors during the API call and parses the signed transaction data. ```go client := appstore.NewStoreClient(&appstore.StoreConfig{ KeyContent: keyBytes, KeyID: "2X9R4HXF34", BundleID: "com.example.app", Issuer: "57246542-96fe-1a63-e053-0824d011072a", Sandbox: false, }) response, err := client.GetTransactionInfo(ctx, transactionID) if err != nil { // See [Errors](api-reference/errors.md) for error handling log.Fatal(err) } // Parse the signed transaction transactions, err := client.ParseSignedTransactions([]string{response.SignedTransactionInfo}) trans := transactions[0] fmt.Println("Product:", trans.ProductID) fmt.Println("Expires:", trans.ExpiresDate) ``` -------------------------------- ### Extend Subscription Renewal Dates Source: https://github.com/richzw/appstore/blob/master/_autodocs/README.md Provides examples for extending subscription renewal dates, both for a single subscription and for all customers of a specific product. Requires specifying the extension duration, reason code, and a unique request identifier. ```go // Single subscription request := appstore.ExtendRenewalDateRequest{ ExtendByDays: 7, ExtendReasonCode: appstore.CustomerSatisfaction, RequestIdentifier: uuid.New().String(), } statusCode, err := client.ExtendSubscriptionRenewalDate(ctx, originalTxnID, request) // Mass extension for all customers massRequest := appstore.MassExtendRenewalDateRequest{ RequestIdentifier: uuid.New().String(), ExtendByDays: 7, ExtendReasonCode: appstore.ServiceIssueOrOutage, ProductId: "com.example.premium", } statusCode, err := client.ExtendSubscriptionRenewalDateForAll(ctx, massRequest) ``` -------------------------------- ### Implement Custom Backoff Stop Condition Source: https://github.com/richzw/appstore/blob/master/_autodocs/api-reference/backoff.md Implement a custom Backoff strategy by defining a struct that satisfies the Backoff interface. This example shows how to create a LimitedBackoff that stops retrying after a maximum number of attempts. ```go type LimitedBackoff struct { maxRetries int current int duration time.Duration } func (b *LimitedBackoff) Pause() time.Duration { b.current++ if b.current > b.maxRetries { return -1 // Stop retrying } return b.duration } ``` -------------------------------- ### Get Transaction History Source: https://github.com/richzw/appstore/blob/master/README.md Fetches the transaction history for a given transaction ID. Supports filtering by product type. Requires store configuration and a client instance. ```go 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 Notification History Source: https://github.com/richzw/appstore/blob/master/_autodocs/configuration.md Retrieves the history of notifications. ```APIDOC ## POST /inApps/v1/notifications/history ### Description Get notification history. ### Method POST ### Endpoint /inApps/v1/notifications/history ### Request Body - **body** (object) - Required - Parameters for retrieving notification history. ### Response #### Success Response (200) - A list of notification history records. ``` -------------------------------- ### Initialize Store Client Source: https://github.com/richzw/appstore/blob/master/_autodocs/MANIFEST.txt Use NewStoreClient for basic initialization or NewStoreClientWithHTTPClient to provide a custom HTTP client with specific configurations like timeouts and proxies. ```go client := store.NewStoreClient(ctx, "your-api-key-id", "your-api-key-issuer-id", "your-private-key") // With custom HTTP client httpClient := &http.Client{ Timeout: 30 * time.Second, } client := store.NewStoreClientWithHTTPClient(ctx, "your-api-key-id", "your-api-key-issuer-id", "your-private-key", httpClient) ``` -------------------------------- ### Get Refund History Source: https://github.com/richzw/appstore/blob/master/README.md Fetches the refund history for a given transaction ID. ```APIDOC ## Get Refund History ### Description Fetches the refund history for a given transaction ID. ### Method `GetRefundHistory` ### Parameters #### Path Parameters - `originalTransactionId` (string) - Required - The ID of the original transaction. ### Request Example ```go 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) } } ``` ### Response #### Success Response (200) - `SignedTransactions` ([]string) - A list of signed transaction information. #### Response Example (Response structure not explicitly defined in source, but implies a list of signed transaction strings) ``` -------------------------------- ### Get Transaction History with Go Source: https://github.com/richzw/appstore/blob/master/_autodocs/api-reference/store-client.md Retrieves a customer's transaction history for a given original transaction ID, supporting pagination and query parameters like product type, sort order, and direction. The response is a slice of history responses, each containing signed transactions for a page. Parse each page's transactions and handle parsing errors individually. ```go query := &url.Values{} query.Set("productType", "AUTO_RENEWABLE") query.Set("sort", "PURCHASE_DATE") query.Set("order", "DESCENDING") responses, err := client.GetTransactionHistory(ctx, "720000124683768", query) if err != nil { log.Fatal(err) } for _, resp := range responses { trans, err := client.ParseSignedTransactions(resp.SignedTransactions) if err != nil { log.Printf("Failed to parse transactions: %v", err) continue } for _, t := range trans { fmt.Printf("Product: %s, Expired: %d\n", t.ProductID, t.ExpiresDate) } } ``` -------------------------------- ### Get Test Notification Status Source: https://github.com/richzw/appstore/blob/master/_autodocs/configuration.md Retrieves the status of a test notification using its token. ```APIDOC ## GET /inApps/v1/notifications/test/{testNotificationToken} ### Description Get test notification status. ### Method GET ### Endpoint /inApps/v1/notifications/test/{testNotificationToken} ### Parameters #### Path Parameters - **testNotificationToken** (string) - Required - The token for the test notification. ### Response #### Success Response (200) - Status of the test notification. ``` -------------------------------- ### Get All Subscription Status Source: https://github.com/richzw/appstore/blob/master/_autodocs/configuration.md Retrieves the status of all subscriptions for a given original transaction ID. ```APIDOC ## GET /inApps/v1/subscriptions/{originalTransactionId} ### Description Get all subscription statuses. ### Method GET ### Endpoint /inApps/v1/subscriptions/{originalTransactionId} ### Parameters #### Path Parameters - **originalTransactionId** (string) - Required - The original transaction ID. ### Response #### Success Response (200) - Subscription status details. ``` -------------------------------- ### Configuration with Custom HTTP Client Source: https://github.com/richzw/appstore/blob/master/_autodocs/configuration.md Demonstrates how to initialize the App Store client with a custom HTTP client, allowing for specific configurations like timeouts and proxy settings. The custom client is passed during client initialization. ```go httpClient := &http.Client{ Timeout: 60 * time.Second, Transport: &http.Transport{ Proxy: http.ProxyFromEnvironment, }, } config := &appstore.StoreConfig{ KeyContent: []byte(keyContent), KeyID: keyID, BundleID: bundleID, Issuer: issuer, } client := appstore.NewStoreClientWithHTTPClient(config, httpClient) ``` -------------------------------- ### Get Error Message Source: https://github.com/richzw/appstore/blob/master/_autodocs/api-reference/errors.md Retrieves the human-readable error message associated with the API response. ```go func (e *Error) ErrorMessage() string Returns the human-readable error message. **Returns:** `string` - Error message from Apple API ``` -------------------------------- ### Get Transaction Info Source: https://github.com/richzw/appstore/blob/master/_autodocs/00-START-HERE.md Retrieves detailed information about a specific transaction using its ID. ```APIDOC ## Get Transaction Info ### Description Fetches transaction information from the App Store using a transaction ID. ### Method `client.GetTransactionInfo(ctx context.Context, transactionID string)` ### Parameters #### Path Parameters - **ctx** (context.Context) - Required - The context for the request. - **transactionID** (string) - Required - The unique identifier for the transaction. ### Response #### Success Response (200) - **SignedTransactionInfo** (string) - The signed transaction information. ### Response Example ```json { "signedTransactionInfo": "..." } ``` ### Related Operations - **ParseSignedTransactions**: Parses the raw signed transaction data into a usable format. ```go response, err := client.GetTransactionInfo(ctx, transactionID) if err != nil { // Handle error log.Fatal(err) } transactions, _ := client.ParseSignedTransactions([]string{response.SignedTransactionInfo}) trans := transactions[0] fmt.Println("Product:", trans.ProductID) fmt.Println("Expires:", trans.ExpiresDate) ``` ``` -------------------------------- ### Configure Sandbox Environment Source: https://github.com/richzw/appstore/blob/master/_autodocs/README.md Set `config.Sandbox` to `true` to use the development and testing environment. The endpoint for this environment is `https://api.storekit-sandbox.itunes.apple.com`. ```go config.Sandbox = true // Endpoint: https://api.storekit-sandbox.itunes.apple.com ``` -------------------------------- ### Initialize StoreConfig with Environment Variables Source: https://github.com/richzw/appstore/blob/master/_autodocs/README.md Load App Store Connect API credentials from environment variables to avoid committing sensitive information. Ensure `APPSTORE_KEY`, `APPSTORE_KEY_ID`, `APPSTORE_BUNDLE_ID`, `APPSTORE_ISSUER`, and `APPSTORE_SANDBOX` are set. ```go config := &appstore.StoreConfig{ KeyContent: []byte(os.Getenv("APPSTORE_KEY")), KeyID: os.Getenv("APPSTORE_KEY_ID"), BundleID: os.Getenv("APPSTORE_BUNDLE_ID"), Issuer: os.Getenv("APPSTORE_ISSUER"), Sandbox: os.Getenv("APPSTORE_SANDBOX") == "true", } ``` -------------------------------- ### StartDateTooFarInPastError Source: https://github.com/richzw/appstore/blob/master/_autodocs/api-reference/errors.md Returned when the start date for a notification history query is more than 90 days in the past. ```go var StartDateTooFarInPastError = newError(4000012, "Invalid request. The start date is earlier than the allowed start date.") ``` -------------------------------- ### StartDateAfterEndDateError Source: https://github.com/richzw/appstore/blob/master/_autodocs/api-reference/errors.md Returned when the start date is after or equal to the end date in a notification history query. ```go var StartDateAfterEndDateError = newError(4000013, "Invalid request. The end date precedes the start date or the dates are the same.") ``` -------------------------------- ### Client Initialization Source: https://github.com/richzw/appstore/blob/master/_autodocs/MANIFEST.txt Functions to create a new store client. You can use a default HTTP client or provide your own. ```APIDOC ## Client Functions ### NewStoreClient Creates a new store client with default HTTP client configuration. #### Signature ```go func NewStoreClient(environment Environment, options ...StoreClientOption) (*StoreClient, error) ``` ### NewStoreClientWithHTTPClient Creates a new store client with a custom HTTP client. #### Signature ```go func NewStoreClientWithHTTPClient(httpClient *http.Client, environment Environment, options ...StoreClientOption) (*StoreClient, error) ``` ``` -------------------------------- ### InvalidStartDateError Source: https://github.com/richzw/appstore/blob/master/_autodocs/api-reference/errors.md Returned when the start date for a notification history query is not a valid timestamp in milliseconds. ```go var InvalidStartDateError = newError(4000015, "Invalid request. The start date is not a timestamp value represented in milliseconds.") ``` -------------------------------- ### Configure Production Environment Source: https://github.com/richzw/appstore/blob/master/_autodocs/configuration.md Set Sandbox to false for production transactions. Ensure transactions match the production environment. ```go config := &appstore.StoreConfig{ Sandbox: false, // Default // ... other config } ``` -------------------------------- ### Get App Transaction Info Source: https://github.com/richzw/appstore/blob/master/_autodocs/configuration.md Retrieves information for an app transaction using its transaction ID. ```APIDOC ## GET /inApps/v1/transactions/appTransactions/{transactionId} ### Description Get app transaction info. ### Method GET ### Endpoint /inApps/v1/transactions/appTransactions/{transactionId} ### Parameters #### Path Parameters - **transactionId** (string) - Required - The ID of the transaction. ### Response #### Success Response (200) - Details about the app transaction. ``` -------------------------------- ### Environment Selection Source: https://github.com/richzw/appstore/blob/master/_autodocs/MANIFEST.txt Configure the client to interact with either the sandbox or production App Store Connect environment. This is critical for testing and live operations. ```go sandboxClient := store.NewStoreClient(ctx, apiKeyID, apiIssuerID, privateKey) sandboxClient.SetEnvironment(store.EnvironmentSandbox) productionClient := store.NewStoreClient(ctx, apiKeyID, apiIssuerID, privateKey) productionClient.SetEnvironment(store.EnvironmentProduction) ``` -------------------------------- ### Get Single Transaction Info Source: https://github.com/richzw/appstore/blob/master/_autodocs/configuration.md Retrieves information for a single transaction using its transaction ID. ```APIDOC ## GET /inApps/v1/transactions/{transactionId} ### Description Get single transaction info. ### Method GET ### Endpoint /inApps/v1/transactions/{transactionId} ### Parameters #### Path Parameters - **transactionId** (string) - Required - The ID of the transaction. ### Response #### Success Response (200) - Details about the transaction. ``` -------------------------------- ### Create StoreClient with Custom HTTP Client Source: https://github.com/richzw/appstore/blob/master/_autodocs/api-reference/store-client.md Initializes a new StoreClient with a custom HTTP client. This is useful for configuring timeouts, proxies, or specific transport settings. The provided httpClient must implement the HTTPClient interface. ```go httpClient := &http.Client{ Timeout: 60 * time.Second, } client := appstore.NewStoreClientWithHTTPClient(config, httpClient) ``` -------------------------------- ### Configure Sandbox Environment Source: https://github.com/richzw/appstore/blob/master/_autodocs/configuration.md Set Sandbox to true for testing. Use this for test transactions and sandbox-only transaction IDs. ```go config := &appstore.StoreConfig{ Sandbox: true, // ... other config } ``` -------------------------------- ### Get API Error Code Source: https://github.com/richzw/appstore/blob/master/_autodocs/api-reference/errors.md Retrieves the specific API error code returned by the App Store. ```go func (e *Error) ErrorCode() int Returns the API error code. **Returns:** `int` - Error code from Apple API **Example:** ```go response, err := client.GetTransactionInfo(ctx, "invalid") if err != nil { code := err.(*appstore.Error).ErrorCode() fmt.Println("Error code:", code) } ``` ``` -------------------------------- ### Configure Production Environment Source: https://github.com/richzw/appstore/blob/master/_autodocs/README.md Set `config.Sandbox` to `false` to use the live production environment for customer transactions. The endpoint is `https://api.storekit.itunes.apple.com`. Remember that production and sandbox environments maintain separate transaction databases. ```go config.Sandbox = false // default // Endpoint: https://api.storekit.itunes.apple.com ``` -------------------------------- ### Get Full Transaction History Source: https://github.com/richzw/appstore/blob/master/_autodocs/configuration.md Retrieves the full transaction history for a given original transaction ID. ```APIDOC ## GET /inApps/v2/history/{originalTransactionId} ### Description Get full transaction history. ### Method GET ### Endpoint /inApps/v2/history/{originalTransactionId} ### Parameters #### Path Parameters - **originalTransactionId** (string) - Required - The original transaction ID. ### Response #### Success Response (200) - A list of transactions. ``` -------------------------------- ### Get Transaction History Source: https://github.com/richzw/appstore/blob/master/README.md Fetches the transaction history for a given transaction ID. It allows filtering by product type. ```APIDOC ## Get Transaction History ### Description Fetches the transaction history for a given transaction ID. It allows filtering by product type. ### Method `GetTransactionHistory` ### Parameters #### Path Parameters - `originalTransactionId` (string) - Required - The ID of the original transaction. #### Query Parameters - `productType` (string) - Required - Can be `AUTO_RENEWABLE` or `NON_CONSUMABLE`. ### Request Example ```go 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) } } ``` ### Response #### Success Response (200) - `SignedTransactions` ([]string) - A list of signed transaction information. #### Response Example (Response structure not explicitly defined in source, but implies a list of signed transaction strings) ``` -------------------------------- ### Token Management - With Config Source: https://github.com/richzw/appstore/blob/master/_autodocs/MANIFEST.txt Generate an API key token with custom configuration, allowing fine-grained control over token generation parameters. ```go tokenConfig := store.TokenConfig{ // Configure token generation parameters } token, err := client.WithConfig(ctx, tokenConfig) if err != nil { // Handle error } ``` -------------------------------- ### Get Notification History Source: https://github.com/richzw/appstore/blob/master/_autodocs/MANIFEST.txt Retrieve a history of notifications sent by the App Store Connect server. This can be useful for debugging and auditing. ```go notificationHistoryRequest := &store.NotificationHistoryRequest{ // Specify filters if needed } history, err := client.GetNotificationHistory(ctx, notificationHistoryRequest) if err != nil { // Handle error } ``` -------------------------------- ### Create StoreClient with Default HTTP Configuration Source: https://github.com/richzw/appstore/blob/master/_autodocs/api-reference/store-client.md Initializes a new StoreClient using default HTTP settings. This client automatically handles JWT token generation and renewal. Ensure your StoreConfig is correctly populated with credentials and bundle information. ```go config := &appstore.StoreConfig{ KeyContent: []byte(privateKeyPEM), KeyID: "2X9R4HXF34", BundleID: "com.example.app", Issuer: "57246542-96fe-1a63-e053-0824d011072a", Sandbox: false, } client := appstore.NewStoreClient(config) ``` -------------------------------- ### Get Refund History Source: https://github.com/richzw/appstore/blob/master/README.md Fetches the refund history for a given transaction ID. Requires store configuration and a client instance. ```go 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) } } ``` -------------------------------- ### Get Subscription Status Source: https://github.com/richzw/appstore/blob/master/_autodocs/README.md Fetches the status of all subscriptions associated with an original transaction ID. Demonstrates parsing renewal information for each subscription. ```APIDOC ## Get Subscription Status ### Description Fetches the status of all subscriptions associated with an original transaction ID. Demonstrates parsing renewal information for each subscription. ### Method `client.GetALLSubscriptionStatuses(ctx, originalTransactionID)` ### Parameters #### Path Parameters - `ctx` (context.Context) - The context for the request. - `originalTransactionID` (string) - The original transaction ID for which to get subscription statuses. ### Response #### Success Response Returns a `SubscriptionStatusResponse` object containing subscription groups and their last transactions. ### Related Operations - `client.ParseNotificationV2RenewalInfo([]string)` ``` -------------------------------- ### Create Custom Certificate Pool Source: https://github.com/richzw/appstore/blob/master/_autodocs/configuration.md Demonstrates how to create a custom certificate pool by appending custom PEM-encoded certificates. This is useful when the default CA bundle is insufficient. ```go // Create custom cert pool certPool := x509.NewCertPool() certPEM := []byte(`-----BEGIN CERTIFICATE-----...`) certPool.AppendCertsFromPEM(certPEM) config := &appstore.StoreConfig{ TrustedCertPool: certPool, // ... other config } ``` -------------------------------- ### Get Test Notification Status Source: https://github.com/richzw/appstore/blob/master/_autodocs/MANIFEST.txt Check the status of a previously sent test notification. This helps in diagnosing issues with notification delivery. ```go status, err := client.GetTestNotificationStatus(ctx) if err != nil { // Handle error } ``` -------------------------------- ### Define StoreConfig for App Store Client Source: https://github.com/richzw/appstore/blob/master/_autodocs/types.md Defines the configuration structure for initializing the StoreClient. All credential fields are required. Use this to set up API access with your private key, issuer ID, and bundle ID. ```go type StoreConfig struct { KeyContent []byte // Loads a .p8 certificate KeyID string // Your private key ID from App Store Connect (Ex: 2X9R4HXF34) BundleID string // Your app's bundle ID Issuer string // Your issuer ID from the Keys page in App Store Connect Audience string // Your audience (aud) for generating the token Sandbox bool // default is Production TokenIssuedAtFunc func() int64 // The token's creation time func. Default is current timestamp TokenExpiredAtFunc func() int64 // The token's expiration time func. Default is one hour later TrustedCertPool *x509.CertPool // The pool of trusted root certificates } ``` -------------------------------- ### Initialize Token with StoreConfig Source: https://github.com/richzw/appstore/blob/master/_autodocs/api-reference/token.md Initializes the Token fields using a provided StoreConfig object. This is typically called internally when creating a new store client. ```go config := &appstore.StoreConfig{ KeyContent: keyBytes, KeyID: "2X9R4HXF34", BundleID: "com.example.app", Issuer: "57246542-96fe-1a63-e053-0824d011072a", } token := &appstore.Token{} token.WithConfig(config) ``` -------------------------------- ### StoreClient Methods Source: https://github.com/richzw/appstore/blob/master/_autodocs/MANIFEST.txt Documentation for StoreClient methods, including transaction querying, subscription management, and consumption tracking. ```APIDOC ## StoreClient Methods ### Description This section details the methods available on the `StoreClient` for interacting with the App Store Server API. It covers functionalities such as querying transaction information, managing subscriptions, and tracking consumption. ### Methods - `GetTransactionInfo(transactionId string)`: Retrieves information for a specific transaction. - `GetTransactionHistory(transactionId string)`: Retrieves the transaction history for a given transaction identifier. - `ExtendSubscriptionRenewalDate(extendRenewalDateRequest ExtendRenewalDateRequest)`: Extends the renewal date for an auto-renewable subscription. - `GetALLSubscriptionStatuses(transactionId string)`: Retrieves all subscription statuses for a given transaction identifier. - `SendConsumptionInfo(consumptionRequest ConsumptionRequest)`: Sends consumption information for a consumable in-app purchase. - `FinishTransaction(transactionId string)`: Marks a transaction as finished, typically used for consumable in-app purchases. ### Error Conditions - `TransactionIdNotFoundError`: Thrown when the provided transaction ID is not found. - `InvalidTransactionIdError`: Thrown when the provided transaction ID is invalid. - `SubscriptionExtensionIneligibleError`: Thrown when a subscription is ineligible for renewal date extension. - `InvalidProductIdError`: Thrown when an invalid product identifier is used. - `InvalidRequestRevisionError`: Thrown when an invalid request revision is provided. - `RateLimitExceededError`: Thrown when the API rate limits are exceeded, often accompanied by retry handling instructions. ``` -------------------------------- ### Context with Timeout Source: https://github.com/richzw/appstore/blob/master/_autodocs/configuration.md Shows how to set a 30-second timeout for API requests using context.WithTimeout. Ensure to defer the cancel function to release resources. ```go // 30-second timeout ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) deferr cancel() response, err := client.GetTransactionInfo(ctx, transactionID) ``` -------------------------------- ### Get Test Notification Status Source: https://github.com/richzw/appstore/blob/master/_autodocs/api-reference/store-client.md Retrieves the status of a previously requested test notification using its token. This is useful for confirming webhook delivery. ```go statusCode, body, err := client.GetTestNotificationStatus(ctx, testNotificationToken) ``` -------------------------------- ### Production Configuration Source: https://github.com/richzw/appstore/blob/master/_autodocs/configuration.md Shows the configuration for the App Store client in a production environment. It also relies on environment variables for credentials and sets the Sandbox flag to false. ```go config := &appstore.StoreConfig{ KeyContent: []byte(os.Getenv("PROD_KEY")), KeyID: os.Getenv("PROD_KEY_ID"), BundleID: "com.example.app", Issuer: os.Getenv("PROD_ISSUER"), Sandbox: false, } client := appstore.NewStoreClient(config) ``` -------------------------------- ### Get Refund History Source: https://github.com/richzw/appstore/blob/master/_autodocs/api-reference/store-client.md Retrieves refund history for a transaction, automatically handling pagination. Use this to check for any refunds associated with a specific purchase. ```go func (c *StoreClient) GetRefundHistory(ctx context.Context, originalTransactionId string) ([]*RefundLookupResponse, error) ``` ```go responses, err := client.GetRefundHistory(ctx, "720000124683768") if err != nil { log.Fatal(err) } for _, resp := range responses { trans, err := client.ParseSignedTransactions(resp.SignedTransactions) if err != nil { continue } for _, t := range trans { if t.RevocationReason != nil { fmt.Printf("Refund reason: %d, Date: %d\n", *t.RevocationReason, t.RevocationDate) } } } ``` -------------------------------- ### Get Subscription Renewal Data Status Source: https://github.com/richzw/appstore/blob/master/_autodocs/MANIFEST.txt Retrieve the status of renewal data for subscriptions. This is useful for understanding subscription health and potential issues. ```go statusResponse, err := client.GetSubscriptionRenewalDataStatus(ctx) if err != nil { // Handle error } ``` -------------------------------- ### Custom HTTP Client Configuration Source: https://github.com/richzw/appstore/blob/master/_autodocs/configuration.md Configure a custom HTTP client with specific timeouts and connection settings. The default timeout is 30 seconds. ```go httpClient := &http.Client{ Timeout: 60 * time.Second, Transport: &http.Transport{ MaxIdleConns: 100, MaxIdleConnsPerHost: 100, IdleConnTimeout: 90 * time.Second, }, } client := appstore.NewStoreClientWithHTTPClient(config, httpClient) ``` -------------------------------- ### Token.WithConfig Source: https://github.com/richzw/appstore/blob/master/_autodocs/api-reference/token.md Initializes the Token fields from a StoreConfig. This method is typically called internally by NewStoreClient. ```APIDOC ## Token.WithConfig ### Description Initializes the Token fields from a StoreConfig. Called internally by NewStoreClient. ### Method func (t *Token) WithConfig(c *StoreConfig) ### Parameters #### Path Parameters - c (*StoreConfig) - Required - Configuration object with API credentials ### Request Example ```go config := &appstore.StoreConfig{ KeyContent: keyBytes, KeyID: "2X9R4HXF34", BundleID: "com.example.app", Issuer: "57246542-96fe-1a63-e053-0824d011072a", } token := &appstore.Token{} token.WithConfig(config) ``` ``` -------------------------------- ### Get Retry After Time Source: https://github.com/richzw/appstore/blob/master/_autodocs/api-reference/errors.md For rate limit errors (HTTP 429), returns the number of milliseconds to wait before retrying. Returns 0 for non-rate-limit errors. ```go func (e *Error) RetryAfter() int64 For rate limit errors (HTTP 429), returns the number of milliseconds to wait before retrying. Returns 0 for non-rate-limit errors. **Returns:** `int64` - Milliseconds to wait (from Retry-After header) **Example:** ```go response, err := client.GetTransactionInfo(ctx, "2000000156693456") if err != nil { if apiErr, ok := err.(*appstore.Error); ok && apiErr.ErrorCode() == 4290000 { fmt.Printf("Rate limited. Retry after %d ms\n", apiErr.RetryAfter()) time.Sleep(time.Duration(apiErr.RetryAfter()) * time.Millisecond) } } ``` ``` -------------------------------- ### App Store Server API Module Structure Source: https://github.com/richzw/appstore/blob/master/_autodocs/README.md Overview of the directory structure for the App Store Server API client library. ```go appstore/ ├── store.go - StoreClient and main API methods ├── token.go - JWT token generation ├── error.go - Error types and constants ├── http.go - HTTP middleware utilities ├── backoff.go - Retry backoff strategies ├── model.go - All data types and structures ├── cert.go - Certificate handling for JWT verification └── pool.go - Certificate pool management ``` -------------------------------- ### Credential Management Source: https://github.com/richzw/appstore/blob/master/_autodocs/MANIFEST.txt Load API credentials (key ID, issuer ID, private key) from environment variables for secure and flexible configuration. ```go apiKeyID := os.Getenv("APPSTORE_API_KEY_ID") apiIssuerID := os.Getenv("APPSTORE_API_ISSUER_ID") privateKeyPath := os.Getenv("APPSTORE_PRIVATE_KEY_PATH") privateKey, err := os.ReadFile(privateKeyPath) if err != nil { // Handle error } client := store.NewStoreClient(ctx, apiKeyID, apiIssuerID, string(privateKey)) ``` -------------------------------- ### Build Complete Request Pipeline Source: https://github.com/richzw/appstore/blob/master/_autodocs/api-reference/http-utilities.md Constructs a full HTTP request pipeline by chaining various middleware functions. This includes adding authorization, rate limiting, retry logic, setting the request details, and handling the response body. Use this pattern to create a robust and configurable HTTP client. ```go var client appstore.HTTPClient = http.DefaultClient // Add authorization client = appstore.SetInitializer(client, func(c appstore.HTTPClient) (appstore.DoFunc, error) { token := getToken() return appstore.AddHeader(c, "Authorization", "Bearer "+token), nil }) // Add rate limiting client = appstore.RateLimit(client, 100) // Add retry logic client = appstore.SetRetry(client, &appstore.JitterBackoff{ Initial: 100 * time.Millisecond, Max: 10 * time.Second, Multiplier: 2.0, }, appstore.ShouldRetryDefault) // Create request client = appstore.SetRequest(ctx, client, "GET", "https://api.example.com/data") // Handle response response := &MyResponse{} client = appstore.SetResponseBodyHandler(client, json.Unmarshal, response) // Execute _, err := client.Do(nil) ``` -------------------------------- ### Get App Transaction Information Source: https://github.com/richzw/appstore/blob/master/_autodocs/api-reference/store-client.md Retrieves detailed app transaction information, including app-level security data, for a given transaction ID. This is useful for verifying transaction integrity. ```go client.GetAppTransactionInfo(ctx, transactionId) ``` -------------------------------- ### Custom HTTP Client with Retry and Rate Limiting Source: https://github.com/richzw/appstore/blob/master/_autodocs/README.md Illustrates how to configure a custom HTTP client with built-in retry logic using a jitter backoff strategy and rate limiting. This allows for more control over API request behavior. ```go httpClient := &http.Client{ Timeout: 60 * time.Second, } backoff := &appstore.JitterBackoff{ Initial: 100 * time.Millisecond, Max: 10 * time.Second, Multiplier: 2.0, } // Build custom pipeline (advanced usage) var client appstore.HTTPClient = httpClient client = appstore.SetRetry(client, backoff, appstore.ShouldRetryDefault) client = appstore.RateLimit(client, 100) // 100 requests/minute appClient := appstore.NewStoreClientWithHTTPClient(config, client) ``` -------------------------------- ### Client Factory Functions Source: https://github.com/richzw/appstore/blob/master/_autodocs/API-SYMBOLS.md Functions to create a new StoreClient instance. ```APIDOC ## Client Factory Functions ### `NewStoreClient` Creates a new store client with default HTTP configuration. #### Signature `NewStoreClient(config *StoreConfig) *StoreClient` ### `NewStoreClientWithHTTPClient` Creates a new store client with a custom HTTP client. #### Signature `NewStoreClientWithHTTPClient(config *StoreConfig, httpClient HTTPClient) *StoreClient` ``` -------------------------------- ### Get All Subscription Statuses Source: https://github.com/richzw/appstore/blob/master/_autodocs/api-reference/store-client.md Retrieves the subscription status for all subscriptions in a group, including the latest transactions and renewal info. Useful for understanding the current state of a user's subscriptions. ```go func (c *StoreClient) GetALLSubscriptionStatuses(ctx context.Context, originalTransactionId string) (*StatusResponse, error) ``` ```go status, err := client.GetALLSubscriptionStatuses(ctx, "720000124683768") if err != nil { log.Fatal(err) } fmt.Printf("App ID: %d, Bundle: %s, Environment: %s\n", status.AppAppleId, status.BundleId, status.Environment) for _, group := range status.Data { fmt.Printf("Group: %s\n", group.SubscriptionGroupIdentifier) for _, item := range group.LastTransactions { trans, _ := client.ParseSignedTransactions([]string{item.SignedTransactionInfo}) if len(trans) > 0 { fmt.Printf(" Status: %d, Product: %s\n", item.Status, trans[0].ProductID) } } } ``` -------------------------------- ### Get Transaction Information Source: https://github.com/richzw/appstore/blob/master/_autodocs/README.md Retrieves detailed information about a specific transaction using its ID. It also shows how to parse the signed transaction data to access product and expiration details. ```APIDOC ## Get Transaction Information ### Description Retrieves detailed information about a specific transaction using its ID. It also shows how to parse the signed transaction data to access product and expiration details. ### Method `client.GetTransactionInfo(ctx, transactionID)` ### Parameters #### Path Parameters - `ctx` (context.Context) - The context for the request. - `transactionID` (string) - The ID of the transaction to retrieve. ### Response #### Success Response Returns a `GetTransactionInfoResponse` object containing `SignedTransactionInfo`. ### Related Operations - `client.ParseSignedTransactions([]string)` ``` -------------------------------- ### Do Source: https://github.com/richzw/appstore/blob/master/_autodocs/api-reference/store-client.md Low-level HTTP method for making custom requests to the App Store API. Automatically handles authentication. ```APIDOC ## Do ### Description Low-level HTTP method for making custom requests to the App Store API. Automatically handles authentication. ### Method Signature ```go func (c *StoreClient) Do(ctx context.Context, method string, url string, body io.Reader) (int, []byte, error) ``` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters Table | Parameter | Type | Required | Default | Description | |-----------|------|----------|---------|-------------| | ctx | context.Context | Yes | — | Context for request cancellation | | method | string | Yes | — | HTTP method (GET, POST, PUT) | | url | string | Yes | — | Full URL to request | | body | io.Reader | No | nil | Request body reader | ### Returns - `int`: HTTP status code - `[]byte`: Response body bytes - `error`: Error object if the request failed ### Request Example ```go // Example usage (assuming 'client' is an initialized StoreClient) statusCode, responseBody, err := client.Do(context.Background(), "GET", "https://api.example.com/v1/items", nil) if err != nil { // Handle error } // Process statusCode and responseBody ``` ### Response #### Success Response (200) - `int`: HTTP status code (e.g., 200) - `[]byte`: Response body as bytes #### Response Example ```json // Example response body (depends on the API endpoint) "{\"data\": \"some_value\"}" ``` ``` -------------------------------- ### Get Subscription Status with App Store Client Source: https://github.com/richzw/appstore/blob/master/_autodocs/README.md Retrieves all subscription statuses for a given original transaction ID. Iterates through subscription groups and their last transactions to parse renewal information. ```go status, err := client.GetALLSubscriptionStatuses(ctx, originalTransactionID) for _, group := range status.Data { fmt.Println("Group:", group.SubscriptionGroupIdentifier) for _, item := range group.LastTransactions { // Parse renewal info renewal, _ := client.ParseNotificationV2RenewalInfo(item.SignedRenewalInfo) fmt.Println("Renews:", renewal.RenewalDate) } } ```