storekit

package module
v0.0.0-...-36b6cd5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 5, 2020 License: Apache-2.0 Imports: 7 Imported by: 1

README

storekit-go

GoDoc

Use this for verifying App Store receipts.

  • Battle proven technology
  • Blockchain free

See GoDoc for detailed API response reference.

Usage example (auto-renewing subscriptions)

package main

import (
	"context"
	"errors"
	"fmt"
	"os"
	"time"

	"github.com/Gurpartap/storekit-go"
)

func main() {
	// Get it from https://AppsToReconnect.apple.com 🤯
	appStoreSharedSecret = os.GetEnv("APP_STORE_SHARED_SECRET")

	// Your own userId
	userId := "12345"

	// Input coming from either user device or subscription notifications webhook
	receiptData := []byte("...")

	err := verifyAndSave(appStoreSharedSecret, userId, receiptData)
	if err != nil {
		fmt.Println("could not verify receipt:", err)
	}
}

func verifyAndSave(appStoreSharedSecret, userId string, receiptData []byte) error {
	// Use .OnProductionEnv() when deploying
	//
	// storekit-go automatically retries sandbox server upon incompatible
	// environment error. This is necessary because App Store Reviewer's purchase
	// requests go through the sandbox server instead of production.
	//
	// Use .WithoutEnvAutoFix() to disable automatic env switching and retrying
	// (not recommended on production)
	client := storekit.NewVerificationClient().OnSandboxEnv()

	// respBody is raw bytes of response, useful for storing, auditing, and for
	// future verification checks. resp is the same parsed and mapped to a struct.
	ctx, _ := context.WithTimeout(context.Background(), 15*time.Second)
	respBody, resp, err := client.Verify(ctx, &storekit.ReceiptRequest{
		ReceiptData:            receiptData,
		Password:               appStoreSharedSecret,
		ExcludeOldTransactions: true,
	})
	if err != nil {
		return err // code: internal error
	}

	if resp.Status != 0 {
		return errors.New(
			fmt.Sprintf("receipt rejected by App Store with status = %d", resp.Status),
		) // code: permission denied
	}

	// If receipt does not contain any active subscription info it is probably a
	// fraudulent attempt at activating subscription from a jailbroken device.
	if len(resp.LatestReceiptInfo) == 0 {
		// keep it 🤫 that we know what's going on
		return errors.New("unknown error") // code: internal (instead of invalid argument)
	}

	// resp.LatestReceiptInfo works for me. but, alternatively (as Apple devs also
	// recommend) you can loop over resp.Receipt.InAppPurchaseReceipt, and filter
	// for the receipt with the highest expiresAtMs to find the appropriate latest
	// subscription (not shown in this example). if you have multiple subscription
	// groups, look for transactions with expiresAt > time.Now().
	for _, latestReceiptInfo := range resp.LatestReceiptInfo {
		productID := latestReceiptInfo.ProductId
		expiresAtMs := latestReceiptInfo.ExpiresDateMs
		// cancelledAtStr := latestReceiptInfo.CancellationDate

		// defensively check for necessary data, because StoreKit API responses can be a
		// bit adventurous
		if productID == "" {
			return errors.New("missing product_id in the latest receipt info") // code: internal error
		}
		if expiresAtMs == 0 {
			return errors.New("missing expiry date in latest receipt info") // code: internal error
		}

		expiresAt := time.Unix(0, expiresAtMs*1000000)

		fmt.Printf(
			"userId = %s has subscribed for product_id = %s which expires_at = %s",
			userId,
			productID,
			expiresAt,
		)

		// ✅ Save or return productID, expiresAt, cancelledAt, respBody
	}
}

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func NewVerificationClient

func NewVerificationClient() *client

NewVerificationClient defaults to production verification URL with auto fix enabled.

Auto fix automatically handles the incompatible receipt environment error. It subsequently gets disabled after the first attempt to avoid unexpected looping.

Types

type AutoRenewStatus

type AutoRenewStatus string

AutoRenewStatus is returned in the JSON response, in the responseBody.Pending_renewal_info array.

The value for this field should not be interpreted as the customer’s subscription status. You can use this value to display an alternative subscription product in your app, such as a lower-level subscription plan to which the user can downgrade from their current plan. Consider presenting an attractive upgrade or downgrade offer in the same subscription group, if the auto_renew_status value is “0”. See Engineering Subscriptions from WWDC 2018 for more information.

https://developer.apple.com/documentation/appstorereceipts/auto_renew_status

const (
	// The customer has turned off automatic renewal for the subscription.
	AutoRenewStatusOff AutoRenewStatus = "0"

	// The subscription will renew at the end of the current subscription period.
	AutoRenewStatusOn AutoRenewStatus = "1"
)

type BillingRetryStatus

type BillingRetryStatus string

BillingRetryStatus indicates whether Apple is attempting to renew an expired subscription automatically.

If the customer’s subscription failed to renew because the App Store was unable to complete the transaction, this value reflects whether the App Store is still trying to renew the subscription. The subscription retry flag is solely indicative of whether a subscription is in a billing retry state. Use this value in conjunction with expiration_intent, expires_date, and transaction_id for more insight.

You can use this field to:

- Determine that the user has been billed successfully, if this field has been removed and there is a new transaction with a future expires_date. Inform the user that there may be an issue with their billing information, if the value is “1”. For example, an expired credit card or insufficient balance could prevent this customer's account from being billed.

