gateway

io.token.proto.gateway /external/src/main/proto/gateway/auth.proto


syntax = "proto3";
package io.token.proto.gateway;
option csharp_namespace = "Tokenio.Proto.Gateway";

import "extensions/field.proto";

// The payload is signed by the client for every request.

// For HTTP communication, the payload consists of some of the HTTP request fields.
// We convert the proto into canonical JSON and sign it.
// https://github.com/tokenio/sdk-js/blob/master/src/http/AuthHeader.js
message HttpAuthPayload {
  string method = 1;       // HTTP method, e.g., "POST"
  string uri_host = 2;     // host, e.g., "api.sandbox.token.io"
  string uri_path = 3;     // path part of URL, e.g., "/aliases"
  string query_string = 4 [(io.token.proto.extensions.field.redact) = true]; // query part of URL, e.g., "tokenId=tt:AMg...bXg5ny:5zKcENpV&offset=null&limit=100"
  string request_body = 5 [(io.token.proto.extensions.field.redact) = true]; // request body, e.g., "{\"memberId\":\"m:Y9GkD...LdEn:5zKtXEAq\"}"
  int64 created_at_ms = 6; // creation time, e.g., "1515710877090"
}

// For gRPC communication, the payload is a serialized protbuf and creation time.
// https://github.com/tokenio/sdk-java/blob/master/lib/src/main/java/io/token/rpc/ClientAuthenticator.java
message GrpcAuthPayload {
  bytes request = 1 [(io.token.proto.extensions.field.redact) = true];
  int64 created_at_ms = 6;
}

io.token.proto.gateway /external/src/main/proto/gateway/gateway.proto


syntax = "proto3";
package io.token.proto.gateway;
option csharp_namespace = "Tokenio.Proto.Gateway";

import "google/api/annotations.proto";
import "grpcbridge/swagger/openapi_v2.proto";

import "account.proto";
import "address.proto";
import "bankinfo.proto";
import "banklink.proto";
import "blob.proto";
import "consent.proto";
import "eidas.proto";
import "alias.proto";
import "member.proto";
import "money.proto";
import "notification.proto";
import "security.proto";
import "submission.proto";
import "subscriber.proto";
import "token.proto";
import "transaction.proto";
import "transfer.proto";
import "transferinstructions.proto";
import "webhook.proto";
import "tsp/bankconfig.proto";
import "extensions/field.proto";
import "extensions/service.proto";
import "extensions/method.proto";

