Os editores usam a integração do lado do servidor principalmente para gerenciar leitores e os
direitos deles. Os editores usam UpdateReaderEntitlements basicamente para atualizar
o registro do Google quanto ao direito de acesso de um ID do produto para um PPID.
Configuração do Google Cloud
A configuração da vinculação de assinaturas no Google Cloud inclui 2 componentes principais:
- Ativação da API para um determinado projeto
- Criação de uma conta de serviço para acessar a API
Ativar a API Subscription Linking
Para usar uma conta de serviço e gerenciar os direitos de um leitor, o projeto do
Google Cloud precisa ter a API Subscription Linking ativada e uma
conta de serviço OAuth configurada. Para ativar a API Subscription Linking em um
projeto, acesse o menu -> APIs e serviços -> Biblioteca e procure por Subscription Linking ou acesse a página diretamente:
https://console.cloud.google.com/apis/library?project=gcp_project_id

Figura 1. Como navegar para a API Library e ativá-la para um projeto do Google Cloud.
Criar uma conta de serviço
As contas de serviço são usadas para permitir o acesso do seu app à API Subscription Linking.
- Crie uma conta de serviço no console do seu projeto.
- Crie credenciais para a conta de serviço e armazene
o arquivo credentials.jsonem um local seguro que possa ser acessado pelo app.
- Conceda o papel de IAM "Administrador de vinculação de assinaturas" à conta de serviço que você criou. Para controle granular dos recursos da conta de serviço, você pode atribuir o papel adequado de acordo com a seguinte tabela.
| Recurso / Papel | Administrador de vinculação de assinaturas | Leitor de vinculação de assinaturas | Leitor de direitos de vinculação de assinaturas | 
|---|---|---|---|
| Receber direitos de leitor | |||
| Receber leitores | |||
| Atualizar direitos de leitor | |||
| Excluir leitores | 
Como usar contas de serviço com a API Subscription Linking
Para autenticar chamadas para a API Subscription Linking com contas de serviço,
use a biblioteca de cliente googleapis (que processa automaticamente solicitações access_token)
ou assine solicitações diretamente com a API REST. Se você estiver usando a API REST, primeiro obtenha um access_token (pela biblioteca de autenticação do Google ou usando um JWT de conta de serviço) e inclua-o no cabeçalho Authorization.
Os exemplos de biblioteca de cliente e API REST a seguir têm código de amostra para mostrar como chamar getReader(), getReaderEntitlements(), updateReaderEntitlements() e deleteReader().
Biblioteca de cliente
Esta seção explica como usar a biblioteca de cliente googleapis no Node.js.
Exemplo de solicitação
Para o campo keyFile no construtor Auth.GoogleAuth,
defina o caminho para sua chave da conta de serviço.
Se não for possível exportar uma chave de conta de serviço devido à política da organização, use o método credencial padrão da conta (ADC). Se você usar o método ADC, não precisará fornecer o campo keyFile, já que o ADC pesquisa credenciais por conta própria.
import {readerrevenuesubscriptionlinking_v1, Auth} from 'googleapis';
const subscriptionLinking = readerrevenuesubscriptionlinking_v1.Readerrevenuesubscriptionlinking;
class SubscriptionLinking {
  constructor() {
    this.auth = new Auth.GoogleAuth({
      keyFile: process.env.KEY_FILE,
      scopes: [
        'https://www.googleapis.com/auth/readerrevenue.subscriptionlinking.manage'
      ],
    })
  }
  init() {
    return new subscriptionLinking(
        {version: 'v1', auth: this.auth})
  }
}
const subscriptionLinkingApi = new SubscriptionLinking();
const client = subscriptionLinkingApi.init();
/**
 * Retrieves details for a specific reader associated with the publication.
 * @async
 * @param {string} ppid - The Publisher Provided ID (ppid) for the reader.
 * @return {Promise<object>} A promise that resolves with the reader's details
 *  from the API.
 */
