Notificaciones push (Dialogflow)

Explorar en Dialogflow

Haz clic en Continuar para importar nuestro ejemplo de notificaciones en Dialogflow. Luego, sigue la para implementar y probar la muestra:

  1. Ingresa un nombre de agente y crea un agente de Dialogflow nuevo para la muestra.
  2. Después de que el agente termine de importar, haz clic en Ir al agente.
  3. En el menú de navegación principal, ve a Entrega.
  4. Habilita el Editor intercalado y, luego, haz clic en Implementar. El editor contiene la muestra código.
  5. En el menú de navegación principal, ve a Integrations (Integraciones) y, luego, haz clic en Google Asistente
  6. En la ventana modal que aparece, habilita Cambios en la vista previa automática y haz clic en Probar. para abrir el simulador de Actions.
  7. En el simulador, ingresa Talk to my test app para probar la muestra.
Continuar

Tu Acción puede enviar notificaciones push a los usuarios cuando sea relevante, como enviar un recordatorio cuando se acerca la fecha límite de una tarea.

En esta guía, usamos el ejemplo de sugerencias de Actions on Google. como referencia para mostrarte cómo configurar notificaciones push para tu acción. Cuando los usuarios invocan esta acción, se pregunta si quieren escuchar una sugerencia. sobre el desarrollo de su propia Acción. Los usuarios pueden elegir una categoría específica o seleccionada al azar para la propina, o pueden elige escuchar la sugerencia más reciente.

Plataformas compatibles

Las notificaciones push están disponibles en dispositivos iOS y Android (los dispositivos iOS deben tener la app de Asistente instalada para recibir notificaciones push). No son actualmente es compatible con bocinas, pantallas inteligentes y otras plataformas que se activan con la voz.

Requisitos previos

Al menos una de las acciones de tu proyecto de acciones debe configurarse como una que activa un intent que se invocará cuando el usuario presione una notificación recibida de el Asistente.

No se pueden configurar tus acciones para activar el intent de bienvenida predeterminado a partir de una notificación push.

Configuración de la consola

Para agregar compatibilidad con notificaciones push a tu acción, haz lo siguiente:

  1. Ve a la Consola de Actions y navega a Crear > Actions (Acciones).

  2. Haz clic en la acción que coincida con el intent de activación adicional que deseas. habilitar notificaciones push.

    Para el ejemplo de sugerencias de Actions on Google, selecciona "tell_latest_tip".

  3. Desplázate hacia abajo hasta la sección Participación del usuario y activa la opción. ¿Te gustaría enviar notificaciones push?

  4. Ingresa un Título del contenido.

    Para el ejemplo de sugerencias de Actions on Google, el título podría ser "Se agregó una sugerencia nueva".

  5. Haz clic en Guardar.

Importaciones

Para los fines de las siguientes secciones, en tu código de entrega, debes declarar las siguientes importaciones:

Dialogflow
const {
  dialogflow,
  UpdatePermission,
  Suggestions,
} = require('actions-on-google');
.
.
SDK de Actions
const {
  actionssdk,
  UpdatePermission,
  Suggestions,
} = require('actions-on-google');

Usuarios que aceptaron participar

Antes de poder enviar notificaciones push a los usuarios, debes pedirles que las acepten. Para ello, muéstrales un chip de sugerencias para pedirles permiso. Cuando te otorgue el permiso, recibirás un ID de usuario actualizado para enviar notificaciones push a ese usuario.

Mostrar chips de sugerencias para habilitar

Para que los usuarios puedan recibir notificaciones push de tu Acción, debes mostrarles un chip de sugerencias para invitarlos a habilitar las notificaciones push.

El siguiente fragmento de código envía al usuario un mensaje que indica que debe recibir sugerencias nuevas. sugerencia junto con una respuesta de texto.