////////////////////////////////////////////////////////////////////////////////////////////////////
// Paging details.
//
message Page {
  string offset = 1;      // Opaque base-64 encoded offset for the client to roundtrip.
  int32 limit = 2;        // Max number of records to return.
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Member registration, key and alias management.
//

message CreateMemberRequest {
  string nonce = 1; // random string; used only to de-duplicate requests.
  io.token.proto.common.member.CreateMemberType member_type = 2;
  string token_request_id = 3; // Optional token request ID, if set the member will be claimed by the TPP initiating the token request.
  string partner_id = 4;
  string realm_id = 5;
}

message CreateMemberResponse {
  string member_id = 1; // newly-created member ID.
}

message RegisterWithEidasRequest {
  io.token.proto.common.eidas.RegisterWithEidasPayload payload = 1; // payload with a certificate
  string signature = 2; // signature of payload signed with the private key of the certificate
}

message RegisterWithEidasResponse {
  string member_id = 1; // ID of a newly-created or already registered with this bank member
  string key_id = 2; // ID of the key that has been added
  string verification_id = 3; // ID of the verification for this certificate
}

message UpdateMemberRequest {
  io.token.proto.common.member.MemberUpdate update = 1;                       // changes
  io.token.proto.common.security.Signature update_signature = 2;              // signature of update field
  repeated io.token.proto.common.member.MemberOperationMetadata metadata = 3; // extra (unsigned) data for aliases
}

message UpdateMemberResponse {
  io.token.proto.common.member.Member member = 1; // updated member structure
}

message GetMemberRequest {
  string member_id = 1; // ID of member to get
}

message GetMemberResponse {
  io.token.proto.common.member.Member member = 1; // member structure
}

message ResolveAliasRequest {
  io.token.proto.common.alias.Alias alias = 1; // alias to resolve

  // for backwards compatibility with older JS clients TODO(RD-2738) remove
  io.token.proto.common.alias.Alias.Type type = 2 [deprecated = true];                    // For example, EMAIL.
  string value = 3 [(io.token.proto.extensions.field.redact) = true, deprecated = true]; // For example, "sandy@example.com"
  string realm  = 4 [deprecated = true];                              // For example, "token"
}

message ResolveAliasResponse {
  io.token.proto.common.token.TokenMember member = 1; // member that owns alias, if any
}

message GetAliasesRequest {}

message GetAliasesResponse {
  repeated io.token.proto.common.alias.Alias aliases = 1;            // verified aliases
  repeated io.token.proto.common.alias.Alias unverified_aliases = 2; // unverified aliases
}

message CompleteVerificationRequest {
  string verification_id = 1; // verification ID
  string code = 2;            // verification code
}

message CompleteVerificationResponse {
  io.token.proto.common.alias.VerificationStatus status = 1;
}

message RetryVerificationRequest {
  string member_id = 1;                        // member ID
  io.token.proto.common.alias.Alias alias = 2; // alias
}

message RetryVerificationResponse {
  string verification_id = 1; // verification ID
}

message GetPairedDevicesRequest {
  option deprecated = true;
}

message GetPairedDevicesResponse {
  option deprecated = true;
  repeated io.token.proto.common.member.Device devices = 1; // linked device info
}

message DeleteMemberRequest {}

message DeleteMemberResponse {}

message NormalizeAliasRequest {
  io.token.proto.common.alias.Alias alias = 1;
}

message NormalizeAliasResponse {
  io.token.proto.common.alias.Alias alias = 1;
}

message SetAppCallbackUrlRequest {
  string app_callback_url = 1; // the custom app call back url
}

message SetAppCallbackUrlResponse {}

message GetRedirectUrlsRequest {}

message GetRedirectUrlsResponse {
  repeated string redirect_urls = 1;
}

message AddRedirectUrlsRequest {
  repeated string redirect_urls = 1;
}

message AddRedirectUrlsResponse {}

message RemoveRedirectUrlsRequest {
  repeated string redirect_urls = 1;
}

message RemoveRedirectUrlsResponse {}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Member account recovery.
//

message BeginRecoveryRequest {
  io.token.proto.common.alias.Alias alias = 1; // alias of member to recover
}

message BeginRecoveryResponse {
  string verification_id = 1; // id to use in later recovery steps
}

message CompleteRecoveryRequest {
  string verification_id = 1;                 // verification id
  string code = 2;                            // verification code (perhaps sent to alias email)
  io.token.proto.common.security.Key key = 3; // new privileged key to use
}

message CompleteRecoveryResponse {
  io.token.proto.common.member.MemberRecoveryOperation recovery_entry = 1;
  io.token.proto.common.alias.VerificationStatus status = 2;
}

message VerifyAliasRequest {
  string verification_id = 1; // verification id
  string code = 2;            // verification code (perhaps sent to alias email)
}

message VerifyAliasResponse {}

message VerifyEidasRequest {
  io.token.proto.common.eidas.VerifyEidasPayload payload = 1; // payload with certificate
  string signature = 2; // signature of payload signed with the private key of the certificate
}

message VerifyEidasResponse {
  io.token.proto.common.eidas.KonsentusVerificationStatus status = 1 [deprecated = true];
  string status_details = 2;
  string verification_id = 3;
  io.token.proto.common.eidas.EidasVerificationStatus eidas_status = 4;
}

message GetEidasVerificationStatusRequest {
  string verification_id = 1;
}

message GetEidasVerificationStatusResponse {
  string alias_value = 1;
  string certificate = 2;
  io.token.proto.common.eidas.KonsentusVerificationStatus status = 3 [deprecated = true];
  string status_details = 4;
  io.token.proto.common.eidas.EidasVerificationStatus eidas_status = 5;
}

message GetEidasCertificateStatusRequest {}

message GetEidasCertificateStatusResponse {
  io.token.proto.common.eidas.EidasCertificateStatus status = 1;
  string certificate = 2;
}

message RecoverEidasRequest {
  io.token.proto.common.eidas.EidasRecoveryPayload payload = 1; // payload with certificate
  string signature = 2; // signature of payload signed with the private key of the certificate
}

message RecoverEidasResponse {
  io.token.proto.common.member.MemberRecoveryOperation recovery_entry = 1;
}

message GetDefaultAgentRequest {}

message GetDefaultAgentResponse {
  string member_id = 1; // ID of the "normal consumer mode" recovery agent
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Member PII/addresses/preferences management.
//

message AddAddressRequest {
  string name = 1;                                                // display name, such as "Office"
  io.token.proto.common.address.Address address = 2;              // shipping address
  io.token.proto.common.security.Signature address_signature = 3; // signature
}

message AddAddressResponse {
  io.token.proto.common.member.AddressRecord address = 1; // new address
}

message GetAddressRequest {
  string address_id = 1; // address ID
}

message GetAddressResponse {
  io.token.proto.common.member.AddressRecord address = 1; // address
}

message GetAddressesRequest {}

message GetAddressesResponse {
  repeated io.token.proto.common.member.AddressRecord addresses = 1; // list of addresses
}

message DeleteAddressRequest {
  string address_id = 1; // address ID
}

message DeleteAddressResponse {}

message SetProfileRequest {
  io.token.proto.common.member.Profile profile = 1; // new profile, picture fields ignored
}

message SetProfileResponse {
  io.token.proto.common.member.Profile profile = 1; // updated profile
}

message GetProfileRequest {
  string member_id = 1; // member ID
}

message GetProfileResponse {
  io.token.proto.common.member.Profile profile = 1; // display information
}

message SetProfilePictureRequest {
  io.token.proto.common.blob.Blob.Payload payload = 1; // image "file"
}

message SetProfilePictureResponse {
}

message GetProfilePictureRequest {
  string member_id = 1;                                     // member ID
  io.token.proto.common.member.ProfilePictureSize size = 2; // ORIGINAL/SMALL/MEDIUM/LARGE
}

message GetProfilePictureResponse {
  io.token.proto.common.blob.Blob blob = 1; // blob with image "file"
}

message SetReceiptContactRequest {
  string member_id = 1;
  io.token.proto.common.member.ReceiptContact contact = 2;
}

message SetReceiptContactResponse {
}

message GetReceiptContactRequest {
  string member_id = 1;
}

message GetReceiptContactResponse {
  io.token.proto.common.member.ReceiptContact contact = 1;
}

message CreateCustomizationRequest {
  io.token.proto.common.blob.Blob.Payload logo = 1;
  map<string, string> colors = 2;
  string consent_text = 3;
  string name = 4;
  string app_name = 5;
}

message CreateCustomizationResponse {
  string customization_id = 1;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Notification service
//

message SubscribeToNotificationsRequest {
  string handler = 1;                           // Who is sending the notification
  map<string, string> handler_instructions = 2; // Available to handler when sending notifications
}

message SubscribeToNotificationsResponse {
  io.token.proto.common.subscriber.Subscriber subscriber = 1; // Represents one subscription
}

message GetSubscribersRequest {}

message GetSubscribersResponse {
  repeated io.token.proto.common.subscriber.Subscriber subscribers = 1; // notification subscriber info
}

message GetSubscriberRequest {
  string subscriber_id = 1; // ID of notification subscriber to get
}

message GetSubscriberResponse {
  io.token.proto.common.subscriber.Subscriber subscriber = 1; // notification subscriber info
}

message UnsubscribeFromNotificationsRequest {
  string subscriber_id = 1; // ID of notification subscriber to unsubscribe
}

message UnsubscribeFromNotificationsResponse {}

message NotifyRequest {
  io.token.proto.common.alias.Alias alias = 1; // alias of member to notify
  io.token.proto.common.notification.NotifyBody body = 2; // notification details
  string realm = 3; // Deprecated
}

message NotifyResponse {
  io.token.proto.common.notification.NotifyStatus status = 1; // was notification accepted?
}

message GetNotificationsRequest {
  Page page = 1; // offset and limit

  // for backwards compatibility with older JS clients TODO(RD-2738) remove
  string offset = 2 [deprecated = true];
  int32 limit = 3 [deprecated = true];
}

message GetNotificationsResponse {
  repeated io.token.proto.common.notification.Notification notifications = 1; // notification details
  string offset = 2; // offset string to get "next page"
}

message GetNotificationRequest {
  string notification_id = 1; // ID of notification to get
}

message GetNotificationResponse {
  io.token.proto.common.notification.Notification notification = 1; // notification details
}

message RequestTransferRequest {
  io.token.proto.common.token.TokenPayload token_payload = 2; // transfer token payload with some values filled in
}

message RequestTransferResponse {
  io.token.proto.common.notification.NotifyStatus status = 1; // was notification accepted?
}

message TriggerStepUpNotificationRequest {
  oneof step_up_type {
    io.token.proto.common.notification.StepUp token_step_up = 1;                  // ask user to endorse token
    io.token.proto.common.notification.BalanceStepUp balance_step_up = 2;         // ask user to approve get-balance
    io.token.proto.common.notification.TransactionStepUp transaction_step_up = 3; // ask user to approve get-transactions
  }
}

message TriggerStepUpNotificationResponse {
  io.token.proto.common.notification.NotifyStatus status = 1; // was notification accepted?
}

message TriggerCreateAndEndorseTokenNotificationRequest {
  string token_request_id = 1;
  io.token.proto.common.notification.AddKey add_key = 2;      // Optional key to add
  io.token.proto.common.member.ReceiptContact contact = 3;    // Optional receipt contact
}

message TriggerCreateAndEndorseTokenNotificationResponse {
  io.token.proto.common.notification.NotifyStatus status = 1; // was notification accepted?
  string notification_id = 2;
}

message TriggerEndorseAndAddKeyNotificationRequest {
  option deprecated = true;         // Use CreateAndEndorseToken instead
  io.token.proto.common.notification.EndorseAndAddKey endorse_and_add_key = 1;
}

message TriggerEndorseAndAddKeyNotificationResponse {
  option deprecated = true;         // Use CreateAndEndorseToken instead
  io.token.proto.common.notification.NotifyStatus status = 1; // was notification accepted?
  string notification_id = 2;
}

message InvalidateNotificationRequest {
  string notification_id = 1;
}

message InvalidateNotificationResponse {
  io.token.proto.common.notification.NotifyStatus status = 1; // was notification accepted?
}

message UpdateNotificationStatusRequest {
  string notification_id = 1;
  io.token.proto.common.notification.Notification.Status status = 2;
}

message UpdateNotificationStatusResponse {}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Bank account management and information access.
//

message LinkAccountsRequest {
  // authorization, normally from bank web site
  io.token.proto.banklink.BankAuthorization bankAuthorization = 1;
}

message LinkAccountsResponse {
  // basic info about newly-linked accounts
  repeated io.token.proto.common.account.Account accounts = 1;
}

message LinkAccountsOauthRequest {
  // OAuth access token, normally from a bank website
  io.token.proto.banklink.OauthBankAuthorization authorization = 1;
}

message LinkAccountsOauthResponse {
  // basic info about newly-linked accounts
  repeated io.token.proto.common.account.Account accounts = 1;
  io.token.proto.banklink.AccountLinkingStatus status = 2;
}

message UnlinkAccountsRequest {
  repeated string account_ids = 1; // IDs of accounts to unlink
}

message UnlinkAccountsResponse {
}

message GetAccountRequest {
  string account_id = 1; // ID of account to get information about
}

message GetAccountResponse {
  io.token.proto.common.account.Account account = 1; // basic account information
}

message GetAccountsRequest {
}

message GetAccountsResponse {
  repeated io.token.proto.common.account.Account accounts = 1; // basic account information
}

message GetBalanceRequest {
  string account_id = 1;
}

message GetBalanceResponse {
  io.token.proto.common.transaction.Balance balance = 1;
  io.token.proto.common.transaction.RequestStatus status = 2;
}

message GetBalancesRequest {
  repeated string account_id = 1;
}

message GetBalancesResponse {
  repeated GetBalanceResponse response = 1;
}

message GetTransactionRequest {
  string account_id = 1;
  string transaction_id = 2;
}

message GetTransactionResponse {
  io.token.proto.common.transaction.Transaction transaction = 1;
  io.token.proto.common.transaction.RequestStatus status = 2;
}

message GetTransactionsRequest {
  string account_id = 1;
  Page page = 2; // Optional paging settings.

  // for backwards compatibility with older JS clients TODO(RD-2738) remove
  string offset = 3 [deprecated = true];
  int32 limit = 4 [deprecated = true];
  // Optional lower bound for a transaction's booking date as returned by the bank, in the format 'YYYY-MM-DD' (e.g. '2016-01-01').
  // If specified, then only transactions whose bank booking date is equal to or later than the given date will be regarded.
  string start_date = 5;
  // Optional upper bound for a transaction's booking date as returned by the bank (= original booking date), in the format 'YYYY-MM-DD' (e.g. '2016-01-01').
  // If specified, then only transactions whose bank booking date is equal to or earlier than the given date will be regarded.
  string end_date = 6;
}

message GetTransactionsResponse {
  repeated io.token.proto.common.transaction.Transaction transactions = 1; // transaction details
  string offset = 2; // Optional offset state for the client to roundtrip.
  io.token.proto.common.transaction.RequestStatus status = 3;
}

message GetStandingOrderRequest {
  string account_id = 1;
  string standing_order_id = 2;
}

message GetStandingOrderResponse {
  io.token.proto.common.transaction.StandingOrder standing_order = 1;
  io.token.proto.common.transaction.RequestStatus status = 2;
}

message GetStandingOrdersRequest {
  string account_id = 1;
  Page page = 2; // Optional paging settings.
}

message GetStandingOrdersResponse {
  repeated io.token.proto.common.transaction.StandingOrder standing_orders = 1;
  string offset = 2; // Optional offset state for the client to roundtrip.
  io.token.proto.common.transaction.RequestStatus status = 3;
}

message ApplyScaRequest {
  repeated string account_id = 1;
}

message ApplyScaResponse {}

message GetDefaultAccountRequest {
  string member_id = 1; // ID of member; must be same as auth'd member
}

message GetDefaultAccountResponse {
  io.token.proto.common.account.Account account = 1; // default account, if any
}

message SetDefaultAccountRequest {
  string member_id = 1;  // ID of member; must be same as auth'd member
  string account_id = 2; // ID of account to set as default
}

message SetDefaultAccountResponse {
}

message ResolveTransferDestinationsRequest {
  string account_id = 1;
}

message ResolveTransferDestinationsResponse {
  repeated io.token.proto.common.transferinstructions.TransferEndpoint destinations = 1 [deprecated=true];
  repeated io.token.proto.common.transferinstructions.TransferDestination transfer_destinations = 2;
}

message ConfirmFundsRequest {
  string account_id = 1;
  io.token.proto.common.money.Money amount = 2;
}

message ConfirmFundsResponse {
  bool funds_available = 1;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Blobs
//

message CreateBlobRequest {
  io.token.proto.common.blob.Blob.Payload payload = 1; // "file" information
}

message CreateBlobResponse {
  string blob_id = 1; // ID of new blob
}

message GetBlobRequest {
  string blob_id = 1; // ID of blob to fetch
}

message GetBlobResponse {
  io.token.proto.common.blob.Blob blob = 1; // "file" information
}

message GetTokenBlobRequest {
  string token_id = 1; // ID of token to use for "permission"
  string blob_id = 2;  // ID of blob to fetch
}

message GetTokenBlobResponse {
  io.token.proto.common.blob.Blob blob = 1; // "file" information
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Token Requests
//

message StoreTokenRequestRequest {
  io.token.proto.common.token.TokenRequestPayload request_payload = 5;
  io.token.proto.common.token.TokenRequestOptions request_options = 6;
}

message StoreTokenRequestResponse {
  io.token.proto.common.token.TokenRequest token_request = 1;
}

message RetrieveTokenRequestRequest {
  string request_id = 1;
}

message RetrieveTokenRequestResponse {
  io.token.proto.common.token.TokenRequest token_request = 1;
  io.token.proto.common.member.Customization customization = 2;
  bool hide_consent = 3;
}

message UpdateTokenRequestRequest {
  string request_id = 1;
  io.token.proto.common.token.TokenRequestOptions request_options = 2;
}

message UpdateTokenRequestResponse {
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Tokens
//

message PrepareTokenRequest {
  io.token.proto.common.token.TokenPayload payload = 1;
  string app_callback_url = 2 [deprecated = true];
}

message PrepareTokenResponse {
  io.token.proto.common.token.TokenPayload resolved_payload = 1;
  io.token.proto.common.token.Policy policy = 2;
}

message CreateTokenRequest {
  io.token.proto.common.token.TokenPayload payload = 1;
  repeated io.token.proto.common.security.Signature signatures = 2;
  string token_request_id = 3; // optional ID of the token request

  // Only useful for HTTP requests
  // specifying type=access in an HTTP request will call CreateAccessToken instead of this endpoint
  // specifying type=transfer in an HTTP request will call CreateTransferToken instead of this endpoint
  // TODO(RD-2738) remove this
  string type = 4 [deprecated = true];
}

message CreateTokenResponse {
  io.token.proto.common.token.Token token = 1;

  // deprecated: used as HTTP response for CreateTransferToken TODO(RD-2738) remove
  io.token.proto.common.token.TransferTokenStatus status = 2 [deprecated = true];
  io.token.proto.common.token.ExternalAuthorizationDetails authorization_details = 3 [deprecated = true];
}

message CreateTransferTokenRequest {
  option deprecated = true; // use CreateTokenRequest instead
  io.token.proto.common.token.TokenPayload payload = 1; // TokenPayload, should have TransferBody
  string token_request_id = 2; // ID of the token request
}

message CreateTransferTokenResponse {
  io.token.proto.common.token.Token token = 1;                                        // new Token
  io.token.proto.common.token.TransferTokenStatus status = 2;                         // success/failure
  io.token.proto.common.token.ExternalAuthorizationDetails authorization_details = 3; // Optional: used when status is FAILURE_EXTERNAL_AUTHORIZATION_REQUIRED
}

message CreateAccessTokenRequest {
  io.token.proto.common.token.TokenPayload payload = 1; // TokenPayload, should have AccessBody
  string token_request_id = 2; // ID of the token request
}

message CreateAccessTokenResponse {
  io.token.proto.common.token.Token token = 1; // new Token
}

message GetTokenRequest {
  string token_id = 1; // ID of Token to fetch
}

message GetTokenResponse {
  io.token.proto.common.token.Token token = 1; // Token
}

message GetActiveAccessTokenRequest {
  string to_member_id = 1; // Member ID of the recipient
}

message GetActiveAccessTokenResponse {
  io.token.proto.common.token.Token token = 1;
}

message GetTokensRequest {
  Type type = 1;          // ACCESS or TRANSFER
  Page page = 2;          // Optional paging settings.
  TokenFilter filter = 3; // optional filter

  enum Type {
    INVALID = 0;
    ACCESS = 1;
    TRANSFER = 2;
  }

  message TokenFilter {
    string source_account_id = 1;      // Transfer Token source account
    string destination_account_id = 2; // Transfer Token destination account
    int64 start_time_ms = 3;           // start time
    int64 end_time_ms = 4;             // end time
    Role role = 5;                     // FROM/TO
    string acting_as_ref_id = 6;       // Optional ref_id of TokenPayload.acting_as

    enum Role {
      ANY = 0;
      FROM = 1;
      TO = 2;
      ISSUER = 3;
    }
  }

  // for backwards compatibility with older JS clients TODO(RD-2738) remove
  string offset = 4 [deprecated = true];
  int32 limit = 5 [deprecated = true];
}

message GetTokensResponse {
  repeated io.token.proto.common.token.Token tokens = 1; // list of Tokens
  string offset = 2;                                     // optional offset state for the client to roundtrip.
}

message EndorseTokenRequest {
  string token_id = 1;                                    // The id of token to endorse
  io.token.proto.common.security.Signature signature = 2; // Signature
}

message EndorseTokenResponse {
  io.token.proto.common.token.TokenOperationResult result = 1; // Success/fail and new token data
}

message CancelTokenRequest {
  string token_id = 1;                                    // The id of token to cancel
  io.token.proto.common.security.Signature signature = 2; // Signature
}

message CancelTokenResponse {
  io.token.proto.common.token.TokenOperationResult result = 1; // Success/fail and new token data
}

message ReplaceTokenRequest {
  message CancelToken {
    string token_id = 1;                                    // The id of token to replace
    io.token.proto.common.security.Signature signature = 2; // Signature canceling old token
  }

  message CreateToken {
    io.token.proto.common.token.TokenPayload payload = 1;           // New token payload
    io.token.proto.common.security.Signature payload_signature = 2; // Optional if endorsement requested.
    string token_request_id = 3;                                    // Optional token request ID
  }

  CancelToken cancel_token = 1;
  CreateToken create_token = 2;
}

message ReplaceTokenResponse {
  io.token.proto.common.token.TokenOperationResult result = 1; // Success/fail and new token data
}

message SignTokenRequestStateRequest {
  io.token.proto.common.token.TokenRequestStatePayload payload = 1;
  string token_request_id = 2;
}

message SignTokenRequestStateResponse {
  io.token.proto.common.security.Signature signature = 1;
}

message GetTokenRequestResultRequest {
  string token_request_id = 1;
}

message GetTokenRequestResultResponse {
  string token_id = 1;
  io.token.proto.common.security.Signature signature = 2;
  string transfer_id = 3;
}

message GetAuthRequestPayloadRequest {
  string auth_request_id = 1;
}

message GetAuthRequestPayloadResponse {
  io.token.proto.common.token.TokenPayload payload = 1;
  string callback_url = 2;
}

message StoreLinkingRequestRequest {
  string callback_url = 1;
  string token_request_id = 2;
}

message StoreLinkingRequestResponse {
  string linking_request_id = 1;
}

message GetLinkingRequestRequest {
  string linking_request_id = 1;
}

message GetLinkingRequestResponse {
  string member_id = 1;
  string callback_url = 2;
  io.token.proto.common.token.TokenRequest token_request = 3;
}

message SetTokenRequestTransferDestinationsRequest {
  string token_request_id = 1;
  repeated io.token.proto.common.transferinstructions.TransferDestination transfer_destinations = 2;
}

message SetTokenRequestTransferDestinationsResponse {}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Transfers.
//

message CreateTransferRequest {
  io.token.proto.common.transfer.TransferPayload payload = 1;     // Desired transfer spec
  io.token.proto.common.security.Signature payload_signature = 2; // Signature
}

message CreateTransferResponse {
  io.token.proto.common.transfer.Transfer transfer = 1; // Resulting transfer spec
  io.token.proto.common.token.ExternalAuthorizationDetails authorization_details = 2; // Optional: used when transfer status is PENDING_EXTERNAL_AUTHORIZATION
}

message CreateStandingOrderRequest {
  string token_id = 1;
}

message CreateStandingOrderResponse {
  io.token.proto.common.submission.StandingOrderSubmission submission = 1; // Resulting standing order submission
  io.token.proto.common.token.ExternalAuthorizationDetails authorization_details = 2; // Optional: used when transfer status is PENDING_EXTERNAL_AUTHORIZATION
}

message CreateBulkTransferRequest {
  string token_id = 1;
}

message CreateBulkTransferResponse {
  io.token.proto.common.transfer.BulkTransfer transfer = 1; // Resulting bulk transfer
}

message GetTransferRequest {
  string transfer_id = 1; // transfer to get
}

message GetTransferResponse {
  io.token.proto.common.transfer.Transfer transfer = 1; // Transfer spec
}

message GetStandingOrderSubmissionRequest {
  string submission_id = 1;
}

message GetStandingOrderSubmissionResponse {
  io.token.proto.common.submission.StandingOrderSubmission submission = 1;
}

message GetTransfersRequest {
  string token_id = 1;       // Deprecated, use filter.token_id instead
  Page page = 2;             // Optional paging settings
  TransferFilter filter = 3; // Filter to restrict query

  message TransferFilter {
    string token_id = 1;                                                        // Optional token ID
    int64 start_time_ms = 2;                                                    // Optional time range
    int64 end_time_ms = 3;                                                      // Optional time range
    io.token.proto.common.transaction.TransactionStatus transaction_status = 4; // Optional status
    Role role = 5;                                                              // Role. Default: ANY
    string acting_as_ref_id = 6;                                                // Optional ref_id of TokenPayload.acting_as

    enum Role {
      ANY = 0;
      PAYER = 1;
      PAYEE = 2;
    }
  }

  // for backwards compatibility with older JS clients TODO(RD-2738) remove
  string offset = 4 [deprecated = true];
  int32 limit = 5 [deprecated = true];
}

message GetTransfersResponse {
  repeated io.token.proto.common.transfer.Transfer transfers = 1; // List of transfers.
  string offset = 2;                                              // Optional offset state for the client to roundtrip.
}

message GetStandingOrderSubmissionsRequest {
  Page page = 1; // Optional paging settings
  StandingOrderSubmissionFilter filter = 2; // Filter to restrict query

  message StandingOrderSubmissionFilter {
    int64 start_time_ms = 1; // Optional time range
    int64 end_time_ms = 2; // Optional time range
    io.token.proto.common.submission.SubmissionStatus submission_status = 3; // Optional status
    Role role = 4; // Role. Default: ANY
    string acting_as_ref_id = 5; // Optional ref_id of TokenPayload.acting_as

    enum Role {
      ANY = 0;
      PAYER = 1;
      PAYEE = 2;
    }
  }
}

message GetStandingOrderSubmissionsResponse {
  repeated io.token.proto.common.submission.StandingOrderSubmission submissions = 1;
  string offset = 2;                                              // Optional offset state for the client to roundtrip.
}

message GetBulkTransferRequest {
  string bulk_transfer_id = 1;

}

message GetBulkTransferResponse {
  io.token.proto.common.transfer.BulkTransfer bulk_transfer = 1;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Bank Information Endpoints.
//

message GetBanksCountriesRequest {
  io.token.proto.common.bank.BankFilter filter = 1 [deprecated = true];     // DEPRECATED. Use fields below. (Optional) Filter by criteria in bank filter. Results must match all filter criteria.

  repeated string ids = 2;
  string search = 3;
  string country = 4 [deprecated = true]; // Use countries instead
  string provider = 5 [deprecated = true]; // Use providers instead
  string destination_country = 6 [deprecated = true]; // Use countries instead
  string tpp_id = 7;
  string bank_code = 9;
  repeated string countries = 10;
  repeated string providers = 11;
  io.token.proto.common.bank.BankFeatures bank_features = 12;
  string member_id = 13; // (Optional) If specified with a TSP member_id, return the countries which the member's configured banks are located in.
}

message GetBanksCountriesResponse {
  repeated string countries = 1;
}

message GetBanksRequest {
  io.token.proto.common.bank.BankFilter filter = 9 [deprecated = true];     // DEPRECATED. Use fields below. (Optional) Filter by criteria in bank filter. Results must match all filter criteria.

  // Paging
  int32 page = 4;                     // Result page to retrieve. Defaults to 1 if not specified
  int32 per_page = 5;                 // Maximum number of records per page. Can be at most 200. Defaults to 200 if not specified.
  string sort = 6;                    // The key to sort the results. Could be one of: name, provider and country. Defaults to name if not specified.
  string member_id = 15;              // (Optional) If specified with a TSP member_id, return the banks which the member is configured with.

  string country = 3 [deprecated = true];              // DEPRECATED. Use countries instead. If specified, return banks whose 'country' matches the given ISO 3166-1 alpha-2 country code (case-insensitive)
  repeated string ids = 1;            // If specified, return banks whose 'id' matches any one of the given ids (case-insensitive). Can be at most 1000.
  string search = 2;                  // If specified, return banks whose 'name' or 'identifier' contains the given search string (case-insensitive)
  string provider = 7 [deprecated = true];             // DEPRECATED. Use providers instead. (Optional) If specified, return banks whose 'provider' matches the provider (case-insensitive)
  string tpp_id = 8;                  // (Optional) If specified, return banks which are integrated with the TPP
  string destination_country = 10 [deprecated = true]; // DEPRECATED. Use countries instead. (Optional) Filter for banks that support sending to the destination country.
  repeated string providers = 11;     // (Optional) Filter for banks whose 'provider' matches the providers (case-insensitive)
  string bank_code = 12;              // (Optional) Filter for banks whose bank code matches the given value (BLZ for German banks only)
  repeated string countries = 13;
  io.token.proto.common.bank.BankFeatures bank_features = 14;
}

message GetBanksResponse {
  repeated io.token.proto.common.bank.Bank banks = 1; // List of "link-able" banks
  io.token.proto.common.bank.Paging paging = 2;       // Paging info
}

message GetBankInfoRequest {
  string bank_id = 1; // Bank id
}

message GetBankInfoResponse {
  io.token.proto.common.bank.BankInfo info = 1; // Linking info
}

message GetBankAuthUrlRequest {
  string bank_id = 1;
  string token_request_id = 2;
}

message GetBankAuthUrlResponse {
  string url = 1;
}

message GetDirectBankAuthUrlRequest {
  option deprecated = true; // Backward compatibility for web-app
  string bank_id = 1;
  string token_request_id = 2;
}

message GetDirectBankAuthUrlResponse {
  option deprecated = true; // Backward compatibility for web-app
  string url = 1;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// TSP client only requests
//

message OnBankAuthCallbackRequest {
  string bank_id = 1; // the bank id of the callback. Typically extracted from the path component of the callback url
  string query = 2;   // the query component of the callback url
}

message OnBankAuthCallbackResponse {
  string token_request_id = 1;
}

message GetExternalMetadataRequest {
  string token_request_id = 1;
}

message GetExternalMetadataResponse {
  io.token.proto.common.bank.OpenBankingStandard standard = 1;
  string consent = 2;
}

message StoreBankConfigRequest {
  string member_id = 1;
  string bank_id = 2;
  io.token.proto.common.tsp.bankconfig.BankConfig bank_config = 3;
}

message StoreBankConfigResponse {
}

message GetBankConfigRequest {
  string member_id = 1;
  string bank_id = 2;
}

message GetBankConfigResponse {
  io.token.proto.common.tsp.bankconfig.BankConfig bank_config = 1;
}

message GetBankConfigsRequest {
  string member_id = 1;
}

message GetBankConfigsResponse {
  map<string, io.token.proto.common.tsp.bankconfig.BankConfig> bank_configs = 1;
}

message DeleteBankConfigRequest {
  string member_id = 1;
  string bank_id = 2;
}

message DeleteBankConfigResponse {
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Bank member only requests.
//
message GetMemberInfoRequest {
  string member_id = 1;
}

message GetMemberInfoResponse {
  io.token.proto.common.member.MemberInfo member_info = 1; // Member info
}

message GetConsentRequest {
  string bank_id = 1;
  string consent_id = 2;
}

message GetConsentResponse {
  io.token.proto.common.consent.Consent consent = 1;
}

message GetConsentsRequest {
  string bank_id = 1;
  io.token.proto.common.account.BankAccount bank_account = 2;
  Page page = 3;
}

message GetConsentsResponse {
  repeated io.token.proto.common.consent.Consent consents = 1;
  string offset = 2;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Testing API calls
//

message CreateTestBankAccountRequest {
  io.token.proto.common.money.Money balance = 1; // starting balance
}

message CreateTestBankAccountResponse {
  io.token.proto.banklink.OauthBankAuthorization authorization = 2; // authorization usable with linkAccounts
}

message GetTestBankNotificationRequest {
  string subscriber_id = 1;   // subscriber ID
  string notification_id = 2; // notification ID
}

message GetTestBankNotificationResponse {
  io.token.proto.common.notification.Notification notification = 1; // notification
}

message GetTestBankNotificationsRequest {
  string subscriber_id = 1; // subscriber ID
}

message GetTestBankNotificationsResponse {
  repeated io.token.proto.common.notification.Notification notifications = 1; // list of notifications
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Report
//

message GetTppPerformanceReportRequest {
  string bank_id = 1;
  int32 days_back = 2;
}

message GetTppPerformanceReportResponse {
  repeated PerformanceSummary summaries = 1;

  message PerformanceSummary {
    string date = 1;
    TppType tpp_type = 2;
    double p50_latency = 3 [deprecated = true];
    double p75_latency = 4 [deprecated = true];
    double p90_latency = 5 [deprecated = true];
    double p95_latency = 6 [deprecated = true];
    double p99_latency = 7 [deprecated = true];
    double p999_latency = 8 [deprecated = true];
    double error_rate = 9;
    int64 error_count = 10;
    int64 request_count = 11;
    string tpp_id = 12;
    double average_latency = 13;

    enum TppType {
      AISP = 0;
      PISP = 1;
      CBPII = 2;
    }
  }
}

message GetAvailabilityReportRequest {
  string bank_id = 1;
  int32 days_back = 2;
}

message GetAvailabilityReportResponse {
  repeated AvailabilitySummary summaries = 1;

  message AvailabilitySummary {
    string date = 1;
    double token_uptime_pct = 2;
    double bank_uptime_pct = 3;
  }
}

message GetTppAccessReportRequest {
  string bank_id = 1;
  int32 days_back = 2;
}

message GetTppAccessReportResponse {
  repeated TppAccessSummary summaries = 1;

  message TppAccessSummary {
    string date = 1;
    TppType tppType = 2;
    int64 total = 3;

    enum TppType {
      AISP = 0;
      PISP = 1;
      CBPII = 2;
    }
  }
}

message GetTppRequestsReportRequest {
  string tpp_member_id = 1;
  int64 from_date_ms = 2;         // UTC time in millis.
  int64 to_date_ms = 3;           // UTC time in millis.
}

message GetTppRequestsReportResponse {
  repeated TppRequestsSummary summaries = 1;

  message TppRequestsSummary {
    int64 ais_count = 1;
    int64 pis_count = 2;
    string date = 3;
  }
}

message GetBankDowntimeReportRequest {
  string bank_id = 1;
  int32 days_back = 2;
}

message GetBankDowntimeReportResponse {
  repeated BankDowntimeSummary summaries = 1;

  message BankDowntimeSummary {
    string bank_name = 1;
    RequestType request_type = 2;
    string start_time = 3;
    string end_time = 4;
    enum RequestType {
      INVALID = 0;
      AIS = 1;
      PIS = 2;
    }
  }
}

message GetBankStatusRequest {
  string bank_id = 1;
}

message GetBankStatusResponse {
  BankStatus bank_status = 1;

  message BankStatus {
    string bank_name = 1;
    string ais_status = 2;
    string pis_status = 3;
    string last_updated_at = 4;
  }
}

message GetBanksStatusRequest {}

message GetBanksStatusResponse {
  repeated BankStatus banks_status = 1;

  message BankStatus {
    string bank_id = 1;
    string ais_status = 2;
    string pis_status = 3;
    string last_updated_at = 4;
  }
}

message GetServiceHealthRequest {}

message GetServiceHealthResponse {}

////////////////////////////////////////////////////////////////////////////////////////////////////
// RESTful Bank API
//
message CreateBankUserRequest {
  string bank_id = 1;
}

message CreateBankUserResponse {
  string user_id = 1;
}

message DeleteBankUserRequest {
  string bank_id = 1;
  string user_id = 2;
}

message DeleteBankUserResponse {}

message RetrieveConsentRequestRequest {
  string bank_id = 1;
  string request_id = 2;
}

message RetrieveConsentRequestResponse {
  io.token.proto.common.consent.ConsentRequest consent_request = 1;
}

message CreateConsentRequest {
  string bank_id = 1;
  io.token.proto.common.consent.CreateConsent params = 2;
}

message CreateConsentResponse {
  io.token.proto.common.consent.Consent consent = 1;
}

message CancelConsentRequest {
  string bank_id = 1;
  string consent_id = 2;
}

message CancelConsentResponse {}

message GetActiveAccessConsentsRequest {
  string bank_id = 1;
  string user_id = 2;
  Page page = 3;
}

message GetActiveAccessConsentsResponse {
  repeated io.token.proto.common.consent.Consent consents = 1;
  string offset = 2;
}

message GetAccessConsentsRequest {
  string bank_id = 1;
  string user_id = 2;
  Page page = 3;
  io.token.proto.common.consent.StatusFilter status = 4;
}

message GetAccessConsentsResponse {
  repeated io.token.proto.common.consent.Consent consents = 1;
  string offset = 2;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Partner endpoints
//
message EnableMemberRequest {
  string member_id = 1;
}

message EnableMemberResponse {}

message DisableMemberRequest {
  string member_id = 1;
}

message DisableMemberResponse {}

message GetMembersUnderPartnerRequest {
  Page page = 1;
}

message GetMembersUnderPartnerResponse {
  repeated io.token.proto.common.member.MemberInfo members = 1;
  string offset = 2; // Optional offset state for the client to roundtrip
}

message SetDefaultCustomizationRequest {
  string customization_id = 1;
}

message SetDefaultCustomizationResponse {}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Webhook endpoints
//

message SetWebhookConfigRequest {
  io.token.proto.common.webhook.Webhook.Config config = 1;
}

message SetWebhookConfigResponse {}

message GetWebhookConfigRequest {}

message GetWebhookConfigResponse {
  io.token.proto.common.webhook.Webhook.Config config = 1;
}

message DeleteWebhookConfigRequest {}

message DeleteWebhookConfigResponse {}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Gateway Service.
//
service GatewayService {
  option (grpcbridge.swagger.root) = {
      info: {
          title: "Token API"
          description: "Token REST API."
          version: "1.0.0"
      };
      host: "api.token.io"
      basePath: "/v1"
  };

  ////////////////////////////////////////////////////////////////////////////////////////////////////
  // Member registration, key and alias management.
  //

  // Create a member. Mints a member ID; newly-created member does not yet
  // have keys, alias, or anything other than an ID.
  // Used by createMember, https://developer.token.io/sdk/#create-a-member
  // (SDK's createMember also uses UpdateMember rpc).
  rpc CreateMember (CreateMemberRequest) returns (CreateMemberResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        post: "/members"
        body: "*"
    };
  }

  // Creates a business member under realm of a bank with an EIDAS alias (with value equal to the
  // authNumber from the certificate) and a public key taken from the certificate.
  // Then onboards it with the provided certificate.
  // A successful onboarding includes verifying the member and the alias and adding permissions
  // based on the certificate.
  // The call is idempotent, so if a member under this realm and with the same verified alias
  // already exists, it returns an ID of the existing member, an ID of the registered eidas key and
  // an ID of the verification for this certificate. If you wish to submit another certificate
  // for an existing member, please use VerifyEidas call instead.
  // Note, that the call is asynchronous and the newly created member might not be onboarded at the
  // time the call returns. You can check the verification status using GetEidasVerificationStatus
  // call with the verification_id returned by this call.
  rpc RegisterWithEidas (RegisterWithEidasRequest) returns (RegisterWithEidasResponse) {
    option (grpcbridge.swagger.operation) = {
      tags: "eidas"
      summary: "Create and register a business member with an eIDAS certificate."
      description: "Create and asynchronously [onboard](https://developer.token.io/token_rest_api_doc/content/k-eidas/member_onboarding.htm?tocpath=eIDAS-related%20REST%20API%20Calls%20for%20Certificate%20Registration%20and%20Verification%7CMember%20Onboarding) "
                   "a business member under realm of a bank.<br>"
                   "**See also:** <br>"
                   "[RegisterWithEidas](https://developer.token.io/token_rest_api_doc/content/k-eidas/register_with_eidas.htm)<br>"
                   "[Certificate and payload signature format](https://developer.token.io/token_rest_api_doc/content/k-eidas/member_onboarding.htm?tocpath=eIDAS-related%20REST%20API%20Calls%20for%20Certificate%20Registration%20and%20Verification%7CMember%20Onboarding#Certific)"
    };
    option (google.api.http) = {
      put: "/eidas/register"
      body: "*"
    };
  }

  // Apply member updates. Used when adding/removing keys, aliases to/from member.
  // These updates require a signature.
  // See how Java SDK's Client.updateMember uses it:
  //   https://developer.token.io/sdk/javadoc/io/token/rpc/Client.html#updateMember-io.token.proto.common.member.MemberProtos.Member-java.util.List-
  // See how JS SDK's AuthHttpClient._memberUpdate uses it:
  //   https://developer.token.io/sdk/esdoc/class/src/http/AuthHttpClient.js~AuthHttpClient.html#instance-method-_memberUpdate
  rpc UpdateMember (UpdateMemberRequest) returns (UpdateMemberResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        post: "/members/{update.member_id}/updates"
        body: "*"
    };
    option (io.token.proto.extensions.service.rate_limit) = {
      selector: [
        {key: "resolve-alias-remote-address", path: "{REMOTE_ADDRESS}"},
        {key: "resolve-alias-source-developer", path: "{DEVELOPER_ID}"}
      ]
    };
  }

  // Get information about a member
  rpc GetMember (GetMemberRequest) returns (GetMemberResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        get: "/members/{member_id}"
    };
  }

  // set profile information (display name)
  // Ignores picture fields; use SetProfilePicture for those.
  // https://developer.token.io/sdk/#profile
  rpc SetProfile (SetProfileRequest) returns (SetProfileResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        put: "/profile"
        body: "*"
    };
  }

  // get a member's profile (display information)
  // https://developer.token.io/sdk/#profile
  rpc GetProfile (GetProfileRequest) returns (GetProfileResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        get: "/members/{member_id}/profile"
    };
  }

  // upload an image to use as auth'd member's profile picture
  // Automatically creates smaller sizes; this works best with square images.
  // https://developer.token.io/sdk/#profile
  rpc SetProfilePicture (SetProfilePictureRequest) returns (SetProfilePictureResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        put: "/profilepicture"
        body: "*"
    };
  }

  // Get member's profile picture (can also use GetBlob with a blob ID from profile)
  // https://developer.token.io/sdk/#profile
  rpc GetProfilePicture (GetProfilePictureRequest) returns (GetProfilePictureResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        get: "/members/{member_id}/profilepicture/{size}"
    };
  }

  // Set a member's contact (e.g. email) for receipt delivery
  rpc SetReceiptContact (SetReceiptContactRequest) returns (SetReceiptContactResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        put: "/receipt-contact"
        body: "*"
    };
  }

  // Get a member's email address for receipts
  rpc GetReceiptContact (GetReceiptContactRequest) returns (GetReceiptContactResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        get: "/receipt-contact"
    };
  }

  // Get ID of member that owns an alias, if any.
  // https://developer.token.io/sdk/#aliases
  rpc ResolveAlias (ResolveAliasRequest) returns (ResolveAliasResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
      get: "/resolve-alias"
    };
    option (io.token.proto.extensions.service.rate_limit) = {
      selector: [
        {key: "resolve-alias-remote-address", path: "{REMOTE_ADDRESS}"},
        {key: "resolve-alias-source-developer", path: "{DEVELOPER_ID}"}
      ]
    };
  }

  // Get the auth'd member's aliases.
  // https://developer.token.io/sdk/#aliases
  rpc GetAliases (GetAliasesRequest) returns (GetAliasesResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
      get: "/aliases"
    };
  }

  // Use a verification code
  rpc CompleteVerification (CompleteVerificationRequest) returns (CompleteVerificationResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
      get: "/verifications/{verification_id}/complete/{code}"
    };
  }

  // Retries verification. For example, if verifying an email alias,
  // re-sends verification-code email to the email address.
  rpc RetryVerification (RetryVerificationRequest) returns (RetryVerificationResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
      post: "/verifications"
      body: "*"
    };
    option (io.token.proto.extensions.service.rate_limit) = {
      selector: [
        {key: "resolve-alias-remote-address", path: "{REMOTE_ADDRESS}"},
        {key: "resolve-alias-source-developer", path: "{DEVELOPER_ID}"}
      ]
    };
  }

  // Get auth'd members paired devices (as created by provisionDevice)
  rpc GetPairedDevices (GetPairedDevicesRequest) returns (GetPairedDevicesResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option deprecated = true;
    option (google.api.http) = {
      get: "/members/devices"
    };
  }

  rpc DeleteMember (DeleteMemberRequest) returns (DeleteMemberResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
      delete: "/members"
    };
  }

  rpc NormalizeAlias (NormalizeAliasRequest) returns (NormalizeAliasResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        get: "/aliases/normalize/{alias.type}/{alias.value}/{alias.realm}"
    };
  }

  rpc SetAppCallbackUrl (SetAppCallbackUrlRequest) returns (SetAppCallbackUrlResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        put: "/members/app-callback-url"
        body: "*"
    };
  }

  rpc GetRedirectUrls (GetRedirectUrlsRequest) returns (GetRedirectUrlsResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
      get: "/redirect-urls"
    };
  }

  rpc AddRedirectUrls (AddRedirectUrlsRequest) returns (AddRedirectUrlsResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
      put: "/redirect-urls"
      body: "*"
    };
  }

  rpc RemoveRedirectUrls (RemoveRedirectUrlsRequest) returns (RemoveRedirectUrlsResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
      delete: "/redirect-urls"
      body: "*"
    };
  }

  ////////////////////////////////////////////////////////////////////////////////////////////////////
  // Member account recovery
  //

  // Begin member recovery. If the member has a "normal consumer" recovery rule,
  // this sends a recovery message to their email address.
  // https://developer.token.io/sdk/#recovery
  rpc BeginRecovery (BeginRecoveryRequest) returns (BeginRecoveryResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
      post: "/recovery/verifications"
      body: "*"
    };
    option (io.token.proto.extensions.service.rate_limit) = {
      selector: [
        {key: "resolve-alias-remote-address", path: "{REMOTE_ADDRESS}"},
        {key: "resolve-alias-source-developer", path: "{DEVELOPER_ID}"}
      ]
    };
  }

  // Complete member recovery.
  // https://developer.token.io/sdk/#recovery
  rpc CompleteRecovery (CompleteRecoveryRequest) returns (CompleteRecoveryResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
      post: "/recovery/verifications/{verification_id}/complete/{code}"
      body: "*"
    };
  }

  // Verify an alias
  rpc VerifyAlias (VerifyAliasRequest) returns (VerifyAliasResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
      put: "/verifications/{verification_id}/complete/{code}"
      body: "*"
    };
  }

  // Verify an eidas
  rpc VerifyEidas (VerifyEidasRequest) returns (VerifyEidasResponse) {
    option (grpcbridge.swagger.operation) = {
      tags: "eidas"
      summary: "Submit an eIDAS certificate for verification."
      description: "Submit an eIDAS certificate for a business member registered under the realm of a bank.<br>"
                   "**See also:**<br>"
                   "[VerifyEidas](https://developer.token.io/token_rest_api_doc/content/k-eidas/verify_eidas.htm)<br>"
                   "[Certificate and payload signature format](https://developer.token.io/token_rest_api_doc/content/k-eidas/member_onboarding.htm?tocpath=eIDAS-related%20REST%20API%20Calls%20for%20Certificate%20Registration%20and%20Verification%7CMember%20Onboarding#Certific)"
    };
    option (google.api.http) = {
      post: "/eidas/verifications"
      body: "*"
      additional_bindings {
        put: "/verifications/eidas"
        body: "*"
      }
    };
  }

  rpc GetEidasVerificationStatus (GetEidasVerificationStatusRequest) returns (GetEidasVerificationStatusResponse) {
    option (grpcbridge.swagger.operation) = {
      tags: "eidas"
      summary: "Get a status of an eIDAS verification."
      description: "Given a verificationId, get a status of the eIDAS verification together with submitted certificate and alias value.<br>"
                   "**See also:**<br>"
                   "[GetEidasVerificationStatus](https://developer.token.io/token_rest_api_doc/content/k-eidas/get_eidas_verification_status.htm)<br>"
    };
    option (google.api.http) = {
      get: "/eidas/verifications/{verification_id}"
    };
  }

  rpc getEidasCertificateStatus (GetEidasCertificateStatusRequest) returns (GetEidasCertificateStatusResponse) {
    option (grpcbridge.swagger.operation) = {
      tags: "eidas"
      summary: "Get a status of the current eIDAS certificate."
      description: "Get a status of an eIDAS certificate on file together with the certificate itself."
                   "**See also:**<br>"
                   "[GetEidasCertificateStatus](https://developer.token.io/token_rest_api_doc/content/k-eidas/get_eidas_certificate.htm)<br>"
    };
    option (google.api.http) = {
      get: "/eidas/status"
    };
  }

  // Recover an eidas-verified member
  rpc RecoverEidasMember (RecoverEidasRequest) returns (RecoverEidasResponse) {
    option (grpcbridge.swagger.operation) = {
      tags: "eidas"
      summary: "Recover an eIDAS-verified member"
      description: "Recover a business member that was onboarded with an eIDAS certificate under a realm of a bank."
                   "**See also:**<br>"
                   "[RecoverEidasMember](https://developer.token.io/token_rest_api_doc/content/k-eidas/recover_eidas_member.htm)<br>"
                   "[Certificate and payload signature format](https://developer.token.io/token_rest_api_doc/content/k-eidas/member_onboarding.htm?tocpath=eIDAS-related%20REST%20API%20Calls%20for%20Certificate%20Registration%20and%20Verification%7CMember%20Onboarding#Certific)"
    };
    option (google.api.http) = {
      post: "/eidas/recovery/operations"
      body: "*"
    };
  }

  // Get member ID of "normal consumer" recovery agent.
  // https://developer.token.io/sdk/#recovery
  rpc GetDefaultAgent (GetDefaultAgentRequest) returns (GetDefaultAgentResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
      get: "/recovery/defaults/agent"
    };
  }

  ////////////////////////////////////////////////////////////////////////////////////////////////////
  // Member addresses and preferences
  //

  // Add a shipping address
  // https://developer.token.io/sdk/#address
  rpc AddAddress (AddAddressRequest) returns (AddAddressResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option deprecated = true;
    option (google.api.http) = {
        post: "/addresses"
        body: "*"
    };
  }

  // Get one of the auth'd member's shipping addresses
  // https://developer.token.io/sdk/#address
  rpc GetAddress (GetAddressRequest) returns (GetAddressResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option deprecated = true;
    option (google.api.http) = {
        get: "/addresses/{address_id}"
    };
  }

  // Get all of the auth'd member's shipping addresses
  // https://developer.token.io/sdk/#address
  rpc GetAddresses (GetAddressesRequest) returns (GetAddressesResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option deprecated = true;
    option (google.api.http) = {
        get: "/addresses"
    };
  }

  // Remove one of the auth'd member's shipping addresses
  // https://developer.token.io/sdk/#address
  rpc DeleteAddress (DeleteAddressRequest) returns (DeleteAddressResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option deprecated = true;
    option (google.api.http) = {
        delete: "/addresses/{address_id}"
    };
  }

  // Set Customization
  // https://developer.token.io/sdk/#customization
  rpc CreateCustomization (CreateCustomizationRequest) returns (CreateCustomizationResponse) {
    option (grpcbridge.swagger.operation) = {
        tags: "requests"
        summary: "Create a customization"
        description: "Creates a customization for a white-labelled web app"
    };
    option (google.api.http) = {
        post: "/customization"
        body: "*"
    };
  }

  ////////////////////////////////////////////////////////////////////////////////////////////////////
  // Devices for notification service
  //

  // subscribe member to notifications
  // https://developer.token.io/sdk/#notifications
  rpc SubscribeToNotifications (SubscribeToNotificationsRequest) returns (SubscribeToNotificationsResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        post: "/subscribers"
        body: "*"
    };
  }

  // get member's notification subscriber[s]
  // https://developer.token.io/sdk/#notifications
  rpc GetSubscribers (GetSubscribersRequest) returns (GetSubscribersResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        get: "/subscribers"
    };
  }

  // get one of a member's notification subscribers
  // https://developer.token.io/sdk/#notifications
  rpc GetSubscriber (GetSubscriberRequest) returns (GetSubscriberResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        get: "/subscribers/{subscriber_id}"
    };
  }

  // unsubscribe one of a member's subscribers from notifications
  // https://developer.token.io/sdk/#notifications
  rpc UnsubscribeFromNotifications (UnsubscribeFromNotificationsRequest) returns (UnsubscribeFromNotificationsResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        delete: "/subscribers/{subscriber_id}"
    };
  }

  // send a notification
  // https://developer.token.io/sdk/#notifications
  rpc Notify (NotifyRequest) returns (NotifyResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        post: "/notify"
        body: "*"
    };
    option (io.token.proto.extensions.service.rate_limit) = {
      selector: [
        {key: "notify-source-ip", path: "{REMOTE_ADDRESS}"},
        {key: "notify-source-developer", path: "{DEVELOPER_ID}"}
      ]
    };
  }

  // get notifications
  // https://developer.token.io/sdk/#polling-for-notifications
  rpc GetNotifications (GetNotificationsRequest) returns (GetNotificationsResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        get: "/notifications"
    };
  }

  // get one particular notification
  // https://developer.token.io/sdk/#polling-for-notifications
  rpc GetNotification (GetNotificationRequest) returns (GetNotificationResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        get: "/notifications/{notification_id}"
    };
  }

  // send transfer-request notification
  // https://developer.token.io/sdk/#request-payment
  rpc RequestTransfer (RequestTransferRequest) returns (RequestTransferResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        post: "/request-transfer"
        body: "*"
    };
    option (io.token.proto.extensions.service.rate_limit) = {
      selector: [
        {key: "notify-source-ip", path: "{REMOTE_ADDRESS}"},
        {key: "notify-source-developer", path: "{DEVELOPER_ID}"}
      ]
    };
  }

  // send step-up (approve with higher-privilege key) request notification
  rpc TriggerStepUpNotification (TriggerStepUpNotificationRequest) returns (TriggerStepUpNotificationResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        post: "/notify/stepup"
        body: "*"
    };
  }

  // send endorse and add key notification (approve with higher-privilege key)
  rpc TriggerEndorseAndAddKeyNotification (TriggerEndorseAndAddKeyNotificationRequest) returns (TriggerEndorseAndAddKeyNotificationResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option deprecated = true;         // Use CreateAndEndorseToken instead
    option (google.api.http) = {
        post: "/notify/endorse-and-add-key"
        body: "*"
    };
  }

  // send create and endorse token notification
  rpc TriggerCreateAndEndorseTokenNotification (TriggerCreateAndEndorseTokenNotificationRequest) returns (TriggerCreateAndEndorseTokenNotificationResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        post: "/notify/create-and-endorse-token"
        body: "*"
    };
  }

  // send invalidate notification
  rpc InvalidateNotification (InvalidateNotificationRequest) returns (InvalidateNotificationResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        post: "/notify/invalidate-notification"
        body: "*"
    };
  }

  // update notification status
  rpc UpdateNotificationStatus (UpdateNotificationStatusRequest) returns (UpdateNotificationStatusResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        put: "/notifications/{notification_id}/status"
        body: "*"
    };
  }

  ////////////////////////////////////////////////////////////////////////////////////////////////////
  // Bank accounts.
  //

  // associate bank accounts with member
  // https://developer.token.io/sdk/#link-a-bank-account
  rpc LinkAccounts (LinkAccountsRequest) returns (LinkAccountsResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        post: "/accounts"
        body: "*"
    };
    option (io.token.proto.extensions.method.kafka_topic) = "account";
  }

  // associate bank accounts with member
  // https://developer.token.io/sdk/#link-a-bank-account
  rpc LinkAccountsOauth (LinkAccountsOauthRequest) returns (LinkAccountsOauthResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        post: "/bank-accounts"
        body: "*"
    };
    option (io.token.proto.extensions.method.kafka_topic) = "account";
  }

  // un-associate bank accounts with member
  // https://developer.token.io/sdk/#link-a-bank-account
  rpc UnlinkAccounts (UnlinkAccountsRequest) returns (UnlinkAccountsResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        delete: "/accounts"
        body: "*"
    };
    option (io.token.proto.extensions.method.kafka_topic) = "account";
  }

  // get info about one linked account
  // https://developer.token.io/sdk/#get-accounts
  rpc GetAccount (GetAccountRequest) returns (GetAccountResponse) {
    option (grpcbridge.swagger.operation) = {
        tags: "accounts"
        summary: "Retrieve account information"
        description: "Given user consent, retrieve information for a specific bank account"
    };
    option (google.api.http) = {
        get: "/accounts/{account_id}"
    };
    option (io.token.proto.extensions.method.kafka_topic) = "account";
  }

  // get info about linked accounts
  // https://developer.token.io/sdk/#get-accounts
  rpc GetAccounts (GetAccountsRequest) returns (GetAccountsResponse) {
    option (grpcbridge.swagger.operation) = {
        tags: "accounts"
        summary: "Retrieve information for all accounts"
        description: "Given user consent, retrieve information for all bank accounts"
    };
    option (google.api.http) = {
        get: "/accounts"
    };
    option (io.token.proto.extensions.method.kafka_topic) = "account";
  }

  // get current and available balance for a linked account
  // https://developer.token.io/sdk/#get-account-balance
  rpc GetBalance (GetBalanceRequest) returns (GetBalanceResponse) {
    option (grpcbridge.swagger.operation) = {
        tags: "accounts"
        summary: "Retrieve account balances"
        description: "Given user consent, retrieve balances for a specific bank account"
    };
    option (google.api.http) = {
        get: "/accounts/{account_id}/balance"
    };
    option (io.token.proto.extensions.method.kafka_topic) = "account_balance";
  }

  rpc GetBalances (GetBalancesRequest) returns (GetBalancesResponse) {
    option (grpcbridge.swagger.operation) = {
        tags: "accounts"
        summary: "Retrieve multiple account balances"
        description: "Given user consent, retrieve balances for multiple bank accounts"
    };
    option (google.api.http) = {
        get: "/account-balance"
    };
    option (io.token.proto.extensions.method.kafka_topic) = "account_balance";
  }

  // get information about a particular transaction
  // https://developer.token.io/sdk/#get-transactions
  rpc GetTransaction (GetTransactionRequest) returns (GetTransactionResponse) {
    option (grpcbridge.swagger.operation) = {
        tags: "accounts"
        summary: "Retrieve transaction information"
        description: "Given user consent, retrieve information for a specific transaction in account"
    };
    option (google.api.http) = {
        get: "/accounts/{account_id}/transaction/{transaction_id}"
    };
    option (io.token.proto.extensions.method.kafka_topic) = "account_transaction";
  }

  // get information about several transactions
  // https://developer.token.io/sdk/#get-transactions
  rpc GetTransactions (GetTransactionsRequest) returns (GetTransactionsResponse) {
    option (grpcbridge.swagger.operation) = {
        tags: "accounts"
        summary: "Retrieve all transactions for an account"
        description: "Given user consent, retrieve information for all transactions in account"
    };
    option (google.api.http) = {
        get: "/accounts/{account_id}/transactions"
    };
    option (io.token.proto.extensions.method.kafka_topic) = "account_transaction";
  }

  // get information about a particular standing order
  rpc GetStandingOrder (GetStandingOrderRequest) returns (GetStandingOrderResponse) {
    option (grpcbridge.swagger.operation) = {
        tags: "accounts"
        summary: "Retrieve standing order information"
        description: "GIven user consent, retrieve information about a specific standing order in account"
    };
    option (google.api.http) = {
        get: "/accounts/{account_id}/standing-orders/{standing_order_id}"
    };
    option (io.token.proto.extensions.method.kafka_topic) = "account_standing_order";
  }

  // get information about several standing orders
  rpc GetStandingOrders (GetStandingOrdersRequest) returns (GetStandingOrdersResponse) {
    option (grpcbridge.swagger.operation) = {
        tags: "accounts"
        summary: "Retrieve information about all standing orders"
        description: "Given user consent, retrieve information about all standing orders in account"
    };
    option (google.api.http) = {
        get: "/accounts/{account_id}/standing-orders"
    };
    option (io.token.proto.extensions.method.kafka_topic) = "account_standing_order";
  }

  rpc ApplySca (ApplyScaRequest) returns (ApplyScaResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        put: "/accounts/sca"
        body: "*"
    };
    option (io.token.proto.extensions.method.kafka_topic) = "account";
  }

  // Get information about the auth'd member's default account.
  // https://developer.token.io/sdk/#default-bank-account
  rpc GetDefaultAccount (GetDefaultAccountRequest) returns (GetDefaultAccountResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
      get: "/members/{member_id}/default-account"
    };
    option (io.token.proto.extensions.method.kafka_topic) = "account";
  }

  // Set one auth'd member's accounts as its default account.
  // https://developer.token.io/sdk/#default-bank-account
  rpc SetDefaultAccount (SetDefaultAccountRequest) returns (SetDefaultAccountResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
      put: "/members/{member_id}/default-account"
      body: "*"
    };
    option (io.token.proto.extensions.method.kafka_topic) = "account";
  }

  // Get the resolved transfer destinations of the given account.
  rpc ResolveTransferDestinations (ResolveTransferDestinationsRequest) returns (ResolveTransferDestinationsResponse) {
    option (grpcbridge.swagger.operation) = {
        tags: "accounts"
        summary: "Get transfer destination"
        description: "Given user consent, get details needed to use the account as a transfer destination"
    };
    option (google.api.http) = {
      get: "/accounts/{account_id}/transfer-destinations"
    };
    option (io.token.proto.extensions.method.kafka_topic) = "account";
  }

  // Confirm that the given account has sufficient funds to cover the charge.
  rpc ConfirmFunds (ConfirmFundsRequest) returns (ConfirmFundsResponse) {
    option (grpcbridge.swagger.operation) = {
        tags: "accounts"
        summary: "Confirm available funds"
        description: "Given user consent, check that sufficient funds are available in account"
    };
    option (google.api.http) = {
      put: "/accounts/{account_id}/funds-confirmation"
      body: "*"
    };
    option (io.token.proto.extensions.method.kafka_topic) = "account";
  }

  ////////////////////////////////////////////////////////////////////////////////////////////////////
  // Testing.
  //

  // Create a test account at "iron" test bank.
  // https://developer.token.io/sdk/#link-a-bank-account
  rpc CreateTestBankAccount (CreateTestBankAccountRequest) returns (CreateTestBankAccountResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        post: "/test/create-account"
        body: "*"
    };
  }

  // Get notification from "iron" test bank. Useful for Token when testing its test bank.
  // Normal way to get a notification is GetNotification.
  rpc GetTestBankNotification (GetTestBankNotificationRequest) returns (GetTestBankNotificationResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        get: "/test/subscribers/{subscriber_id}/notifications/{notification_id}"
    };
  }

  // Get notifications from "iron" test bank. Useful for Token when testing its test bank.
  // Normal way to get notifications is GetNotifications.
  rpc GetTestBankNotifications (GetTestBankNotificationsRequest) returns (GetTestBankNotificationsResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        get: "/test/subscribers/{subscriber_id}/notifications"
    };
  }

  ////////////////////////////////////////////////////////////////////////////////////////////////////
  // Blobs.
  //

  // Create a blob.
  // https://developer.token.io/sdk/#transfer-token-options
  rpc CreateBlob (CreateBlobRequest) returns (CreateBlobResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        post: "/blobs"
        body: "*"
    };
  }

  // Fetch a blob. Works if the authenticated member is the blob's
  // owner or if the blob is public-access.
  // https://developer.token.io/sdk/#transfer-token-options
  rpc GetBlob (GetBlobRequest) returns (GetBlobResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        get: "/blobs/{blob_id}"
    };
  }

  // Fetch a blob using a Token's authority. Works if Blob is attached to token
  // and authenticated member is the Token's "from" or "to".
  // https://developer.token.io/sdk/#transfer-token-options
  rpc GetTokenBlob (GetTokenBlobRequest) returns (GetTokenBlobResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option deprecated = true;
    option (google.api.http) = {
        get: "/tokens/{token_id}/blobs/{blob_id}"
    };
  }

  ////////////////////////////////////////////////////////////////////////////////////////////////////
  // Tokens Requests.
  //

  // Store a Token Request
  rpc StoreTokenRequest (StoreTokenRequestRequest) returns (StoreTokenRequestResponse) {
    option (grpcbridge.swagger.operation) = {
        tags: "requests"
        summary: "Create a token request"
        description: "Persists required information used by the Token web app to complete a transaction"
    };
    option (google.api.http) = {
        post: "/token-requests"
        body: "*"
    };
    option (io.token.proto.extensions.method.kafka_topic) = "token_request";
  }

  // Retrieve a Token Request
  rpc RetrieveTokenRequest (RetrieveTokenRequestRequest) returns (RetrieveTokenRequestResponse) {
    option (grpcbridge.swagger.operation) = {
        tags: "requests"
        summary: "Find a token request"
        description: "Retrieves a specific token request by token ID"
    };
    option (google.api.http) = {
        get: "/token-requests/{request_id}"
    };
    option (io.token.proto.extensions.method.kafka_topic) = "token_request";
  }

  rpc UpdateTokenRequest (UpdateTokenRequestRequest) returns (UpdateTokenRequestResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        put: "/token-requests/{request_id}"
        body: "*"
    };
    option (io.token.proto.extensions.method.kafka_topic) = "token_request";
  }

  rpc SetTokenRequestTransferDestinations(SetTokenRequestTransferDestinationsRequest) returns (SetTokenRequestTransferDestinationsResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        put: "/token-requests/{token_request_id}/transfer-destinations"
        body: "*"
    };
    option (io.token.proto.extensions.method.kafka_topic) = "token_request";
  }

  ////////////////////////////////////////////////////////////////////////////////////////////////////
  // Tokens.
  //

  // Prepare a token (resolve token payload and determine policy)
  rpc PrepareToken (PrepareTokenRequest) returns (PrepareTokenResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        post: "/tokens/prepare"
        body: "*"
    };
    option (io.token.proto.extensions.method.kafka_topic) = "access_token";
  }

  // Create a Token.
  rpc CreateToken (CreateTokenRequest) returns (CreateTokenResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        post: "/tokens"
        body: "*"
    };
    option (io.token.proto.extensions.service.rate_limit) = {
      selector: [
        {key: "resolve-alias-remote-address", path: "{REMOTE_ADDRESS}"},
        {key: "resolve-alias-source-developer", path: "{DEVELOPER_ID}"}
      ]
    };
    option (io.token.proto.extensions.method.kafka_topic) = "transfer_token";
  }

  // Create a Transfer Token.
  // https://developer.token.io/sdk/#create-transfer-token
  rpc CreateTransferToken (CreateTransferTokenRequest) returns (CreateTransferTokenResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        // unused: use /tokens?type=transfer to reach this endpoint
        post: "/transfer-tokens"
        body: "*"
    };
    option (io.token.proto.extensions.service.rate_limit) = {
      selector: [
        {key: "resolve-alias-remote-address", path: "{REMOTE_ADDRESS}"},
        {key: "resolve-alias-source-developer", path: "{DEVELOPER_ID}"}
      ]
    };
    option deprecated = true; // use CreateToken instead
  }

  // Create an Access Token.
  // https://developer.token.io/sdk/#create-access-token
  rpc CreateAccessToken (CreateAccessTokenRequest) returns (CreateAccessTokenResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        // unused: use /tokens?type=access to reach this endpoint
        post: "/access-tokens"
        body: "*"
    };
    option (io.token.proto.extensions.service.rate_limit) = {
      selector: [
        {key: "resolve-alias-remote-address", path: "{REMOTE_ADDRESS}"},
        {key: "resolve-alias-source-developer", path: "{DEVELOPER_ID}"}
      ]
    };
    option (io.token.proto.extensions.method.kafka_topic) = "access_token";
  }

  // Get information about one token.
  // https://developer.token.io/sdk/#redeem-transfer-token
  rpc GetToken (GetTokenRequest) returns (GetTokenResponse) {
    option (grpcbridge.swagger.operation) = {
        tags: "tokens"
        summary: "Find a token"
        description: "Get information about a specific token for the authenticated member"
    };
    option (google.api.http) = {
        get: "/tokens/{token_id}"
    };
    option (io.token.proto.extensions.method.kafka_topic) = "token";
  }

  // Get existing Access Token where the calling member is the
  // remitter and provided member is the beneficiary.
  rpc GetActiveAccessToken (GetActiveAccessTokenRequest) returns (GetActiveAccessTokenResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        get: "/tokens/active-access-token/{to_member_id}"
    };
    option (io.token.proto.extensions.method.kafka_topic) = "access_token";
  }

  // Gets list of tokens the member has given/received.
  // Used by getTransferTokens, getAccessTokens.
  // https://developer.token.io/sdk/#get-tokens
  // https://developer.token.io/sdk/#replace-access-token
  rpc GetTokens (GetTokensRequest) returns (GetTokensResponse) {
    option (grpcbridge.swagger.operation) = {
        tags: "tokens"
        summary: "Retrieve a list of tokens"
        description: "Get a list of all tokens for the authenticated member"
    };
    option (google.api.http) = {
        get: "/tokens"
    };
    option (io.token.proto.extensions.method.kafka_topic) = "token";
  }

  // Endorse a token
  // https://developer.token.io/sdk/#endorse-transfer-token
  // https://developer.token.io/sdk/#endorse-access-token
  rpc EndorseToken (EndorseTokenRequest) returns (EndorseTokenResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        put: "/tokens/{token_id}/endorse"
        body: "*"
    };
    option (io.token.proto.extensions.method.kafka_topic) = "token";
  }

  // Cancel a token
  // https://developer.token.io/sdk/#cancel-transfer-token
  // https://developer.token.io/sdk/#cancel-access-token
  rpc CancelToken (CancelTokenRequest) returns (CancelTokenResponse) {
    option (grpcbridge.swagger.operation) = {
        tags: "tokens"
        summary: "Cancel a token"
        description: "Cancel a specific token by Token ID"
    };
    option (google.api.http) = {
        put: "/tokens/{token_id}/cancel"
        body: "*"
    };
    option (io.token.proto.extensions.method.kafka_topic) = "token";
  }

  // Replace an access token
  // https://developer.token.io/sdk/#replace-access-token
  //
  // See how replaceAndEndorseToken uses it:
  //   https://developer.token.io/sdk/esdoc/class/src/http/AuthHttpClient.js~AuthHttpClient.html#instance-method-replaceAndEndorseToken
  rpc ReplaceToken (ReplaceTokenRequest) returns (ReplaceTokenResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        post: "/tokens/{cancel_token.token_id}/replace"
        body: "*"
    };
    option (io.token.proto.extensions.method.kafka_topic) = "token";
  }

  // Request a Token signature on a token request state payload (tokenId | state)
  rpc SignTokenRequestState (SignTokenRequestStateRequest) returns (SignTokenRequestStateResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        put: "/sign-token-request-state"
        body: "*"
    };
    option (io.token.proto.extensions.method.kafka_topic) = "token_request";
  }

  // Get the token request result from the token request id
  rpc GetTokenRequestResult (GetTokenRequestResultRequest) returns (GetTokenRequestResultResponse) {
    option (grpcbridge.swagger.operation) = {
        tags: "requests"
        summary: "Obtain the result of a token request"
        description: "Checks whether a token request result is available"
    };
    option (google.api.http) = {
        get: "/token-requests/{token_request_id}/token_request_result"
    };
    option (io.token.proto.extensions.method.kafka_topic) = "token_request";
  }

  // Gets a payload to sign
  rpc GetAuthRequestPayload (GetAuthRequestPayloadRequest) returns (GetAuthRequestPayloadResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        get: "/auth-request-payloads/{auth_request_id}"
    };
    option (io.token.proto.extensions.method.kafka_topic) = "token";
  }

  // Stores a linking request
  rpc StoreLinkingRequest (StoreLinkingRequestRequest) returns (StoreLinkingRequestResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        post: "/linking-requests"
        body: "*"
    };
    option (io.token.proto.extensions.method.kafka_topic) = "linking_request";
  }

  // Gets a linking request
  rpc GetLinkingRequest (GetLinkingRequestRequest) returns (GetLinkingRequestResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        get: "/linking-requests/{linking_request_id}"
    };
    option (io.token.proto.extensions.method.kafka_topic) = "linking_request";
  }

