Webhook service

To use fulfillment in a production system, you should implement and deploy a webhook service. To handle fulfillment, your webhook service needs to accept JSON requests and return JSON responses as specified in this guide. The detailed processing flow for fulfillment and webhooks is described in the fulfillment overview document.

Webhook service requirements

The following requirements must be met by your webhook service:

  • It must handle HTTPS requests. HTTP is not supported. If you host your webhook service on Google Cloud Platform using a Compute or Serverless Computing solution, see the product documentation for serving with HTTPS. For other hosting options, see Get an SSL certificate for your domain.
  • Its URL for requests must be publicly accessible.
  • It must handle POST requests with a JSON WebhookRequest body.
  • It must respond to WebhookRequest requests with a JSON WebhookResponse body.

Authentication

It's important to secure your webhook service, so that only you or your Dialogflow agent are authorized to make requests. Dialogflow supports the following mechanisms for authentication:

  • Basic authentication with login and password. This is configured when enabling fulfillment.
  • Authentication with authentication headers. This is configured when enabling fulfillment.
  • Mutual TLS authentication.

Webhook request

When an intent configured for fulfillment is matched, Dialogflow sends an HTTPS POST webhook request to your webhook service. The body of this request is a JSON object with information about the matched intent.

See the WebhookRequest reference documentation for details.

Here is a sample request:

{
  "responseId": "response-id",
  "session": "projects/project-id/agent/sessions/session-id",
  "queryResult": {
    "queryText": "End-user expression",
    "parameters": {
      "param-name": "param-value"
    },
    "allRequiredParamsPresent": true,
    "fulfillmentText": "Response configured for matched intent",
    "fulfillmentMessages": [
      {
        "text": {
          "text": [
            "Response configured for matched intent"
          ]
        }
      }
    ],
    "outputContexts": [
      {
        "name": "projects/project-id/agent/sessions/session-id/contexts/context-name",
        "lifespanCount": 5,
        "parameters": {
          "param-name": "param-value"
        }
      }
    ],
    "intent": {
      "name": "projects/project-id/agent/intents/intent-id",
      "displayName": "matched-intent-name"
    },
    "intentDetectionConfidence": 1,
    "diagnosticInfo": {},
    "languageCode": "en"
  },
  "originalDetectIntentRequest": {}
}

Webhook response

Once your webhook receives a webhook request, it needs to send a webhook response. The body of this response is a JSON object with the following information:

The following limitations apply to your response:

  • The response must occur within 10 seconds for Google Assistant applications or 5 seconds for all other applications, otherwise the request will time out.
  • The response must be less than or equal to 64 KiB in size.

See the WebhookResponse reference documentation for details.

Text response

Example for a text response:

{
  "fulfillmentMessages": [
    {
      "text": {
        "text": [
          "Text response from webhook"
        ]
      }
    }
  ]
}

Card response

Example for a card response:

{
  "fulfillmentMessages": [
    {
      "card": {
        "title": "card title",
        "subtitle": "card text",
        "imageUri": "https://example.com/images/example.png",
        "buttons": [
          {
            "text": "button text",
            "postback": "https://example.com/path/for/end-user/to/follow"
          }
        ]
      }
    }
  ]
}

Google Assistant response

Example for a Google Assistant response:

{
  "payload": {
    "google": {
      "expectUserResponse": true,
      "richResponse": {
        "items": [
          {
            "simpleResponse": {
              "textToSpeech": "this is a Google Assistant response"
            }
          }
        ]
      }
    }
  }
}

Context

Example that sets output context:

{
  "fulfillmentMessages": [
    {
      "text": {
        "text": [
          "Text response from webhook"
        ]
      }
    }
  ],
  "outputContexts": [
    {
      "name": "projects/project-id/agent/sessions/session-id/contexts/context-name",
      "lifespanCount": 5,
      "parameters": {
        "param-name": "param-value"
      }
    }
  ]
}

Event

Example that invokes a custom event:

{
  "followupEventInput": {
    "name": "event-name",
    "languageCode": "en-US",
    "parameters": {
      "param-name": "param-value"
    }
  }
}

Session entity

Example that sets a session entity:

{
  "fulfillmentMessages": [
    {
      "text": {
        "text": [
          "Choose apple or orange"
        ]
      }
    }
  ],
  "sessionEntityTypes":[
    {
      "name":"projects/project-id/agent/sessions/session-id/entityTypes/fruit",
      "entities":[
        {
          "value":"APPLE_KEY",
          "synonyms":[
            "apple",
            "green apple",
            "crabapple"
          ]
        },
        {
          "value":"ORANGE_KEY",
          "synonyms":[
            "orange"
          ]
        }
      ],
      "entityOverrideMode":"ENTITY_OVERRIDE_MODE_OVERRIDE"
    }
  ]
}

Enable and manage fulfillment

To enable and manage fulfillment for your agent with the console:

  1. Go to the Dialogflow ES Console.
  2. Select an agent.
  3. Select Fulfillment in the left sidebar menu.
  4. Toggle the Webhook field to Enabled.
  5. Provide the details for your webhook service in the form. If your webhook doesn't require authentication, leave the authentication fields blank.
  6. Click Save at the bottom of the page.

Screenshot of enabling fulfillment.

To enable and manage fulfillment for your agent with the API, see the agent reference. The getFulfillment and updateFulfillment methods can be used to manage fulfillment settings.

To enable fulfillment for an intent with the console:

  1. Select Intents in the left sidebar menu.
  2. Select an intent.
  3. Scroll down to the Fulfillment section.
  4. Toggle Enable webhook call for this intent to on.
  5. Click Save.

To enable fulfillment for an intent with the API, see the intents reference. Set the webhookState field to WEBHOOK_STATE_ENABLED.

Webhook errors

If your webhook service encounters an error, it should return one of the following HTTP status codes:

  • 400 Bad Request
  • 401 Unauthorized
  • 403 Forbidden
  • 404 Not found
  • 500 Server fault
  • 503 Service Unavailable

In any of the following error situations, Dialogflow responds to the end-user with the built-in response configured for the intent currently matched:

  • Response timeout exceeded.
  • Error status code received.
  • Response is invalid.
  • Webhook service is unavailable.

In addition, if the intent match was triggered by a detect intent API call, the status field in the detect intent response contains the webhook error information. For example:

"status": {
    "code": 206,
    "errorType": "webhook call failed with %error Code% error"
}

Samples

The following sample shows how to receive a WebhookRequest and send a WebhookResponse. This sample references intents created in the quickstart.

Go

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
)

type intent struct {
	DisplayName string `json:"displayName"`
}

type queryResult struct {
	Intent intent `json:"intent"`
}

type text struct {
	Text []string `json:"text"`
}

type message struct {
	Text text `json:"text"`
}

// webhookRequest is used to unmarshal a WebhookRequest JSON object. Note that
// not all members need to be defined--just those that you need to process.
// As an alternative, you could use the types provided by
// the Dialogflow protocol buffers:
// https://godoc.org/google.golang.org/genproto/googleapis/cloud/dialogflow/v2#WebhookRequest
type webhookRequest struct {
	Session     string      `json:"session"`
	ResponseID  string      `json:"responseId"`
	QueryResult queryResult `json:"queryResult"`
}

// webhookResponse is used to marshal a WebhookResponse JSON object. Note that
// not all members need to be defined--just those that you need to process.
// As an alternative, you could use the types provided by
// the Dialogflow protocol buffers:
// https://godoc.org/google.golang.org/genproto/googleapis/cloud/dialogflow/v2#WebhookResponse
type webhookResponse struct {
	FulfillmentMessages []message `json:"fulfillmentMessages"`
}

// welcome creates a response for the welcome intent.
func welcome(request webhookRequest) (webhookResponse, error) {
	response := webhookResponse{
		FulfillmentMessages: []message{
			{
				Text: text{
					Text: []string{"Welcome from Dialogflow Go Webhook"},
				},
			},
		},
	}
	return response, nil
}

// getAgentName creates a response for the get-agent-name intent.
func getAgentName(request webhookRequest) (webhookResponse, error) {
	response := webhookResponse{
		FulfillmentMessages: []message{
			{
				Text: text{
					Text: []string{"My name is Dialogflow Go Webhook"},
				},
			},
		},
	}
	return response, nil
}

// handleError handles internal errors.
func handleError(w http.ResponseWriter, err error) {
	w.WriteHeader(http.StatusInternalServerError)
	fmt.Fprintf(w, "ERROR: %v", err)
}

// HandleWebhookRequest handles WebhookRequest and sends the WebhookResponse.
func HandleWebhookRequest(w http.ResponseWriter, r *http.Request) {
	var request webhookRequest
	var response webhookResponse
	var err error

	// Read input JSON
	if err = json.NewDecoder(r.Body).Decode(&request); err != nil {
		handleError(w, err)
		return
	}
	log.Printf("Request: %+v", request)

	// Call intent handler
	switch intent := request.QueryResult.Intent.DisplayName; intent {
	case "Default Welcome Intent":
		response, err = welcome(request)
	case "get-agent-name":
		response, err = getAgentName(request)
	default:
		err = fmt.Errorf("Unknown intent: %s", intent)
	}
	if err != nil {
		handleError(w, err)
		return
	}
	log.Printf("Response: %+v", response)

	// Send response
	if err = json.NewEncoder(w).Encode(&response); err != nil {
		handleError(w, err)
		return
	}
}