- Implement a grace period to improve recovery, if the value is “1” and the expires_date is in the past. A grace period is free or limited subscription access while a subscriber is in a billing retry state. See Engineering Subscriptions from WWDC 2018 for more information.

https://developer.apple.com/documentation/appstorereceipts/is_in_billing_retry_period

const (
	// The App Store has stopped attempting to renew the subscription.
	BillingRetryStatusStoppedAttemptingRenewal BillingRetryStatus = "0"

	// The App Store is attempting to renew the subscription.
	BillingRetryStatusAttemptingRenewal BillingRetryStatus = "1"
)

type ExpirationIntent

type ExpirationIntent string

ExpirationIntent is the reason a subscription expired.

const (
	// The customer voluntarily canceled their subscription.
	ExpirationIntentVoluntarilyCancelled ExpirationIntent = "1"

	// Billing error for example, the customer's payment information was no longer
	// valid.
	ExpirationIntentBillingIssue ExpirationIntent = "2"

	// The customer did not agree to a recent price increase.
	ExpirationIntentDidNotAcceptPriceIncrease ExpirationIntent = "3"

	// The product was not available for purchase at the time of renewal.
	ExpirationIntentProductNotAvailable ExpirationIntent = "4"

	// Unknown error.
	ExpirationIntentUnknown ExpirationIntent = "5"
)

type InAppOwnershipType

type InAppOwnershipType string

InAppOwnershipType is the relationship of the user with the family-shared purchase to which they have access.

When family members benefit from a shared subscription, App Store updates their receipt to include the family-shared purchase. Use the value of in_app_ownership_type to understand whether a transaction belongs to the purchaser or a family member who benefits. This field appears in the App Store server notifications unified receipt (unified_receipt.Latest_receipt_info) and in transaction receipts (responseBody.Latest_receipt_info). For more information about Family Sharing, see Supporting Family Sharing in Your App.

const (
	InAppOwnershipTypeFamilyShared InAppOwnershipType = "FAMILY_SHARED"
	InAppOwnershipTypePurchased    InAppOwnershipType = "PURCHASED"
)

type InAppPurchaseReceipt

type InAppPurchaseReceipt struct {
	// The time Apple customer support canceled a transaction, or the time an
	// auto-renewable subscription plan was upgraded, in a date-time format similar
	// to the ISO 8601. This field is only present for refunded transactions.
	CancellationDate string `json:"cancellation_date,omitempty"`

	// The time Apple customer support canceled a transaction, or the time an
	// auto-renewable subscription plan was upgraded, in UNIX epoch time format, in
	// milliseconds.This field is only present for refunded transactions.Use this
	// time format for processing dates.
	// information.
	CancellationDateMs int64 `json:"cancellation_date_ms,string,omitempty"`

	// The time Apple customer support canceled a transaction, or the time an
	// auto-renewable subscription plan was upgraded, in the Pacific Time zone. This
	// field is only present for refunded transactions.
	CancellationDatePst string `json:"cancellation_date_pst,omitempty"`

	// The reason for a refunded transaction. When a customer cancels a transaction,
	// the App Store gives them a refund and provides a value for this key. A value
	// of “1” indicates that the customer canceled their transaction due to an
	// actual or perceived issue within your app. A value of “0” indicates that the
	// transaction was canceled for another reason; for example, if the customer
	// made the purchase accidentally.
	CancellationReason string `json:"cancellation_reason,omitempty"`

	// The time a subscription expires or when it will renew, in a date-time format
	// similar to the ISO 8601.
	ExpiresDate string `json:"expires_date,omitempty"`

	// The time a subscription expires or when it will renew, in UNIX epoch time
	// format, in milliseconds.Use this time format for processing dates.
	ExpiresDateMs int64 `json:"expires_date_ms,string,omitempty"`

	// The time a subscription expires or when it will renew, in the Pacific Time
	// zone.
	ExpiresDatePst string `json:"expires_date_pst,omitempty"`

	// A value that indicates whether the user is the purchaser of the product, or
	// is a family member with access to the product through Family Sharing.
	// Possible Values:
	//  - FAMILY_SHARED: The transaction belongs to a family member who
	// benefits from service.
	//  - PURCHASED: The transaction belongs to the purchaser.
	InAppOwnershipType InAppOwnershipType `json:"in_app_ownership_type,omitempty"`

	// An indicator of whether an auto-renewable subscription is in the introductory
	// price period.
	IsInIntroOfferPeriod string `json:"is_in_intro_offer_period,omitempty"`

	// An indication of whether a subscription is in the free trial period.
	IsTrialPeriod string `json:"is_trial_period,omitempty"`

	// An indicator that a subscription has been canceled due to an upgrade. This
	// field is only present for upgrade transactions.
	//
	// Although not documented, this field helps maintain compatibility with LatestReceiptInfo
	IsUpgraded string `json:"is_upgraded,omitempty"`

	// The reference name of a subscription offer that you configured in App Store
	// Connect. This field is present when a customer redeemed a subscription offer
	// code. For more information about offer codes, see [Set Up Offer Codes](https://help.apple.com/app-store-connect/#/dev6a098e4b1),
	// and [Implementing Offer Codes in Your App](https://developer.apple.com/documentation/storekit/in-app_purchase/subscriptions_and_offers/implementing_offer_codes_in_your_app).
	//
	// Although not documented, this field helps maintain compatibility with LatestReceiptInfo
	OfferCodeRefName string `json:"offer_code_ref_name,omitempty"`

	// The time of the original in-app purchase, in a date-time format similar to
	// ISO 8601.
	OriginalPurchaseDate string `json:"original_purchase_date,omitempty"`

	// The time of the original in-app purchase, in UNIX epoch time format, in
	// milliseconds. For an auto-renewable subscription, this value indicates the
	// date of the subscription's initial purchase. The original purchase date
	// applies to all product types and remains the same in all transactions for the
	// same product ID. This value corresponds to the original transaction’s
	// transactionDate property in StoreKit. Use this time format for processing
	// dates.
	OriginalPurchaseDateMs int64 `json:"original_purchase_date_ms,string,omitempty"`

	// The time of the original in-app purchase, in the Pacific Time zone.
	OriginalPurchaseDatePst string `json:"original_purchase_date_pst,omitempty"`

	// OriginalTransactionIdentifier is the transaction identifier of the original
	// transaction for a transaction that restores a previous transaction.
	// Otherwise, identical to the transaction identifier.
	OriginalTransactionId string `json:"original_transaction_id,omitempty"`

	// The unique identifier of the product purchased. You provide this value when
	// creating the product in App Store Connect, and it corresponds to the
	// productIdentifier property of the SKPayment object stored in the
	// transaction's payment property.
	ProductId string `json:"product_id,omitempty"`

	// The identifier of the subscription offer redeemed by the user.
	PromotionalOfferId string `json:"promotional_offer_id,omitempty"`

	// The time the App Store charged the user's account for a purchased or restored
	// product, or the time the App Store charged the user’s account for a
	// subscription purchase or renewal after a lapse, in a date-time format similar
	// to ISO 8601.
	PurchaseDate string `json:"purchase_date,omitempty"`

	// For consumable, non-consumable, and non-renewing subscription products, the
	// time the App Store charged the user's account for a purchased or restored
	// product, in the UNIX epoch time format, in milliseconds. For auto-renewable
	// subscriptions, the time the App Store charged the user’s account for a
	// subscription purchase or renewal after a lapse, in the UNIX epoch time
	// format, in milliseconds. Use this time format for processing dates.
	PurchaseDateMs int64 `json:"purchase_date_ms,string,omitempty"`

	// The time the App Store charged the user's account for a purchased or restored
	// product, or the time the App Store charged the user’s account for a
	// subscription purchase or renewal after a lapse, in the Pacific Time zone.
	PurchaseDatePst string `json:"purchase_date_pst,omitempty"`

	// The number of consumable products purchased. This value corresponds to the
	// quantity property of the SKPayment object stored in the transaction's payment
	// property. The value is usually “1” unless modified with a mutable payment.
	// The maximum value is 10.
	Quantity int `json:"quantity,string,omitempty"`

	// The identifier of the subscription group to which the subscription belongs. The
	// value for this field is identical to the subscriptionGroupIdentifier property in
	// SKProduct.
	//
	// Although not documented, this field helps maintain compatibility with LatestReceiptInfo
	SubscriptionGroupIdentifier string `json:"subscription_group_identifier,omitempty"`

	// A unique identifier for a transaction such as a purchase, restore, or
	// renewal.
	//
	// This value corresponds to the transaction’s transactionIdentifier property.
	//
	// For a transaction that restores a previous transaction, this value is
	// different from the transaction identifier of the original purchase
	// transaction. In an auto-renewable subscription receipt, a new value for the
	// transaction identifier is generated every time the subscription automatically
	// renews or is restored on a new device.
	TransactionId string `json:"transaction_id,omitempty"`

	// A unique identifier for purchase events across devices, including
	// subscription-renewal events. This value is the primary key for identifying
	// subscription purchases.
	WebOrderLineItemId string `json:"web_order_line_item_id,omitempty"`
}

InAppPurchaseReceipt is an array that contains the in-app purchase receipt fields for all in-app purchase transactions. https://developer.apple.com/documentation/appstorereceipts/responsebody/receipt/in_app

type LatestReceiptInfo

