Viber Python Bot Async API
This is async version of viberbot package. Fully compatible with sync package version.
Use this library to develop a bot for Viber platform.
The library is available on GitHub as well as a package on PyPI.
This package can be imported using pip by adding the following to your requirements.txt
:
aioviberbot==0.7.0
License
This library is released under the terms of the Apache 2.0 license. See License for more information.
Library Prerequisites
- python >= 3.7.0
- An Active Viber account on a platform which supports Public Accounts/ bots (iOS/Android). This account will automatically be set as the account administrator during the account creation process.
- Active Public Account/bot - Create an account here.
- Account authentication token - unique account identifier used to validate your account in all API requests. Once your account is created your authentication token will appear in the account’s “edit info” screen (for admins only). Each request posted to Viber by the account will need to contain the token.
- Webhook - Please use a server endpoint URL that supports HTTPS. If you deploy on your own custom server, you'll need a trusted (ca.pem) certificate, not self-signed. Read our blog post on how to test your bot locally.
Contributing
If you think that there's a bug or there's anything else needed to be changed and you want to change it yourself, you can always create a new Pull request.
Please make sure that your change doesn't break anything and all the unit tests passes.
Also, please make sure that the current tests cover your change, if not please add tests.
We are using pytest, so if you want to run the tests from the commandline just follow the relevant steps after cloning the repo and creating your branch:
# installing the dependencies:
python setup.py develop
# run the unit tests
pytest tests/
Let's get started!
Installing
Creating a basic Viber bot is simple:
- Install the library with pip
pip install aioviberbot
- Import
aioviberbot.api
library to your project - Create a Public Account or bot and use the API key from https://developers.viber.com
- Configure your bot as described in the documentation below
- Start your web server
- Call
set_webhook(url)
with your web server url
A simple Echo Bot
Firstly, let's import and configure our bot
from aioviberbot import Api
from aioviberbot.api.bot_configuration import BotConfiguration
bot_configuration = BotConfiguration(
name='PythonSampleBot',
avatar='http://viber.com/avatar.jpg',
auth_token='YOUR_AUTH_TOKEN_HERE',
)
viber = Api(bot_configuration)
Create an HTTPS server
Next thing you should do is starting a https server.
and yes, as we said in the prerequisites it has to be https server. Create a server however you like, for example with aiohttp
:
from aiohttp import web
async def webhook(request: web.Request) -> web.Response:
request_data = await request.read()
logger.debug('Received request. Post data: %s', request_data)
return web.json_response({'ok': True})
if __name__ == '__main__':
app = web.Application()
app.router.add_route('POST', '/webhook', webhook),
web.run_app(app)
Setting a webhook
After the server is up and running you can set a webhook.
Viber will push messages sent to this URL. web server should be internet-facing.
await viber.set_webhook('https://mybotwebserver.com:443/')
Logging
This library uses the standard python logger. If you want to see its logs you can configure the logger:
logger = logging.getLogger('aioviberbot')
logger.setLevel(logging.DEBUG)
handler = logging.StreamHandler()
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
Do you supply a basic types of messages?
Well, funny you ask. Yes we do. All the Message types are located in aioviberbot.api.messages
package. Here's some examples:
from aioviberbot.api.messages import (
TextMessage,
ContactMessage,
PictureMessage,
VideoMessage,
)
from aioviberbot.api.messages.data_types.contact import Contact
text_message = TextMessage(text='sample text message!')
contact = Contact(name='Viber user', phone_number='0123456789')
contact_message = ContactMessage(contact=contact)
picture_message = PictureMessage(text='Check this', media='http://site.com/img.jpg')
video_message = VideoMessage(media='http://mediaserver.com/video.mp4', size=4324)
Have you noticed how we created the TextMessage
? There's all bunch of message types you should get familiar with.
Creating them is easy! Every message object has it's own unique constructor corresponding to it's API implementation, click on them to see it!
Check out the full API documentation for more advanced uses.
Let's add it all up and reply with a message!
from aiohttp import web
from aioviberbot import Api
from aioviberbot.api.bot_configuration import BotConfiguration
from aioviberbot.api.messages.text_message import TextMessage
from aioviberbot.api.viber_requests import ViberConversationStartedRequest
from aioviberbot.api.viber_requests import ViberMessageRequest
from aioviberbot.api.viber_requests import ViberSubscribedRequest
viber = Api(BotConfiguration(
name='PythonSampleBot',
avatar='http://viber.com/avatar.jpg',
auth_token='YOUR_AUTH_TOKEN_HERE'
))
async def webhook(request: web.Request) -> web.Response:
request_data = await request.read()
signature = request.headers.get('X-Viber-Content-Signature')
if not viber.verify_signature(request_data, signature):
raise web.HTTPForbidden
viber_request = viber.parse_request(request_data)
if isinstance(viber_request, ViberMessageRequest):
await viber.send_messages(
viber_request.sender.id,
[viber_request.message],
)
elif isinstance(viber_request, ViberSubscribedRequest):
await viber.send_messages(
viber_request.user.id,
[TextMessage(text='Thanks for subscribing!')],
)
elif isinstance(viber_request, ViberConversationStartedRequest):
await viber.send_messages(
viber_request.user.id,
[TextMessage(text='Thanks for starting conversation!')],
)
return web.json_response({'ok': True})
async def set_webhook_signal(app: web.Application):
await viber.set_webhook('https://mybotwebserver.com/webhook')
if __name__ == '__main__':
app = web.Application()
app.on_startup.append(set_webhook_signal)
app.router.add_route('POST', '/webhook', webhook),
web.run_app(app)
As you can see there's a bunch of Request
types here's a list of them.
Viber API
Api class
from aioviberbot import Api
New Api()
Param | Type | Description |
---|
bot_configuration | object | BotConfiguration |
client_session | object | Optional aiohttp.ClientSession , pass if you want to use your own session for api requests |
Api.set_webhook(url)
Param | Type | Description |
---|
url | string | Your web server url |
webhook_events | list | optional list of subscribed events |
send_name | bool | optional should receive the user name |
send_photo | bool | optional should receive the user photo |
Returns List of registered event_types
.
event_types = await viber.set_webhook('https://example.com/webhook')
Api.unset_webhook()
Returns None
.
await viber.unset_webhook()
Api.get_account_info()
Returns an object
with the following JSON.
account_info = await viber.get_account_info()
Api.verify_signature(request_data, signature)
Param | Type | Description |
---|
request_data | string | the post data from request |
signature | string | sent as header X-Viber-Content-Signature |
Returns a boolean
suggesting if the signature is valid.
if not viber.verify_signature(await request.read(), request.headers.get('X-Viber-Content-Signature')):
raise web.HTTPForbidden
Api.parse_request(request_data)
Param | Type | Description |
---|
request_data | string | the post data from request |
Returns a ViberRequest
object.
There's a list of ViberRequest objects
viber_request = viber.parse_request(await request.read())
Api.send_messages(to, messages)
Param | Type | Description |
---|
to | string | Viber user id |
messages | list | list of Message objects |
Returns list
of message tokens of the messages sent.
tokens = await viber.send_messages(
to=viber_request.sender.id,
messages=[TextMessage(text='sample message')],
)
Api.broadcast_messages(broadcast_list, messages)
Param | Type | Description |
---|
broadcast_list | list | list of Viber user ids |
messages | list | list of Message objects |
Returns list
of message tokens of the messages sent.
tokens = await viber.broadcast_messages(
broadcast_list=[
"ABB102akPCRKFaqxWnafEIA==",
"ABB102akPCRKFaqxWna111==",
"ABB102akPCRKFaqxWnaf222==",
],
messages=[TextMessage(text='sample message')],
)
Api.post_messages_to_public_account(to, messages)
Param | Type | Description |
---|
sender | string | Viber user id |
messages | list | list of Message objects |
Returns list
of message tokens of the messages sent.
tokens = await viber.post_messages_to_public_account(
sender=viber_request.sender.id,
messages=[TextMessage(text='sample message')],
)
Api.get_online(viber_user_ids)
Param | Type | Description |
---|
viber_user_ids | array of strings | Array of Viber user ids |
Returns a dictionary of users
.
users = await viber.get_online(['user1id', 'user2id'])
Api.get_user_details(viber_user_id)
Param | Type | Description |
---|
viber_user_ids | string | Viber user id |
The get_user_details
function will fetch the details of a specific Viber user based on his unique user ID. The user ID can be obtained from the callbacks sent to the account regarding user's actions. This request can be sent twice during a 12 hours period for each user ID.
user_data = await viber.get_user_details('userId')
Request object
Param | Type | Notes |
---|
event_type | string | according to EventTypes enum |
timestamp | long | Epoch of request time |
- ViberRequest
- .event_type ⇒
string
- .timestamp ⇒
long
ViberConversationStartedRequest object
Inherits from ViberRequest
Conversation started event fires when a user opens a conversation with the Public Account/ bot using the “message” button (found on the account’s info screen) or using a deep link.
This event is not considered a subscribe event and doesn't allow the account to send messages to the user; however, it will allow sending one "welcome message" to the user. See sending a welcome message below for more information.
Param | Type | Notes |
---|
event_type | string | always equals to the value of EventType.CONVERSATION_STARTED |
message_token | string | Unique ID of the message |
type | string | The specific type of conversation_started event. |
context | string | Any additional parameters added to the deep link used to access the conversation passed as a string |
user | UserProfile | the user started the conversation UserProfile |
subscribed | boolean | Indicates whether a user is already subscribed |
- ViberConversationStartedRequest
- message_token ⇒
string
- type ⇒
string
- context ⇒
string
- user ⇒
UserProfile
ViberDeliveredRequest object
Inherits from ViberRequest
Param | Type | Notes |
---|
event_type | string | always equals to the value of EventType.DELIVERED |
message_token | string | Unique ID of the message |
user_id | string | Unique Viber user id |
- ViberDeliveredRequest
- message_token ⇒
string
- user_id ⇒
string
ViberFailedRequest object
Inherits from ViberRequest
Param | Type | Notes |
---|
event_type | string | always equals to the value of EventType.FAILED |
message_token | string | Unique ID of the message |
user_id | string | Unique Viber user id |
desc | string | Failure description |
- ViberFailedRequest
- message_token ⇒
string
- user_id ⇒
string
- desc ⇒
string
ViberMessageRequest object
Inherits from ViberRequest
Param | Type | Notes |
---|
event_type | string | always equals to the value of EventType.MESSAGE |
message_token | string | Unique ID of the message |
message | Message | Message object |
sender | UserProfile | the user started the conversation UserProfile |
- ViberMessageRequest
- message_token ⇒
string
- message ⇒
Message
- sender ⇒
UserProfile
ViberSeenRequest object
Inherits from ViberRequest
Param | Type | Notes |
---|
event_type | string | always equals to the value of EventType.SEEN |
message_token | string | Unique ID of the message |
user_id | string | Unique Viber user id |
- ViberSeenRequest
- message_token ⇒
string
- user_id ⇒
string
ViberSubscribedRequest object
Inherits from ViberRequest
Param | Type | Notes |
---|
event_type | string | always equals to the value of EventType.SUBSCRIBED |
user | UserProfile | the user started the conversation UserProfile |
ViberUnsubscribedRequest object
Inherits from ViberRequest
Param | Type | Notes |
---|
event_type | string | always equals to the value of EventType.UNSUBSCRIBED |
user_id | string | Unique Viber user id |
UserProfile object
Param | Type | Notes |
---|
id | string | --- |
name | string | --- |
avatar | string | Avatar URL |
country | string | currently set in CONVERSATION_STARTED event only |
language | string | currently set in CONVERSATION_STARTED event only |
Message Object
Common Members for Message
interface:
Param | Type | Description |
---|
timestamp | long | Epoch time |
keyboard | JSON | keyboard JSON |
trackingData | JSON | JSON Tracking Data from Viber Client |
Common Constructor Arguments Message
interface:
Param | Type | Description |
---|
optionalKeyboard | JSON | Writing Custom Keyboards |
optionalTrackingData | JSON | Data to be saved on Viber Client device, and sent back each time message is received |
TextMessage object
message = TextMessage(text='my text message')
URLMessage object
Member | Type | Description |
---|
media | string | URL string |
message = URLMessage(media='http://my.siteurl.com')
ContactMessage object
from aioviberbot.api.messages.data_types.contact import Contact
contact = Contact(name='Viber user', phone_number='+0015648979', avatar='http://link.to.avatar')
contact_message = ContactMessage(contact=contact)
PictureMessage object
Member | Type | Description |
---|
media | string | url of the message (jpeg only) |
text | string | |
thumbnail | string | |
message = PictureMessage(media='http://www.thehindubusinessline.com/multimedia/dynamic/01458/viber_logo_JPG_1458024f.jpg', text='Viber logo')
VideoMessage object
Member | Type | Description |
---|
media | string | url of the video |
size | int | |
thumbnail | string | |
duration | int | |
message = VideoMessage(media='http://site.com/video.mp4', size=21499)
LocationMessage object
Member | Type |
---|
location | Location |
from aioviberbot.api.messages.data_types.location import Location
location = Location(lat=0.0, lon=0.0)
location_message = LocationMessage(location=location)
StickerMessage object
message = StickerMessage(sticker_id=40100)
FileMessage object
Member | Type |
---|
media | string |
size | long |
file_name | string |
message = FileMessage(media=url, size=size_in_bytes, file_name=file_name)
RichMediaMessage object
Member | Type |
---|
rich_media | string (JSON) |
SAMPLE_RICH_MEDIA = """{
"BgColor": "#69C48A",
"Buttons": [
{
"Columns": 6,
"Rows": 1,
"BgColor": "#454545",
"BgMediaType": "gif",
"BgMedia": "http://www.url.by/test.gif",
"BgLoop": true,
"ActionType": "open-url",
"Silent": true,
"ActionBody": "www.tut.by",
"Image": "www.tut.by/img.jpg",
"TextVAlign": "middle",
"TextHAlign": "left",
"Text": "<b>example</b> button",
"TextOpacity": 10,
"TextSize": "regular"
}
]
}"""
SAMPLE_ALT_TEXT = 'upgrade now!'
message = RichMediaMessage(rich_media=SAMPLE_RICH_MEDIA, alt_text=SAMPLE_ALT_TEXT)
KeyboardMessage object
Member | Type |
---|
keyboard | JSON |
tracking_data | JSON |
message = KeyboardMessage(tracking_data=tracking_data, keyboard=keyboard)
Sending a welcome message
The Viber API allows sending messages to users only after they subscribe to the account. However, Viber will allow the account to send one “welcome message” to a user as the user opens the conversation, before the user subscribes.
The welcome message will be sent as a response to a conversation_started
callback, which will be received from Viber once the user opens the conversation with the account. To learn more about this event and when is it triggered see Conversation started
in the callbacks section.
Welcome message flow
Sending a welcome message will be done according to the following flow:
- User opens 1-on-1 conversation with account.
- Viber server send
conversation_started
even to PA’s webhook. - The account receives the
conversation_started
and responds with an HTTP response which includes the welcome message as the response body.
The welcome message will be a JSON constructed according to the send_message requests structure, but without the receiver
parameter. An example welcome message would look like this:
async def webhook(request: web.Request) -> web.Response:
request_data = await request.read()
viber_request = viber.parse_request(request_data)
if isinstance(viber_request, ViberConversationStartedRequest):
await viber.send_messages(
viber_request.user.id,
[TextMessage(text='Welcome!')],
)
return web.json_response({'ok': True})
Join the conversation on Gitter.