Skip to content

weareviaai/via-platform

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

47 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

VIA AI Public Interfaces

Table of Contents

Prerequisites

The following sections reference a few values from your VIA AI tenant account that are accessible from the VIA AI Console:

  • Project ID: The ID of the project is available from the Projects view
  • Tenant API Key: The tenant-specific API key will be made available to you by your VIA AI contact
  • Webhook Secret: The webhook secret is available from the project settings, webhooks configuration view

VIA Messaging API

Authentication

Use Bearer token authentication using your tenant API key:

{
    "Content-Type": "application/json",
    "Authorization": "Bearer <YOUR TENANT API KEY>"
}

Sending a message

To post a message to a VIA concierge conversation use:

POST /api/message

With the following body payload (example):

{
    "project_id": 770,
    "from_id": "user@wearevia.ai",
    "message_text": "What events take place in San Diego in Oct 17-19, 2025?",
    "new_conversation": true,
    "params": {
        "param1": "param1 value",
        "param2": "param2 value"
    }
}
  • project_id: Your concierge project ID (viewable from the VIA AI Console)
  • from_id: A unique user identifier
  • message_text: Your message text
  • new_conversation: Use true to start a new conversation. If false, and a conversation already exists for the specified from_id the conversation will continue. Otherwise a new conversation will be created.
  • language: optional language identifier
  • params: Optional parameters. Parameters are accessible via instruction variables

The response:

{
    "success": true,
    "conversation_id": "r7z2vGJGukw610UQwonSl50y"
}

Use the conversation_id returned value to correlate the response over webhook with the appropriate message that was sent. Messages are always delivered in the order they were received.

Receiving VIA Platform Events using Webhooks

To receive VIA platform responses you will need to install a webhook via the VIA Console, subscribe to the message_reply event (see below) and verify the webhook successfully against your client.

VIA will call your webhook with the following payload:

{
  "timstamp": "<TIMESTAMP IN ISO FORMAT>",
  "project_id": "<PROJECT ID>",
  "event_id": "<EVENT_ID>", 
  "event_payload": "<EVENT PAYLOAD OBJECT>"
}

Supported Webhooks Event Types

message_reply

This event will be generated as a response to a /api/message call. The event payload object varies and depends on which schema is used by the AI to render the result. For example:

{
  "via_api_reply": {
    "response_type": "<RESPONSE TYPE (presentation schema name)>",
    "response": "<AI GENERATED PRESENTATION OBJECT>"
  },
  "followon": "How can I help you?",
  "options": [
    {
      "label": "Ask me another question",
      "emoji": "❔",
      "llm_value": "<AI GENERATED VALUE TO BE SENT BACK TO LLM>"
    },
    {
      "label": "Continue",
      "emoji": "πŸ‘",
      "llm_value": "<AI GENERATED VALUE TO BE SENT BACK TO LLM>"
    }
  ]
}

Controlling the Message Output JSON Format Using a Presentation Schema

Presentation Schemas can be used to control the returned reply to a message in order to utilize different rendering methods (referring specifically to the via_api_reply/response property in the returned message_reply payload). The via_api_reply/response type will contain schema ID used by the AI to format the output. Presentation schemas can be defined from the VIA Console, under the Instructions tab. You need to provide a unique ID for your schema and for API calls, the platform needs to be API. You may use explicit JSON or use node.js Zod module to define it using code.

When sending a message simply request the result to be returned using the presentation schema ID. For example: "What events take place in San Diego in Oct 17-19, 2025? Return your answer using the my_event_response schema"

Note If a schema cannot be found, the returned payload will be formatted using the default schema which is essentially one block of markdown formatted text.

itinerary_created

This event will be generated whenever a new itinerary is created, usually at the end of a successful conversation. The event payload will contain the itinerary object (refer to the examples in the repo)

user_profile_created, user_profile_updated

This event will be generated whenever a user profile has been created or updated. The event payload will contain the aggregated user profile (AUP, refer to the examples in the repo).

conversation_profile_created

This event will be generated whenever a new user conversation profile is created (UCP, refer to the examples in the repo). The conversation profile contains an AI-generated summary (typically using a reasoning model) of the conversation where the prompt is defined at the tenant level (i.e. is identical for all tenant projects) by a VIA admin. User profiles are created and updated based on one or more conversation profiles.

conversation_issue_created

This event will be generated whenever the VIA platform detects a conversation with negative sentiment. The detection time depends on how often summarization is applied to the conversation (typically every 1h). The event payload will cointain the conversation summary object generated by an AI prompt. The summary object has an arbitrary format that depends on the type of summary being conducted.

Setting up a Webhook

From the VIA Console, define a new webhook to receive reply messages. You must enable and verify the webhook in order to activate it. VIA will attempt to call your webhook up to 5 tries using the following strategy:

(Next Attempt Timestamp) = (Initial Delay) * 2 ^ (Retry Attempt)

Initial delay is normally set to 1 second but may change slightly depending on system load

Authenticating Your Webhook

VIA implements a security mechanism for webhook authentication by employing a digital signature. This signature is crafted using a secret key provided during the webhook setup alongside the request body. The resulting data is encapsulated in the signature header property. The process to calculate the signature is as follows:

HMAC-SHA256 = {Base64(HmacSHA256(body_bytes, YOUR_WEBHOOK_SECRET))}

To verify the request came from VIA, compute an HMAC digest using your secret key and the body and compare it to the signature portion (after the space) contained in the header. If they match, you can be sure the webhook was sent from VIA. Otherwise, ensure your code returns an unspecific error immediately without invoking additional logic.

This signature header property contains the SHA algorithm used to generate the signature e.g. sha256, a '=' separator, and the signature itself.

signature: sha256 HMAC-SHA256

e.g. signature: sha256=37d2725109df92747ffcee59833a1d1262d74b9703fa1234c789407218b4a4ef

You must verify your webhook from the VIA Console so that it will be called

Example VIA Webhook Receiver

Use the VIA Console to obtain your unique webhook secret

node.js

var express = require('express')
const crypto = require('crypto');
var app = express()

// Set your runtime variables
let secret = '<YOUR WEBHOOK SECRET>';
let port = 8080;

// Signature verification
const verifyHmac = (
    receivedHmacHeader,
    receivedBody,
    secret
) => {
    const hmacParts = receivedHmacHeader.split('=')
    const receivedHmac = hmacParts[1]
    const hash = crypto
        .createHmac(hmacParts[0], secret)
        .update(receivedBody)
        .digest('hex')
    return receivedHmac == hash
}

app.use(express.raw({ type: "*/*" }))

// Main webhook entry point
app.post('/webhook', function (req, res) {

    // Some initial basic verification
    if (!req.headers.signature) {
        console.log('Signature doesn\'t exist');
        return res.sendStatus(500);
    }
    else {
        console.log('Signature: ' + req.headers.signature);
    }

    // Verify source from signature
    if (!verifyHmac(req.headers.signature, req.body, secret)) {
        console.log('Signature verification failed');
        return res.sendStatus(500);
    }

    console.log("Signature verified");

    // Extract payload
    let payload = JSON.parse(req.body);
    console.log(JSON.stringify(payload, null, 4));

    // Parse the actual payload here
    // TODO

    res.send('Ok')
})

console.log(`Listening for events on ` + port)
app.listen(port);

Python

from flask import Flask
from flask import request
import hashlib, hmac, json

app = Flask(__name__)

# Set your runtime variables
secret = '<YOUR WEBHOOK SECRET>'
port = 8080

# Signature verification
def verifyHmac(received_hmac_header, received_body, secret):
    hmac_parts = received_hmac_header.split('=')
    received_hmac = hmac_parts[1]
    hash = hmac.new(bytes(secret, 'UTF-8'), received_body, hashlib.sha256).hexdigest()
    return received_hmac == hash

# Main webhook entry point
@app.route('/webhook', methods=['POST'])
def webhook():
    # Some initial basic verification
    if 'signature' not in request.headers:
        print("Signature doesn't exist")
        return '', 500
    else:
        print('Signature:', request.headers['signature'])

    # Verify source from signature
    if not verifyHmac(request.headers['signature'], request.data, secret):
        print('Signature verification failed')
        return '', 500

    print('Signature verified')

    # Extract payload
    payload = request.get_json()
    print(json.dumps(payload, indent=4))

    # Parse the actual payload here
    # TODO

    return 'Ok'

if __name__ == '__main__':
    print('Listening for events on ' + str(port))
    app.run(port=port)

VIA Payload Examples

This repo contains the following VIA payload samples:

  1. Flights: When searching for flights only, the payload describes a list of categorized flight search results and their respective attributes
  2. Hotels: When searching for hotels only, the payload describes a list of categorized hotels search results and their respective attributes
  3. Packages: Dynamic packages are bundles between flight and hotel products that are offered together. Packages can be dynamic (e.g. any hotel offered with any flight) or static (flights offered with specific hotels) as indicated the relationship vacation_id
  4. Itinerary: At the end of a successful user conversation, the VIA concierge generates an itinerary object representing all the selection the user has made for the travel plan.
  5. User Conversation Profile (UCP): Represents all the information the VIA has learned about a user in a single conversation.
  6. Aggregated User Profile (AUP): The aggregated user profile represents all the information that VIA has learned about a particular user up to the current point of time. This is based on multiple conversations conducted with the user.

Note: Payload currently supports only flights and hotels

Contributors