type LatestReceiptInfo struct {
	// The time Apple customer support canceled a transaction, in a date-time format
	// similar to the ISO 8601. This field is only present for refunded
	// transactions.
	CancellationDate string `json:"cancellation_date,omitempty"`

	// The time Apple customer support canceled a transaction, or the time an
	// auto-renewable subscription plan was upgraded, in UNIX epoch time format, in
	// milliseconds. This field is only present for refunded transactions. Use this
	// time format for processing dates.
	// information.
	CancellationDateMs int64 `json:"cancellation_date_ms,string,omitempty"`

	// The time Apple customer support canceled a transaction, in the Pacific Time
	// zone. This field is only present for refunded transactions.
	CancellationDatePst string `json:"cancellation_date_pst,omitempty"`

	// The reason for a refunded transaction. When a customer cancels a transaction,
	// the App Store gives them a refund and provides a value for this key. A value
	// of “1” indicates that the customer canceled their transaction due to an
	// actual or perceived issue within your app. A value of “0” indicates that the
	// transaction was canceled for another reason; for example, if the customer
	// made the purchase accidentally.
	CancellationReason string `json:"cancellation_reason,omitempty"`

	// The time a subscription expires or when it will renew, in a date-time format
	// similar to the ISO 8601.
	ExpiresDate string `json:"expires_date,omitempty"`

	// The time a subscription expires or when it will renew, in UNIX epoch time
	// format, in milliseconds. Use this time format for processing dates.
	ExpiresDateMs int64 `json:"expires_date_ms,string,omitempty"`

	// The time a subscription expires or when it will renew, in the Pacific Time
	// zone.
	ExpiresDatePst string `json:"expires_date_pst,omitempty"`

	// A value that indicates whether the user is the purchaser of the product, or
	// is a family member with access to the product through Family Sharing.
	// Possible Values:
	//  - FAMILY_SHARED: The transaction belongs to a family member who
	// benefits from service.
	//  - PURCHASED: The transaction belongs to the purchaser.
	InAppOwnershipType InAppOwnershipType `json:"in_app_ownership_type,omitempty"`

	// An indicator of whether an auto-renewable subscription is in the introductory
	// price period.
	IsInIntroOfferPeriod string `json:"is_in_intro_offer_period,omitempty"`

	// An indicator of whether a subscription is in the free trial period.
	IsTrialPeriod string `json:"is_trial_period,omitempty"`

	// An indicator that a subscription has been canceled due to an upgrade. This
	// field is only present for upgrade transactions.
	IsUpgraded string `json:"is_upgraded,omitempty"`

	// The reference name of a subscription offer that you configured in App Store
	// Connect. This field is present when a customer redeemed a subscription offer
	// code. For more information about offer codes, see [Set Up Offer Codes](https://help.apple.com/app-store-connect/#/dev6a098e4b1),
	// and [Implementing Offer Codes in Your App](https://developer.apple.com/documentation/storekit/in-app_purchase/subscriptions_and_offers/implementing_offer_codes_in_your_app).
	OfferCodeRefName string `json:"offer_code_ref_name,omitempty"`

	// The time of the original app purchase, in a date-time format similar to ISO
	// 8601.
	OriginalPurchaseDate string `json:"original_purchase_date,omitempty"`

	// The time of the original app purchase, in UNIX epoch time format, in
	// milliseconds. Use this time format for processing dates. For an
	// auto-renewable subscription, this value indicates the date of the
	// subscription's initial purchase. The original purchase date applies to all
	// product types and remains the same in all transactions for the same product
	// ID. This value corresponds to the original transaction’s transactionDate
	// property in StoreKit.
	OriginalPurchaseDateMs int64 `json:"original_purchase_date_ms,string,omitempty"`

	// The time of the original app purchase, in the Pacific Time zone.
	OriginalPurchaseDatePst string `json:"original_purchase_date_pst,omitempty"`

	// The transaction identifier of the original purchase.
	OriginalTransactionId string `json:"original_transaction_id,omitempty"`

	// The unique identifier of the product purchased. You provide this value when
	// creating the product in App Store Connect, and it corresponds to the
	// productIdentifier property of the SKPayment object stored in the transaction's
	// payment property.
	ProductId string `json:"product_id,omitempty"`

	// The identifier of the subscription offer redeemed by the user.
	PromotionalOfferId string `json:"promotional_offer_id,omitempty"`

	// The time the App Store charged the user's account for a purchased or restored
	// product, or the time the App Store charged the user’s account for a subscription
	// purchase or renewal after a lapse, in a date-time format similar to ISO 8601.
	PurchaseDate string `json:"purchase_date,omitempty"`

	// For consumable, non-consumable, and non-renewing subscription products, the time
	// the App Store charged the user's account for a purchased or restored product, in
	// the UNIX epoch time format, in milliseconds. For auto-renewable subscriptions, the
	// time the App Store charged the user’s account for a subscription purchase or
	// renewal after a lapse, in the UNIX epoch time format, in milliseconds. Use this
	// time format for processing dates.
	PurchaseDateMs int64 `json:"purchase_date_ms,string,omitempty"`

	// The time the App Store charged the user's account for a purchased or restored
	// product, or the time the App Store charged the user’s account for a subscription
	// purchase or renewal after a lapse, in the Pacific Time zone.
	PurchaseDatePst string `json:"purchase_date_pst,omitempty"`

	// The number of consumable products purchased. This value corresponds to the
	// quantity property of the SKPayment object stored in the transaction's payment
	// property. The value is usually “1” unless modified with a mutable payment. The
	// maximum value is 10.
	Quantity int `json:"quantity,string,omitempty"`

	// The identifier of the subscription group to which the subscription belongs. The
	// value for this field is identical to the subscriptionGroupIdentifier property in
	// SKProduct.
	SubscriptionGroupIdentifier string `json:"subscription_group_identifier,omitempty"`

	// A unique identifier for a transaction such as a purchase, restore, or renewal.
	TransactionId string `json:"transaction_id,omitempty"`

	// A unique identifier for purchase events across devices, including
	// subscription-renewal events. This value is the primary key for identifying
	// subscription purchases.
	WebOrderLineItemId string `json:"web_order_line_item_id,omitempty"`
}

LatestReceiptInfo is an array that contains all in-app purchase transactions. https://developer.apple.com/documentation/appstorereceipts/responsebody/latest_receipt_info

