Quick Summary

In our modern world, being able to reward people you admire, friends or family has been seen as a major improvement in Fintech.

With the introduction of the lightning network, being able to send bitcoin with great speed has improved transfers and transactions with bitcoin. Bitnob just announced its integration of the lightning network to provide fast bitcoin transactions for its users and African businesses.

In this tutorial, we will build a tipping platform that allows you to tip business users on the lightning network and we will be building on the Bitnob API.

This tutorial has a hosted frontend and API. While testing, use the following emails; precious@bitnob.com and bernard@bitnob.com

What is the Bitnob API?

The Bitnob API is a business API built to help businesses provide Bitcoin access to their customers.

It comes with these features:

  • Lightning
  • Bitcoin backed Loans (NobCredit)
  • Onchain Transactions

We will be building with some actions of the Lightning and Onchain feature. Check out the docs to read more.

Getting Started

To get started with the tutorial, register as a business on the sandbox version. This will give you access to the API keys you need for integration.

Set up your business information. You can skip


After this step,  visit setting under account to get your API key.

You’re good to go!

Development

To build our API, We will be working with the following dependencies:

  • Python 3.6+
  • FastAPI
  • Bitnob API
  • Bitnob python SDK

Scaffold Project

We will create a new directory to house our application

$ mkdir tipping-platform
$ cd tipping-platform

To start building, the first step is to create and activate a virtual environment for our project:

$ python3 -m venv venv
$ source venv/bin/activate

The next step is to install Bitnob and FastAPI

$ pip install bitnob fastapi[all] dotenv

The bitnob package is a python SDK that comes with pre-built actions that allow businesses to interact better with the Bitnob API. They are also available SDKs for several languages.

Setting Up Entry File

Every application has an entry file from which every functionality is exposed. create a new file, main.py and set up FastAPI.

$ touch main.py

#main.py

from fastapi import FastAPI
app = FastAPI()

@app.get("/")
async def root():    
	return {"message": "Tipping Platform"}

run $ uvicorn main:app --reload

Set Up Env Keys

We have to set the env keys to run our SDK and bitnob API successfully. The BITNOB_PRODUCTION is set to False when running on sandbox and True when running on production. While the BITNOB_API_KEY is your API key from the dashboard.

For app, add the following to your .env file, at the root of your application.

BITNOB_API_KEY=sk.bc987.XXXXXXXXXXXXXXXXXXXXX
BITNOB_PRODUCTION=False

Running our app without adding the BITNOB_API_KEY will throw a BitnobBadKeyError() error. Not setting BITNOB_PRODUCTION to False or not setting at all, makes it run on Production mode.

Tipping Class

We will be creating a Tipping class that performs all actions of our tipping platform.

$ mkdir src
$ touch __init__.py
$ touch src/tip.py


We are to create a source folder for our application src, this will house our Tipping class, schemas and routers.

The next step is to create a file tip.py for the Tipping class.

For our API we will be using the Customer, Lightning and Onchain functions from the bitnob package

from dotenv import load_dotenv
from bitnob import Customer, Lightning, Onchain

load_dotenv()

customer = Customer()
lightning = Lightning()
onchain = Onchain()

load_dotenv() imports our env keys into the environment.

For our Tipping class we need the following actions;

  • Get a user
  • Tip User, this consists of two sub-actions; create Lightning invoice for a user ands create BTC Address for user
class Tipping:
    def __init__(self):
    	pass

    def get_user(self, email):
        user = customer.get_customer_by_email(email=email)
        return user

    def create_lightning_invoice_for_user(self, email, sats):
        payload = {
        "description": "money stops nonsense on sunday",
        "tokens": sats,
        "private": False,
        "is_including_private_channels": False,
        "is_fallback_included": False,
        "customerEmail": email
        }
        data = lightning.create_invoice(body=payload)
        return data

    def generate_btc_address_for_user(self, email, label):
        payload = {
        "label": label,
        "customerEmail": email,
        }
        data = onchain.generate_address(body=payload)
        return data

    def tip_user(self, sats, email, label):
        invoice = self.create_lightning_invoice_for_user(email=email,
        sats=sats)
        address = self.generate_btc_address_for_user(email, label)
        data = {
        "address": address["data"]["address"],
        "invoice": invoice["data"]["request"],
        }
        return data
        

The get_user() function uses the email to call the customer .get_customer_by_email() function, it returns an error that the user isn’t found or the data of the user.

create_lightning_invoice_for_user() and generate_btc_address_for_user() creates a lightning invoice and BTC address for the user respectively. The invoice works with the sats passed but the address from the BTC can take in any amount.

Finally, the tip_user() takes the data returned and gets the address from generate_btc_address_for_user() and request from the create_lightning_invoice_for_user().

Schema and Routing

Schema

Our schema is needed for our get_user and create_tip endpoint. The pydantic schemas check the data being passed to the endpoint and ensures it has the passed keys and correct format.

$ touch src/schema.py
#schema.py

from pydantic import BaseModel
from typing import Optional

class Tip(BaseModel):
    email: str
    description: Optional[str] = None
    sats: float
    label: str

class User(BaseModel):
    email: str

The Optional class sets the description key to unrequired, so it doesn’t throw an error when not passed.

Routing

At this point, we will connect our functions to endpoints

$ touch src/routes.py

#src/routes.py

from fastapi import APIRouter
from .tip import Tipping
from .schema import *

router = APIRouter()
tip = Tipping()

@router.post("/create_tip/")
async def create_tip(tip_data: Tip):
    return tip.tip_user(sats=tip_data.sats, email=tip_data.email,
    label=tip_data.label)

@router.post("/get_user/")
async def get_user(user: User):
	return tip.get_user(user.email)

The next step is to add the router to the app in main.py

#main.py

from src.routes import router

@app.get("/")
async def root():
    return {"message": "Tipping Platform"}

app.include_router(router)

Tipping User

We are done with building our API, we will be testing our application by trying the API on its docs. Get the app running;

$ uvicorn main:app --reload

visit http://127.0.0.1:8000/docs

This will return an address and lightning invoice for the user;

Conclusion

Now users on your business can be tipped just using their email. And using the lightning network it gets to them in seconds!
There are lots of possibilities that can be built the Bitnob API for businesses.