////////////////////////////////////////////////////////////////////////////////////////////////////
  // Token Transfers.
  //

  // Redeem a transfer token, creating a transfer.
  // https://developer.token.io/sdk/#redeem-transfer-token
  //
  // See how redeemToken calls it:
  //   https://developer.token.io/sdk/esdoc/class/src/http/AuthHttpClient.js~AuthHttpClient.html#instance-method-redeemToken
  rpc CreateTransfer (CreateTransferRequest) returns (CreateTransferResponse) {
    option (grpcbridge.swagger.operation) = {
        tags: "transfers"
        summary: "Initiate a bank transfer"
        description: "Creates a request to move money between accounts"
    };
    option (google.api.http) = {
        post: "/transfers"
        body: "*"
    };
    option (io.token.proto.extensions.method.kafka_topic) = "transfer";
  }

  // Redeem a standing order token, creating a standing order submission.
  rpc CreateStandingOrder (CreateStandingOrderRequest) returns (CreateStandingOrderResponse) {
    option (grpcbridge.swagger.operation) = {
        tags: "transfers"
        summary: "Create a standing order submisison"
        description: "Submit a request for a standing order creation"
    };
    option (google.api.http) = {
        post: "/standing-order-submissions"
        body: "*"
    };
    option (io.token.proto.extensions.method.kafka_topic) = "transfer_standing_order_submission";
  }

  // Redeem a bulk transfer token, creating a bulk transfer submission.
  rpc CreateBulkTransfer (CreateBulkTransferRequest) returns (CreateBulkTransferResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        post: "/bulk-transfers"
        body: "*"
    };
    option (io.token.proto.extensions.method.kafka_topic) = "transfer_bulk_transfer";
  }

  // Get information about one transfer.
  // https://developer.token.io/sdk/#get-transfers
  rpc GetTransfer (GetTransferRequest) returns (GetTransferResponse) {
    option (grpcbridge.swagger.operation) = {
        tags: "transfers"
        summary: "Retrieve a transfer"
        description: "Retrieves information about a specific transfer in account"
    };
    option (google.api.http) = {
        get: "/transfers/{transfer_id}"
    };
    option (io.token.proto.extensions.method.kafka_topic) = "transfer";
  }

  // Get information about one standing order submission
  rpc GetStandingOrderSubmission (GetStandingOrderSubmissionRequest) returns (GetStandingOrderSubmissionResponse) {
    option (grpcbridge.swagger.operation) = {
        tags: "transfers"
        summary: "Find a standing order submission"
        description: "Retrieve a standing order submission by its ID"
    };
    option (google.api.http) = {
        get: "/standing-order-submissions/{submission_id}"
    };
    option (io.token.proto.extensions.method.kafka_topic) = "transfer_standing_order_submission";
  }

  // Get information about one bulk transfer
  rpc GetBulkTransfer (GetBulkTransferRequest) returns (GetBulkTransferResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        get: "/bulk-transfers/{bulk_transfer_id}"
    };
    option (io.token.proto.extensions.method.kafka_topic) = "transfer_bulk_transfer";
  }

  // Get a list of the auth'd member's submissions.
  // https://developer.token.io/sdk/#get-submissions
  rpc GetTransfers (GetTransfersRequest) returns (GetTransfersResponse) {
    option (grpcbridge.swagger.operation) = {
        tags: "transfers"
        summary: "Retrieve all transfers"
        description: "Retrieves information for all transfers in account"
    };
    option (google.api.http) = {
        get: "/transfers"
    };
    option (io.token.proto.extensions.method.kafka_topic) = "transfer";
  }

  // Get a list of the auth'd member's recurring submissions.
  rpc GetStandingOrderSubmissions (GetStandingOrderSubmissionsRequest) returns (GetStandingOrderSubmissionsResponse) {
    option (grpcbridge.swagger.operation) = {
        tags: "transfers"
        summary: "Retrieve a list of standing order submissions"
        description: "Retrieve all standing order submissions"
    };
    option (google.api.http) = {
        get: "/standing-order-submissions"
    };
    option (io.token.proto.extensions.method.kafka_topic) = "transfer_standing_order_submission";
  }

  ////////////////////////////////////////////////////////////////////////////////////////////////////
  // Bank Information Endpoints.
  //

  // Get a list of "link-able" bank countries.
  rpc GetBanksCountries (GetBanksCountriesRequest) returns (GetBanksCountriesResponse) {
    option (grpcbridge.swagger.operation) = {
        tags: "info"
        summary: "Get list of bank countries"
        description: "Retrieve the list of countries with Token-integrated banks"
    };
    option (google.api.http) = {
        get: "/bank/countries"
        additional_bindings {
          get: "/banks/countries" // deprecated
        }
    };
  }

  // Get a list of "link-able" banks.
  // https://developer.token.io/sdk/#link-a-bank-account
  rpc GetBanks (GetBanksRequest) returns (GetBanksResponse) {
    option (grpcbridge.swagger.operation) = {
        tags: "info"
        summary: "Get list of banks matching criteria"
        description: "Retrieve the list of Token-integrated banks matching feature criteria for the selected country"
    };
    option (google.api.http) = {
        get: "/banks"
    };
  }

  // Get information useful for linking one bank.
  // https://developer.token.io/sdk/#link-a-bank-account
  rpc GetBankInfo (GetBankInfoRequest) returns (GetBankInfoResponse) {
    option (grpcbridge.swagger.operation) = {
        tags: "info"
        summary: "Get bank information"
        description: "Retrieve information about the Token-supported bank identified"
    };
    option (google.api.http) = {
        get: "/banks/{bank_id}/info"
    };
  }

  rpc GetBankAuthUrl (GetBankAuthUrlRequest) returns (GetBankAuthUrlResponse) {
    option (grpcbridge.swagger.operation) = {
        tags: "info"
        summary: "Produce bank authorization url"
        description: "Generates a bank authorization url for the given token request id"
    };
    option (google.api.http) = {
      post: "/banks/{bank_id}/token-requests/{token_request_id}/urls"
      additional_bindings {
        post: "/banks/{bank_id}/token-requests/{token_request_id}"
      }
    };
  }

  rpc GetDirectBankAuthUrl (GetDirectBankAuthUrlRequest) returns (GetDirectBankAuthUrlResponse) {
    option (grpcbridge.swagger.operation) = {
        tags: "info"
        summary: "Get directly integrated bank authorization url"
        description: "Generates a directly integrated bank authorization url for the given token request id"
    };
    option (google.api.http) = {
        get: "/banks/{bank_id}/token-requests/{token_request_id}/url"
        additional_bindings {
          get: "/banks/{bank_id}/token-requests/{token_request_id}/auth-url"
        }
    };
    option deprecated = true; // Backward compatibility for web-app
  }

  ////////////////////////////////////////////////////////////////////////////////////////////////////
  // TSP only endpoints
  //
  rpc OnBankAuthCallback (OnBankAuthCallbackRequest) returns (OnBankAuthCallbackResponse) {
    option (grpcbridge.swagger.operation) = {
        tags: "tsp"
        summary: "On callback"
        description: "Process bank auth callback notification"
    };
    option (google.api.http) = {
        post: "/banks/{bank_id}/callback"
    };
    option (io.token.proto.extensions.method.kafka_topic) = "token_request";
  }

  rpc GetExternalMetadata (GetExternalMetadataRequest) returns (GetExternalMetadataResponse) {
    option (grpcbridge.swagger.operation) = {
        tags: "tsp"
        summary: "Get external metadata"
        description: "Get the external metadata from the bank"
    };
    option (google.api.http) = {
        get: "/token-requests/{token_request_id}/external-metadata"
    };
  }

  rpc StoreBankConfig (StoreBankConfigRequest) returns (StoreBankConfigResponse) {
    option (grpcbridge.swagger.operation) = {
        tags: "bankConfigs"
        summary: "Store bank config"
        description: "Store the bank config"
    };
    option (google.api.http) = {
        put: "/members/{member_id}/bank-configs/{bank_id}"
    };
  }

  rpc GetBankConfig (GetBankConfigRequest) returns (GetBankConfigResponse) {
    option (grpcbridge.swagger.operation) = {
        tags: "bankConfigs"
        summary: "Get bank config"
        description: "Get the bank config"
    };
    option (google.api.http) = {
        get: "/members/{member_id}/bank-configs/{bank_id}"
    };
  }

  rpc GetBankConfigs (GetBankConfigsRequest) returns (GetBankConfigsResponse) {
    option (grpcbridge.swagger.operation) = {
        tags: "bankConfigs"
        summary: "Get bank configs"
        description: "Get all bank configs"
    };
    option (google.api.http) = {
        get: "/members/{member_id}/bank-configs"
    };
  }

  rpc DeleteBankConfig (DeleteBankConfigRequest) returns (DeleteBankConfigResponse) {
    option (grpcbridge.swagger.operation) = {
        tags: "bankConfigs"
        summary: "Delete bank config"
        description: "Delete the bank config"
    };
    option (google.api.http) = {
        delete: "/members/{member_id}/bank-configs/{bank_id}"
    };
  }

  ////////////////////////////////////////////////////////////////////////////////////////////////////
  // Bank member only requests.
  //
  // Get member information about a member who links at least an account from this bank
  rpc GetMemberInfo (GetMemberInfoRequest) returns (GetMemberInfoResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        get: "/members/info/{member_id}"
    };
  }

  rpc GetConsent (GetConsentRequest) returns (GetConsentResponse) {
    option (grpcbridge.swagger.operation) = {
        tags: "banks"
        summary: "Gets a consent"
        description: "Gets a consent with the consent id"
    };
    option (google.api.http) = {
        get: "/banks/{bank_id}/consents/{consent_id}"
    };
  }

  rpc GetConsents (GetConsentsRequest) returns (GetConsentsResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        get: "/banks/{bank_id}/consents"
        additional_bindings {
            get: "/consents"
            body: "*"
        }
    };
  }

  ////////////////////////////////////////////////////////////////////////////////////////////////////
  // Reports (bank member only requests).
  //
  // Get TPP performance report.
  rpc GetTppPerformanceReport (GetTppPerformanceReportRequest) returns (GetTppPerformanceReportResponse) {
    option (grpcbridge.swagger.operation) = {
        tags: "banks"
        summary: "Gets the TPP performance report"
        description: "Gets the TPP performance report"
    };
    option (google.api.http) = {
        get: "/banks/{bank_id}/reports/tpp-performance"
        additional_bindings {
            get: "/reports/{bank_id}/tpp_performance_report"
        }
    };
  }

  //Get availability report.
  rpc GetAvailabilityReport (GetAvailabilityReportRequest) returns (GetAvailabilityReportResponse) {
    option (grpcbridge.swagger.operation) = {
        tags: "banks"
        summary: "Gets the availability report"
        description: "Gets the availability report"
    };
    option (google.api.http) = {
        get: "/banks/{bank_id}/reports/availability"
        additional_bindings {
            get: "/reports/{bank_id}/availability_report"
        }
    };
  }

  rpc GetTppAccessReport (GetTppAccessReportRequest) returns (GetTppAccessReportResponse) {
    option (grpcbridge.swagger.operation) = {
        tags: "banks"
        summary: "Gets the TPP access report"
        description: "Gets the TPP access report"
    };
    option (google.api.http) = {
        get: "/banks/{bank_id}/reports/tpp-access"
        additional_bindings {
            get: "/reports/{bank_id}/tpp_access_report"
        }
    };
  }


  rpc GetServiceHealth (GetServiceHealthRequest) returns (GetServiceHealthResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        get: "reports/service/health"
    };
  }

////////////////////////////////////////////////////////////////////////////////////////////////////
// Reports (portal requests).
//
// Get TPP requests report.
rpc GetTppRequestsReport (GetTppRequestsReportRequest) returns (GetTppRequestsReportResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        get: "/reports/{tpp_member_id}/tpp_requests_report/from/{from_date_ms}/to/{to_date_ms}"
    };
  }

  rpc GetBankDowntimeReport (GetBankDowntimeReportRequest) returns (GetBankDowntimeReportResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (google.api.http) = {
        get: "/reports/{bank_id}/bank_downtime_report/from/{days_back}"
    };
  }

  rpc GetBankStatus (GetBankStatusRequest) returns (GetBankStatusResponse) {
    option (grpcbridge.swagger.operation) = {
        tags: "reports"
        summary: "Get AIS and PIS status for a bank"
        description: "Indicates when AIS and PIS services are up or down"
    };
    option (google.api.http) = {
        get: "/reports/banks/{bank_id}/status"
    };
  }

  rpc GetBanksStatus (GetBanksStatusRequest) returns (GetBanksStatusResponse) {
    option (grpcbridge.swagger.operation) = {
        tags: "reports"
        summary: "Returns statuses for all banks"
        description: "Returns the current AIS and PIS service status for all banks"
    };
    option (google.api.http) = {
        get: "/reports/banks/status"
    };
  }

  ////////////////////////////////////////////////////////////////////////////////////////////////////
  // RESTful Bank API
  //
  rpc CreateBankUser (CreateBankUserRequest) returns (CreateBankUserResponse) {
    option (grpcbridge.swagger.operation) = {
        tags: "banks"
        summary: "Creates a user"
        description: "Returns a user id in the bank's realm"
    };
    option (google.api.http) = {
        post: "/banks/{bank_id}/users"
    };
  }

  rpc DeleteBankUser (DeleteBankUserRequest) returns (DeleteBankUserResponse) {
    option (grpcbridge.swagger.operation) = {
        tags: "banks"
        summary: "Deletes a user"
        description: "Deletes a user by the user id in bank's realm"
    };
    option (google.api.http) = {
        delete: "/banks/{bank_id}/users/{user_id}"
    };
  }

  rpc RetrieveConsentRequest (RetrieveConsentRequestRequest) returns (RetrieveConsentRequestResponse) {
    option (grpcbridge.swagger.operation) = {
        tags: "banks"
        summary: "Retrieves a consent request"
        description: "Retrieves a consent request by the request id"
    };
    option (google.api.http) = {
        get: "/banks/{bank_id}/consent-requests/{request_id}"
    };
  }

  rpc CreateConsent (CreateConsentRequest) returns (CreateConsentResponse) {
    option (grpcbridge.swagger.operation) = {
        tags: "banks"
        summary: "Creates a consent"
        description: "Creates a consent with a consent request"
    };
    option (google.api.http) = {
        post: "/banks/{bank_id}/consents"
        body: "*"
    };
  }

  rpc CancelConsent (CancelConsentRequest) returns (CancelConsentResponse) {
    option (grpcbridge.swagger.operation) = {
        tags: "banks"
        summary: "Cancels a consent"
        description: "Cancels a consent with the consent id"
    };
    option (google.api.http) = {
        delete: "/banks/{bank_id}/consents/{consent_id}"
    };
  }

  rpc GetActiveAccessConsents (GetActiveAccessConsentsRequest) returns (GetActiveAccessConsentsResponse) {
    option (grpcbridge.swagger.operation) = {
        tags: "banks"
        summary: "Get active access consents"
        description: "Returns active access consents for a user id"
    };
    option (google.api.http) = {
        post: "/banks/{bank_id}/users/{user_id}/access-consents"
    };
  }

  rpc GetAccessConsents (GetAccessConsentsRequest) returns (GetAccessConsentsResponse) {
    option (grpcbridge.swagger.operation) = {
        tags: "banks"
        summary: "Get access consents"
        description: "Returns access consents for a user id"
    };
    option (google.api.http) = {
        get: "/banks/{bank_id}/users/{user_id}/access-consents"
    };
  }

  ////////////////////////////////////////////////////////////////////////////////////////////////////
  // Partner endpoints
  //
  rpc EnableMember (EnableMemberRequest) returns (EnableMemberResponse) {
    option (grpcbridge.swagger.operation) = {
      tags: "partner"
      summary: "Enables a member"
      description: "Enables a member that's under the realm of the partner"
    };
    option (google.api.http) = {
      put: "/partner/members/{member_id}/enable"
    };
  }

  rpc DisableMember (DisableMemberRequest) returns (DisableMemberResponse) {
    option (grpcbridge.swagger.operation) = {
      tags: "partner"
      summary: "Disables a member"
      description: "Disables a member that's under the realm of the partner"
    };
    option (google.api.http) = {
      put: "/partner/members/{member_id}/disable"
    };
  }

  rpc GetMembersUnderPartner (GetMembersUnderPartnerRequest) returns (GetMembersUnderPartnerResponse) {
    option (grpcbridge.swagger.operation) = {
      tags: "partner"
      summary: "Get a list of members"
      description: "Get a list of members registered under the realm of the partner"
    };
    option (google.api.http) = {
      get: "/partner/members"
    };
  }

  rpc SetDefaultCustomization (SetDefaultCustomizationRequest) returns (SetDefaultCustomizationResponse) {
    option (grpcbridge.swagger.exclude) = true;
    option (grpcbridge.swagger.operation) = {
      tags: "partner"
      summary: "Sets partner's default customization."
      description: "Sets a customization that should be used by the businesses under the realm of the partner."
    };
    option (google.api.http) = {
      put: "/partner/customization/{customization_id}"
    };
  }

  ////////////////////////////////////////////////////////////////////////////////////////////////////
  // Webhook endpoints
  //
  rpc SetWebhookConfig (SetWebhookConfigRequest) returns (SetWebhookConfigResponse) {
    option (grpcbridge.swagger.operation) = {
      tags: "webhook"
      summary: "Sets the webhook config"
      description: "Sets the webhook config"
    };
    option (google.api.http) = {
      put: "/webhook/config"
      body: "*"
    };
  }

  rpc GetWebhookConfig (GetWebhookConfigRequest) returns (GetWebhookConfigResponse) {
    option (grpcbridge.swagger.operation) = {
      tags: "webhook"
      summary: "Gets the webhook config"
      description: "Gets the webhook config"
    };
    option (google.api.http) = {
      get: "/webhook/config"
    };
  }

  rpc DeleteWebhookConfig (DeleteWebhookConfigRequest) returns (DeleteWebhookConfigResponse) {
    option (grpcbridge.swagger.operation) = {
      tags: "webhook"
      summary: "Deletes the webhook config"
      description: "Deletes the webhook config"
    };
    option (google.api.http) = {
      delete: "/webhook/config"
    };
  }
}