type Notification

type Notification struct {
	// An identifier that App Store Connect generates and the App Store uses to
	// uniquely identify the auto-renewable subscription that the user’s
	// subscription renews. Treat this value as a 64-bit integer.
	AutoRenewAdamId string `json:"auto_renew_adam_id,omitempty"`

	// The product identifier of the auto-renewable subscription that the user’s
	// subscription renews.
	AutoRenewProductId string `json:"auto_renew_product_id,omitempty"`

	// The current renewal status for an auto-renewable subscription product. Note
	// that these values are different from those of the auto_renew_status in the
	// receipt.
	// Possible values: true, false
	AutoRenewStatus string `json:"auto_renew_status,omitempty"`

	// The time at which the user turned on or off the renewal status for an
	// auto-renewable subscription, in a date-time format similar to the ISO 8601
	// standard.
	AutoRenewStatusChangeDate string `json:"auto_renew_status_change_date,omitempty"`

	// The time at which the user turned on or off the renewal status for an
	// auto-renewable subscription, in UNIX epoch time format, in milliseconds. Use
	// this time format to process dates.
	AutoRenewStatusChangeDateMs int64 `json:"auto_renew_status_change_date_ms,string,omitempty"`

	// The time at which the user turned on or off the renewal status for an
	// auto-renewable subscription, in the Pacific time zone.
	AutoRenewStatusChangeDatePst string `json:"auto_renew_status_change_date_pst,omitempty"`

	// The environment for which App Store generated the receipt.
	// Possible values: Sandbox, PROD
	Environment string `json:"environment,omitempty"`

	// The reason a subscription expired. This field is only present for an expired
	// auto-renewable subscription. See expiration_intent for more information.
	ExpirationIntent ExpirationIntent `json:"expiration_intent,omitempty"`

	// The subscription event that triggered the notification.
	NotificationType NotificationType `json:"notification_type,omitempty"`

	// The same value as the shared secret you submit in the password field of the
	// requestBody when validating receipts.
	Password string `json:"password,omitempty"`

	// An object that contains information about the most-recent, in-app purchase
	// transactions for the app.
	UnifiedReceipt UnifiedReceipt `json:"unified_receipt,omitempty"`

	// A string that contains the app bundle ID.
	Bid string `json:"bid,omitempty"`

	// A string that contains the app bundle version.
	Bvrs string `json:"bvrs,omitempty"`
}

Notification is the JSON data sent in the server notification from the App Store.

Use the information in the response body to react quickly to changes in your users’ subscription states. The fields available in any one notification sent to your server are dependent on the notification_type, which indicates the event that triggered the notification.

https://developer.apple.com/documentation/appstoreservernotifications/responsebody

type NotificationType

type NotificationType string

NotificationType is the type that describes the in-app purchase event for which the App Store sent the notification.

You receive and can react to server notifications in real time for the subscription and refund events that these notification type values describe. The notification_type appears in the responseBody.

https://developer.apple.com/documentation/appstoreservernotifications/notification_type

const (
	// Indicates that either Apple customer support canceled the subscription or the
	// user upgraded their subscription. The cancellation_date key contains the date
	// and time of the change.
	NotificationTypeCancel NotificationType = "CANCEL"

	// Indicates that the customer made a change in their subscription plan that
	// takes effect at the next renewal. The currently active plan isn’t affected.
	NotificationTypeDidChangeRenewalPref NotificationType = "DID_CHANGE_RENEWAL_PREF"

	// Indicates a change in the subscription renewal status. In the JSON response,
	// check auto_renew_status_change_date_ms to know the date and time of the last
	// status update. Check auto_renew_status to know the current renewal status.
	NotificationTypeDidChangeRenewalStatus NotificationType = "DID_CHANGE_RENEWAL_STATUS"

	// Indicates a subscription that failed to renew due to a billing issue. Check
	// is_in_billing_retry_period to know the current retry status of the
	// subscription. Check grace_period_expires_date to know the new service
	// expiration date if the subscription is in a billing grace period.
	NotificationTypeDidFailToRenew NotificationType = "DID_FAIL_TO_RENEW"

	// Indicates a successful automatic renewal of an expired subscription that
	// failed to renew in the past. Check expires_date to determine the next renewal
	// date and time.
	NotificationTypeDidRecover NotificationType = "DID_RECOVER"

	// Indicates that a customer’s subscription has successfully auto-renewed for a
	// new transaction period.
	NotificationTypeDidRenew NotificationType = "DID_RENEW"

	// Occurs at the user’s initial purchase of the subscription. Store
	// latest_receipt on your server as a token to verify the user’s subscription
	// status at any time by validating it with the App Store.
	NotificationTypeInitialBuy NotificationType = "INITIAL_BUY"

	// Indicates the customer renewed a subscription interactively, either by using
	// your app’s interface, or on the App Store in the account’s Subscriptions
	// settings. Make service available immediately.
	NotificationTypeInteractiveRenewal NotificationType = "INTERACTIVE_RENEWAL"

	// Indicates that App Store has started asking the customer to consent to your
	// app’s subscription price increase. In the
	// unified_receipt.Pending_renewal_info object, the price_consent_status value
	// is 0, indicating that App Store is asking for the customer’s consent, and
	// hasn't received it. The subscription won’t auto-renew unless the user agrees
	// to the new price. When the customer agrees to the price increase, the system
	// sets price_consent_status to 1. Check the receipt using verifyReceipt to view
	// the updated price-consent status.
	NotificationTypePriceIncreaseConsent NotificationType = "PRICE_INCREASE_CONSENT"

	// Indicates that App Store successfully refunded a transaction. The
	// cancellation_date_ms contains the timestamp of the refunded transaction. The
	// original_transaction_id and product_id identify the original transaction and
	// product. The cancellation_reason contains the reason.
	NotificationTypeRefund NotificationType = "REFUND"
)

type PendingRenewalInfo

type PendingRenewalInfo struct {
	// The current renewal preference for the auto-renewable subscription. The value
	// for this key corresponds to the productIdentifier property of the product
	// that the customer’s subscription renews. This field is only present if the
	// user downgrades or crossgrades to a subscription of a different duration for
	// the subsequent subscription period.
	AutoRenewProductId string `json:"auto_renew_product_id,omitempty"`

	// The current renewal status for the auto-renewable subscription.
	AutoRenewStatus AutoRenewStatus `json:"auto_renew_status,omitempty"`

	// The reason a subscription expired. This field is only present for a receipt
	// that contains an expired auto-renewable subscription.
	ExpirationIntent ExpirationIntent `json:"expiration_intent,omitempty"`

	// The time at which the grace period for subscription renewals expires, in a
	// date-time format similar to the ISO 8601.
	GracePeriodExpiresDate string `json:"grace_period_expires_date,omitempty"`

	// The time at which the grace period for subscription renewals expires, in UNIX
	// epoch time format, in milliseconds. This key is only present for apps that
	// have Billing Grace Period enabled and when the user experiences a billing
	// error at the time of renewal. Use this time format for processing dates.
	GracePeriodExpiresDateMs int64 `json:"grace_period_expires_date_ms,string,omitempty"`

	// The time at which the grace period for subscription renewals expires, in the
	// Pacific Time zone.
	GracePeriodExpiresDatePst string `json:"grace_period_expires_date_pst,omitempty"`

	// A flag that indicates Apple is attempting to renew an expired subscription
	// automatically. This field is only present if an auto-renewable subscription
	// is in the billing retry state.
	IsInBillingRetryPeriod BillingRetryStatus `json:"is_in_billing_retry_period,omitempty"`

	// The reference name of a subscription offer that you configured in App Store
	// Connect. This field is present when a customer redeemed a subscription offer
	// code. For more information about offer codes, see [Set Up Offer Codes](https://help.apple.com/app-store-connect/#/dev6a098e4b1),
	// and [Implementing Offer Codes in Your App](https://developer.apple.com/documentation/storekit/in-app_purchase/subscriptions_and_offers/implementing_offer_codes_in_your_app).
	OfferCodeRefName string `json:"offer_code_ref_name,omitempty"`

	// The transaction identifier of the original purchase.
	OriginalTransactionId string `json:"original_transaction_id,omitempty"`

	// The price consent status for a subscription price increase. This field is
	// only present if the customer was notified of the price increase. The default
	// value is "0" and changes to "1" if the customer consents.
	PriceConsentStatus PriceConsentStatus `json:"price_consent_status,omitempty"`

	// The unique identifier of the product purchased. You provide this value when
	// creating the product in App Store Connect, and it corresponds to the
	// productIdentifier property of the SKPayment object stored in the
	// transaction's payment property.
	ProductId string `json:"product_id,omitempty"`
}

PendingRenewalInfo is an array of elements that refers to auto-renewable subscription renewals that are open or failed in the past. https://developer.apple.com/documentation/appstorereceipts/responsebody/pending_renewal_info

type PriceConsentStatus

type PriceConsentStatus string
const (
	// The App Store hasn't yet requested consent from the customer.
	PriceConsentStatusNotRequested PriceConsentStatus = ""

	// The App Store is asking for the customer's consent, and hasn't received it.
	PriceConsentStatusAwaitingConsent PriceConsentStatus = "0"

	// The App Store has received customer's consent.
	PriceConsentStatusConsented PriceConsentStatus = "1"
)

type Receipt