Dialogflow para Node.js
conv.ask('I can send you push notifications. Would you like that?');
conv.ask(new Suggestions('Send notifications'));
.
.
SDK de Actions para Node.js
conv.ask(' I can send you push notifications. Would you like that?');
conv.ask(new Suggestions('Send notifications'));
.
.
Dialogflow Java
responseBuilder
    .add("I can send you push notifications. Would you like that?")
    .addSuggestions(new String[] {
        "Send notifications"
    });
.
.
SDK de Actions para Java
responseBuilder
    .add("I can send you push notifications. Would you like that?")
    .addSuggestions(new String[] {
        "Send notifications"
    });
.
.
JSON de Dialogflow

Ten en cuenta que el siguiente JSON describe una respuesta de webhook.

{
  "payload": {
    "google": {
      "expectUserResponse": true,
      "richResponse": {
        "items": [
          {
            "simpleResponse": {
              "textToSpeech": "Hi! Welcome to Push Notifications!"
            }
          },
          {
            "simpleResponse": {
              "textToSpeech": "I can send you push notifications. Would you like that?"
            }
          }
        ],
        "suggestions": [
          {
            "title": "Send notifications"
          }
        ]
      }
    }
  }
}
.
.
JSON del SDK de Actions

Ten en cuenta que el siguiente JSON describe una respuesta de webhook.

{
  "expectUserResponse": true,
  "expectedInputs": [
    {
      "possibleIntents": [
        {
          "intent": "actions.intent.TEXT"
        }
      ],
      "inputPrompt": {
        "richInitialPrompt": {
          "items": [
            {
              "simpleResponse": {
                "textToSpeech": "Hi! Welcome to Push Notifications!"
              }
            },
            {
              "simpleResponse": {
                "textToSpeech": " I can send you push notifications. Would you like that?"
              }
            }
          ],
          "suggestions": [
            {
              "title": "Send notifications"
            }
          ]
        }
      }
    }
  ]
}

Después de que presione el chip, deberás pedirle el permiso UPDATE. En el siguiente código, se muestra cómo hacerlo con askForUpdatePermission de la biblioteca cliente de Node.js.

Dialogflow para Node.js
  1. Abre tu agente en la consola de Dialogflow y selecciona el intent que estás configurando para las actualizaciones.
  2. Desplázate hacia abajo hasta Respuesta y abre la pestaña Asistente de Google.
  3. Haz clic en Agregar contenido del mensaje y selecciona Chips de sugerencias.
  4. Configura el texto del chip en un elemento que invite al usuario a aceptar. En la Ejemplo de sugerencias de Actions on Google: configuramos el chip en Alertarme sobre sugerencias nuevas.
  5. Agregar otro intent de Dialogflow, llamado por ejemplo setup_push, y Establece la acción correspondiente, por ejemplo, setup.push. La expresión del usuario de este intent debe coincidir con el texto del chip de habilitación. en nuestro ejemplo Alertarme cuando haya nuevas sugerencias.
En el siguiente fragmento, se muestra cómo solicitar el permiso con las Acciones en la biblioteca cliente de Google para Node.js:
app.intent('Subscribe to Notifications', (conv) => {
  conv.ask(new UpdatePermission({
    intent: 'Notification',
  }));
});
.
.
SDK de Actions para Node.js

Debes configurar tu solución de CLN para activar una función que solicite permiso si la expresión del usuario coincide con el valor de las notificaciones push mensaje de aceptación. A continuación, se muestra un ejemplo muy básico basado en la coincidencia de cadenas:

conv.ask(new UpdatePermission({
  intent: 'Notification',
}));
.
.
Dialogflow Java
  1. Abre tu agente en la consola de Dialogflow y selecciona el intent que estás configurando para las actualizaciones.
  2. Desplázate hacia abajo hasta Respuesta y abre la pestaña Asistente de Google.
  3. Haz clic en Agregar contenido del mensaje y selecciona Chips de sugerencias.
  4. Configura el texto del chip en un elemento que invite al usuario a aceptar. En la Ejemplo de sugerencias de Actions on Google: configuramos el chip en Alertarme sobre sugerencias nuevas.
  5. Agregar otro intent de Dialogflow, llamado por ejemplo setup_push, y Establece la acción correspondiente, por ejemplo, setup.push. La expresión del usuario de este intent debe coincidir con el texto del chip de habilitación. en nuestro ejemplo Alertarme cuando haya nuevas sugerencias.
En el siguiente fragmento, se muestra cómo solicitar el permiso con las Acciones en la biblioteca cliente de Google Java/Kotlin:
@ForIntent("Subscribe to Notifications")
public ActionResponse subscribeToNotifications(ActionRequest request) {
  ResponseBuilder responseBuilder = getResponseBuilder(request);
  responseBuilder.add(new UpdatePermission().setIntent("Notification"));
  return responseBuilder.build();
}
.
.
SDK de Actions para Java

Debes configurar tu solución de CLN para activar una función que solicite permiso si la expresión del usuario coincide con el valor de las notificaciones push mensaje de aceptación. A continuación, se muestra un ejemplo muy básico basado en la coincidencia de cadenas:

ResponseBuilder responseBuilder = getResponseBuilder(request);
responseBuilder.add(new UpdatePermission().setIntent("Notification"));
return responseBuilder.build();
.
.
JSON de Dialogflow

Ten en cuenta que el siguiente JSON describe una respuesta de webhook en la que se usa Dialogflow.

{
  "payload": {
    "google": {
      "expectUserResponse": true,
      "systemIntent": {
        "intent": "actions.intent.PERMISSION",
        "data": {
          "@type": "type.googleapis.com/google.actions.v2.PermissionValueSpec",
          "permissions": [
            "UPDATE"
          ],
          "updatePermissionValueSpec": {
            "intent": "tell_latest_tip"
          }
        }
      }
    }
  }
}
.
.
JSON del SDK de Actions

Ten en cuenta que el JSON a continuación describe una respuesta de webhook que usa el SDK de Actions.

{
  "expectUserResponse": true,
  "expectedInputs": [
    {
      "possibleIntents": [
        {
          "intent": "actions.intent.PERMISSION",
          "inputValueData": {
            "@type": "type.googleapis.com/google.actions.v2.PermissionValueSpec",
            "permissions": [
              "UPDATE"
            ],
            "updatePermissionValueSpec": {
              "intent": "tell_latest_tip"
            }
          }
        }
      ]
    }
  ]
}
.

Finaliza la suscripción

Para finalizar la suscripción desde tu webhook de Node.js, debes guardar el el ID de notificaciones del usuario y el intent que seleccionó. Ambos se pasan como si el usuario otorga el permiso.

Si tu acción se creó con Dialogflow, debes hacer lo siguiente:

  • Agrega un intent que controle el actions_intent_PERMISSION.
  • Especifica el nombre de la Action del intent en algo que tu webhook pueda filtrar para más adelante.

El siguiente código muestra cómo controlar un intent de Dialogflow con un intent llamado finish_push_setup con el nombre de acción finish.push.setup:

Dialogflow para Node.js
app.intent('Confirm Notifications Subscription', (conv) => {
  if (conv.arguments.get('PERMISSION')) {
    const updatesUserId = conv.arguments.get('UPDATES_USER_ID');
    // Store user ID in database for later use
    conv.close(`Ok, I'll start alerting you.`);
  } else {
    conv.close(`Ok, I won't alert you.`);
  }
});
.
.
SDK de Actions para Node.js
app.intent('actions.intent.PERMISSION', (conv) => {
  if (conv.arguments.get('PERMISSION')) {
    const updatesUserId = conv.arguments.get('UPDATES_USER_ID');
    // Store user ID in database for later use
    conv.close(`Ok, I'll start alerting you.`);
  } else {
    conv.close(`Ok, I won't alert you.`);
  }
});
.
.
Dialogflow Java
@ForIntent("Confirm Notifications Subscription")
public ActionResponse confirmNotificationsSubscription(ActionRequest request) {
  // Verify the user has subscribed for push notifications
  ResponseBuilder responseBuilder = getResponseBuilder(request);
  if (request.isPermissionGranted()) {
    Argument userId = request.getArgument(ConstantsKt.ARG_UPDATES_USER_ID);
    if (userId != null) {
      // Store the user's ID in the database
    }
    responseBuilder.add("Ok, I'll start alerting you.");
  } else {
    responseBuilder.add("Ok, I won't alert you.");
  }
  responseBuilder.endConversation();
  return responseBuilder.build();
}
.
.
SDK de Actions para Java
@ForIntent("actions.intent.PERMISSION")
public ActionResponse confirmNotificationsSubscription(ActionRequest request) {
  // Verify the user has subscribed for push notifications
  ResponseBuilder responseBuilder = getResponseBuilder(request);
  if (request.isPermissionGranted()) {
    Argument userId = request.getArgument(ConstantsKt.ARG_UPDATES_USER_ID);
    if (userId != null) {
      // Store the user's ID in the database
    }
    responseBuilder.add("Ok, I'll start alerting you.");
  } else {
    responseBuilder.add("Ok, I won't alert you.");
  }
  responseBuilder.endConversation();
  return responseBuilder.build();
}
.
.
JSON de Dialogflow

Ten en cuenta que el siguiente JSON describe una solicitud al webhook.

{
  "responseId": "ee9e7ed5-fa1a-48c6-aac7-f9fbe94f1f58-712767ed",
  "queryResult": {
    "queryText": "actions_intent_PERMISSION",
    "action": "confirm.subscription",
    "parameters": {},
    "allRequiredParamsPresent": true,
    "fulfillmentMessages": [
      {
        "text": {
          "text": [
            ""
          ]
        }
      }
    ],
    "outputContexts": [
      {
        "name": "projects/PROJECT_ID/agent/sessions/ABwppHGIgmmU3zBcYMF_vWoHaM4JUo3wniYBHdbUF25l63G7EQWjRnlne8Ar7AOcRHWn1lrEKGy8qdP0UXLcWDBq93k/contexts/actions_capability_screen_output"
      },
      {
        "name": "projects/PROJECT_ID/agent/sessions/ABwppHGIgmmU3zBcYMF_vWoHaM4JUo3wniYBHdbUF25l63G7EQWjRnlne8Ar7AOcRHWn1lrEKGy8qdP0UXLcWDBq93k/contexts/actions_capability_account_linking"
      },
      {
        "name": "projects/PROJECT_ID/agent/sessions/ABwppHGIgmmU3zBcYMF_vWoHaM4JUo3wniYBHdbUF25l63G7EQWjRnlne8Ar7AOcRHWn1lrEKGy8qdP0UXLcWDBq93k/contexts/actions_capability_media_response_audio"
      },
      {
        "name": "projects/PROJECT_ID/agent/sessions/ABwppHGIgmmU3zBcYMF_vWoHaM4JUo3wniYBHdbUF25l63G7EQWjRnlne8Ar7AOcRHWn1lrEKGy8qdP0UXLcWDBq93k/contexts/actions_capability_audio_output"
      },
      {
        "name": "projects/PROJECT_ID/agent/sessions/ABwppHGIgmmU3zBcYMF_vWoHaM4JUo3wniYBHdbUF25l63G7EQWjRnlne8Ar7AOcRHWn1lrEKGy8qdP0UXLcWDBq93k/contexts/actions_capability_web_browser"
      },
      {
        "name": "projects/PROJECT_ID/agent/sessions/ABwppHGIgmmU3zBcYMF_vWoHaM4JUo3wniYBHdbUF25l63G7EQWjRnlne8Ar7AOcRHWn1lrEKGy8qdP0UXLcWDBq93k/contexts/google_assistant_input_type_keyboard"
      },
      {
        "name": "projects/PROJECT_ID/agent/sessions/ABwppHGIgmmU3zBcYMF_vWoHaM4JUo3wniYBHdbUF25l63G7EQWjRnlne8Ar7AOcRHWn1lrEKGy8qdP0UXLcWDBq93k/contexts/actions_intent_permission",
        "parameters": {
          "PERMISSION": true,
          "text": "yes",
          "UPDATES_USER_ID": "ABwppHHssyPbvEBF1mgN7Ddwb7mkhiVohW9PZ--I_svqy7zFElA4DHkf9pn04UBd5gwZo26_RfXCQ8otcztyIfe6MCQ"
        }
      }
    ],
    "intent": {
      "name": "projects/PROJECT_ID/agent/intents/c7f7b30b-5b88-4bb5-b0b8-1cd0862d1dd2",
      "displayName": "Confirm Notifications Subscription"
    },
    "intentDetectionConfidence": 1,
    "languageCode": "en"
  },
  "originalDetectIntentRequest": {
    "source": "google",
    "version": "2",
    "payload": {
      "user": {
        "permissions": [
          "UPDATE"
        ],
        "locale": "en-US",
        "userVerificationStatus": "VERIFIED"
      },
      "conversation": {
        "conversationId": "ABwppHGIgmmU3zBcYMF_vWoHaM4JUo3wniYBHdbUF25l63G7EQWjRnlne8Ar7AOcRHWn1lrEKGy8qdP0UXLcWDBq93k",
        "type": "ACTIVE",
        "conversationToken": "[]"
      },
      "inputs": [
        {
          "intent": "actions.intent.PERMISSION",
          "rawInputs": [
            {
              "inputType": "KEYBOARD",
              "query": "yes"
            }
          ],
          "arguments": [
            {
              "name": "PERMISSION",
              "boolValue": true,
              "textValue": "true"
            },
            {
              "name": "text",
              "rawText": "yes",
              "textValue": "yes"
            },
            {
              "name": "UPDATES_USER_ID",
              "textValue": "ABwppHHssyPbvEBF1mgN7Ddwb7mkhiVohW9PZ--I_svqy7zFElA4DHkf9pn04UBd5gwZo26_RfXCQ8otcztyIfe6MCQ"
            }
          ]
        }
      ],
      "surface": {
        "capabilities": [
          {
            "name": "actions.capability.SCREEN_OUTPUT"
          },
          {
            "name": "actions.capability.ACCOUNT_LINKING"
          },
          {
            "name": "actions.capability.MEDIA_RESPONSE_AUDIO"
          },
          {
            "name": "actions.capability.AUDIO_OUTPUT"
          },
          {
            "name": "actions.capability.WEB_BROWSER"
          }
        ]
      },
      "availableSurfaces": [
        {
          "capabilities": [
            {
              "name": "actions.capability.AUDIO_OUTPUT"
            },
            {
              "name": "actions.capability.SCREEN_OUTPUT"
            },
            {
              "name": "actions.capability.WEB_BROWSER"
            }
          ]
        }
      ]
    }
  },
  "session": "projects/PROJECT_ID/agent/sessions/ABwppHGIgmmU3zBcYMF_vWoHaM4JUo3wniYBHdbUF25l63G7EQWjRnlne8Ar7AOcRHWn1lrEKGy8qdP0UXLcWDBq93k"
}
.
.
JSON del SDK de Actions

Ten en cuenta que el siguiente JSON describe una solicitud al webhook.

{
  "user": {
    "permissions": [
      "UPDATE"
    ],
    "locale": "en-US",
    "userVerificationStatus": "VERIFIED"
  },
  "conversation": {
    "conversationId": "ABwppHEP6OAFZHkSGEiZ5HYM9qrlk8YtIH1DQmJ52cxXELSPvM-kSc_tMJ_5O6ITbgVJlY9i2FIsKWjE_HXLke48",
    "type": "NEW"
  },
  "inputs": [
    {
      "intent": "actions.intent.PERMISSION",
      "rawInputs": [
        {
          "inputType": "KEYBOARD",
          "query": "yes"
        }
      ],
      "arguments": [
        {
          "name": "PERMISSION",
          "boolValue": true,
          "textValue": "true"
        },
        {
          "name": "text",
          "rawText": "yes",
          "textValue": "yes"
        },
        {
          "name": "UPDATES_USER_ID",
          "textValue": "ABwppHFvBKC-tMYUsUjJkm3YECgZvd6A3sOc7KuQvO4ZdQX3bGLmyoQ41dh4Zmtlzv_kaOKBt1Sf6eRpNbayynrl"
        }
      ]
    }
  ],
  "surface": {
    "capabilities": [
      {
        "name": "actions.capability.AUDIO_OUTPUT"
      },
      {
        "name": "actions.capability.WEB_BROWSER"
      },
      {
        "name": "actions.capability.SCREEN_OUTPUT"
      },
      {
        "name": "actions.capability.ACCOUNT_LINKING"
      },
      {
        "name": "actions.capability.MEDIA_RESPONSE_AUDIO"
      }
    ]
  },
  "availableSurfaces": [
    {
      "capabilities": [
        {
          "name": "actions.capability.AUDIO_OUTPUT"
        },
        {
          "name": "actions.capability.SCREEN_OUTPUT"
        },
        {
          "name": "actions.capability.WEB_BROWSER"
        }
      ]
    }
  ]
}

Envíe notificaciones

Puedes enviar notificaciones push a los usuarios con la API de Actions. Para usar esta API, debes activar la API en tu proyecto de Google Cloud, configurar y descargar una Clave de cuenta de servicio JSON. Consulta el paso 8 en las instrucciones de la muestra de código aquí.

Luego, puedes usar la biblioteca cliente de Google OAuth2 para intercambiar la clave de la cuenta de servicio. para un token de acceso y usarlo para autenticar tus solicitudes a la API de Actions.

Obtener una clave de cuenta de servicio

  1. Ve a esta URL y reemplaza “example-project-1”. al final con el ID del proyecto. en la Consola de Actions: https://console.developers.google.com/apis/api/actions.googleapis.com/overview?project=example-project-1
  2. Si ves el botón Habilitar, haz clic en él. De lo contrario, continúa con el paso 3.
  3. Ve a esta URL y reemplaza “example-project-1”. al final con el ID del proyecto. en la Consola de Actions: https://console.developers.google.com/apis/credentials?project=example-project-1
  4. Haz clic en Crear credenciales > Clave de cuenta de servicio.
  5. Haz clic en el cuadro Seleccionar debajo de Cuenta de servicio y, a continuación, en Nuevo servicio. Cuenta.
  6. Asígnale un nombre a la cuenta de servicio, como “notificaciones” y el Rol de Propietario del proyecto.
  7. Selecciona el tipo de clave JSON y haz clic en Crear. Una clave de cuenta de servicio JSON es descargado en tu máquina local.

Intercambia la clave por un token de acceso y envía una notificación

Para enviar una notificación a través de la API de Actions, debes intercambiar la clave de la cuenta de servicio para un token de acceso. Recomendamos usar un cliente de la API de Google biblioteca para hacerlo. En la serie de fragmentos de código que aparece a continuación, usaremos el Biblioteca cliente de Node.js de la API de Google.

  1. Instala la biblioteca cliente de la API de Google y solicita lo siguiente: npm install googleapis request --save
  2. Usa el siguiente código para obtener un token de acceso de la clave de la cuenta de servicio y envía una notificación push:
Dialogflow para Node.js
const {google} = require('googleapis');
const request = require('request');

const jwtClient = new google.auth.JWT(
  serviceAccount.client_email, null, serviceAccount.private_key,
  ['https://www.googleapis.com/auth/actions.fulfillment.conversation'],
  null
);

jwtClient.authorize((err, tokens) => {
  if (!err) {
    request.post('https://actions.googleapis.com/v2/conversations:send', {
      auth: {
        bearer: tokens.access_token,
      },
      json: true,
      body: {
        customPushMessage: {
          userNotification: {
            title: 'Push Notification Title',
          },
          target: {
            userId: '<UPDATES_USER_ID>',
            intent: 'Notification Intent',
          },
        },
        isInSandbox: true,
      },
    }, (err, httpResponse, body) => {
      console.log(`${httpResponse.statusCode}: ${httpResponse.statusMessage}`);
    });
  }
});
.
.
SDK de Actions para Node.js
const {google} = require('googleapis');
const request = require('request');

const jwtClient = new google.auth.JWT(
  serviceAccount.client_email, null, serviceAccount.private_key,
  ['https://www.googleapis.com/auth/actions.fulfillment.conversation'],
  null
);

jwtClient.authorize((err, tokens) => {
  if (!err) {
    request.post('https://actions.googleapis.com/v2/conversations:send', {
      auth: {
        bearer: tokens.access_token,
      },
      json: true,
      body: {
        customPushMessage: {
          userNotification: {
            title: 'Push Notification Title',
          },
          target: {
            userId: '<UPDATES_ORDER_ID>',
            intent: 'Notification Intent',
          },
        },
        isInSandbox: true,
      },
    }, (err, httpResponse, body) => {
      console.log(`${httpResponse.statusCode}: ${httpResponse.statusMessage}`);
    });
  }
});
.
.
Dialogflow Java
final class Notification {

  private final String title;

  Notification(String title) {
    this.title = title;
  }

  String getTitle() {
    return title;
  }
}

final class Target {

  private final String userId;
  private final String intent;
  private final String locale;

  Target(String userId, String intent, String locale) {
    this.userId = userId;
    this.intent = intent;
    this.locale = locale;
  }

  String getUserId() {
    return userId;
  }

  String getIntent() {
    return intent;
  }

  String getLocale() {
    return locale;
  }
}

final class PushMessage {

  private final Notification userNotification;
  private final Target target;

  PushMessage(Notification userNotification, Target target) {
    this.userNotification = userNotification;
    this.target = target;
  }

  Notification getUserNotification() {
    return userNotification;
  }

  Target getTarget() {
    return target;
  }
}

final class PushNotification {

  private final PushMessage customPushMessage;
  private boolean isInSandbox;

  PushNotification(PushMessage customPushMessage, boolean isInSandbox) {
    this.customPushMessage = customPushMessage;
    this.isInSandbox = isInSandbox;
  }

  PushMessage getCustomPushMessage() {
    return customPushMessage;
  }

  boolean getIsInSandbox() {
    return isInSandbox;
  }
}

private PushNotification createNotification(String title, String userId, String intent, String locale) {
  Notification notification = new Notification(title);
  Target target = new Target(userId, intent, locale);
  PushMessage message = new PushMessage(notification, target);
  boolean isInSandbox = true;
  return new PushNotification(message, isInSandbox);
}

private ServiceAccountCredentials loadCredentials() throws IOException {
  String actionsApiServiceAccountFile =
      this.getClass().getClassLoader().getResource("service-account.json").getFile();
  InputStream actionsApiServiceAccount = new FileInputStream(actionsApiServiceAccountFile);
  ServiceAccountCredentials serviceAccountCredentials =
      ServiceAccountCredentials.fromStream(actionsApiServiceAccount);
  return (ServiceAccountCredentials)
      serviceAccountCredentials.createScoped(
          Collections.singleton(
              "https://www.googleapis.com/auth/actions.fulfillment.conversation"));
}

private String getAccessToken() throws IOException {
  AccessToken token = loadCredentials().refreshAccessToken();
  return token.getTokenValue();
}

public void sendNotification(String title, String userId, String intent, String locale) throws IOException {
  Preconditions.checkNotNull(title, "title cannot be null.");
  Preconditions.checkNotNull(userId, "userId cannot be null.");
  Preconditions.checkNotNull(intent, "intent cannot be null.");
  Preconditions.checkNotNull(locale, "locale cannot be null");
  PushNotification notification = createNotification(title, userId, intent, locale);

  HttpPost request = new HttpPost("https://actions.googleapis.com/v2/conversations:send");

  String token = getAccessToken();

  request.setHeader("Content-type", "application/json");
  request.setHeader("Authorization", "Bearer " + token);

  StringEntity entity = new StringEntity(new Gson().toJson(notification));
  entity.setContentType(ContentType.APPLICATION_JSON.getMimeType());
  request.setEntity(entity);
  HttpClient httpClient = HttpClientBuilder.create().build();
  httpClient.execute(request);
}
.
.
SDK de Actions para Java
final class Notification {

  private final String title;

  Notification(String title) {
    this.title = title;
  }

  String getTitle() {
    return title;
  }
}

final class Target {

  private final String userId;
  private final String intent;

  Target(String userId, String intent) {
    this.userId = userId;
    this.intent = intent;
  }

  String getUserId() {
    return userId;
  }

  String getIntent() {
    return intent;
  }
}

final class PushMessage {

  private final Notification userNotification;
  private final Target target;

  PushMessage(Notification userNotification, Target target) {
    this.userNotification = userNotification;
    this.target = target;
  }

  Notification getUserNotification() {
    return userNotification;
  }

  Target getTarget() {
    return target;
  }
}

final class PushNotification {

  private final PushMessage customPushMessage;
  private boolean isInSandbox;

  PushNotification(PushMessage customPushMessage, boolean isInSandbox) {
    this.customPushMessage = customPushMessage;
    this.isInSandbox = isInSandbox;
  }

  PushMessage getCustomPushMessage() {
    return customPushMessage;
  }

  boolean getIsInSandbox() {
    return isInSandbox;
  }
}

private PushNotification createNotification(String title, String userId, String intent) {
  Notification notification = new Notification(title);
  Target target = new Target(userId, intent);
  PushMessage message = new PushMessage(notification, target);
  boolean isInSandbox = true;
  return new PushNotification(message, isInSandbox);
}

private ServiceAccountCredentials loadCredentials() throws IOException {
  String actionsApiServiceAccountFile =
      this.getClass().getClassLoader().getResource("service-account.json").getFile();
  InputStream actionsApiServiceAccount = new FileInputStream(actionsApiServiceAccountFile);
  ServiceAccountCredentials serviceAccountCredentials =
      ServiceAccountCredentials.fromStream(actionsApiServiceAccount);
  return (ServiceAccountCredentials)
      serviceAccountCredentials.createScoped(
          Collections.singleton(
              "https://www.googleapis.com/auth/actions.fulfillment.conversation"));
}

private String getAccessToken() throws IOException {
  AccessToken token = loadCredentials().refreshAccessToken();
  return token.getTokenValue();
}

public void sendNotification(String title, String userId, String intent) throws IOException {
  Preconditions.checkNotNull(title, "title cannot be null.");
  Preconditions.checkNotNull(userId, "userId cannot be null.");
  Preconditions.checkNotNull(intent, "intent cannot be null.");
  PushNotification notification = createNotification(title, userId, intent);

  HttpPost request = new HttpPost("https://actions.googleapis.com/v2/conversations:send");

  String token = getAccessToken();

  request.setHeader("Content-type", "application/json");
  request.setHeader("Authorization", "Bearer " + token);

  StringEntity entity = new StringEntity(new Gson().toJson(notification));
  entity.setContentType(ContentType.APPLICATION_JSON.getMimeType());
  request.setEntity(entity);
  HttpClient httpClient = HttpClientBuilder.create().build();
  httpClient.execute(request);
}