async function getReader(ppid) {
  const publicationId = process.env.PUBLICATION_ID;
  return await client.publications.readers.get({
    name: `publications/${publicationId}/readers/${ppid}`,
  });
}
/**
 * Updates the entitlements for a specific reader.
 * @async
 * @param {string} ppid - The Publisher Provided ID (ppid) for the reader whose
 *  entitlements are being updated.
 * @return {Promise<object>} A promise that resolves with the result of the
 *  updated entitlements object.
 */
async function updateReaderEntitlements(ppid) {
  const publicationId = process.env.PUBLICATION_ID;
  const requestBody = {
    /*
    Refer to
    https://developers.google.com/news/subscribe/subscription-linking/appendix/glossary#entitlements_object
    */
    entitlements : [{
      product_id: `${publicationId}:basic`,
      subscription_token: 'abc1234',
      detail: 'This is our basic plan',
      expire_time: '2025-10-21T03:05:08.200564Z'
    }]
  };
  return await client.publications.readers.updateEntitlements({
    name: `publications/${publicationId}/readers/${ppid}/entitlements`,
    requestBody
  });
}
/**
 * Retrieves the current entitlements for a specific reader.
 * @async
 * @param {string} ppid - The Publisher Provided ID (ppid) for the reader.
 * @return {Promise<object>} A promise that resolves with the reader's entitlements object.
 */
async function getReaderEntitlements(ppid) {
  const publicationId = process.env.PUBLICATION_ID;
  return await client.publications.readers.getEntitlements({
    name: `publications/${publicationId}/readers/${ppid}/entitlements`
  });
}
/**
 * Deletes a specific Subscription Linkikng reader record associated with the publication.
 * @async
 * @param {string} ppid - The Publisher Provided ID (ppid) for the reader to be deleted.
 * @param {boolean=} forceDelete - If true, delete the user even if their
 *  entitelements are not empty
 * @return {Promise<object>} A promise that resolves upon successful deletion
 *  with an empty object ({})
 */
async function deleteReader(ppid, forceDelete = false) {
  const publicationId = process.env.PUBLICATION_ID;
  return await client.publications.readers.delete({
    name: `publications/${publicationId}/readers/${ppid}`
    force: forceDelete
  });
}
REST API
Se você quiser chamar endpoints da API REST, use um dos métodos para
receber accessToken e definir o cabeçalho Authorization.
1. Usar a biblioteca GoogleAuth
Para a chave credentials, use uma chave de conta de serviço
ou uma credencial padrão da conta (ADC).
Se você usar o método ADC, não precisará fornecer o campo credentials, já que o ADC procura credenciais por conta própria.
import { GoogleAuth } from 'google-auth-library';
import credentialJson from 'path_to_your_json_file' with { type: 'json' };
const auth = new GoogleAuth({
    credentials: credential_json,
    scopes: [
      'https://www.googleapis.com/auth/readerrevenue.subscriptionlinking.manage'
    ]
});
async function getAccessToken() {
    const accessToken = await auth.getAccessToken();
    return accessToken;
}
2. Gerar um access_token usando um JWT de conta de serviço
import fetch from 'node-fetch';
import jwt from 'jsonwebtoken';
function getSignedJwt() {
  /*
    Either store the service account credentials string in an environmental variable
    Or implement logic to fetch it.
  */
  const key_file = process.env.CREDENTIALS_STRING
  const issueDate = new Date();
  const expireMinutes = 60;
  const offsetInSeconds = issueDate.getTimezoneOffset() * 60000;
  const expireDate = new Date(issueDate.getTime() + (expireMinutes * 60000));
  const iat = Math.floor((issueDate.getTime() + offsetInSeconds) / 1000);
  const exp = Math.floor((expireDate.getTime() + offsetInSeconds) / 1000);
  const token = {
    iss: key_file.client_email,
    iat,
    exp,
    aud: 'https://oauth2.googleapis.com/token',
    scope:'https://www.googleapis.com/auth/readerrevenue.subscriptionlinking.manage',
  }
  return jwt.sign(token, key_file.private_key, {
    algorithm: 'RS256',
    keyid: key_file.private_key_id,
  })
}
async function getAccessToken(signedJwt) {
  let body = new URLSearchParams();
  body.set('grant_type', 'urn:ietf:params:oauth:grant-type:jwt-bearer');
  body.set('assertion', signedJwt);
  const response = await fetch('https://oauth2.googleapis.com/token', {
    method: 'POST',
    headers: {'Content-Type': 'application/x-www-form-urlencoded'},
    body
  })
  const accessResponse = await response.json();
  return accessResponse.access_token;
}
Exemplo de código para chamadas da API REST com a biblioteca Google Auth
import { GoogleAuth } from 'google-auth-library';
import fetch from 'node-fetch'
import credentialJson from 'path_to_your_json_file' with { type: 'json' };
const BASE_SUBSCRIPTION_LINKING_API_URL='https://readerrevenuesubscriptionlinking.googleapis.com/v1';
const publicationId = process.env.PUBLICATION_ID
const auth = new GoogleAuth({
    credentials: credentialJson,
    scopes: [
      'https://www.googleapis.com/auth/readerrevenue.subscriptionlinking.manage'
    ]
});
async function getAccessToken() {
    const accessToken = await auth.getAccessToken();
    return accessToken;
}
/**
 * Retrieves details for a specific reader associated with the publication.
 * @async
 * @param {string} ppid - The Publisher Provided ID (ppid) for the reader.
 * @return {object} reader json for the given ppid
 */
async function getReader(ppid) {
  const endpoint = `${BASE_SUBSCRIPTION_LINKING_API_URL}/publications/${publicationId}/readers/${ppid}`;
  const accessToken = await getAccessToken();
  const response = await fetch(endpoint, {
     method: 'GET',
     headers: {
       Authorization: `Bearer ${accessToken}`,
     },
   });
  const reader = await response.json();
  return reader;
}
/**
 * Updates the entitlements for a specific reader.
 * @async
 * @param {string} ppid - The Publisher Provided ID (ppid) for the reader.
 * @return {object} the updated entitlements object in json.
 */
async function updateReaderEntitlements(ppid) {
  const endpoint = `${BASE_SUBSCRIPTION_LINKING_API_URL}/publications/${publicationId}/readers/${ppid}/entitlements`;
  const requestBody = {
    /*
    Refer to
    https://developers.google.com/news/subscribe/subscription-linking/appendix/glossary#entitlements_object
    */
    entitlements : [{
      product_id: `${publicationId}:basic`,
      subscription_token: 'abc1234',
      detail: 'This is our basic plan',
      expire_time: '2025-10-21T03:05:08.200564Z'
    }]
  };
  const response = await fetch(endpoint, {
     method: 'PATCH',
     headers: {
       Authorization: `Bearer ${accessToken}`,
       'Content-Type': 'application/json',
     },
     body: JSON.stringify(requestBody)
   })
  const updatedEntitlements = await response.json();
  return updatedEntitlements;
}
/**
 * Retrieves the current entitlements for a specific reader.
 * @async
 * @param {string} ppid - The Publisher Provided ID (ppid) for the reader.
 * @return {object} the reader's entitlements object in json.
 */
async function getReaderEntitlements(ppid) {
  const endpoint = `${BASE_SUBSCRIPTION_LINKING_API_URL}/publications/${publicationId}/readers/${ppid}/entitlements`;
  const accessToken = await getAccessToken();
  const response = await fetch(endpoint, {
     method: 'GET',
     headers: {
       Authorization: `Bearer ${accessToken}`,
     },
   });
  const entitlements = await response.json();
  return entitlements;
}
/**
 * Deletes a specific Subscription Linkikng reader record associated with the publication.
 * @async
 * @param {string} ppid - The Publisher Provided ID (ppid) for the reader.
 * @param {boolean=} forceDelete - If true, delete the user even if their
 *  entitelements are not empty
 * @return {object} returns an empty object ({}) if the delete operation is successful
 */
async function deleteReader(ppid, forceDelete = false) {
  const endpoint = `${BASE_SUBSCRIPTION_LINKING_API_URL}/publications/${publicationId}/readers/${ppid}?force=${forceDelete}`;
  const response = await fetch(endpoint, {
     method: 'DELETE',
     headers: {
       Authorization: `Bearer ${accessToken}`,
     }
   });
  const result = await response.json();
  return result;
}