type Receipt struct {
	// See app_item_id.
	AdamId int64 `json:"adam_id,omitempty"`

	// Generated by App Store Connect and used by the App Store to uniquely identify
	// the app purchased. Apps are assigned this identifier only in production.
	// Treat this value as a 64-bit long integer.
	AppItemId int64 `json:"app_item_id,omitempty"`

	// The app’s version number. The app's version number corresponds to the value
	// of CFBundleVersion (in iOS) or CFBundleShortVersionString (in macOS) in the
	// Info.plist. In production, this value is the current version of the app on
	// the device based on the receipt_creation_date_ms. In the sandbox, the value
	// is always "1.0".
	ApplicationVersion string `json:"application_version,omitempty"`

	// The bundle identifier for the app to which the receipt belongs. You provide
	// this string on App Store Connect. This corresponds to the value of
	// CFBundleIdentifier in the Info.plist file of the app.
	BundleId string `json:"bundle_id,omitempty"`

	// A unique identifier for the app download transaction.
	DownloadId int64 `json:"download_id,omitempty"`

	// The time the receipt expires for apps purchased through the Volume Purchase
	// Program, in a date-time format similar to the ISO 8601.
	ExpirationDate string `json:"expiration_date,omitempty"`

	// The time the receipt expires for apps purchased through the Volume Purchase
	// Program, in UNIX epoch time format, in milliseconds. If this key is not
	// present for apps purchased through the Volume Purchase Program, the receipt
	// does not expire. Use this time format for processing dates.
	ExpirationDateMs int64 `json:"expiration_date_ms,string,omitempty"`

	// The time the receipt expires for apps purchased through the Volume Purchase
	// Program, in the Pacific Time zone.
	ExpirationDatePst string `json:"expiration_date_pst,omitempty"`

	// An array that contains the in-app purchase receipt fields for all in-app
	// purchase transactions.
	InApp []InAppPurchaseReceipt `json:"in_app,omitempty"`

	// The version of the app that the user originally purchased. This value does
	// not change, and corresponds to the value of CFBundleVersion (in iOS) or
	// CFBundleShortVersionString (in macOS) in the Info.plist file of the original
	// purchase. In the sandbox environment, the value is always "1.0".
	OriginalApplicationVersion string `json:"original_application_version,omitempty"`

	// The time of the original app purchase, in a date-time format similar to ISO
	// 8601.
	OriginalPurchaseDate string `json:"original_purchase_date,omitempty"`

	// The time of the original app purchase, in UNIX epoch time format, in
	// milliseconds. Use this time format for processing dates.
	OriginalPurchaseDateMs int64 `json:"original_purchase_date_ms,string,omitempty"`

	// The time of the original app purchase, in the Pacific Time zone.
	OriginalPurchaseDatePst string `json:"original_purchase_date_pst,omitempty"`

	// The time the user ordered the app available for pre-order, in a date-time
	// format similar to ISO 8601.
	PreorderDate string `json:"preorder_date,omitempty"`

	// The time the user ordered the app available for pre-order, in UNIX epoch time
	// format, in milliseconds. This field is only present if the user pre-orders
	// the app. Use this time format for processing dates.
	PreorderDateMs int64 `json:"preorder_date_ms,string,omitempty"`

	// The time the user ordered the app available for pre-order, in the Pacific
	// Time zone.
	PreorderDatePst string `json:"preorder_date_pst,omitempty"`

	// The time the App Store generated the receipt, in a date-time format similar
	// to ISO 8601.
	ReceiptCreationDate string `json:"receipt_creation_date,omitempty"`

	// The time the App Store generated the receipt, in UNIX epoch time format, in
	// milliseconds. Use this time format for processing dates. This value does not
	// change.
	ReceiptCreationDateMs int64 `json:"receipt_creation_date_ms,string,omitempty"`

	// The time the App Store generated the receipt, in the Pacific Time zone.
	ReceiptCreationDatePst string `json:"receipt_creation_date_pst,omitempty"`

	// The type of receipt generated. The value corresponds to the environment in
	// which the app or VPP purchase was made. Possible values: Production,
	// ProductionVPP, ProductionSandbox, ProductionVPPSandbox
	ReceiptType string `json:"receipt_type,omitempty"`

	// The time the request to the verifyReceipt endpoint was processed and the
	// response was generated, in a date-time format similar to ISO 8601.
	RequestDate string `json:"request_date,omitempty"`

	// The time the request to the verifyReceipt endpoint was processed and the
	// response was generated, in UNIX epoch time format, in milliseconds. Use this
	// time format for processing dates.
	RequestDateMs int64 `json:"request_date_ms,string,omitempty"`

	// The time the request to the verifyReceipt endpoint was processed and the
	// response was generated, in the Pacific Time zone.
	RequestDatePst string `json:"request_date_pst,omitempty"`

	// An arbitrary number that identifies a revision of your app. In the sandbox,
	// this key's value is “0”. Use this value to identify the version of the app
	// that the customer bought.
	VersionExternalIdentifier int64 `json:"version_external_identifier,omitempty"`
}

Receipt is the decoded version of the encoded receipt data sent with the request to the App Store. https://developer.apple.com/documentation/appstorereceipts/responsebody/receipt

type ReceiptRequest

type ReceiptRequest struct {
	// ReceiptData contains the base64 encoded receipt data. Required.
	ReceiptData []byte `json:"receipt-data"`

	// Password is your app’s shared secret (a hexadecimal string). Required.
	//
	// Use this field only for receipts that contain auto-renewable subscriptions.
	Password string `json:"password"`

	// ExcludeOldTransactions is only used for app receipts that contain
	// auto-renewable or non-renewing subscriptions.
	//
	// Set this value to true for the response to include only the latest renewal transaction
	// for any subscriptions.
	ExcludeOldTransactions bool `json:"exclude-old-transactions,omitempty"`
}

ReceiptRequest is the JSON you submit with the request to the App Store.

To receive a decoded receipt for validation, send a request with the encoded receipt data to the App Store. For auto-renewable subscriptions, include the app password and optionally an exclusion flag. Send this JSON data using the HTTP POST request method.

type ReceiptResponse

type ReceiptResponse struct {
	// The environment for which the receipt was generated.
	// Possible values: Sandbox, Production
	Environment string `json:"environment,omitempty"`

	// IsRetryable is an indicator that an error occurred during the request. A
	// value of 1 indicates a temporary issue; retry validation for this receipt at
	// a later time. A value of 0 indicates an unresolvable issue; do not retry
	// validation for this receipt. Only applicable to status codes 21100-21199.
	IsRetryable bool `json:"is-retryable,omitempty"`

	// The latest Base64 encoded app receipt. Only returned for receipts that
	// contain auto-renewable subscriptions.
	LatestReceipt []byte `json:"latest_receipt,omitempty"`

	// LatestReceiptInfo is an array that contains all in-app purchase transactions.
	// This excludes transactions for consumable products that have been marked as
	// finished by your app. Only returned for receipts that contain auto-renewable
	// subscriptions.
	LatestReceiptInfo []LatestReceiptInfo `json:"latest_receipt_info,omitempty"`

	// In the JSON file, an array where each element contains the pending renewal
	// information for each auto-renewable subscription identified by the
	// product_id. Only returned for app receipts that contain auto-renewable
	// subscriptions.
	PendingRenewalInfo []PendingRenewalInfo `json:"pending_renewal_info,omitempty"`

	// A JSON representation of the receipt that was sent for verification.
	Receipt Receipt `json:"receipt,omitempty"`

	// Either 0 if the receipt is valid, or a status code if there is an error. The
	// status code reflects the status of the app receipt as a whole.
	Status ReceiptResponseStatus `json:"status,omitempty"`
}

ReceiptResponse is the JSON data returned in the response from the App Store. https://developer.apple.com/documentation/appstorereceipts/responsebody

type ReceiptResponseStatus

type ReceiptResponseStatus int

ReceiptResponseStatus is the status of the app receipt. The value for status is 0 if the receipt is valid, or a status code if there is an error. The status code reflects the status of the app receipt as a whole. For example, if you send a valid app receipt that contains an expired subscription, the response is 0 because the receipt is valid. Status codes 21100-21199 are various internal data access errors. https://developer.apple.com/documentation/appstorereceipts/status

const (
	// Undocumented but occurs
	ReceiptResponseStatusUnknown ReceiptResponseStatus = -1

	// Receipt is valid.
	ReceiptResponseStatusOK ReceiptResponseStatus = 0

	// The request to the App Store was not made using the HTTP POST request method.
	ReceiptResponseStatusAppStoreCannotRead ReceiptResponseStatus = 21000

	// This status code is no longer sent by the App Store.
	ReceiptResponseStatusNoLongerSent ReceiptResponseStatus = 21001

	// The data in the receipt-data property was malformed or the service
	// experienced a temporary issue. Try again.
	ReceiptResponseStatusDataMalformed ReceiptResponseStatus = 21002

	// The receipt could not be authenticated.
	ReceiptResponseStatusNotAuthenticated ReceiptResponseStatus = 21003

	// The shared secret you provided does not match the shared secret on file for
	// your account.
	ReceiptResponseStatusSharedSecretDoesNotMatch ReceiptResponseStatus = 21004

	// The receipt server was temporarily unable to provide the receipt. Try again.
	ReceiptResponseStatusReceiptServerUnavailable ReceiptResponseStatus = 21005

	// This receipt is valid but the subscription has expired. When this status code
	// is returned to your server, the receipt data is also decoded and returned as
	// part of the response. Only returned for iOS 6-style transaction receipts for
	// auto-renewable subscriptions.
	ReceiptResponseStatusValidButSubscriptionExpired ReceiptResponseStatus = 21006

	// This receipt is from the test environment, but it was sent to the production
	// environment for verification.
	ReceiptResponseStatusSandboxReceiptSentToProduction ReceiptResponseStatus = 21007

	// This receipt is from the production environment, but it was sent to the test
	// environment for verification.
	ReceiptResponseStatusProductionReceiptSentToSandbox ReceiptResponseStatus = 21008

	// Internal data access error. Try again later.
	ReceiptResponseStatusBadAccess ReceiptResponseStatus = 21009

	// The user account cannot be found or has been deleted.
	ReceiptResponseStatusCouldNotBeAuthorized ReceiptResponseStatus = 21010
)

type UnifiedReceipt

type UnifiedReceipt struct {
	// The environment for which App Store generated the receipt.
	// Possible values: Sandbox, Production
	Environment string `json:"environment,omitempty"`

	// The latest Base64-encoded app receipt.
	LatestReceipt []byte `json:"latest_receipt,omitempty"`

	// An array that contains the latest 100 in-app purchase transactions of the
	// decoded value in latest_receipt. This array excludes transactions for
	// consumable products your app has marked as finished. The contents of this
	// array are identical to those in LatestReceiptInfo in the
	// verifyReceipt endpoint response for receipt validation.
	LatestReceiptInfo []LatestReceiptInfo `json:"latest_receipt_info,omitempty"`

	// An array where each element contains the pending renewal information for each
	// auto-renewable subscription identified in product_id. The contents of this
	// array are identical to those in PendingRenewalInfo in the
	// verifyReceipt endpoint response for receipt validation.
	PendingRenewalInfo []PendingRenewalInfo `json:"pending_renewal_info,omitempty"`

	// The status code, where 0 indicates that the notification is valid.
	Status int `json:"status,omitempty"`
}

UnifiedReceipt is an object that contains information about the most-recent, in-app purchase transactions for the app.

https://developer.apple.com/documentation/appstoreservernotifications/unified_receipt

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL