syntax = "proto3";
import "google/protobuf/timestamp.proto";

package code.justin.tv.revenue.subscriptions;
option go_package = "substwirp";

service Subscriptions {
    // Subscriptions
    // =============
    // FulfillSubscription creates/upgrades subscription for user to product.
    rpc FulfillSubscription (FulfillSubscriptionRequest) returns (FulfillSubscriptionResponse);

    // CreateSubscription creates a new subscription without the extra steps that FulfillSubscription
    // does, such as creating chat notification tokens. CreateSubscription is called by
    // FulfillSubscription as one of its steps.
    // The following steps will be executed during CreateSubscription:
    //   Lock using redis
    //   CanSubscribe?
    //   Create subscription entitlement
    //   Send entitlementSNS
    //   Unlock
    rpc CreateSubscription (CreateSubscriptionRequest) returns (CreateSubscriptionResponse);

    // CancelSubscription cancels user's subscription to product.
    rpc CancelSubscription (CancelSubscriptionRequest) returns (CancelSubscriptionResponse);

    // UpdateSubscription updates user's subscription to product.
    // The following steps will be executed during UpdateSubscription:
    //   Update subscription entitlement
    //   Send entitlementSNS
    rpc UpdateSubscription (UpdateSubscriptionRequest) returns (UpdateSubscriptionResponse);

    // CanSubscribe returns whether user can subscribe to product for a given platform.
    rpc CanSubscribe (CanSubscribeRequest) returns (CanSubscribeResponse);

    // ListUserSubscriptions returns a paginated list of user's active subscriptions.
    rpc ListUserSubscriptions (ListUserSubscriptionsRequest) returns (ListUserSubscriptionsResponse);

    // ListUserExpiredSubscriptions returns a list of user's expired subscriptions sorted by most recently expired. An expired sub refers to the most recent ticket - that is not active.
    rpc ListUserExpiredSubscriptions (ListUserExpiredSubscriptionsRequest) returns (ListUserExpiredSubscriptionsResponse);

    // GetUserChannelSubscriptionWithPaymentsData returns the highest max tier active subscription with payments data for an owner channel pair.
    rpc GetUserChannelSubscriptionWithPaymentsData (GetUserChannelSubscriptionWithPaymentsDataRequest) returns (GetUserChannelSubscriptionWithPaymentsDataResponse);

    // GetUserSubscriptions returns the list of all a user's active subscriptions without payment data. Will return highest tier sub per channel.
    rpc GetUserSubscriptions (GetUserSubscriptionsRequest) returns (GetUserSubscriptionsResponse);

    // GetUserChannelSubscription returns the highest max tier active subscription without payments data for a user channel pair.
    // This should be used when you need to know if a user channel pair is subscribed.
    rpc GetUserChannelSubscription (GetUserChannelSubscriptionRequest) returns (GetUserChannelSubscriptionResponse);

    // GetUserSubscriptions returns the list of a user's active subscriptions without payments data given a list of product_ids.
    rpc GetUserProductSubscriptions (GetUserProductSubscriptionsRequest) returns (GetUserProductSubscriptionsResponse);

    // GetUserProductSubscriptionWithPaymentsData returns the list of a user's active subscriptions with payments data given a list of product_ids
    rpc GetUserProductSubscriptionsWithPaymentsData (GetUserProductSubscriptionsWithPaymentsDataRequest) returns (GetUserProductSubscriptionsWithPaymentsDataResponse);

    // GetChannelSubscriptions returns a paginated list of active subscribers to a channel.
    rpc GetChannelSubscriptions (GetChannelSubscriptionsRequest) returns (GetChannelSubscriptionsResponse);

    // GetSubscriptionByID returns Subscriptions given an Owner, Product, and Origin or a TicketID.
    // Prefer to use Owner, Product, Origin if possible as TicketID will not be supported in the future.
    rpc GetSubscriptionByID (GetSubscriptionByIDRequest) returns (GetSubscriptionByIDResponse);

    // GetHistoricalUserTickets returns all Subscriptions (tickets) a user has, active or inactive.
    // Created for Payments to move Mulan off of SiteDB. DO NOT USE.
    rpc GetHistoricalUserTickets (GetHistoricalUserTicketsRequest) returns (GetHistoricalUserTicketsResponse);

    // GetChannelSubscriptionsAfterTime returns a paginated list of subscribers after a given time
    rpc GetChannelSubscriptionsAfterTime (GetChannelSubscriptionsAfterTimeRequest) returns (GetChannelSubscriptionsAfterTimeResponse);

    // Subscriber Badges
    // =====
    // TakedownBadges takes down one or more custom subscriber badges belonging to a broadcaster
    rpc TakedownBadges (TakedownBadgesRequest) returns (TakedownBadgesResponse);

    //TakedownAllBadges takes down all badges belonging to a broadcaster
    rpc TakedownAllBadges (TakedownAllBadgesRequest) returns (TakedownAllBadgesResponse);

    // GetSubscriberBadge returns the correctly subscription tenure based badge for a channel and user pair
    rpc GetSubscriberBadge (GetSubscriberBadgeRequest) returns (GetSubscriberBadgeResponse);

    // InvalidateBadgeCache invalidates the cached badges for a set of users
    rpc InvalidateBadgeCache (InvalidateBadgeCacheRequest) returns (InvalidateBadgeCacheResponse);

    // GetChannelBadge returns the badges given their channel id
    rpc GetChannelBadge (GetChannelBadgeRequest) returns (GetChannelBadgeResponse);

    // DeleteChannelBadge deletes a specific badge given their channel and badge id
    rpc DeleteChannelBadge (DeleteChannelBadgeRequest) returns (DeleteChannelBadgeResponse);

    // CreateChannelBadgeUploadConfig returns the badge image and upload id and url
    rpc CreateChannelBadgeUploadConfig (CreateChannelBadgeUploadConfigRequest) returns (CreateChannelBadgeUploadConfigResponse);

    // CreateChannelBadge returns the badge image and upload id and url
    rpc CreateChannelBadge (CreateChannelBadgeRequest) returns (CreateChannelBadgeResponse);

    rpc GetBadgeProgress (GetBadgeProgressRequest) returns (GetBadgeProgressResponse);

    rpc CreateBadgeFlair (CreateBadgeFlairRequest) returns (CreateBadgeFlairResponse);

    rpc GetBadgeFlair (GetBadgeFlairRequest) returns (GetBadgeFlairResponse);

    // GetFounderBadgeAvailability returns available slots of founder badges given the channel id
    rpc GetFounderBadgeAvailability (GetFounderBadgeAvailabilityRequest) returns (GetFounderBadgeAvailabilityResponse);

    // IsFounder returns whether the user has a founder badge entitlement for the given channel id
    rpc IsFounder (IsFounderRequest) returns (IsFounderResponse);

    // Score
    // =====
    // SetScore sets the subscription high score given a channel and current score.
    rpc SetScore (SetScoreRequest) returns (SetScoreResponse);

    //CalculateSubscriberScore returns the subscriber score given their channel id.
    rpc CalculateSubscriberCount (CalculateSubscriberCountRequest) returns (CalculateSubscriberCountResponse);

    // ChatNotification
    // =====
    // CreateChatNotificationToken creates a chat notification token
    rpc CreateChatNotificationToken (CreateChatNotificationTokenRequest) returns (CreateChatNotificationTokenResponse);

    // UseChatNotificationToken posts a chat notification token, marks it as used given a token_id.
    rpc UseChatNotificationToken (UseChatNotificationTokenRequest) returns (UseChatNotificationTokenResponse);

    // GetAvailableTokens gets all the tokens that are available that belong to a user and channel.
    rpc GetUserChannelChatNotificationToken (GetUserChannelChatNotificationTokenRequest) returns (GetUserChannelChatNotificationTokenResponse);

    // GetAllUsedChatNotificationTokens returns a historical list of a user's used chat notification tokens sorted by createdAt date to a channel.
    rpc GetAllUsedChatNotificationTokens (GetAllUsedChatNotificationTokensRequest) returns (GetAllUsedChatNotificationTokensResponse);

    rpc AllowReplayForLastUsedChatNotificationToken (AllowReplayForLastUsedChatNotificationTokenRequest) returns (AllowReplayForLastUsedChatNotificationTokenResponse);

    // UserSettings
    // ============
    // GetUserSettings gets the user subscription settings.
    rpc GetUserSettings (GetUserSettingsRequest) returns (GetUserSettingsResponse);

    // SetUserSettings sets the user subscription settings.
    rpc SetUserSettings (SetUserSettingsRequest) returns (SetUserSettingsResponse);

    // GetCreatorBadgeFlairSetting gets the user setting representing if the user, as an affiliate or partner, has
    // enabled default/custom badge flair or disabled the feature ("none").
    rpc GetCreatorBadgeFlairSetting (GetCreatorBadgeFlairSettingRequest) returns (GetCreatorBadgeFlairSettingResponse);

    // SetCreatorBadgeFlairSetting writes the user setting representing if the user, as an affiliate or partner,
    // has enabled the badge flair feature.
    rpc SetCreatorBadgeFlairSetting (SetCreatorBadgeFlairSettingRequest) returns (SetCreatorBadgeFlairSettingResponse);

    // External Product
    // ================
    // GetExternalProductTemplateSKU returns a template SKU which can be used to fetch external product's attributes
    // from third party subscription providers like Apple, Google.
    rpc GetExternalProductTemplateSKU (GetExternalProductTemplateSKURequest) returns (GetExternalProductTemplateSKUResponse);

    // GetExternalProductPurchasableSKU does subscription eligibility checks and returns SKU for purchase from
    // external subscriptions providers (e.g, Apple, Google)
    rpc GetExternalProductPurchasableSKU (GetExternalProductPurchasableSKURequest) returns (GetExternalProductPurchasableSKUResponse);

    // Paid Upgrades
    // =======
    // GetPaidUpgrades returns a list of paid upgrades from a list of subKeys.
    rpc GetPaidUpgrades (GetPaidUpgradesRequest) returns (GetPaidUpgradesResponse);

    // FulfillPaidUpgrade creates a Subscription and a Paid Upgrade.
    rpc FulfillPaidUpgrade (FulfillPaidUpgradeRequest) returns (FulfillPaidUpgradeResponse);

    // CreatePaidUpgrades creates a paid upgrade from a subKey.
    rpc CreatePaidUpgrade (CreatePaidUpgradeRequest) returns (CreatePaidUpgradeResponse);

    // CancelPaidUpgrade cancels the paid upgrade from a subKey.
    rpc CancelPaidUpgrade (CancelPaidUpgradeRequest) returns (CancelPaidUpgradeResponse);

    // Gifts
    // ======
    // InsertGift creates a new gift record in the gifts table without checking product, eligibilty or sending notifications.
    rpc InsertGift (InsertGiftRequest) returns (InsertGiftResponse);

    // CancelGift cancels a subscription gift.
    rpc CancelGift (CancelGiftRequest) returns (CancelGiftResponse);

    // GetGifts determines if there are gifts associated with supplied POODs.
    rpc GetGifts (GetGiftsRequest) returns (GetGiftsResponse);

    // CanGift determines if a sender can gift a subscription to a recipient.
    rpc CanGift (CanGiftRequest) returns (CanGiftResponse);

    // GetGiftPromotion returns the active gift promotion for subscription products.
    rpc GetGiftPromotion (GetGiftPromotionRequest) returns (GetGiftPromotionResponse);

    // GetPaidUpgradePromotion returns the active gift promotion for a user's subscription products
    rpc GetPaidUpgradePromotion (GetPaidUpgradePromotionRequest) returns (GetPaidUpgradePromotionResponse);

    // GetPromotions returns active Promotions for the given ticket products and user (if the user is provided)
    rpc GetPromotions (GetPromotionsRequest) returns (GetPromotionsResponse);

    // CanSenderGift determines if a sender is allowed to gift to recipients
    rpc CanSenderGift (CanSenderGiftRequest) returns (CanSenderGiftResponse);

    // CanGiftRecipient determines if a recipient is allowed to receive a gift from a particular sender depending on the type of gift.
    rpc CanGiftRecipient (CanGiftRecipientRequest) returns (CanGiftRecipientResponse);

    // FulfillGifts asynchronously entitles gift subscription for a given request.
    rpc FulfillGifts (FulfillGiftsRequest) returns (FulfillGiftsResponse);

    // SendGiftChatNotification sends a chat notification indicating the recipient has been gifted a sub.
    rpc SendGiftChatNotification (SendGiftChatNotificationRequest) returns (SendGiftChatNotificationResponse);

    // SendMMGChatNotification sends a chat notification indicating the sender has gifted a sub to a recipient.
    rpc SendMMGChatNotification (SendMMGChatNotificationRequest) returns (SendMMGChatNotificationResponse);

    // SendMMGStartChatNotification sends a chat notification that indicates the start of a mass mystery gift.
    rpc SendMMGStartChatNotification (SendMMGStartChatNotificationRequest) returns (SendMMGStartChatNotificationResponse);

    // SendPayForwardChatNotification sends a chat notification that indicates a user's gift subscription was "paid forward" to another user.
    rpc SendPayForwardChatNotification (SendPayForwardChatNotificationRequest) returns (SendPayForwardChatNotificationResponse);

    // GetRelatedChannels gets related channels to a product.
    rpc GetRelatedChannels (GetRelatedChannelsRequest) returns (GetRelatedChannelsResponse);

    // GetGiftOffers gets all available gift offers for a particular product depending on the platform and gift type.
    rpc GetGiftOffers (GetGiftOffersRequest) returns (GetGiftOffersResponse);

    // GetCommunityGiftBundles returns the display metadata that backs the `subscriptionProducts.gifting.community` GQL resolver
    // It contains info about the number of gifts and the URLs to image assets for these bundles.
    rpc GetCommunityGiftBundles (GetCommunityGiftBundlesRequest) returns (GetCommunityGiftBundlesResponse);

    // GetGiftCount gets the current count of gifts given by the user in the channel
    rpc GetGiftsSentCount (GetGiftsSentCountRequest) returns (GetGiftsSentCountResponse);

    // GrantGifterBadge will entitle the proper gifter badge to a user in a given channel with a given expiration time.
    rpc GrantGifterBadge (GrantGifterBadgeRequest) returns (GrantGifterBadgeResponse);

    // GetLatestGiftEndPerChannel will return a mapping of channelIDs to the date that their last active gift in each channel will end.
    rpc GetLatestGiftEndPerChannel (GetLatestGiftEndPerChannelRequest) returns (GetLatestGiftEndPerChannelResponse);

    // ModerateUserFromGifterLeaderboard should be called when any factor leading to moderation changes. This will recheck all reasons a
    // user might be moderated from a leaderboard and will set the moderation status appropriately.
    rpc ModerateUserFromGifterLeaderboard (ModerateUserFromGifterLeaderboardRequest) returns (ModerateUserFromGifterLeaderboardResponse);

    // UpdateLeaderboardBadges will check the current state of badges against the current leaderboard and grant or revoke badges accordingly.
    rpc UpdateLeaderboardBadges (UpdateLeaderboardBadgesRequest) returns (UpdateLeaderboardBadgesResponse);

    // Emoticons
    // ======
    // GetEmotePrefix gets the emote prefix for a given channel ID.
    rpc GetEmotePrefix (GetEmotePrefixRequest) returns (GetEmotePrefixResponse);

    // CreateEmoticon creates a subscription emoticon.
    rpc CreateEmoticon (CreateEmoticonRequest) returns (CreateEmoticonReponse);

    // DeleteEmoticon deletes a subscription emote
    rpc DeleteEmoticon (DeleteEmoticonRequest) returns (DeleteEmoticonResponse);

    rpc GetAllEmoticonsByProductIDs (GetAllEmoticonsByProductIDsRequest) returns (GetAllEmoticonsByProductIDsResponse);

    // Get standing status of a user. Can be "in good standing" or "not in good standing".
    // Partners are considered to be in “good standing” if they have not had a conduct infraction within the last 90 days.
    rpc GetPartnerStanding (GetPartnerStandingRequest) returns (GetPartnerStandingResponse);

    rpc GetChannelEmoteLimits (GetChannelEmoteLimitsRequest) returns (GetChannelEmoteLimitsResponse);

    // Pending Emoticons
    // ======
    // GetPendingEmoticonByID returns a particular pending emoticon for use in the aegis GQL loader
    rpc GetPendingEmoticonsByIDs (GetPendingEmoticonsByIDsRequest) returns (GetPendingEmoticonsByIDsResponse);

    // GetPendingEmoticons returns an array of pending emoticons for the moderation team's approval flow.
    rpc GetPendingEmoticons (GetPendingEmoticonsRequest) returns (GetPendingEmoticonsResponse);

    // ReviewPendingEmoticons accepts an array of approve or reject actions and either approves or rejects each emoticon
    rpc ReviewPendingEmoticons (ReviewPendingEmoticonsRequest) returns (ReviewPendingEmoticonsResponse);

    // Products
    // =========
    // GetProductsByIDs returns a list of products given a list of product ids.
    // Max size of 100 ids.
    rpc GetProductsByIDs (GetProductsByIDsRequest) returns (GetProductsByIDsResponse);

    // GetProductsByNames returns a list of products given a list of product short names with length x, 0 < x <=100.
    rpc GetProductsByNames (GetProductsByNamesRequest) returns (GetProductsByNamesResponse);

    // GetChannelProducts accepts a channelID and returns a list of active products owned by the channel.
    // If the channel belongs to a teamsub, it will return the teamsub product.
    rpc GetChannelProducts (GetChannelProductsRequest) returns (GetChannelProductsResponse);

    // UpdateProduct updates the fields of the given product.
    rpc UpdateProduct (UpdateProductRequest) returns (UpdateProductResponse);

    // Updates all products for a given channel.
    rpc UpdateChannelProducts (UpdateChannelProductsRequest) returns (UpdateChannelProductsResponse);

    // EmailSubscribers publishes to a queue to initiate the email process.
    rpc EmailSubscribers (EmailSubscribersRequest) returns (EmailSubscribersResponse);

    rpc EmailGlobalEmote (EmailGlobalEmoteRequest) returns (EmailGlobalEmoteResponse);

    rpc EmailPendingPrefixApproval (EmailPendingPrefixApprovalRequest) returns (EmailPendingPrefixApprovalResponse);

    // Tickets
    // ========

    //RedeemSubscription redeems a user subscription from a channel to another channel
    rpc RedeemSubscription (RedeemSubscriptionRequest) returns (RedeemSubscriptionResponse);

    //GetUserChannelRedemption returns the RedeemedSubscription if any
    rpc GetRedeemedSubscription (RedeemedSubscriptionRequest) returns (RedeemedSubscriptionResponse);

    //GetTicketsByOriginIDs returns the tickets/subscriptions given origin_ids
    rpc GetTicketsByOriginIDs (GetTicketsByOriginIDsRequest) returns (GetTicketsByOriginIDsResponse);

    //GetTicketsByOwnerIDAndOriginID returns the tickets/subscriptions given owner_id and origin_id
    rpc GetTicketsByOwnerIDAndOriginID (GetTicketsByOwnerIDAndOriginIDRequest) returns (GetTicketsByOwnerIDAndOriginIDResponse);

    //GetUnexpiredUserTicketsByProducts returns the unexpired tickets/subscriptions given owner_id and product_ids.
    //This api was added for octane M4 where payments-service uses it to populate a cache of tickets that are used for checkout.
    rpc GetUnexpiredUserTicketsByProducts (GetUnexpiredUserTicketsByProductsRequest) returns (GetUnexpiredUserTicketsByProductsResponse);

    //GrantAdminSubscription fulfills a channel subscription to a user, and is intended to be granted from the Admin Panel.
    rpc GrantAdminSubscription (GrantAdminSubscriptionRequest) returns (GrantAdminSubscriptionResponse);

    // Revenue Configs
    // =======
    // GetRevenueConfig returns a revenue config by id for a product
    rpc GetRevenueConfig (GetRevenueConfigRequest) returns (GetRevenueConfigResponse);

    // CreateRevenueConfig creates a revenue config for a product
    rpc CreateRevenueConfig (CreateRevenueConfigRequest) returns (CreateRevenueConfigResponse);

    // UpdateRevenueConfig updates a revenue config by id for a product
    rpc UpdateRevenueConfig (UpdateRevenueConfigRequest) returns (UpdateRevenueConfigResponse);

    // DeleteRevenueConfig deletes a revenue config by id for a product
    rpc DeleteRevenueConfig (DeleteRevenueConfigRequest) returns (DeleteRevenueConfigResponse);

    // GetRevenueConfigsByProductID returns all revenue configs for a given product
    rpc GetRevenueConfigsByProductID (GetRevenueConfigsByProductIDRequest) returns (GetRevenueConfigsByProductIDResponse);

    // GetActiveRevenueConfigByProductID returns the currently active revenue config for a given product
    rpc GetActiveRevenueConfigByProductID (GetActiveRevenueConfigByProductIDRequest) returns (GetActiveRevenueConfigByProductIDResponse);

    // Creator Gifts
    // =======

    rpc GetCreatorGiftsBalance (GetCreatorGiftsBalanceRequest) returns (GetCreatorGiftsBalanceResponse);

    rpc FulfillCreatorGifts (FulfillCreatorGiftsRequest) returns (FulfillCreatorGiftsResponse);

    rpc AddCreatorGiftsBalance (AddCreatorGiftsBalanceRequest) returns (AddCreatorGiftsBalanceResponse);

    rpc DeductCreatorGiftsBalance (DeductCreatorGiftsBalanceRequest) returns (DeductCreatorGiftsBalanceResponse);
}

message EmailPendingPrefixApprovalRequest {
    string user_id = 1;
    string prefix = 2;
    string state = 3;
    string emoticon_set_id = 4 [deprecated = true];
}

message EmailPendingPrefixApprovalResponse {
}

message EmailGlobalEmoteRequest {
    string owner_name = 1;
    string owner_email = 2;
    string emote_id = 3;
}

message EmailGlobalEmoteResponse {
}

message EmailSubscribersRequest {
    string channel_id = 1;
    string title = 2;
    string text = 3;
}

message EmailSubscribersResponse {
}

// Score
// =====
message EmoticonLevel {
    int64 minimum_score = 1;
    int64 emoticon_limit = 2;
}

message SetScoreRequest {
    string channel_id = 1; // Required
    int64 subscriber_score = 2; // Required
}

message SetScoreResponse {
    int64 subscriber_score = 1;
    int64 emoticon_limit = 2;
    EmoticonLevel next_level = 3;
}

message SubscriptionCount {
    int64 score = 1;
    EmoticonLevel next_level = 2;
    map<string, int64> count_breakdown = 3;
    map<string, int64> score_breakdown = 4;
    int64 ticket_count = 5;
    int64 emoticon_limit = 6;
}

message CalculateSubscriberCountRequest {
    string channel_id = 1;
}

message CalculateSubscriberCountResponse {
    SubscriptionCount subs_count = 1;
}

// UserSettings
// ============
message GetUserSettingsRequest {
    string user_id = 1;
}

message GetUserSettingsResponse {
    bool gifts_in_followed_channels_only = 1;
    bool hide_gift_count = 2;
    bool hide_subscription_status = 3;
    bool hide_founder_badges = 4;
    bool hide_badge_modifiers = 5;
}

message SetUserSettingsRequest {
    string user_id = 1;
    bool gifts_in_followed_channels_only = 2;
    OptionalBool receive_gifts_in_followed_channels_only = 3;
    OptionalBool hide_gift_count = 4;
    OptionalBool hide_subscription_status = 5;
    OptionalBool hide_founder_badges = 6;
    OptionalBool hide_badge_modifiers = 7;
}

message SetUserSettingsResponse {
    bool gifts_in_followed_channels_only = 1;
    bool hide_gift_count = 2;
    bool hide_subscription_status = 3;
    bool hide_founder_badges = 4;
    bool hide_badge_modifiers = 5;
}

message OptionalBool {
    bool value = 1;
}

enum BadgeFlairSetting {
    BADGE_FLAIR_NONE = 0;
    BADGE_FLAIR_DEFAULT = 1;
    BADGE_FLAIR_CUSTOM = 2;
}

message GetCreatorBadgeFlairSettingRequest {
    string user_id = 1;
}

message GetCreatorBadgeFlairSettingResponse {
    string user_id = 1;
    BadgeFlairSetting badge_flair_setting = 2;
}

message SetCreatorBadgeFlairSettingRequest {
    string user_id = 1;
    BadgeFlairSetting badge_flair_setting = 2;
}

message SetCreatorBadgeFlairSettingResponse {
    string user_id = 1;
    BadgeFlairSetting badge_flair_setting = 2;
}

// Subscriptions
// =============
enum Platform {
    PLATFORM_NONE = 0;
    PLATFORM_WEB = 1;
    PLATFORM_IOS = 2;
    PLATFORM_ANDROID = 3;
    PLATFORM_AMAZON = 4; // only used for incoming twirp requests
    PLATFORM_MOBILE_ALL = 5;
}

enum SubscriptionType {
    // Subscription paid by the user.
    SUBSCRIPTION_PAID = 0;
    // Subscription created by spending a prime token.
    SUBSCRIPTION_PRIME = 1;
    // Free subscription created by admin tools.
    SUBSCRIPTION_ADMIN = 2;
    // When upgrading a non-recurring gift subscription to a recurring paid subscription.
    SUBSCRIPTION_GIFT_PAID_UPGRADE = 3;
    // When upgrading a non-recurring prime subscription to a recurring paid subscription.
    SUBSCRIPTION_PRIME_PAID_UPGRADE = 4;
    // Subscription for gift recipient.
    SUBSCRIPTION_GIFT = 5;
    // When resubscribing from a DNRd sub with a recurring payment plan
    SUBSCRIPTION_DNRD_RESUB_RECURRING = 6;
    // When resubscribing from a DNRd sub with a one-time purchase
    SUBSCRIPTION_DNRD_RESUB_NONRECURRING = 7;
    // Subscription based on a redeemed code.
    SUBSCRIPTION_CODE_REDEMPTION = 8;
    // When continuing a sub that was granted by a redeemed code.
    SUBSCRIPTION_CODE_REDEMPTION_PAID_UPGRADE = 9;
    // When using subtokens to redeem a one-time subscription
    SUBSCRIPTION_TOKEN = 10;
}

// Subscription defines a user's entitlement to product for a time period.
message Subscription {
    string id = 1;
    string channel_id = 2;
    string owner_id = 3;
    string product_id = 4;
    string origin_id = 5;
    google.protobuf.Timestamp benefit_start = 6;
    google.protobuf.Timestamp benefit_end = 7;
    string access_guid = 8;
    google.protobuf.Timestamp updated_on = 9;
    google.protobuf.Timestamp created_on = 10;
    string created_by = 11;
    string purchase_profile_id = 12;
}

message FormerSubscriber {
    string id = 1; // user id of the subscriber
    string channel_id = 2; // channel id the user was subscribed to
}

enum SubscriptionState {
    // Default state: Unspecified state means no state was provided
    SUBSCRIPTION_STATE_UNSPECIFIED = 0;
    // Recovered indicates a subscription that has recovered from an interrupted state
    SUBSCRIPTION_STATE_RECOVERED = 1;
}

message FulfillSubscriptionRequest {
    string owner_id = 1;
    string product_id = 2;
    string origin_id = 3;
    google.protobuf.Timestamp benefit_start = 4;
    google.protobuf.Timestamp benefit_end = 5;
    Platform platform = 6;
    SubscriptionType subscription_type = 7;
    int32 quantity = 8;
    SubscriptionState subscription_state = 9;
    string fulfillment_id = 10;
}

message FulfillSubscriptionResponse {
    Subscription subscription = 1;
}

// CreateSubscription
// ===================
message CreateSubscriptionRequest {
    string owner_id = 1;
    string product_id = 2;
    string origin_id = 3;
    google.protobuf.Timestamp benefit_start = 4;
    google.protobuf.Timestamp benefit_end = 5;
    SubscriptionType subscription_type = 6;
}
message CreateSubscriptionResponse {
    Subscription subscription = 1;
}

// CancelSubscription
// ==================
message CancelSubscriptionRequest {
    string owner_id = 1;
    string product_id = 2;
    string origin_id = 3;
}

message CancelSubscriptionResponse {
}

// UpdateSubscription
// ==================
message UpdateSubscriptionRequest {
    oneof subscription {
        string id = 1; //ticket.ID for legacy use
        SubKey key = 2;
    }
    google.protobuf.Timestamp benefit_end = 3;
}

message UpdateSubscriptionResponse {
}

message CanSubscribeRequest {
    string owner_id = 1;
    string product_id = 2;
    Platform platform = 3;
    SubscriptionType subscription_type = 4;
    int32 quantity = 5;
}

message CanSubscribeResponse {
    bool can_subscribe = 1;
}

// ListUserSubscriptionsRequest is the body of ListUserSubscriptions request.
message ListUserSubscriptionsRequest {
    string owner_id = 1; // ID of the twitch user whose subscriptions are requested.
    int64 limit = 2; // the maximum number of the results to return.
    string cursor = 3; // cursor for id from previous request.
    Platform platform = 4; // platform where subscription was purchased, only required if filter is platform.
    enum Filter {
        ALL = 0; // All active subscriptions.
        PLATFORM = 1; // only subscriptions purchased on a platform, specified in the input as platform.
        GIFT = 2; // only subscriptioons received through gifts from another twitch user.
        NOTPRIME = 3; // all active subscriptions except prime and turbo.
    }
    Filter filter = 5; // Only return subscriptions for a given filter value.
}

message ListUserExpiredSubscriptionsRequest {
    string owner_id = 1; // ID of the twitch user whose subscriptions are requested.
    int64 limit = 2; // maximum amount of expired subs returned. 0<limit<=100
    int64 offset = 3; // from which index of sorted order by most recently expired to start return from. 0<=offset<len(expiredSubs of a user) TODO: Deprecate this once callers are migrated to use cursor pagination
    string cursor = 4; // An ID provided by previous ListUserExpiredSubscriptionsRequest calls to allow paginated results.
}

message GetUserChannelSubscriptionWithPaymentsDataRequest {
    string owner_id = 1; // ID of the twitch user who has this subscription.
    string channel_id = 2; // ID of the twitch channel.
}

message GetUserChannelSubscriptionRequest {
    string owner_id = 1; // ID of the twitch user who has this subscription.
    string channel_id = 2; // ID of the twitch channel.
}

// UserSubscription defines active subscription for a twitch user.
message UserSubscription {
    string subscription_id = 1; // ID of the active subscription.
    string owner_id = 2; // ID of the twitch user who has this subscription.
    string product_id = 3; // ID of the subscription product.
    string origin_id = 4; // ID of the origin which serves as a back index into purchase system.
    google.protobuf.Timestamp benefit_start = 5; // Start date of the benefit.
    google.protobuf.Timestamp benefit_end = 6; // End date of the benefit.
    Platform platform = 7; // Platform where this sub was purchased.
    google.protobuf.Timestamp renews_at = 8; // Date when subscription renews, will be nil if subscription doesn't renew.
    string ext_purchase_sku = 9; // SKU for managing third party subscriptions, will be nil if there is no sku associated with the purchase.
    bool is_prime = 10; // Whether subscription was purchased using Twitch Prime.
    bool is_gift = 11; // Whether subscription was received through a gift from another twitch user.
    bool is_refundable = 12; // Whether subscription is able to be refunded.
    bool is_dnrd = 13; // Whether user has set their recurring subscription to do-not-renew
    google.protobuf.Timestamp updated_on = 14; // Date subscription was last updated.
    bool is_stacked = 15; // Whether subscription has multiple orders associated with it
}

// Element of a list of UserSubscriptions
message UserSubscriptionResult {
    UserSubscription subscription = 1; // user's subscription.
    string cursor = 2; // cursor to look up subscription following this result.
}

message SubscriptionResult {
    Subscription subscription = 1; // user's subscription without payments information
    string cursor = 2; // cursor to look up subscription following this result.
}

message ListUserExpiredSubscriptionsResponse {
    repeated SubscriptionResult subscriptions = 1; // List of subscriptions and cursors
    bool has_previous_page = 2; // Whether there were previous results
    bool has_next_page = 3; // Whether there are more results.
}

// ListUserSubscriptionsResponse is the response to a ListUserSubscriptions request.
message ListUserSubscriptionsResponse {
    repeated UserSubscriptionResult results = 1; // List of user subscriptions and cursors.
    bool has_previous_page = 2; // Whether there were previous results.
    bool has_next_page = 3; // Whether there are more results.
}

message GetUserChannelSubscriptionWithPaymentsDataResponse {
    UserSubscription subscription = 1; // user's subscription with payments data.
}

message GetUserChannelSubscriptionResponse {
    Subscription subscription = 1; // user's subscription.
}

message GetUserProductSubscriptionsRequest {
    string owner_id = 1;
    repeated string product_ids = 2;
}

message GetUserProductSubscriptionsResponse {
    repeated Subscription subscriptions = 1;
}

message GetUserProductSubscriptionsWithPaymentsDataRequest {
    string owner_id = 1;
    repeated string product_ids = 2;
}

message GetUserProductSubscriptionsWithPaymentsDataResponse {
    repeated UserSubscription subscriptions = 1; // user's subscription with payments data.
}


message GetUserSubscriptionsRequest {
    string owner_id = 1;
}

message GetUserSubscriptionsResponse {
    repeated Subscription subscriptions = 1;
}

// GetChannelSubscriptions
message GetChannelSubscriptionsRequest {
    string channel_id = 1;
    int32 limit = 2;
    int32 offset = 3; // TODO Remove in favor of cursor pagination after migrating callers, field 5.
    enum OrderBy {
        NONE = 0;
        UPDATED_AT = 1;
    }
    OrderBy order_by = 4;
    string cursor = 5; // An ID provided by previous GetChannelSubscription calls to allow paginated results.
}

message GetChannelSubscriptionsResponse {
    repeated Subscription subscriptions = 1;
    string cursor = 2; // A value that can be used by subsequent requests to get the next page of results.
}

// GetChannelSubscriptionsAfterTime
message GetChannelSubscriptionsAfterTimeRequest {
    string channel_id = 1; // The channel that we should retrieve the subscribers for
    google.protobuf.Timestamp after_time = 2; // The time that we should use to retrieve the subscribers that subbed after this given time
    int32 limit = 3;
    int32 offset = 4;
    bool filter_cancelled_subscriptions = 5; // Optional: boolean to determine whether or not to filter cancelled subscriptions from returning
}

message GetChannelSubscriptionsAfterTimeResponse {
    repeated Subscription subscriptions = 1;
    bool has_next_page = 2;
}

// GetSubscriptionByID
message GetSubscriptionByIDRequest {
    oneof subscription {
        SubKey sub_key = 1; // Use SubKey if possible
        string id = 2; // For legacy use
    }
}
message GetSubscriptionByIDResponse {
    Subscription subscription = 1;
}

// GetHistoricalUserTickets
message GetHistoricalUserTicketsRequest {
    string owner_id = 1;
}
message GetHistoricalUserTicketsResponse {
    repeated Subscription subscriptions = 1;
}

// Subscriber Badges
// ================
message TakedownBadgesRequest {
    string channel_id = 1;
    repeated string badge_ids = 2;
    string reason = 3;
}

message TakedownBadgesResponse {
    repeated string badges_removed = 1;
}

message TakedownAllBadgesRequest {
    string channel_id = 1;
    string reason = 2;
}

message TakedownAllBadgesResponse {
    repeated string badges_removed = 1;
}

message GetSubscriberBadgeRequest {
    string channel_id = 1; // id of the channel to check for this subscriber badge
    string user_id = 2; // id of the user to check for this subscriber badge
}

message GetSubscriberBadgeResponse {
    BadgeType badge_type = 1;
    string badge_version = 2;
    string dynamic_data = 3;
}

message InvalidateBadgeCacheRequest {
    repeated string user_ids = 1;
    string channel_id = 2;
}

message InvalidateBadgeCacheResponse {
}

enum BadgeType {
    NO_BADGE = 0; // no badge means a user is not a subscriber
    DEFAULT_BADGE = 1; // default subscription badge
    SUBSCRIBER_BADGE = 2; // subscription badges based on tenure months
    FOUNDER_BADGE = 3; // Subscription Badges based on Founder status
}

message BadgeFlair {
    string image_1x_url = 1;
    string image_2x_url = 2;
    string image_4x_url = 3;
    string tier = 4;
}

message GetBadgeFlairRequest {
    string channel_id = 1;
}

message GetBadgeFlairResponse {
    string channel_id = 1;
    repeated BadgeFlair flairs = 2;
}

message CreateBadgeFlairRequest{
    string channel_id = 1;
    string tier = 2;
    string image_1x_id = 3;
    string image_2x_id = 4;
    string image_4x_id = 5;
}

message CreateBadgeFlairResponse{}

message GetBadgeProgressRequest{
    string user_id = 1;
    string channel_id = 2;
}

message GetBadgeProgressResponse{
    repeated BadgeProgress badges = 1;
}


message GetChannelBadgeRequest {
    string channel_id = 1;
}

message GetChannelBadgeResponse {
    repeated ChannelBadge badges = 1;
}

message DeleteChannelBadgeRequest {
    string channel_id = 1;
    int32 badge_id = 2;
    string channel_tenure_method_id = 3;
    string modifier = 4;
}

message DeleteChannelBadgeResponse {
    int32 id = 1;
    int32 required_tenure_months = 2;
    string channel_tenure_method_id = 3;
    string badge_version = 4;
}

message CreateChannelBadgeUploadConfigRequest {
    string channel_id = 1;
    int32 size = 2;
}

message CreateChannelBadgeUploadConfigResponse {
    string upload_url = 1;
    string upload_id = 2;
    string image_url = 3;
    string image_id = 4;
}

message CreateChannelBadgeRequest {
    string channel_id = 1;
    string image_1x_id = 2;
    string image_2x_id = 3;
    string image_4x_id = 4;
    int32 required_tenure_months = 5;
    string modifier = 6;
}

message CreateChannelBadgeResponse {
    int32 id = 1;
    string image_1x_url = 2;
    string image_2x_url = 3;
    string image_4x_url = 4;
    int32 required_tenure_months = 5;
    string title = 6;
    string channel_tenure_method_id = 7;
    string modifier = 8;
    string badge_version = 9;
}

message GetFounderBadgeAvailabilityRequest {
    string channel_id = 1;
}

message GetFounderBadgeAvailabilityResponse {
    int32 available_slots = 1;
}

message IsFounderRequest {
    string channel_id = 1;
    string user_id = 2;
}

message IsFounderResponse {
    bool is_founder = 1;
}

message ChannelBadge {
    int32 id = 1;
    string image_1x_url = 2;
    string image_2x_url = 3;
    string image_4x_url = 4;
    int32 required_tenure_months = 5;
    string title = 6;
    string channel_tenure_method_id = 7;
    string modifier = 8;
}

message BadgeProgress {
    string image_1x_url = 1;
    string image_2x_url = 2;
    string image_4x_url = 3;
    string version = 4;
    int32 required_tenure_months = 5;
    float progressMade = 6;
}

// External Product
// ================
message GetExternalProductTemplateSKURequest {
    string product_id = 1;
    Platform platform = 2;
    string country_code = 3; // GeoIP ISO country code
}

message GetExternalProductTemplateSKUResponse {
    string sku_id = 1;
}

message GetExternalProductPurchasableSKURequest {
    string owner_id = 1;
    string product_id = 2;
    Platform platform = 3;
    string country_code = 4; // GeoIP ISO country code
}

message GetExternalProductPurchasableSKUResponse {
    string sku_id = 1;
}

// Paid Upgrades
// =============
// SubKey is used to identify unique subscriptions based on
// product owner and origin.

message SubKey {
    string product = 1;
    string owner = 2;
    string origin = 3;
}

message PaidUpgrade {
    SubKey base_key = 1;
    SubKey upgrade_key = 2;
    string entitlement_id = 3;
    google.protobuf.Timestamp start_date = 4;
    string tier = 5;
    int32 price = 6;
    string price_id = 7; //Used by price service
    SubscriptionType subscription_type = 8;
    bool is_cancelable = 9;
}

message GetPaidUpgradesRequest {
    repeated SubKey keys = 1;
}

message GetPaidUpgradesResponse {
    repeated PaidUpgrade paid_upgrades = 1;
}

message CreatePaidUpgradeRequest {
    SubKey base_key = 1;
    SubKey upgrade_key = 2;
    SubscriptionType subscription_type = 3;
}

message CreatePaidUpgradeResponse {
    PaidUpgrade paid_upgrade = 1;
}

message CancelPaidUpgradeRequest {
    SubKey base_key = 1;
    SubKey upgrade_key = 2;
}

message CancelPaidUpgradeResponse {
}

message FulfillPaidUpgradeRequest {
    string owner_id = 1;
    string product_id = 2;
    string origin_id = 3;
    google.protobuf.Timestamp benefit_start = 4;
    google.protobuf.Timestamp benefit_end = 5;
    SubKey base_key = 6; // base_key is the subscription information to be upgraded.
    SubscriptionType subscription_type = 7; // Type of upgrade
}

message FulfillPaidUpgradeResponse {
    PaidUpgrade paid_upgrade = 1;
}
// Chat Notifications
// ======
// Example Body for CreateChatNotificationTokenRequest:
//{
//	    "owner_id": "29386024", Who does the token belong to?
//      "product_id": "834",    Which ticket product?
//      "available_at": "2018-01-02T15:04:05Z",    When is the token granted?
//      "is_prime" : {"value": true}, specifies whether or not the token is coming from a prime sub. Defaults to paid/not-prime if unspecified.
//		"new_ticket_interval" : {"access_start" : "2018-06-18T15:04:05Z",   used for multi-month subscriptions since the ticket does not
//							    "access_end" : "2018-07-18T15:04:05Z"}      persist before chat notification call is made from payments service
//}
message CreateChatNotificationTokenRequest {
    string owner_id = 1; // Required
    string product_id = 2; // Required
    google.protobuf.Timestamp available_at = 3; // Required
    OptionalBool is_prime = 4;
    NewTicketInterval new_ticket_interval = 5;
}

message CreateChatNotificationTokenResponse {
    string message = 1;
}

message NewTicketInterval {
    google.protobuf.Timestamp access_start = 1;
    google.protobuf.Timestamp access_end = 2;
}

// Example Body for UseChatNotificationTokenRequest:
//{
//	    "token_id": "29386024", which token do we want to use?
//      "authed_user_id": "834",   the id of the authed user calling this endpoint
//      "custom_message": "im a custom message", do we want to post a custom message?
//}
message UseChatNotificationTokenRequest {
    string token_id = 1;
    string authed_user_id = 2; // Required
    string custom_message = 3;
    OptionalBool share_streak = 4;
    string channel_id = 5;
}

message UseChatNotificationTokenResponse {
    string message = 1;
}

message GetUserChannelChatNotificationTokenRequest {
    string user_id = 1; //Which user owns this token?
    string channel_id = 2; // Which channel does the token belong to?
    bool is_cumulative_tenure_load_test = 3; // To be used ONLY for cumulative tenure load testing
}

message GetUserChannelChatNotificationTokenResponse {
    ChatNotificationToken chat_notification_token = 1; //Available chat notification token
}

message GetAllUsedChatNotificationTokensRequest {
    string user_id = 1; // id of user that owns tokens
    string channel_id = 2; // id of channel that tokens were used on
}

message GetAllUsedChatNotificationTokensResponse {
    repeated UsedChatNotificationTokenItem used_chat_tokens = 1; // list of used chat tokens
}

message AllowReplayForLastUsedChatNotificationTokenRequest {
    string owner_id = 1;
    string channel_id = 2;
    string tenure = 3;
    string method = 4;
}

message AllowReplayForLastUsedChatNotificationTokenResponse {
}

message ChatNotificationToken {
    string id = 1; // id of chatnotification token
    string message = 2; // message to post
    string month = 3; // tenure months
    string kind = 4; // tier information
    int32 cumulative_tenure_month = 5; // cumulative tenure months
    int32 streak_tenure_month = 6; // streak tenure months
    bool is_gift_subscription = 7;
    string gifter_id = 8;
}

message UsedChatNotificationTokenItem {
    string owner = 1;
    string channel = 2;
    string tenure = 3;
    string method = 4;
    bool streak_shared = 5;
    int32 streak_value = 6;
    string custom_message_text = 7;
    bool custom_message_shared = 8;
    string product = 9;
    string tier = 10;
    bool is_prime = 11;
    bool allow_replay = 12;
    google.protobuf.Timestamp created_at = 13;
    google.protobuf.Timestamp updated_at = 14;
}

// Gifts
// ======
message Gift {
    string sender = 1; // tuid of the gift sender
    string recipient = 2; // tuid of the gift recipient
    string product = 3; // id of the subscription product
    string origin = 4; // origin id of the gift purchase
    GiftState state = 5; // state of the gift in gift store
    google.protobuf.Timestamp gift_date = 6; // date at which gift was purchased
    GiftType gift_type = 7; // type of the gift in gift store
    bool anon_gift = 8; // whether this gift is anonymous
    int32 gift_months = 9; // the number of months gifted
}

enum GiftState {
    GIFT_NONE = 0;
    GIFT_ACCEPTED = 1; // recipient accepted the gift
    GIFT_CANCELED = 2; // recipient canceled the gift
}

// GiftKey is used to identify gifts using product, origin, owner (receiver), domain.
// This is convention from HATS so that consumers don't need to store extra information.
// Product, owner, origin, domain (POOD) is used as a hash key in the gifts dynamo table
// for blazing fast lookups.
message GiftKey {
    string product = 1;
    string origin = 2;
    string recipient = 3;
}

// InsertGiftRequest is the body of a InsertGift rpc request.
message InsertGiftRequest {
    string sender = 1; // tuid of the gift sender
    string recipient = 2; // tuid of the gift receiver
    string product = 3; // id of the subscription product
    string origin = 4; // origin id of the gift purchase
    GiftType gift_type = 5; // the type of gift eg: mystery or standard
    bool anon_gift = 6; // whether this gift is anonymous
    int32 gift_months = 7; // the number of months gifted
}

// CreateGiftResponse is the response to a CreateGift rpc request.
message InsertGiftResponse {
    Gift gift = 1; // the newly created gift
}

// CancelGiftRequest is the body of a CancelGift rpc request.
message CancelGiftRequest {
    string product = 1; // id of the subscription product
    string origin = 2; // origin id of the gift purchase
    string recipient = 3; // tuid of the gift recipient
}

// CancelGiftResponse is the response of a CancelGift rpc request.
message CancelGiftResponse {
    Gift canceled_gift = 1; // the canceled gift
}

// GetGifts
message GetGiftsRequest {
    repeated GiftKey keys = 1;
}
message GetGiftsResponse {
    repeated Gift gifts = 1;
}

// CanGift
message CanGiftRequest {
    string sender = 1;
    string recipient = 2;
    string product = 3;
}
message CanGiftResponse {
    bool can_gift = 1;
}

// CanSenderGift
message CanSenderGiftRequest {
    string sender_id = 1; // id of the user sending gifts
    string product_id = 2; // id of the subscription product
    int32 gift_quantity = 3; // number of gifts

}
message CanSenderGiftResponse {
    bool can_gift = 1; // true if the sender can send gifts
}

// CanGiftRecipient
message CanGiftRecipientRequest {
    string sender_id = 1; // id of the user sending gifts
    string product_id = 2; // id of the subscription product
    string recipient_id = 3; // id of the recipient
    GiftType gift_type = 4; // the type of gift eg: mystery or selected
}

message CanGiftRecipientResponse {
    bool can_gift = 1;
    string reason = 2;
}

// Uniquely identifies a gift offer by the product, gift type and quantity
message GiftOfferId {
    string product = 1; // The product id for this gift offer. EX: GIFT_TYPE_MYSTERY/GIFT_TYPE_STANDARD
    GiftType gift_type = 2; // The type of gift for this gift offer.
    int32 quantity = 3; // The amount of gifts this gift offer is for.
}

// GiftPromotion describes the promotion on a subscription product.
message GiftPromotion {
    string product_id = 1; // Product ID of the channel this gift promotion is for
    int64 new_price = 2; // New price for this product after promotion applied
    int64 old_price = 3; // Old price for this product before promotion applied
    DiscountType discount_type = 4; // Discount Type for this promotion
    int64 discount_value = 5; // Amount of a discount applied for this promotion
    string error = 6; // Any errors reported while trying to receive a promotion
    string third_party_sku = 7; // ThirdPartySKU used by third party clients to use for pricing information
    int32 new_quantity = 8; // Amount of this product that is being offered in this promotion(ex: 6 gifts instead of 5)
    int32 old_quantity = 9; // Old amount of this product before promotion was applied
    GiftOfferId gift_offer_id = 10; // Unique identifier of a gift offer
}

// Promotion describes the promotion on a subscription product.
// Generic Promotion object to use for promos moving forward
message Promotion {
    string product_id = 1;
    int64 new_price = 2;
    int64 old_price = 3;
    DiscountType discount_type = 4;
    int64 discount_value = 5;
    string error = 6;
}

// DiscountType is the type of the discount.
enum DiscountType {
    DISCOUNT_NONE = 0;
    DISCOUNT_PERCENTOFF = 1;
    DISCOUNT_FIXEDVALUEOFF = 2;
}

// GetGiftPromotionRequest describes the request of GetGiftPromotion.
message GetGiftPromotionRequest {
    repeated string product_ids = 1; // List of product IDs to check for promotions.
    string user_id = 2; // User ID of the authed logged in user that is trying to send a gift.
    Platform platform = 3; // Platform the request was made from.
    repeated GiftOfferId gift_offer_ids = 4; // Unique identifiers for gift offers that should be checked for promotions(ex: check promos for community gifts of 5 and 10)
}

// GetGiftPromotionResponse describes the response of GetGiftPromotion.
message GetGiftPromotionResponse {
    bool is_promotion_active = 1;
    repeated GiftPromotion gift_promotions = 2;
}

// GetPaidUpgradePromotionRequest describes the request of GetPaidUpgradePromotion
message GetPaidUpgradePromotionRequest {
    string user_id = 1;
    repeated string product_ids = 2;
}

// GetPaidUpgradePromotionResponse describes the response of GetPaidUpgradePromotion
message GetPaidUpgradePromotionResponse {
    repeated Promotion promotions = 2;
}

// PaymentsPromotion contains the ID of the active promotion that is stored in another payments-owned system.
message PaymentsPromotion {
    string PriceID = 1;
    string Error = 2;
}

// GetPromotionRequest describes the request of GetPromotion
message GetPromotionsRequest {
    repeated string product_ids = 1; // required
    string user_id = 2; // optional, if user_id is supplied, the response will contain IsUserEligibleForDiscount for the given user<->product relationship.
}

// GetPromotionResponse describes the response of GetPromotion
message GetPromotionsResponse {
    map<string, PaymentsPromotion> promotions = 1; // product ID -> PaymentsPromotion
}

enum GiftType {
    GIFT_TYPE_NONE = 0;
    GIFT_TYPE_MYSTERY = 1;
    GIFT_TYPE_STANDARD = 2;
    GIFT_TYPE_COMMUNITY = 3; // COMMUNITY and MYSTERY are the same type of gift, MYSTERY is an older/deprecated name and we should use COMMUNITY when possible
    GIFT_TYPE_CREATOR = 4;
}

// FulfillGiftsRequest is the body of FulfillGifts rpc request.
message FulfillGiftsRequest {
    string sender_id = 1; // Tuid of the gift sender.
    string product_id = 2; // ID of the gifted product.
    string origin_id = 3; // Origin ID of the gift purchase which serves as back index into payments system.
    GiftType gift_type = 4; // Type of Gift (eg, MYSTERY).
    int32 gift_quantity = 5; // Number of gifts. Use this for mystery gifting. Do not use for non mystery case.
    google.protobuf.Timestamp benefit_start = 6; // Start date of the gift benefit.
    google.protobuf.Timestamp benefit_end = 7; // End date of the gift benefit.
    repeated string recipient_ids = 8; // Tuid of the gift recipients. Use this for single or multi gift. Use gift_quantity for Mystery Gifting
    bool anon_gift = 9; // Whether this gift is anonymous
    string sku_id = 10; // Optional SKU ID parameter that represents an external product SKU that was used to purchase this gift
    Platform platform = 11; // Optional Platform paramter that this gift purchase was fulfilled on
}

// FulFillGiftsResponse is an empty response. If subscriptions service can not fulfill this error, it will return appropriate error.
// Error codes:
// 1. InvalidArgumentError : If request is invalid
// 2. FailedPrecondition: If one of the eligibility pre-condition is not true.
// 3. InternalError: If there was an internal server error fulfilling the gift request.
message FulfillGiftsResponse {
}

// SendGiftChatNotificationRequest is the body of the SendGiftChatNotification rpc request.
message SendGiftChatNotificationRequest {
    string sender_id = 1; // tuid of the gift sender
    string recipient_id = 2; // tuid of the gift receiver
    string product_id = 3; // id of the subscription product
    string channel_id = 4; // id of the channel
    bool anon_gift = 5; // whether this notification should be anonymous
    GiftType gift_type = 6; // type of the gift
    string origin_id = 7; // id of the origin
    int32 gift_months = 8; // the number of months gifted
}

// SendGiftChatNotificationResponse is an empty response
message SendGiftChatNotificationResponse {
}

// SendMMGChatNotificationRequest is the body of the SendMMGChatNotification rpc request.
message SendMMGChatNotificationRequest {
    string sender_id = 1; // tuid of the gift sender
    string recipient_id = 2; // tuid of the gift receiver
    string product_id = 3; // id of the subscription product
    string channel_id = 4; // id of the channel owner
    string origin_id = 5; // id of the origin
}

// SendMMGChatNotificationResponse is an empty response
message SendMMGChatNotificationResponse {
}

// SendMMGStartChatNotificationRequest is the body of the SendMMGStartChatNotification rpc request.
message SendMMGStartChatNotificationRequest {
    string sender_id = 1; // ID of the gift sender.
    string product_id = 2; // ID of the gifted product.
    string channel_id = 3; // User ID of the channel this gift is occuring in.
    int32 gift_quantity = 4; // Number of gifts in this mass mystery gift.
    bool anon_gift = 5; // whether this notification should be anonymous
    string origin_id = 6; // ID of the origin
}

// SendMMGStartChatNotificationRequest is an empty response
message SendMMGStartChatNotificationResponse {
}

// SendPayForwardChatNotificationRequest is the body of the SendPayForwardChatNotification rpc request.
message SendPayForwardChatNotificationRequest {
    string sender_id = 1; // tuid of the gift sender
    string recipient_id = 2; // tuid of the gift receiver, if gift_type = GIFT_TYPE_STANDARD
    string channel_id = 3; // id of the channel
    bool anon_gift = 4; // whether this notification should be anonymous
    GiftType gift_type = 5; // type of the gift
    string origin_id = 6; // origin ID of current transaction
}

// SendPayForwardChatNotificationResponse is an empty response
message SendPayForwardChatNotificationResponse {
}

message GiftOffer {
    GiftType gift_type = 1; // The type of gift in this gift offer. EX: GIFT_TYPE_MYSTERY/GIFT_TYPE_STANDARD
    string sku_id = 2; // SKU which can be used to fetch external product's attributes from third party subscription providers like Apple, Google.
    int32 quantity = 3; // Amount of gifts in this gift offer is for
}

message GetGiftOffersRequest {
    GiftType gift_type = 1; // The type of gift in this gift offer. EX: GIFT_TYPE_MYSTERY/GIFT_TYPE_STANDARD
    Platform platform = 2; // The platform in which this request is being made from. EX: Android/iOS/Web
    string country_code = 3; // GeoIP ISO country code the request is being made from.
    string product_id = 4; // The product id of the channel to retrieve the available gift offers.
}

message GetGiftOffersResponse {
    repeated GiftOffer gift_offers = 1; // list of gift offers for the requested gift type
}

message GetCommunityGiftBundlesRequest {
    string client_id = 1; // The client ID of the client making the request. This is used to translate to a platform internally.
    repeated string tiers = 2; // The list of tiers for which these gift bundles apply
    string user_id = 3;
}

message GetCommunityGiftBundlesResponse {
    // Map of tier -> list of bundles for that tier
    map<string, CommunityGiftBundleList> results = 1;
}

// just a list wrapper for bundles. Required to stuff them in a map.
message CommunityGiftBundleList {
    repeated CommunityGiftBundle bundles = 1;
}

message CommunityGiftBundle {
    // What type of bundle this is (used for presentment to the user)
    enum GiftBundleType {
        UNKNOWN = 0;
        BUNDLE = 1; // A preset bundle of fixed-quantity community gift subscriptions.
        CUSTOM = 2; // A bundle with a recommended initial quantity of gift subscriptions
    }
    GiftBundleType bundle_type = 1;

    // The number of gifts in this bundle
    int32 quantity = 2;

    // The image assets associated with this bundle.
    message GiftBundleAssets {
        string imageUrl1x = 1;
        string imageUrl2x = 2;
        string imageUrl3x = 3;
        string imageUrl4x = 4;
    }
    GiftBundleAssets assets = 3;
    string offer_id = 4;
}

message GetGiftsSentCountRequest {
    string sender_id = 1;
    string channel_id = 2;
}

message GetGiftsSentCountResponse {
    int32 count = 1;
}

message GrantGifterBadgeRequest {
    string sender_id = 1;
    string channel_id = 2;
    google.protobuf.Timestamp access_end = 3;
}

message GrantGifterBadgeResponse {
}

message GetLatestGiftEndPerChannelRequest {
    string sender_id = 1;
    bool include_expired = 2;
}

message GetLatestGiftEndPerChannelResponse {
    map<string, google.protobuf.Timestamp> channel_access_ends = 1; // mapping of channelID to the date that the sender's last active gift in that channel will end
}

message ModerateUserFromGifterLeaderboardRequest {
    string sender_id = 1;
    string channel_id = 2;
}

message ModerateUserFromGifterLeaderboardResponse {
}

message UpdateLeaderboardBadgesRequest {
    string channel_id = 1;
    string user_id = 2;
    string event_id = 3;
    int32 event_value = 4;
}

message UpdateLeaderboardBadgesResponse {
}

// GetRelatedChannelsRequest is the body of the GetRelatedChannels rpc request
message GetRelatedChannelsRequest {
    string product_id = 1;
}

// GetRelatedChannelsResponse is the body of the GetRelatedChannels rpc response
message GetRelatedChannelsResponse {
    repeated string channel_ids = 1;
}

// Emoticons
// ======
message GetEmotePrefixRequest {
    string owner_id = 1;
}

message GetEmotePrefixResponse {
    repeated string prefixes = 1;
}

message CreateEmoticonRequest {
    string user_id = 1;
    string code_suffix = 2;
    string product_id = 3;
    string image28_id = 4;
    string image56_id = 5;
    string image112_id = 6;
}

message CreateEmoticonReponse {
    string id = 1;
    string code = 2;
    string product_id = 3;
    string group_id = 4;
    string state = 5;
}

message DeleteEmoticonRequest {
    string id = 1;
    string code = 2;
    bool deleteImages = 3;
}

message DeleteEmoticonResponse {
    string id = 1;
    string code = 2;
    bool deletedImages = 3;
}

message GetAllEmoticonsByProductIDsRequest {
    repeated string product_ids = 1;
}

message GetAllEmoticonsByProductIDsResponse {
    repeated EmoticonGroup emoticon_groups = 1;
}

message EmoticonGroup {
    string product_id = 1;
    repeated Emoticon emoticons = 2;
}

message Emoticon {
    string id = 1;
    string code = 2;
    string group_id = 3;
    EmoticonState state = 4;
}

// State of the emote.
enum EmoticonState {
    EmoticonState_NONE = 0;
    EmoticonState_ACTIVE = 1;
    EmoticonState_PENDING = 2;
    EmoticonState_INACTIVE = 3;
}

// State of the emote prefix.
enum EmoticonPrefixState {
    PREFIX_UNKNOWN = 0;
    PREFIX_UNSET = 1;
    PREFIX_ACTIVE = 2;
    PREFIX_REJECTED = 3;
    PREFIX_PENDING = 4;
}

// GetPartnerStandingRequest takes a user_id to find the partner standing status for.
message GetPartnerStandingRequest {
    string user_id = 1;
}

// GetPartnerStandingStatusResponse returns the partner standing status for a given user.
// Partners are considered to be in “good standing” if they have not had a conduct infraction within the last 90 days.
message GetPartnerStandingResponse {
    bool is_in_good_standing = 1;
}

message GetChannelEmoteLimitsRequest {
    string channel_id = 1;
}

message GetChannelEmoteLimitsResponse {
    string channel_id = 1;
    repeated ProductEmoteLimit limits = 2;
}

message ProductEmoteLimit {
    string product_id = 1;
    string tier = 2; // 1000, 2000, 3000
    int32 emote_limit = 3;
}

// Pending Emoticons
// =========
message GetPendingEmoticonsByIDsRequest {
    repeated string emoticon_ids = 1;
}

message GetPendingEmoticonsByIDsResponse {
    repeated PendingEmoticon emoticons = 1;
}

// GetPendingEmoticonsRequest
message GetPendingEmoticonsRequest {
    EmoticonFilter filter = 1;
    int32 count = 2; // Defaults to 25 - must be > 0
    EmoticonBucket bucket = 3;
    google.protobuf.Timestamp after_timestamp = 4;
}

// GetPendingEmoticonsResponse
message GetPendingEmoticonsResponse {
    repeated PendingEmoticon emoticons = 1;
    int32 total_count = 2;
}

message ReviewPendingEmoticonsRequest {
    repeated ReviewPendingEmoticonRequest reviews = 1;
    string admin_id = 2; // The LDAP ID of the admin who took this action
}

message ReviewPendingEmoticonRequest {
    string id = 1;
    bool approve = 2;
    string decline_reason = 3; // One of a set of well-known decline reasons
    string decline_explanation = 4; // A more descriptive explanation written by the admin
}

message ReviewPendingEmoticonsResponse {
    repeated ReviewPendingEmoticonResponse results = 1;
}

message ReviewPendingEmoticonResponse {
    string id = 1;
    bool succeeded = 2;
    string new_status = 3;
}

message EmoticonBucket {
    int32 requested = 1;
    int32 bucket_count = 2;
}

enum EmoticonFilter {
    EmoticonFilter_All = 0;
    EmoticonFilter_Partner = 1;
    EmoticonFilter_Affiliate = 2;
}

// PendingEmoticon contains all the data necessary for Moderation to view and judge an emoticon
message PendingEmoticon {
    string id = 1;
    string prefix = 2;
    string code = 3;
    string owner_id = 4;
    google.protobuf.Timestamp upload_time = 5;
}

// Products
// =========
message Product {
    string id = 1;
    string short_name = 2; // Short name is used as a "pretty" ID to identify the product in URLs.
    string display_name = 3; // The custom name of the product set by the channel owner.
    repeated string emoticon_set_ids = 4; // IDs of the emoticon sets granted by this product.
    int32 price = 5; // Price in cents USD
    bool hide_ads = 6; // Whether this product grants ad free viewing on the owner channel.
    string type = 7; // Identifies chansub, teamsub...
    string owner_id = 8; // The id of the channel that the product belongs to.
    string tier = 9; // The tier of the product. Can be 1000, 2000, 3000.
    ProductInterval interval = 10; // Identifies the recurring interval of the subscription.
    repeated string bitrate_access = 11; // If not empty, contains info about what bitrates subs have access to.
    bool subonly_archives = 12; // Whether this channel has vods behind subonly restriction and if this ticket grants access to them.
    string emoticon_set_id = 13;
    string price_id = 14; // This id is a mapping of price to id that will be received by Price service.
    google.protobuf.Timestamp benefit_start = 15; // Benefit start used for one time products
    google.protobuf.Timestamp benefit_end = 16; // Benefit end used for one time products
    bool refundable = 17; // Whether this product is refundable or not.
    ProductState state = 18; // State of product: active or inactive.
    bool recurring = 19; // Whether this product is recurring or not.
    string owner_type = 20; // The type of user User / Team
    string external_product_id = 21; // The external product id
}

message ProductInterval {
    int32 duration = 1;
    ProductIntervalUnit unit = 2;
}
enum ProductIntervalUnit {
    ProductIntervalUnit_NONE = 0; // Default value.
    ProductIntervalUnit_WEEK = 1; // Weekly recurring subscription.
    ProductIntervalUnit_MONTH = 2; // Monthly recurring subscription.
    ProductIntervalUnit_YEAR = 3; // Yearly recurring subscription.
    ProductIntervalUnit_ONETIME = 4; // Subscription that lasts forever.
}

enum ProductState {
    ProductState_UNKNOWN = 0; // Default value.
    ProductState_ACTIVE = 1; // Active product.
    ProductState_INACTIVE = 2; // Inactive product.
}

enum ProductStateFilter {
    ProductStateFilter_ACTIVE = 0;
    ProductStateFilter_ALL = 1;
    ProductStateFilter_INACTIVE = 2;
}

// Takes in a list of product_ids. Max 100.
message GetProductsByIDsRequest {
    repeated string product_ids = 1;
}
// Returns a list of products.
message GetProductsByIDsResponse {
    repeated Product products = 1;
}

// Takes in a list of product_names. Max 100.
message GetProductsByNamesRequest {
    repeated string product_names = 1;
}

// Returns a list of products.
message GetProductsByNamesResponse {
    repeated Product products = 1;
}

// Accepts a single channel ID.
message GetChannelProductsRequest {
    string channel_id = 1;
    string client_id = 2;
    ProductStateFilter state_filter = 3; // Optional: Sets the filter on products. Defaults to Active products only.
    bool include_teamsub_owners = 4; // Optional: If set to true it will return teamsub products for which the given channel_id is a team owner. Defaults to false
}

// Returns a list of products.
message GetChannelProductsResponse {
    repeated Product products = 1;
}

// UpdateProductRequest is the request for UpdateProduct rpc method.
message UpdateProductRequest {
    string product_id = 1; // REQUIRED: ID of the twitch subscription product.
    string display_name = 2; // REQUIRED: Display name of the subscription product.
}

message UpdateProductResponse {
    string product_id = 1;
    string display_name = 2; // Resultant display_name that is set
}

// UpdateChannelProductsRequest is the body of UpdateChannelProducts rpc method.
message UpdateChannelProductsRequest {
    string channel_id = 1; // REQUIRED: ID of the twitch channel.
    bool hide_ads = 2; // REQUIRED: Toggle to enable ad free viewing on this channel.
    bool subonly_archives = 3; // REQUIRED: Toggle to enable sub only vods restriction on this channel.
}

message UpdateChannelProductsResponse {
    string channel_id = 1;
    bool hide_ads = 2; // Resultant hide_ads option that is set
    bool subonly_archives = 3; // Resultant subonly_archives option that is set
}

// TicketData includes only the information from tickets that would be required to create a chronobreak grant
message TicketGrantData {
    string origin_id = 1;
    google.protobuf.Timestamp benefit_start = 2;
    google.protobuf.Timestamp benefit_end = 3;
    google.protobuf.Timestamp updated_on = 4;
    google.protobuf.Timestamp created_on = 5;
}

message RedeemSubscriptionRequest {
    string user_id = 1;
    string off_boarded_channel_id = 2;
    string redeem_channel_id = 3;
}

message RedeemSubscriptionResponse {
    Subscription subscription = 1;
}

message RedeemedSubscriptionRequest {
    string user_id = 1;
    string off_boarded_channel_id = 2;
}

message RedeemedSubscriptionResponse {
    string user_id = 1;
    string user_login = 2;
    string off_boarded_channel_id = 3;
    string off_boarded_channel_login = 4;
    string redeemed_channel_id = 5;
    string redeemed_channel_login = 6;
    string tier = 7;
    google.protobuf.Timestamp created_at = 8;
    google.protobuf.Timestamp updated_at = 9;
}

message GetTicketsByOwnerIDAndOriginIDRequest {
    string owner_id = 1;
    string origin_id = 2;
}

message GetTicketsByOwnerIDAndOriginIDResponse {
    repeated Subscription subscriptions = 1;
}

message GetUnexpiredUserTicketsByProductsRequest {
    string owner_id = 1;
    repeated string product_ids = 2;
}

message GetUnexpiredUserTicketsByProductsResponse {
    repeated Subscription subscriptions = 1;
}

message GrantAdminSubscriptionRequest {
    string user_id = 1;
    string product_id = 2;
}

message GrantAdminSubscriptionResponse {
}

// Revenue Configs
// =====
message RevenueConfig {
    string id = 1;
    string product_id = 2;
    int32 rev_split_percent = 3;
    google.protobuf.Timestamp start_date = 4;
    google.protobuf.Timestamp created_at = 5;
    google.protobuf.Timestamp updated_at = 6;
    bool is_legacy = 7;
}

message GetRevenueConfigRequest {
    string revenue_config_id = 1;
}

message GetRevenueConfigResponse {
    RevenueConfig revenue_config = 1;
}

message CreateRevenueConfigRequest {
    string product_id = 1;
    int32 rev_split_percent = 2;
    google.protobuf.Timestamp start_date = 3;
    string legacy_id = 4; // optional param to specify the id of the record for migration purposes.
}

message CreateRevenueConfigResponse {
    RevenueConfig revenue_config = 1;
}

message UpdateRevenueConfigRequest {
    string revenue_config_id = 1;
    int32 rev_split_percent = 2;
    google.protobuf.Timestamp start_date = 3;
}

message UpdateRevenueConfigResponse {
    RevenueConfig revenue_config = 1;
}

message DeleteRevenueConfigRequest {
    string revenue_config_id = 1;
}

message DeleteRevenueConfigResponse {
    RevenueConfig revenue_config = 1;
}

message GetRevenueConfigsByProductIDRequest {
    string product_id = 1;
}

message GetRevenueConfigsByProductIDResponse {
    repeated RevenueConfig revenue_configs = 1;
}

message GetActiveRevenueConfigByProductIDRequest {
    string product_id = 1;
    google.protobuf.Timestamp date = 2; // optional param to get the active product for a specific date. default is now.
    bool requires_user_authorization = 3;
    string user_id = 4;
}

message GetActiveRevenueConfigByProductIDResponse {
    RevenueConfig revenue_config = 1;
}

message GetCreatorGiftsBalanceRequest {
    string user_id = 1;
}

message GetCreatorGiftsBalanceResponse {
    int64 balance = 1;
}

message FulfillCreatorGiftsRequest {
    string user_id = 1;
    int32 quantity = 2;
    string origin_id = 3;
}

message FulfillCreatorGiftsResponse {}

message AddCreatorGiftsBalanceRequest {
    string user_id = 1;
    int32 quantity = 2;
}

message AddCreatorGiftsBalanceResponse {
    int32 updated_balance = 1;
}

message DeductCreatorGiftsBalanceRequest {
    string user_id = 1;
    int32 quantity = 2;
}

message DeductCreatorGiftsBalanceResponse {
    int32 updated_balance = 1;
}

message GetTicketsByOriginIDsRequest {
    repeated string origin_ids = 1;
}

message GetTicketsByOriginIDsResponse {
    repeated Subscription subscriptions = 1;
}
