You are viewing documentation for our open source project which is maintained by the community. If you want to get started building assistants with Rasa please check out our latest [documentation here](/content/docs/index.html).

When a Rasa assistant calls a custom action, it sends a request to the action server. Rasa only knows about whatever events and responses come back in the request response; it's up to the action server to call the correct code based on the action name that Rasa provides.

To better understand what happens when Rasa calls a custom action, consider the following example:

You have deployed a weather bot to both Facebook and Slack. The user can ask for the weather with the intent `ask_weather`. There is a slot `location` which will be filled if the user has specified a location. The action `action_tell_weather` will use an API to get the weather forecast, using a default location if the user doesn't specify one. The action will set the `temperature` to the maximum temperature of the weather forecast. The message returned will differ according to the channel they are using.

##### Compressed body in HTTP requests

Rasa has the capability to compress the HTTP request body for custom actions. By default, this option is off to keep backward compatibility with older versions of custom action servers which did not receive the compressed body in the HTTP request for custom actions. To enable this option, set environment variable COMPRESS_ACTION_SERVER_REQUEST to `True`.

Rasa SDK versions `3.2.2`, `3.3.1`, `3.4.1` and upwards, support both compressed and non-compressed body in the HTTP request for running custom action server. There is no additional setup required.

## Custom Action Input

Your action server receives the following payload from the Rasa server:

```json
{
  "next_action": "action_tell_weather",
  "sender_id": "2687378567977106",
  "tracker": {
    "sender_id": "2687378567977106",
    "slots": {
      "location": null,
      "temperature": null
    },
    "latest_message": {
      "text": "/ask_weather",
      "intent": {
        "name": "ask_weather",
        "confidence": 1
      },
      "intent_ranking": [
        {
          "name": "ask_weather",
          "confidence": 1
        }
      ],
      "entities": []
    },
    "latest_event_time": 1599850576.655345,
    "followup_action": null,
    "paused": false,
    "events": [
      {
        "event": "action",
        "timestamp": 1599850576.654908,
        "name": "action_session_start",
        "policy": null,
        "confidence": null
      },
      {
        "event": "session_started",
        "timestamp": 1599850576.654916
      },
      {
        "event": "action",
        "timestamp": 1599850576.654928,
        "name": "action_listen",
        "policy": null,
        "confidence": null
      },
      {
        "event": "user",
        "timestamp": 1599850576.655345,
        "text": "/ask_weather",
        "parse_data": {
          "text": "/ask_weather",
          "intent": {
            "name": "ask_weather",
            "confidence": 1
          },
          "intent_ranking": [
            {
              "name": "ask_weather",
              "confidence": 1
            }
          ],
          "entities": []
        },
        "input_channel": "facebook",
        "message_id": "3f2f2317dada4908b7a841fd3eab6bf9",
        "metadata": {}
      }
    ],
    "latest_input_channel": "facebook",
    "active_form": {},
    "latest_action_name": "action_listen"
  },
  "domain": {
    "config": {
      "store_entities_as_slots": true
    },
    "session_config": {
      "session_expiration_time": 60,
      "carry_over_slots_to_new_session": true
    },
    "intents": [
      {
        "greet": {
          "use_entities": true
        }
      },
      {
        "ask_weather": {
          "use_entities": true
        }
      }
    ],
    "entities": [],
    "slots": {
      "location": {
        "type": "rasa.core.slots.UnfeaturizedSlot",
        "initial_value": null,
        "auto_fill": true
      },
      "temperature": {
        "type": "rasa.core.slots.UnfeaturizedSlot",
        "initial_value": null,
        "auto_fill": true
      }
    },
    "responses": {
      "utter_greet": [
        {
          "text": "Hey! How are you?"
        }
      ]
    },
    "actions": [
      "action_tell_weather",
      "utter_greet"
    ],
    "forms": []
  },
  "version": "2.0.0"
}
```

### `next_action`

The `next_action` field tells your action server what action to run. Your actions don't have to be implemented as classes, but they do have to be callable by name.

In the example case, your action server should run the action `action_tell_weather`.

### `sender_id`

The `sender_id` tells you the unique ID of the user having the conversation. Its format varies according to the input channel. What it tells you about the user also depends on the input channel and how the user is identified by the channel.

In the example case, the `sender_id` is not used for anything.

### `tracker`

The `tracker` contains information about the conversation, including a history of events and a record of all slots:

- `sender_id`: The same `sender_id` as is available in the top level of the payload
- `slots`: Each slot in your bot's domain and its value at the current time
- `latest_message`: The attributes of the latest message
- `latest_event_time`: The timestamp at which the last event was added to the tracker
- `followup_action`: The action called was a forced follow up action
- `paused`: Whether the conversation is currently paused
- `events`: A list of all previous events
- `latest_input_channel`: The input channel from which the last user message was received
- `active_form`: The name of the currently active form, if any
- `latest_action_name`: The name of the last action the bot executed

In the example case, your custom action uses the value of the `location` slot (if it is set) to get the weather forecast. It also checks the `latest_input_channel` property and formats the message payload so that it will display correctly in Facebook Messenger.

### `domain`

The `domain` is a json representation of your `domain.yaml` file. It is unlikely that a custom action will refer to its contents, as they are static and do not indicate the state of the conversation.

You can control if an action should receive a domain or not.

### `version`

This is the version of the Rasa server. A custom action is also unlikely to refer to this, although you might use it in a verification step if your action server is only compatible with certain Rasa versions.

## Custom Action Output

The Rasa server expects a dictionary of `events` and `responses` as a response to a custom action call.

### `events`

Events are how your action server can influence the conversation. In the example case, your custom action should store the maximum temperature in the `temperature` slot, so it needs to return a `slot` event. To set the slot and do nothing else, your response payload would look like this:

```json
{
  "events": [
    {
      "event": "slot",
      "timestamp": null,
      "name": "temperature",
      "value": "30"
    }
  ],

"responses": []
}
```

Note that events will be applied to the tracker in the order you list them; with `slot` events, the order won't matter, but with other event types it can.

### `responses`

A response can be of any of the response types described in the documentation on rich responses. In the example case, you want to send the user a message with the weather forecast. To send a regular text message, the response payload would look like this:

```json
{
  "events": [
    {
      "event": "slot",
      "timestamp": null,
      "name": "temperature",
      "value": "30"
    }
  ],

"responses": [
    {
      "text": "This is your weather forecast!"
    }
  ]
}
```

However, you want to make use of your channels' specific capabilities. Since the `latest_input_channel` was Facebook, you add a response with a custom payload that will be rendered as a media message according to Facebook's API spec. Your response payload then looks like this:

```json
{
  "events": [
    {
      "event": "slot",
      "timestamp": null,
      "name": "temperature",
      "value": "30"
    }
  ],

"responses": [
    {
      "text": "This is your weather forecast!"
    },
    {
      "attachment": {
        "type": "template",
        "payload": {
          "template_type": "media",
          "elements": [
            {
              "media_type": "weather_forcast.gif",
              "attachment_id": "<id from facebook upload endpoint>"
            }
          ]
        }
      }
    }
  ]
}
```

When this response is sent back to the Rasa server, Rasa will apply the `slot` event and two responses to the tracker, and return both messages to the user.

## Special Action Types

There are special action types that are automatically triggered under certain circumstances, namely default actions and slot validation actions. These special action types have predefined naming conventions that must be followed to maintain the automatic triggering behavior.

You can customize a default action by implementing a custom action with exactly the same name. Please see the docs on default actions for the expected behavior of each action.

Slot validation actions are run on every user turn, depending on whether a form is active or not. A slot validation action that should run when a form is not active must be called `action_validate_slot_mappings`. A slot validation action that should run when a form is active must be called `validate_<form name>`. These actions are expected to return `SlotSet` events only and to behave like the Rasa SDK `ValidationAction` class and `FormValidationAction` class respectively.
