Push bildirimleri (Dialogflow)

Dialogflow'da keşfet

Dialogflow'daki bildirim örneğimizi içe aktarmak için Devam'ı tıklayın. Ardından örneği dağıtmak ve test etmek için aşağıdaki adımları uygulayın:

  1. Bir temsilci adı girin ve örnek için yeni bir Dialogflow aracısı oluşturun.
  2. Temsilci içe aktarma işlemini tamamladıktan sonra Temsilciye git'i tıklayın.
  3. Ana gezinme menüsünden Karşılama'ya gidin.
  4. Satır İçi Düzenleyici'yi etkinleştirin ve ardından Dağıt'ı tıklayın. Düzenleyici, örnek kodu içerir.
  5. Ana gezinme menüsünden Entegrasyonlar'a gidin ve Google Asistan'ı tıklayın.
  6. Görüntülenen kalıcı pencerede, Değişiklikleri otomatik önizleme'yi etkinleştirin ve İşlem simülatörünü açmak için Test et'i tıklayın.
  7. Örneği test etmek için simülasyon aracında Talk to my test app ifadesini girin.
Devam

İşleminiz uygun olduğunda kullanıcılara bildirim gönderebilir. Örneğin, bir görevin son tarihi yaklaştığında hatırlatıcı gönderebilirsiniz.

Bu kılavuzda, İşleminiz için push bildirimlerini nasıl ayarlayacağınızı göstermek amacıyla referans olarak Actions on Google ipuçları örneğine yer verilmiştir. Kullanıcılar bu İşlemi çağırdığında, kendi Action'larını geliştirmeyle ilgili bir ipucu almak isteyip istemedikleri sorulur. Kullanıcılar, ipucu için belirli veya rastgele seçilen bir kategoriyi seçebilir veya en son ipucunu dinlemeyi tercih edebilir.

Desteklenen yüzeyler

Push bildirimleri, Android ve iOS cihazlarda kullanılabilir (iOS cihazlarda push bildirimlerini almak için Asistan uygulaması yüklü olmalıdır). Sesle etkinleştirilen hoparlörlerde, akıllı ekranlarda veya diğer yüzeylerde şu anda desteklenmemektedir.

Ön koşullar

Actions projenizdeki İşlemlerden en az biri, kullanıcı Asistan'dan alınan bir bildirime dokunduğunda çağrılacak olan bir tetikleyici amaç olarak yapılandırılmalıdır.

İşlemleriniz bir push bildiriminden Varsayılan Karşılama Niyeti'ni tetikleyecek şekilde yapılandırılamaz.

Konsol kurulumu

İşleminize push bildirimi desteği eklemek için:

  1. Actions Console'a, ardından Derleme > İşlemler bölümüne gidin.

  2. Push bildirimlerini etkinleştirmek istediğiniz ek tetikleme amacıyla eşleşen İşlemi tıklayın.

    Actions on Google ipuçları örneği için "tell_latest_tip" seçilir.

  3. Kullanıcı etkileşimi bölümüne gidin ve Push bildirimi göndermek ister misiniz? seçeneğini etkinleştirin.

  4. Bir İçerik başlığı girin.

    Actions on Google ipucu örneğinin başlığı "Yeni ipucu eklendi" olabilir.

  5. Kaydet'i tıklayın.

İçe Aktarımlar

Sonraki bölümlerin amaçları doğrultusunda, sipariş karşılama kodunuzda aşağıdaki içe aktarma işlemlerini beyan etmeniz gerekir:

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

Kaydolan kullanıcılar

Kullanıcılara push bildirimleri gönderebilmeniz için öncelikle bu bildirimleri etkinleştirmelerini istemeniz gerekir. İzin almak için öneri çipi göstererek bu işlemi gerçekleştirebilirsiniz. Kullanıcı izin verdiğinde, bu kullanıcıya push bildirimleri göndermek için bir güncelleme kullanıcı kimliği alırsınız.

Etkinleştirme için öneri çiplerini göster

Kullanıcıların İşleminizden push bildirimleri alabilmesi için onlara bir öneri çipi gösterip push bildirimlerini etkinleştirmelerini sağlamanız gerekir.

Aşağıdaki kod snippet'i, kullanıcıya metin yanıtıyla birlikte "Yeni ipuçları hakkında uyarı ver" öneri çipi gönderir.

Dialogflow Node.js
conv.ask('I can send you push notifications. Would you like that?');
conv.ask(new Suggestions('Send notifications'));
Actions SDK 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"
    });
Actions SDK Java
responseBuilder
    .add("I can send you push notifications. Would you like that?")
    .addSuggestions(new String[] {
        "Send notifications"
    });
Dialogflow JSON

Aşağıdaki JSON'un bir webhook yanıtını açıkladığını unutmayın.

{
  "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"
          }
        ]
      }
    }
  }
}
Actions SDK JSON

Aşağıdaki JSON'un bir webhook yanıtını açıkladığını unutmayın.

{
  "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"
            }
          ]
        }
      }
    }
  ]
}

Kullanıcılar çipe dokunduktan sonra UPDATE iznini almanız gerekir. Aşağıdaki kod, bunu Node.js istemci kitaplığındaki askForUpdatePermission işleviyle nasıl yapacağınızı göstermektedir.

Dialogflow Node.js
  1. Dialogflow konsolunda aracınızı açın ve güncellemeler için yapılandırdığınız niyeti seçin.
  2. Aşağı kaydırarak Yanıt'a gidin ve Google Asistan sekmesini açın.
  3. Mesaj içeriği ekle'yi tıklayın ve Öneri çipleri'ni seçin.
  4. Çip metnini, kullanıcıyı etkinleştirmeye davet eden bir şeye ayarlayın. Actions on Google ipuçları örneğinde, çipi Yeni ipuçları konusunda uyar olarak ayarladık.
  5. Örneğin setup_push adlı başka bir Dialogflow niyeti ekleyin ve setup.push gibi karşılık gelen bir işlem ayarlayın. Bu amacın kullanıcı ifadesi, Yeni ipuçları konusunda beni uyar örneğimizdeki kayıt çipinin metniyle eşleşmelidir.
Aşağıdaki snippet'te Node.js için Actions on Google istemci kitaplığını kullanarak iznin nasıl isteneceği gösterilmektedir:
app.intent('Subscribe to Notifications', (conv) => {
  conv.ask(new UpdatePermission({
    intent: 'Notification',
  }));
});
Actions SDK Node.js

NLU çözümünüzü, kullanıcı ifadesi push bildirimleri etkinleştirme isteminin değeriyle eşleşirse izni isteyen bir işlevi tetikleyecek şekilde yapılandırmanız gerekir. Aşağıda, dize eşleştirmeye dayalı çok temel bir örnek verilmiştir:

conv.ask(new UpdatePermission({
  intent: 'Notification',
}));
Dialogflow Java
  1. Dialogflow konsolunda aracınızı açın ve güncellemeler için yapılandırdığınız niyeti seçin.
  2. Aşağı kaydırarak Yanıt'a gidin ve Google Asistan sekmesini açın.
  3. Mesaj içeriği ekle'yi tıklayın ve Öneri çipleri'ni seçin.
  4. Çip metnini, kullanıcıyı etkinleştirmeye davet eden bir şeye ayarlayın. Actions on Google ipuçları örneğinde, çipi Yeni ipuçları konusunda uyar olarak ayarladık.
  5. Örneğin setup_push adlı başka bir Dialogflow niyeti ekleyin ve setup.push gibi karşılık gelen bir işlem ayarlayın. Bu amacın kullanıcı ifadesi, Yeni ipuçları konusunda beni uyar örneğimizdeki kayıt çipinin metniyle eşleşmelidir.
Aşağıdaki snippet'te Actions on Google Java/Kotlin istemci kitaplığını kullanarak iznin nasıl isteneceği gösterilmektedir:
@ForIntent("Subscribe to Notifications")
public ActionResponse subscribeToNotifications(ActionRequest request) {
  ResponseBuilder responseBuilder = getResponseBuilder(request);
  responseBuilder.add(new UpdatePermission().setIntent("Notification"));
  return responseBuilder.build();
}
Actions SDK Java

NLU çözümünüzü, kullanıcı ifadesi push bildirimleri etkinleştirme isteminin değeriyle eşleşirse izni isteyen bir işlevi tetikleyecek şekilde yapılandırmanız gerekir. Aşağıda, dize eşleştirmeye dayalı çok temel bir örnek verilmiştir:

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

Aşağıdaki JSON dosyasında Dialogflow kullanan bir webhook yanıtının açıklandığını unutmayın.

{
  "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"
          }
        }
      }
    }
  }
}
Actions SDK JSON

Aşağıdaki JSON'un, Actions SDK'sı kullanan bir webhook yanıtını açıkladığını unutmayın.

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

Aboneliği tamamlama

Aboneliği Node.js webhook'unuzdan sonlandırmak için kullanıcının bildirim kimliğini ve seçtiği niyeti kaydetmeniz gerekir. Kullanıcı izin verirse her ikisi de bağımsız değişken olarak aktarılır.

İşleminiz Dialogflow ile derlenmişse şunları yapmanız gerekir:

  • actions_intent_PERMISSION işlemini yapan bir intent ekleyin.
  • Webhook'unuzun daha sonra filtreleyebilmesi için amacın İşlem adını belirtin.

Aşağıdaki kod, işlem adı finish.push.setup olan finish_push_setup adlı bir niyetle Dialogflow niyetinin nasıl işleneceğini gösterir:

Dialogflow 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.`);
  }
});
Actions SDK 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();
}
Actions SDK 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();
}
Dialogflow JSON

Aşağıdaki JSON'un webhook'a yapılan bir isteği açıkladığını unutmayın.

{
  "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"
}
Actions SDK JSON

Aşağıdaki JSON'un webhook'a yapılan bir isteği açıkladığını unutmayın.

{
  "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"
        }
      ]
    }
  ]
}

Bildirim gönder

Actions API'yi kullanarak kullanıcılara push bildirimleri gönderebilirsiniz. Bu API'yi kullanmak için Google Cloud projenizde API'yi etkinleştirmeniz ve bir JSON hizmet hesabı anahtarı indirip indirmeniz gerekir. Buradaki kod örneğindeki talimatlarda yer alan 8. adıma bakın.

Daha sonra Google OAuth2 istemci kitaplığını kullanarak hizmet hesabı anahtarını erişim jetonuyla değiştirebilir ve bu jetonu Actions API'ye yönelik isteklerinizin kimliğini doğrulamak için kullanabilirsiniz.

Hizmet hesabı anahtarı alma

  1. Şu URL'ye gidin: Sondaki "example-project-1" kısmını Actions konsolunda proje kimliğinizle değiştirin: https://console.developers.google.com/apis/api/actions.googleapis.com/overview?project=example-project-1
  2. Etkinleştir düğmesini görüyorsanız bu düğmeyi tıklayın. Adres eklemeniz gerekmiyorsa 3. adıma geçin.
  3. Şu URL'ye gidin. Sondaki "example-project-1" ifadesini, Actions konsolunda proje kimliğinizle değiştirin: https://console.developers.google.com/apis/credentials?project=example-project-1
  4. Kimlik bilgileri oluştur > Hizmet Hesabı Anahtarı'nı tıklayın.
  5. Hizmet Hesabı altındaki Seç kutusunu ve Yeni Hizmet Hesabı'nı tıklayın.
  6. Hizmet Hesabına "bildirimler" ve Proje Sahibi'nin Rolü gibi bir ad verin.
  7. JSON anahtar türünü seçin ve Create'i (Oluştur) tıklayın. Yerel makinenize bir JSON hizmet hesabı anahtarı indirilir.

Anahtarı bir erişim jetonuyla değiştirin ve bildirim gönderin

Actions API üzerinden bildirim göndermek için hizmet hesabı anahtarını erişim jetonuyla değiştirmeniz gerekir. Bunun için bir Google API istemci kitaplığı kullanmanızı öneririz. Takip eden kod snippet'i serisinde Google API Node.js istemci kitaplığını kullanıyoruz.

  1. Google API istemci kitaplığını yükleyip isteyin: npm install googleapis request --save
  2. Hizmet hesabı anahtarından erişim jetonu almak ve push bildirimi göndermek için aşağıdaki kodu kullanın:
Dialogflow 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}`);
    });
  }
});
Actions SDK 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);
}
Actions SDK 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);
}