diff --git a/uncloud/uncloud_pay/models.py b/uncloud/uncloud_pay/models.py
index a29dc3c..3be3c2c 100644
--- a/uncloud/uncloud_pay/models.py
+++ b/uncloud/uncloud_pay/models.py
@@ -4,6 +4,9 @@ from django.contrib.auth import get_user_model
 from django.core.validators import MinValueValidator
 from django.utils.translation import gettext_lazy as _
 from django.utils import timezone
+from math import ceil
+from datetime import timedelta
+from calendar import monthrange
 
 import uuid
 
@@ -38,7 +41,7 @@ class Bill(models.Model):
         orders = Order.objects.filter(bill=self)
         for order in orders:
             for order_record in order.records:
-                bill_record = BillRecord(order_record)
+                bill_record = BillRecord(self, order_record)
                 bill_records.append(bill_record)
 
         return bill_records
@@ -47,18 +50,66 @@ class Bill(models.Model):
     def total(self):
         return reduce(lambda acc, record: acc + record.amount(), self.records, 0)
 
+    @property
+    def final(self):
+        # A bill is final when its ending date is passed.
+        return self.ending_date < timezone.now()
+
 class BillRecord():
-    def __init__(self, order_record):
-        self.order = order_record.order.uuid
+    def __init__(self, bill, order_record):
+        self.bill = bill
+        self.order = order_record.order
         self.setup_fee = order_record.setup_fee
         self.recurring_price = order_record.recurring_price
         self.recurring_period = order_record.recurring_period
         self.description = order_record.description
 
     def amount(self):
-        # TODO: Billing logic here!
+        # Compute billing delta.
+        billed_until = self.bill.ending_date
+        if self.order.ending_date != None and self.order.ending_date < self.order.ending_date:
+            billed_until = self.order.ending_date
+
+        billed_from = self.bill.starting_date
+        if self.order.starting_date > self.bill.starting_date:
+            billed_from = self.order.starting_date
+
+        if billed_from > billed_until:
+            # TODO: think about and check edges cases. This should not be
+            # possible.
+            raise Exception('Impossible billing delta!')
+
+        billed_delta = billed_until - billed_from
+
+        # TODO: refactor this thing?
+        # TODO: weekly
+        # TODO: yearly
         if self.recurring_period == RecurringPeriod.PER_MONTH:
+            days = ceil(billed_delta / timedelta(days=1))
+
+            # XXX: we assume monthly bills for now.
+            if (self.bill.starting_date.year != self.bill.starting_date.year or
+                self.bill.starting_date.month != self.bill.ending_date.month):
+                    raise Exception('Bill {} covers more than one month. Cannot bill PER_MONTH.'.
+                        format(self.bill.uuid))
+
+            # XXX: minumal length of monthly order is to be enforced somewhere else.
+            (_, days_in_month) = monthrange(
+                    self.bill.starting_date.year,
+                    self.bill.starting_date.month)
+            adjusted_recurring_price = self.recurring_price / days_in_month
+            recurring_price = adjusted_recurring_price * days
+
             return self.recurring_price # TODO
+        elif self.recurring_period == RecurringPeriod.PER_DAY:
+            days = ceil(billed_delta / timedelta(days=1))
+            return self.recurring_price * days
+        elif self.recurring_period == RecurringPeriod.PER_HOUR:
+            hours = ceil(billed_delta / timedelta(hours=1))
+            return self.recurring_price * hours
+        elif self.recurring_period == RecurringPeriod.PER_SECOND:
+            seconds = ceil(billed_delta / timedelta(seconds=1))
+            return self.recurring_price * seconds
         else:
             raise Exception('Unsupported recurring period: {}.'.
                     format(record.recurring_period))
@@ -75,12 +126,14 @@ class BillRecord():
 # agree on deal => That's what we want to keep archived.
 #
 # /!\ BIG FAT WARNING /!\ #
+
 class Order(models.Model):
     uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
     owner = models.ForeignKey(get_user_model(),
                               on_delete=models.CASCADE,
                               editable=False)
 
+    # TODO: enforce ending_date - starting_date to be larger than recurring_period.
     creation_date = models.DateTimeField(auto_now_add=True)
     starting_date = models.DateTimeField(auto_now_add=True)
     ending_date = models.DateTimeField(blank=True,
@@ -129,6 +182,14 @@ class OrderRecord(models.Model):
     def recurring_period(self):
         return self.order.recurring_period
 
+    @property
+    def starting_date(self):
+        return self.order.starting_date
+
+    @property
+    def ending_date(self):
+        return self.order.ending_date
+
 class PaymentMethod(models.Model):
     uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
     owner = models.ForeignKey(get_user_model(),
diff --git a/uncloud/uncloud_pay/serializers.py b/uncloud/uncloud_pay/serializers.py
index 6c6c04e..d523b7a 100644
--- a/uncloud/uncloud_pay/serializers.py
+++ b/uncloud/uncloud_pay/serializers.py
@@ -22,7 +22,7 @@ class BillSerializer(serializers.ModelSerializer):
     class Meta:
         model = Bill
         fields = ['owner', 'total', 'due_date', 'creation_date',
-                'starting_date', 'ending_date', 'records']
+                'starting_date', 'ending_date', 'records', 'final']
 
 class PaymentSerializer(serializers.ModelSerializer):
     class Meta: