> ## Documentation Index
> Fetch the complete documentation index at: https://docs.outrival.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Server Events

> Learn how to set up Webhooks and receive Server Events with OutRival.

Webhooks in the OutRival app allow for real-time notifications about specific events within the application. By providing a Webhook URL and a Webhook Secret, you can configure the OutRival app to call your specified URL during certain events. This enables your application to react and handle updates as they happen.

## Configuring Webhooks

To set up webhooks, you need to provide two pieces of information:

* **Webhook URL**: The endpoint URL to which the notifications should be sent.
* **Webhook Secret**: A secret key used to generate a signature for each payload, ensuring the security and integrity of the data being transmitted.

When an event occurs, the OutRival app generates a POST request to the provided Webhook URL. The payload of this request contains information about the event, and the `x-signature` header contains a signature generated from the payload using the Webhook Secret. This signature must be used to verify that the request is indeed from OutRival.

The payload of the webhook is structured as follows:

<ResponseField name="event" type="enum<string>" required>
  The type of server event.

  Available options: `status-changed`, `conversation-updated`, `function-call`
</ResponseField>

<ResponseField name="type" type="enum<string>" required>
  The type of chat modality.

  Available options: `VOICE`, `TEXT`, `SMS`
</ResponseField>

<ResponseField name="companionId" type="string" required>
  A unique identifier for the companion involved in the event
</ResponseField>

<ResponseField name="data" type="object" required>
  An object containing event-specific information (Event Data Details)
</ResponseField>

## Event Data Details

<Tabs>
  <Tab title="status-changed">
    <ResponseField name="messages" type="array<Message>" required>
      An array of chat messages

      <Expandable title="Message">
        <ResponseField name="role" type="enum<string>" required>
          Role of the chat message sender

          Available options: `bot`, `user`
        </ResponseField>

        <ResponseField name="content" type="string">
          Text of the chat message
        </ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="status" type="enum<string>">
      Chat current status

      Available options: `queued`, `ringing`, `in-progress`, `forwarding`, `ended`
    </ResponseField>

    {" "}

    <ResponseField name="startedAt" type="string" required>
      Chat started timestamp
    </ResponseField>

    {" "}

    <ResponseField name="endedAt" type="string">
      Chat ended timestamp
    </ResponseField>

    {" "}

    <ResponseField name="endedReason" type="string">
      The reason the chat ended
    </ResponseField>

    <ResponseField name="phoneNumber" type="string">
      User's phone number for SMS and Phone Call chats
    </ResponseField>
  </Tab>

  <Tab title="conversation-updated">
    <ResponseField name="messages" type="array<Message>" required>
      An array of chat messages

      <Expandable title="Message">
        <ResponseField name="role" type="enum<string>" required>
          Role of the chat message sender

          Available options: `bot`, `user`
        </ResponseField>

        <ResponseField name="content" type="string">
          Text of the chat message
        </ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="phoneNumber" type="string">
      User's phone number for SMS and Phone Call chats
    </ResponseField>

    <ResponseField name="timestamp" type="string" required>
      Conversation update timestamp
    </ResponseField>
  </Tab>

  <Tab title="function-call">
    <ResponseField name="name" type="string" required>
      Name of the called function
    </ResponseField>

    <ResponseField name="parameters" type="object">
      Object with parameters of the function call
    </ResponseField>
  </Tab>
</Tabs>

## Security and Verification

To ensure the security of the webhook mechanism, it is crucial to verify the `x-signature` header in each incoming request. This signature is generated by hashing the payload with the Webhook Secret. Your endpoint should compute the hash with the received payload and the secret you provided when setting up the webhook. If the computed hash matches the `x-signature` header, the request can be considered authentic and from OutRival.

Here are a few examples of how to verify the signature in different programming languages:

<Tabs>
  <Tab title="Node.js">
    ```javascript theme={null}
      const express = require('express');
      const crypto = require('crypto');

    const app = express();
    app.use(express.raw({ type: "*/*", limit: "10mb" })); // Set the encoding for express.raw()

    app.post('/your-webhook-endpoint', (req, res) => {
    const payload = req.body.toString("utf-8");
    const secret = 'your_shared_secret';
    const xSignature = req.headers['x-signature'];

        const generatedSignature = crypto.createHmac("sha256", secret).update(payload).digest("hex");

        if (generatedSignature === xSignature) {
          console.log('Signature is valid.');
          res.status(200).send('Signature verified');
        } else {
          console.log('Signature is invalid.');
          res.status(403).send('Invalid signature');
        }

    });

    app.listen(3000, () => console.log('Server running on port 3000'));

    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    from flask import Flask, request, jsonify
    import hmac
    import hashlib
    import json

    app = Flask(__name__)

    @app.route('/your-webhook-endpoint', methods=['POST'])
    def webhook():
        payload = request.json
        secret = 'your_shared_secret'
        x_signature = request.headers.get('X-Signature')

        generated_signature = hmac.new(secret.encode(), msg=json.dumps(payload).encode(), digestmod=hashlib.sha256).hexdigest()

        if generated_signature == x_signature:
            print('Signature is valid.')
            return jsonify({'message': 'Signature verified'}), 200
        else:
            print('Signature is invalid.')
            return jsonify({'message': 'Invalid signature'}), 403

    if __name__ == '__main__':
        app.run(debug=True, port=5000)
    ```
  </Tab>

  <Tab title="Ruby">
    ```ruby theme={null}
    from flask import Flask, request, jsonify
    import hmac
    import hashlib
    import json

    app = Flask(**name**)

    @app.route('/your-webhook-endpoint', methods=['POST'])
    def webhook():
    payload = request.json
    secret = 'your_shared_secret'
    x_signature = request.headers.get('X-Signature')

        generated_signature = hmac.new(secret.encode(), msg=json.dumps(payload).encode(), digestmod=hashlib.sha256).hexdigest()

        if generated_signature == x_signature:
            print('Signature is valid.')
            return jsonify({'message': 'Signature verified'}), 200
        else:
            print('Signature is invalid.')
            return jsonify({'message': 'Invalid signature'}), 403

    if **name** == '**main**':
    app.run(debug=True, port=5000)

    ```
  </Tab>

  <Tab title="PHP">
    ```php theme={null}
    <?php

    $secret = 'your_shared_secret';
    $payload = file_get_contents('php://input');
    $xSignature = $_SERVER['HTTP_X_SIGNATURE'] ?? '';

    $generatedSignature = hash_hmac('sha256', $payload, $secret);

    if (hash_equals($generatedSignature, $xSignature)) {
        http_response_code(200);
        echo 'Signature verified';
    } else {
        http_response_code(403);
        echo 'Invalid signature';
    }
    ```
  </Tab>

  <Tab title="C#">
    ```csharp theme={null}
    using Microsoft.AspNetCore.Builder;
    using Microsoft.AspNetCore.Http;
    using System;
    using System.IO;
    using System.Security.Cryptography;
    using System.Text;
    using System.Threading.Tasks;

    public class VerifySignatureMiddleware
    {
    private readonly RequestDelegate \_next;

        public VerifySignatureMiddleware(RequestDelegate next)
        {
            _next = next;
        }

        public async Task InvokeAsync(HttpContext context)
        {
            var secret = Encoding.UTF8.GetBytes("your_shared_secret");
            var payload = await new StreamReader(context.Request.Body).ReadToEndAsync();
            context.Request.Body.Position = 0; // Reset the stream for further reading

            var xSignature = context.Request.Headers["X-Signature"].ToString();
            using var hmac = new HMACSHA256(secret);
            var computedSignature = BitConverter.ToString(hmac.ComputeHash(Encoding.UTF8.GetBytes(payload))).Replace("-", "").ToLower();

            if (computedSignature.Equals(xSignature, StringComparison.OrdinalIgnoreCase))
            {
                await _next(context);
            }
            else
            {
                context.Response.StatusCode = 403;
                await context.Response.WriteAsync("Invalid signature");
            }
        }

    }

    // Extension method used to add the middleware to the HTTP request pipeline.
    public static class VerifySignatureMiddlewareExtensions
    {
    public static IApplicationBuilder UseVerifySignatureMiddleware(this IApplicationBuilder builder)
    {
    return builder.UseMiddleware<VerifySignatureMiddleware>();
    }
    }

    ```

    To use this middleware, add it to your application's request pipeline in the `Startup.cs` file:

    ```csharp theme={null}
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        // Other configurations...

        app.UseVerifySignatureMiddleware();

        // Further configurations...
    }
    ```
  </Tab>
</Tabs>

## Best Practices

* **Endpoint Resilience**: Ensure your webhook endpoint is designed to handle varying loads and can process requests in a timely manner.
* **Security**: Always verify the `x-signature` to confirm the authenticity of the incoming requests.
* **Error Handling**: Implement robust error handling to manage different types of payload and potential errors.

For any further questions or assistance with setting up webhooks, please contact our support team.
