airyhq / airy

💬 Open Source App Framework to build streaming apps with real-time data - 💎 Build real-time data pipelines and make real-time data universally accessible - 🤖 Join historical and real-time data in the stream to create smarter ML and AI applications. - ⚡ Standardize complex data ingestion and stream data to apps with pre-built connectors
https://airy.co/docs/core
Apache License 2.0
369 stars 44 forks source link

Chat Plugin: Initialize/resume conversations with identity via Contacts #2632

Open steffh opened 2 years ago

steffh commented 2 years ago

Is your feature request related to a problem? Please describe.

As a web developer using the Airy Live Chat Plugin, I would want to initialize the Airy Live Chat Plugin for an identified user (e.g. after log in), so that not multiple conversations are being created for such user, but a new conversation is being created should it not exist yet, or existing conversations can be continued

Describe the solution you'd like

I want to be able to use a unique identifier, e.g. an external unique user id or an email address to identify users (e.g. after they logged in) to create new conversations (or resume existing ones).

The current Get a Resume Token implementation (https://airy.co/docs/core/api/endpoints/chatplugin#get-a-resume-token) already provides for a similar functionality:

You can also obtain a resume token on behalf of the user. To do so you need to call this endpoint with the system API token set on the Authorization header and with the channel and conversation ID.

We could require the backend of the external service to call a route similar to POST /chatplugin.resumeToken (ideally we should rename that route) with an authenticated request using the systemToken:

POST /contacts.identify
{
   "channel_id": "UUID", // required 
   "external_id": "SOME_ID" // optional, type string, some unique ID in a remote system
   "email": "SOME_EMAIL_ADDRESS" // optional, type string, some unique email address
   "phone_number": "SOME_PHONE_NUMBER" // optional, type string, some unique phone number
   "metadata": {
      "key": "value", // optional key value pairs
      "ip_address": "192.168.XX.XXX" // example
   }
}

Response:

{
   "contact": 
         { 
            "id": "AIRY_CONTACT_ID" // existing or newly created based on provided identifiers,
            "email": "SOME_EMAIL_ADRESS", 
            "first_name": "SOME_FIRST_NAME",
            ... // populated with further information from the contact object
         },
   "conversations": // this should be an array because contacts can be merged, leading to multiple conversations with the same channel
    [
        { 
            "id": "SOME_UUID",
            "channel": { 
                "id": "SOME_CHANNEL_ID",
                "source": "chat_plugin", // SOURCE TYPE, e.g. "chat_plugin", "facebook", etc.  
            },
            "resume_token": "SOME_TOKEN" // token to initialize or resume the conversation in chat plugin
            "last_message": {.// standard payload, https://airy.co/docs/core/api/endpoints/conversations#list }
         }
    ]
}

Describe alternatives you've considered

We could also extend the functionality of POST chatplugin.authenticate but would have to resolve security considerations, as this route is currently not protected.

We would require a way to make sure only people that authenticated vis-à-vis a third party system we trust, e.g. the backend of service in possession of the Airy systemToken or ideally another type of client_secret can authorize users based on credentials to create new or access existing conversations.

Additional context

This is highly relevant for in-app chat usage as well, using additional identifiers such as email, UUIDs, Device IDs, etc.

chrismatix commented 2 years ago

@steffh Thank you the proposal makes sense to me. A question regarding the /contacts.identify endpoint: It's essentially a lookup, correct? Do we include metadata here as a search criterion or what is it for?