Repository: cuenca-mx/arcus-python

Issue:
update Tranasction.status to refunded on successful cancelation
[`Transaction.cancel()`](https://github.com/cuenca-mx/arcus-python/blob/master/arcus/resources/transactions.py#L29-L30) returns the raw response `dict` from the arcus API. It should also update the transaction in place iff the cancelation was successful.

Discussion:

Patch:
diff --git a/.travis.yml b/.travis.yml
index dc3112b..74ea356 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -27,7 +27,7 @@ jobs:
         - make install-test
         - pip install coveralls
       script:
-        - python setup.py test
+        - pytest --vcr-record=none
         - coveralls
     - stage: PyPI Upload
       python: 3.7
diff --git a/arcus/client.py b/arcus/client.py
index 98dd2d2..d0c09a6 100644
--- a/arcus/client.py
+++ b/arcus/client.py
@@ -82,7 +82,7 @@ class Client:
             raise InvalidAuth
         elif response.status_code == 404:
             raise NotFound(data['message'])
-        elif response.status_code == 422:
+        elif response.status_code in [400, 422]:
             raise UnprocessableEntity(**data)
         else:
             response.raise_for_status()
diff --git a/arcus/exc.py b/arcus/exc.py
index 06d7f7b..d78af28 100644
--- a/arcus/exc.py
+++ b/arcus/exc.py
@@ -11,11 +11,6 @@ class InvalidAuth(ArcusException):
     """Invalid API authentication credentials"""
 
 
-class InvalidAccountNumber(ArcusException):
-    def __init__(self, account_number: str):
-        self.message = f'{account_number} is an invalid account_number'
-
-
 class InvalidBiller(ArcusException):
     def __init__(self, biller_id: Union[int, str]):
         self.message = f'{biller_id} is an invalid biller_id'
@@ -49,7 +44,22 @@ class UnprocessableEntity(ArcusException):
         return getattr(self, 'message', self.__class__.__doc__)
 
 
+class InvalidAccountNumber(UnprocessableEntity):
+    def __init__(self, code: str, account_number: str, biller_id: int):
+        message = (
+            f'{account_number} is an invalid account_number for biller '
+            f'{biller_id}'
+        )
+        super().__init__(
+            code, message, biller_id=biller_id, account_number=account_number
+        )
+
+
 class InvalidOperation(UnprocessableEntity):
     def __init__(self, code: str, transaction_id: Union[int, str]):
-        self.message = f'Unable to cancel the transaction {transaction_id}'
-        super().__init__(code, self.message, transaction_id=transaction_id)
+        message = f'Unable to cancel the transaction {transaction_id}'
+        super().__init__(code, message, transaction_id=transaction_id)
+
+
+class InvalidAmount(UnprocessableEntity):
+    pass
diff --git a/arcus/resources/bills.py b/arcus/resources/bills.py
index d8b93cd..b766a61 100644
--- a/arcus/resources/bills.py
+++ b/arcus/resources/bills.py
@@ -2,8 +2,9 @@ import datetime
 from dataclasses import dataclass, field
 from typing import Optional, Union
 
-from arcus.exc import (InvalidAccountNumber, InvalidBiller, NotFound,
-                       UnprocessableEntity)
+from arcus.exc import (
+    InvalidAccountNumber, InvalidAmount, InvalidBiller, NotFound,
+    UnprocessableEntity)
 
 from .base import Resource
 from .transactions import Transaction
@@ -41,8 +42,8 @@ class Bill(Resource):
         except NotFound:
             raise InvalidBiller(biller_id)
         except UnprocessableEntity as ex:
-            if ex.code == 'R2':
-                raise InvalidAccountNumber(account_number)
+            if ex.code in ['R2', 'R29']:
+                raise InvalidAccountNumber(ex.code, account_number, biller_id)
             else:
                 raise
         return cls(**bill_dict)
@@ -54,6 +55,12 @@ class Bill(Resource):
         if not isinstance(amount, float):
             raise TypeError('amount must be a float')
         data = dict(amount=amount, currency=self.balance_currency)
-        transaction_dict = self._client.post(
-            f'{self._endpoint}/{self.id}/pay', data)
+        try:
+            transaction_dict = self._client.post(
+                f'{self._endpoint}/{self.id}/pay', data)
+        except UnprocessableEntity as ex:
+            if ex.code == 'R102':
+                raise InvalidAmount(ex.code, ex.message, amount=amount)
+            else:
+                raise
         return Transaction(**transaction_dict)
diff --git a/arcus/resources/topups.py b/arcus/resources/topups.py
index eeaa489..3dc9991 100644
--- a/arcus/resources/topups.py
+++ b/arcus/resources/topups.py
@@ -2,6 +2,8 @@ import datetime
 from dataclasses import dataclass, field
 from typing import Optional
 
+from arcus.exc import InvalidAccountNumber, UnprocessableEntity
+
 from .base import Resource
 
 """
@@ -14,6 +16,7 @@ TOPUP_API_VERSION = '1.6'
 
 @dataclass
 class Topup(Resource):
+    _endpoint = '/bill/pay'
 
     id: int
     biller_id: int
@@ -54,12 +57,25 @@ class Topup(Resource):
                     amount=amount,
                     currency=currency,
                     name_on_account=name_on_account)
-        topup_dict = cls._client.post(
-            '/bill/pay', data, api_version=TOPUP_API_VERSION)
+        try:
+            topup_dict = cls._client.post(
+                cls._endpoint, data, api_version=TOPUP_API_VERSION)
+        except UnprocessableEntity as ex:
+            if ex.code == 'R5':
+                raise InvalidAccountNumber(ex.code, account_number, biller_id)
+            else:
+                raise
         return Topup(**topup_dict)
 
+    @classmethod
+    def get(cls, _):
+        raise NotImplementedError(
+            f'{cls.__name__}.get(id) is unsupported by the API. Use '
+            f'Transaction.get(id) instead.'
+        )
+
     @classmethod
     def list(cls):
         raise NotImplementedError(
             f"{cls.__name__}.list() hasn't been implemented or isn't "
-            f"supported by the API.")
+            f'supported by the API.')
diff --git a/arcus/resources/transactions.py b/arcus/resources/transactions.py
index 5eb1ff8..f8f3d3f 100644
--- a/arcus/resources/transactions.py
+++ b/arcus/resources/transactions.py
@@ -29,11 +29,18 @@ class Transaction(Resource):
             cls._client.get(f'{cls._endpoint}?q[id_eq]={transaction_id}'))
         return Transaction(**transaction_dict['transactions'][0])
 
+    def refresh(self):
+        updated = self.get(self.id)
+        for attr, value in updated.__dict__.items():
+            setattr(self, attr, value)
+
     def cancel(self) -> dict:
         try:
-            return self._client.post('/transaction/cancel', dict(id=self.id))
+            resp = self._client.post('/transaction/cancel', dict(id=self.id))
         except UnprocessableEntity as ex:
             if ex.code in ['R26', 'R103']:
                 raise InvalidOperation(ex.code, self.id)
             else:
                 raise
+        self.refresh()
+        return resp
diff --git a/setup.py b/setup.py
index 7aac541..4cbad45 100644
--- a/setup.py
+++ b/setup.py
@@ -24,7 +24,7 @@ with open('README.md', 'r') as f:
 
 setuptools.setup(
     name='arcus',
-    version='0.2.10',
+    version='1.0.2',
     author='Cuenca',
     author_email='dev@cuenca.com',
     description='Arcus API Client',


Test patch:
diff --git a/tests/resources/cassettes/test_amount_too_low.yaml b/tests/resources/cassettes/test_amount_too_low.yaml
new file mode 100644
index 0000000..7af9cc5
--- /dev/null
+++ b/tests/resources/cassettes/test_amount_too_low.yaml
@@ -0,0 +1,83 @@
+interactions:
+- request:
+    body: '{"biller_id": 40, "account_number": "501000000007"}'
+    headers:
+      Accept: [application/vnd.regalii.v3.1+json]
+      Accept-Encoding: ['gzip, deflate']
+      Authorization: ['APIAuth 88879c1b066dc9aea6201f27be2bbba9:0gGhOKBCqJnQijkr+61x8bxzQ+c=']
+      Connection: [keep-alive]
+      Content-Length: ['51']
+      Content-MD5: [PtZUYQ9bmh3ULNV0W7ZNdw==]
+      Content-Type: [application/json]
+      Date: ['Sun, 28 Jul 2019 15:09:20 GMT']
+      User-Agent: [python-requests/2.21.0]
+    method: POST
+    uri: https://api.casiregalii.com/bills
+  response:
+    body: {string: '{"type":"bill","id":8390,"biller_id":40,"account_number":"501000000007","name_on_account":null,"due_date":null,"balance":549.0,"balance_currency":"MXN","balance_updated_at":"2019-07-28T15:09:21Z","error_code":null,"error_message":null,"status":"linked","migrated_at":null,"mfa_challenges":[]}'}
+    headers:
+      Cache-Control: ['max-age=0, private, must-revalidate']
+      Connection: [keep-alive]
+      Content-Type: [application/json; charset=utf-8]
+      Date: ['Sun, 28 Jul 2019 15:09:22 GMT']
+      ETag: [W/"29fa251c1dbaca8c77f31dafb0580798"]
+      Strict-Transport-Security: [max-age=31536000; includeSubDomains]
+      Transfer-Encoding: [chunked]
+      X-Request-Id: [a189887d-dac5-4381-bbaf-0b15f73a9612]
+      X-Runtime: ['1.811842']
+    status: {code: 200, message: OK}
+- request:
+    body: '{}'
+    headers:
+      Accept: [application/vnd.regalii.v3.1+json]
+      Accept-Encoding: ['gzip, deflate']
+      Authorization: ['APIAuth 88879c1b066dc9aea6201f27be2bbba9:uX2OBRr3DMmR6+RiYTqSZxh5lWk=']
+      Connection: [keep-alive]
+      Content-Length: ['2']
+      Content-MD5: [mZFLkyvTelC5g8XnyQrpOw==]
+      Content-Type: [application/json]
+      Date: ['Sun, 28 Jul 2019 15:09:22 GMT']
+      User-Agent: [python-requests/2.21.0]
+    method: GET
+    uri: https://api.casiregalii.com/bills/8390
+  response:
+    body: {string: '{"type":"bill","id":8390,"biller_id":40,"account_number":"501000000007","name_on_account":null,"due_date":null,"balance":549.0,"balance_currency":"MXN","balance_updated_at":"2019-07-28T15:09:21Z","error_code":null,"error_message":null,"status":"linked","migrated_at":null,"mfa_challenges":[]}'}
+    headers:
+      Cache-Control: ['max-age=0, private, must-revalidate']
+      Connection: [keep-alive]
+      Content-Type: [application/json; charset=utf-8]
+      Date: ['Sun, 28 Jul 2019 15:09:22 GMT']
+      ETag: [W/"29fa251c1dbaca8c77f31dafb0580798"]
+      Strict-Transport-Security: [max-age=31536000; includeSubDomains]
+      Transfer-Encoding: [chunked]
+      X-Request-Id: [93d06206-d23f-49dd-9cf5-f916835a20c0]
+      X-Runtime: ['0.088213']
+    status: {code: 200, message: OK}
+- request:
+    body: '{"amount": 0.01, "currency": "MXN"}'
+    headers:
+      Accept: [application/vnd.regalii.v3.1+json]
+      Accept-Encoding: ['gzip, deflate']
+      Authorization: ['APIAuth 88879c1b066dc9aea6201f27be2bbba9:8Rx0fQQrLRdfLD8Jevq3jrPzfKE=']
+      Connection: [keep-alive]
+      Content-Length: ['35']
+      Content-MD5: [y/YL8kAiyFrfQ6mQknvv7g==]
+      Content-Type: [application/json]
+      Date: ['Sun, 28 Jul 2019 15:09:23 GMT']
+      User-Agent: [python-requests/2.21.0]
+    method: POST
+    uri: https://api.casiregalii.com/bills/8390/pay
+  response:
+    body: {string: '{"code":"R102","message":"Parameter amount cannot be less than
+        0.1: amount"}'}
+    headers:
+      Cache-Control: [no-cache]
+      Connection: [keep-alive]
+      Content-Type: [application/json; charset=utf-8]
+      Date: ['Sun, 28 Jul 2019 15:09:23 GMT']
+      Strict-Transport-Security: [max-age=31536000; includeSubDomains]
+      Transfer-Encoding: [chunked]
+      X-Request-Id: [d93a3f16-5325-4db6-9ceb-136e4f98186c]
+      X-Runtime: ['0.018683']
+    status: {code: 400, message: Bad Request}
+version: 1
diff --git a/tests/resources/cassettes/test_cancel_bill_fail.yaml b/tests/resources/cassettes/test_cancel_bill_fail.yaml
index 4551338..2c44c07 100644
--- a/tests/resources/cassettes/test_cancel_bill_fail.yaml
+++ b/tests/resources/cassettes/test_cancel_bill_fail.yaml
@@ -4,72 +4,66 @@ interactions:
     headers:
       Accept: [application/vnd.regalii.v3.1+json]
       Accept-Encoding: ['gzip, deflate']
-      Authorization: ['APIAuth 88879c1b066dc9aea6201f27be2bbba9:pdRsPs9sFwhIlrg8V+tZuoQ9lqE=']
+      Authorization: ['APIAuth 88879c1b066dc9aea6201f27be2bbba9:QZn7cZn0zejWqkMIZBfZlc6eFS4=']
       Connection: [keep-alive]
       Content-Length: ['51']
       Content-MD5: [PwKwTwz6VF3g47PSroLXIQ==]
       Content-Type: [application/json]
-      Date: ['Fri, 22 Feb 2019 18:08:24 GMT']
+      Date: ['Sun, 21 Jul 2019 15:54:21 GMT']
       User-Agent: [python-requests/2.21.0]
     method: POST
     uri: https://api.casiregalii.com/bills
   response:
-    body: {string: '{"type":"bill","id":8392,"biller_id":35,"account_number":"123456851236","name_on_account":null,"due_date":null,"balance":361.0,"balance_currency":"MXN","balance_updated_at":"2019-02-22T18:08:24Z","error_code":null,"error_message":null,"status":"linked","migrated_at":null,"mfa_challenges":[]}'}
+    body: {string: '{"type":"bill","id":8392,"biller_id":35,"account_number":"123456851236","name_on_account":null,"due_date":"2019-09-14T00:00:00Z","balance":558.0,"balance_currency":"MXN","balance_updated_at":"2019-07-21T15:54:21Z","error_code":null,"error_message":null,"status":"linked","migrated_at":null,"mfa_challenges":[]}'}
     headers:
       Cache-Control: ['max-age=0, private, must-revalidate']
       Connection: [keep-alive]
       Content-Type: [application/json; charset=utf-8]
-      Date: ['Fri, 22 Feb 2019 18:08:25 GMT']
-      ETag: [W/"0f0fdf24e92bb8b63dcdd1422b43c1ac"]
-      Strict-Transport-Security: [max-age=31536000]
+      Date: ['Sun, 21 Jul 2019 15:54:23 GMT']
+      ETag: [W/"01bde92423fa519b9951ecb9d062341b"]
+      Strict-Transport-Security: [max-age=31536000; includeSubDomains]
       Transfer-Encoding: [chunked]
-      X-Content-Type-Options: [nosniff]
-      X-Frame-Options: [SAMEORIGIN]
-      X-Request-Id: [ec13fd1e-811d-4b17-82d0-aa4d5947d13e]
-      X-Runtime: ['1.083835']
-      X-XSS-Protection: [1; mode=block]
+      X-Request-Id: [f0814481-b5e0-4bc0-9cbc-01f632509fdb]
+      X-Runtime: ['1.515979']
     status: {code: 200, message: OK}
 - request:
-    body: '{"amount": 361.0, "currency": "MXN"}'
+    body: '{"amount": 558.0, "currency": "MXN"}'
     headers:
       Accept: [application/vnd.regalii.v3.1+json]
       Accept-Encoding: ['gzip, deflate']
-      Authorization: ['APIAuth 88879c1b066dc9aea6201f27be2bbba9:AIan8w1fpxy/xn/NottDaJz8Hpw=']
+      Authorization: ['APIAuth 88879c1b066dc9aea6201f27be2bbba9:jYe8dO/JQ+1e45oLlYiY904aqLg=']
       Connection: [keep-alive]
       Content-Length: ['36']
-      Content-MD5: [OOj9iXZU2vGQy6h3EZQVFg==]
+      Content-MD5: [rLvh75pGsAPcR1CJIkj03g==]
       Content-Type: [application/json]
-      Date: ['Fri, 22 Feb 2019 18:08:25 GMT']
+      Date: ['Sun, 21 Jul 2019 15:54:23 GMT']
       User-Agent: [python-requests/2.21.0]
     method: POST
     uri: https://api.casiregalii.com/bills/8392/pay
   response:
-    body: {string: '{"type":"transaction","id":48860,"amount":361.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":18.74,"transaction_fee":3.0,"total_usd":18.89,"hours_to_fulfill":24,"created_at":"2019-02-22T18:08:26Z","status":"sent"}'}
+    body: {string: '{"type":"transaction","id":69752,"amount":558.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":29.35,"transaction_fee":3.0,"total_usd":29.51,"hours_to_fulfill":24,"created_at":"2019-07-21T15:54:23Z","status":"sent"}'}
     headers:
       Cache-Control: ['max-age=0, private, must-revalidate']
       Connection: [keep-alive]
       Content-Type: [application/json; charset=utf-8]
-      Date: ['Fri, 22 Feb 2019 18:08:26 GMT']
-      ETag: [W/"2d4080165f50859cff51d40b47fd5a43"]
-      Strict-Transport-Security: [max-age=31536000]
+      Date: ['Sun, 21 Jul 2019 15:54:23 GMT']
+      ETag: [W/"cb48669cb7dd50db7cb768268b48b558"]
+      Strict-Transport-Security: [max-age=31536000; includeSubDomains]
       Transfer-Encoding: [chunked]
-      X-Content-Type-Options: [nosniff]
-      X-Frame-Options: [SAMEORIGIN]
-      X-Request-Id: [6c29c51c-6295-490a-a520-b5009ab32a52]
-      X-Runtime: ['0.068822']
-      X-XSS-Protection: [1; mode=block]
+      X-Request-Id: [f482532b-0306-4a12-9388-6e52a71cc5aa]
+      X-Runtime: ['0.084575']
     status: {code: 201, message: Created}
 - request:
-    body: '{"id": 48860}'
+    body: '{"id": 69752}'
     headers:
       Accept: [application/vnd.regalii.v3.1+json]
       Accept-Encoding: ['gzip, deflate']
-      Authorization: ['APIAuth 88879c1b066dc9aea6201f27be2bbba9:FJTQD1+63yGbCNnlAn+PeaMmujE=']
+      Authorization: ['APIAuth 88879c1b066dc9aea6201f27be2bbba9:Q87JPbRRBlBHxasWy5uMm16vHk0=']
       Connection: [keep-alive]
       Content-Length: ['13']
-      Content-MD5: [dE1HV45wXp8LQgdfTQ5Nog==]
+      Content-MD5: [gTHDAg2r3bbjrnJoC7OD0w==]
       Content-Type: [application/json]
-      Date: ['Fri, 22 Feb 2019 18:08:26 GMT']
+      Date: ['Sun, 21 Jul 2019 15:54:23 GMT']
       User-Agent: [python-requests/2.21.0]
     method: POST
     uri: https://api.casiregalii.com/transaction/cancel
@@ -79,27 +73,52 @@ interactions:
       Cache-Control: ['max-age=0, private, must-revalidate']
       Connection: [keep-alive]
       Content-Type: [application/json; charset=utf-8]
-      Date: ['Fri, 22 Feb 2019 18:08:26 GMT']
-      ETag: [W/"db0d73e6dab3e6ac7e916f3c7659ec9f"]
-      Strict-Transport-Security: [max-age=31536000]
+      Date: ['Sun, 21 Jul 2019 15:54:23 GMT']
+      ETag: [W/"7c9aab828943e845cc0d5431f05d00d0"]
+      Strict-Transport-Security: [max-age=31536000; includeSubDomains]
       Transfer-Encoding: [chunked]
-      X-Content-Type-Options: [nosniff]
-      X-Frame-Options: [SAMEORIGIN]
-      X-Request-Id: [b65d14dd-4ba2-4f07-bdb1-3c90fadc5a64]
-      X-Runtime: ['0.077043']
-      X-XSS-Protection: [1; mode=block]
+      X-Request-Id: [84ed71f8-fe49-47b5-962b-c31ef264c2ab]
+      X-Runtime: ['0.066264']
     status: {code: 200, message: OK}
 - request:
-    body: '{"id": 48860}'
+    body: '{}'
     headers:
       Accept: [application/vnd.regalii.v3.1+json]
       Accept-Encoding: ['gzip, deflate']
-      Authorization: ['APIAuth 88879c1b066dc9aea6201f27be2bbba9:FJTQD1+63yGbCNnlAn+PeaMmujE=']
+      Authorization: ['APIAuth 88879c1b066dc9aea6201f27be2bbba9:vSpPMmgnQr8aGd5lUEGxsqc0WQc=']
+      Connection: [keep-alive]
+      Content-Length: ['2']
+      Content-MD5: [mZFLkyvTelC5g8XnyQrpOw==]
+      Content-Type: [application/json]
+      Date: ['Sun, 21 Jul 2019 15:54:23 GMT']
+      User-Agent: [python-requests/2.21.0]
+    method: GET
+    uri: https://api.casiregalii.com/transactions?q[id_eq]=69752
+  response:
+    body: {string: '{"transactions":[{"type":"transaction","id":69752,"amount":558.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":29.35,"transaction_fee":3.0,"total_usd":29.51,"hours_to_fulfill":24,"created_at":"2019-07-21T15:54:23Z","status":"refunded"}]}'}
+    headers:
+      Cache-Control: ['max-age=0, private, must-revalidate']
+      Connection: [keep-alive]
+      Content-Type: [application/json; charset=utf-8]
+      Date: ['Sun, 21 Jul 2019 15:54:23 GMT']
+      ETag: [W/"967586dff2bb735497fe03db314ba90d"]
+      Strict-Transport-Security: [max-age=31536000; includeSubDomains]
+      Transfer-Encoding: [chunked]
+      X-Pagination: ['{"total_entries":1,"total_pages":1,"previous_page":null,"current_page":1,"next_page":null}']
+      X-Request-Id: [a3f3a543-e752-4788-809f-eae4e447fc5d]
+      X-Runtime: ['0.225773']
+    status: {code: 200, message: OK}
+- request:
+    body: '{"id": 69752}'
+    headers:
+      Accept: [application/vnd.regalii.v3.1+json]
+      Accept-Encoding: ['gzip, deflate']
+      Authorization: ['APIAuth 88879c1b066dc9aea6201f27be2bbba9:Q87JPbRRBlBHxasWy5uMm16vHk0=']
       Connection: [keep-alive]
       Content-Length: ['13']
-      Content-MD5: [dE1HV45wXp8LQgdfTQ5Nog==]
+      Content-MD5: [gTHDAg2r3bbjrnJoC7OD0w==]
       Content-Type: [application/json]
-      Date: ['Fri, 22 Feb 2019 18:08:26 GMT']
+      Date: ['Sun, 21 Jul 2019 15:54:23 GMT']
       User-Agent: [python-requests/2.21.0]
     method: POST
     uri: https://api.casiregalii.com/transaction/cancel
@@ -109,86 +128,77 @@ interactions:
       Cache-Control: [no-cache]
       Connection: [keep-alive]
       Content-Type: [application/json; charset=utf-8]
-      Date: ['Fri, 22 Feb 2019 18:08:26 GMT']
-      Strict-Transport-Security: [max-age=31536000]
+      Date: ['Sun, 21 Jul 2019 15:54:23 GMT']
+      Strict-Transport-Security: [max-age=31536000; includeSubDomains]
       Transfer-Encoding: [chunked]
-      X-Content-Type-Options: [nosniff]
-      X-Frame-Options: [SAMEORIGIN]
-      X-Request-Id: [89844ba4-a6c9-457a-8398-010524e55c22]
-      X-Runtime: ['0.017627']
-      X-XSS-Protection: [1; mode=block]
+      X-Request-Id: [fa3cdbd6-f09e-4f9f-b8a4-d9677a9437de]
+      X-Runtime: ['0.018721']
     status: {code: 422, message: Unprocessable Entity}
 - request:
     body: '{"biller_id": 37, "account_number": "7259047384"}'
     headers:
       Accept: [application/vnd.regalii.v3.1+json]
       Accept-Encoding: ['gzip, deflate']
-      Authorization: ['APIAuth 88879c1b066dc9aea6201f27be2bbba9:YVN09AIOrL2RKA9HPt3EFCenrKk=']
+      Authorization: ['APIAuth 88879c1b066dc9aea6201f27be2bbba9:GdrTj9sK1EvWeq6f46cC35Jo3Zk=']
       Connection: [keep-alive]
       Content-Length: ['49']
       Content-MD5: [62F3V1wBjtV3NfAN13xtMg==]
       Content-Type: [application/json]
-      Date: ['Fri, 22 Feb 2019 18:08:27 GMT']
+      Date: ['Sun, 21 Jul 2019 15:54:23 GMT']
       User-Agent: [python-requests/2.21.0]
     method: POST
     uri: https://api.casiregalii.com/bills
   response:
-    body: {string: '{"type":"bill","id":12617,"biller_id":37,"account_number":"7259047384","name_on_account":null,"due_date":null,"balance":849.0,"balance_currency":"MXN","balance_updated_at":"2019-02-22T18:08:27Z","error_code":null,"error_message":null,"status":"linked","migrated_at":null,"mfa_challenges":[]}'}
+    body: {string: '{"type":"bill","id":12617,"biller_id":37,"account_number":"7259047384","name_on_account":null,"due_date":null,"balance":856.0,"balance_currency":"MXN","balance_updated_at":"2019-07-21T15:54:23Z","error_code":null,"error_message":null,"status":"linked","migrated_at":null,"mfa_challenges":[]}'}
     headers:
       Cache-Control: ['max-age=0, private, must-revalidate']
       Connection: [keep-alive]
       Content-Type: [application/json; charset=utf-8]
-      Date: ['Fri, 22 Feb 2019 18:08:28 GMT']
-      ETag: [W/"b8ba424906022b7343393e33f0c6732a"]
-      Strict-Transport-Security: [max-age=31536000]
+      Date: ['Sun, 21 Jul 2019 15:54:24 GMT']
+      ETag: [W/"820f03d3a934ff211b71dcb14288cae4"]
+      Strict-Transport-Security: [max-age=31536000; includeSubDomains]
       Transfer-Encoding: [chunked]
-      X-Content-Type-Options: [nosniff]
-      X-Frame-Options: [SAMEORIGIN]
-      X-Request-Id: [e77193ba-c83e-4950-bdab-b78b4fe53fc2]
-      X-Runtime: ['1.069654']
-      X-XSS-Protection: [1; mode=block]
+      X-Request-Id: [88075d52-2514-47ed-9cee-dbc7bfc36d0f]
+      X-Runtime: ['1.051953']
     status: {code: 200, message: OK}
 - request:
-    body: '{"amount": 849.0, "currency": "MXN"}'
+    body: '{"amount": 856.0, "currency": "MXN"}'
     headers:
       Accept: [application/vnd.regalii.v3.1+json]
       Accept-Encoding: ['gzip, deflate']
-      Authorization: ['APIAuth 88879c1b066dc9aea6201f27be2bbba9:mcAhRwktHi9ShHTYWnNrSpn2RFQ=']
+      Authorization: ['APIAuth 88879c1b066dc9aea6201f27be2bbba9:NeCJpr0DCZLobuAn34fk8Fn8Wck=']
       Connection: [keep-alive]
       Content-Length: ['36']
-      Content-MD5: [yzUrrRh934gL/5zROQHxhA==]
+      Content-MD5: [Q4xShKt8aUAC0TiFxJac6Q==]
       Content-Type: [application/json]
-      Date: ['Fri, 22 Feb 2019 18:08:28 GMT']
+      Date: ['Sun, 21 Jul 2019 15:54:25 GMT']
       User-Agent: [python-requests/2.21.0]
     method: POST
     uri: https://api.casiregalii.com/bills/12617/pay
   response:
-    body: {string: '{"type":"transaction","id":48861,"amount":849.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":44.06,"transaction_fee":3.0,"total_usd":44.22,"hours_to_fulfill":48,"created_at":"2019-02-22T18:08:28Z","status":"sent"}'}
+    body: {string: '{"type":"transaction","id":69753,"amount":856.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":45.03,"transaction_fee":3.0,"total_usd":45.18,"hours_to_fulfill":48,"created_at":"2019-07-21T15:54:25Z","status":"sent"}'}
     headers:
       Cache-Control: ['max-age=0, private, must-revalidate']
       Connection: [keep-alive]
       Content-Type: [application/json; charset=utf-8]
-      Date: ['Fri, 22 Feb 2019 18:08:28 GMT']
-      ETag: [W/"931f37442a03f91a2615c4976b9dfe98"]
-      Strict-Transport-Security: [max-age=31536000]
+      Date: ['Sun, 21 Jul 2019 15:54:25 GMT']
+      ETag: [W/"3fe770e0f777534674b46a7de024ba74"]
+      Strict-Transport-Security: [max-age=31536000; includeSubDomains]
       Transfer-Encoding: [chunked]
-      X-Content-Type-Options: [nosniff]
-      X-Frame-Options: [SAMEORIGIN]
-      X-Request-Id: [bb75e86d-dcae-4c85-85ab-a6f908069b2d]
-      X-Runtime: ['0.068081']
-      X-XSS-Protection: [1; mode=block]
+      X-Request-Id: [901b0b25-1ede-460c-a276-f403aebb710a]
+      X-Runtime: ['0.658053']
     status: {code: 201, message: Created}
 - request:
-    body: '{"id": 48861}'
+    body: '{"id": 69753}'
     headers:
       Accept: [application/vnd.regalii.v3.1+json]
       Accept-Encoding: ['gzip, deflate']
-      Authorization: ['APIAuth 88879c1b066dc9aea6201f27be2bbba9:NJzLq7FjZTQAFc5jAhArSZpcUuc=']
+      Authorization: ['APIAuth 88879c1b066dc9aea6201f27be2bbba9:mmTif7eSQb+iad5oGzy9Le59Doo=']
       Connection: [keep-alive]
       Content-Length: ['13']
-      Content-MD5: [ZFIA2aS5IoRZws58Ar6eew==]
+      Content-MD5: [HHeIuvJq9OjQ4FRtF+nCHQ==]
       Content-Type: [application/json]
-      Date: ['Fri, 22 Feb 2019 18:08:28 GMT']
+      Date: ['Sun, 21 Jul 2019 15:54:25 GMT']
       User-Agent: [python-requests/2.21.0]
     method: POST
     uri: https://api.casiregalii.com/transaction/cancel
@@ -198,13 +208,10 @@ interactions:
       Cache-Control: [no-cache]
       Connection: [keep-alive]
       Content-Type: [application/json; charset=utf-8]
-      Date: ['Fri, 22 Feb 2019 18:08:28 GMT']
-      Strict-Transport-Security: [max-age=31536000]
+      Date: ['Sun, 21 Jul 2019 15:54:26 GMT']
+      Strict-Transport-Security: [max-age=31536000; includeSubDomains]
       Transfer-Encoding: [chunked]
-      X-Content-Type-Options: [nosniff]
-      X-Frame-Options: [SAMEORIGIN]
-      X-Request-Id: [204401da-dddb-44d8-aab2-b92661503fd0]
-      X-Runtime: ['0.018907']
-      X-XSS-Protection: [1; mode=block]
+      X-Request-Id: [473f1e82-4e06-4ea3-b221-c5ffa3acce46]
+      X-Runtime: ['0.021597']
     status: {code: 422, message: Unprocessable Entity}
 version: 1
diff --git a/tests/resources/cassettes/test_cancel_bill_success.yaml b/tests/resources/cassettes/test_cancel_bill_success.yaml
index 99ca10f..1ee1aa5 100644
--- a/tests/resources/cassettes/test_cancel_bill_success.yaml
+++ b/tests/resources/cassettes/test_cancel_bill_success.yaml
@@ -22,7 +22,6 @@ interactions:
       Date: ['Wed, 20 Feb 2019 18:04:01 GMT']
       ETag: [W/"dd87d39290b1120f2cf381549ede60fd"]
       Strict-Transport-Security: [max-age=31536000]
-      Transfer-Encoding: [chunked]
       X-Content-Type-Options: [nosniff]
       X-Frame-Options: [SAMEORIGIN]
       X-Request-Id: [c333c234-e11c-4f23-b7e8-e6a0d7c7deeb]
@@ -52,7 +51,6 @@ interactions:
       Date: ['Wed, 20 Feb 2019 18:04:02 GMT']
       ETag: [W/"211e1cb7b0058d0db06e0d14a803ab63"]
       Strict-Transport-Security: [max-age=31536000]
-      Transfer-Encoding: [chunked]
       X-Content-Type-Options: [nosniff]
       X-Frame-Options: [SAMEORIGIN]
       X-Request-Id: [4a720fa0-d562-49fd-9389-d2cedd5363f1]
@@ -82,7 +80,6 @@ interactions:
       Date: ['Wed, 20 Feb 2019 18:04:02 GMT']
       ETag: [W/"db0d73e6dab3e6ac7e916f3c7659ec9f"]
       Strict-Transport-Security: [max-age=31536000]
-      Transfer-Encoding: [chunked]
       X-Content-Type-Options: [nosniff]
       X-Frame-Options: [SAMEORIGIN]
       X-Request-Id: [1f6ed9b0-ed7b-4e3f-96ee-df74a135c5a7]
@@ -112,7 +109,6 @@ interactions:
       Date: ['Wed, 20 Feb 2019 18:04:03 GMT']
       ETag: [W/"88dc55289d98449c69d465ea7d2989fb"]
       Strict-Transport-Security: [max-age=31536000]
-      Transfer-Encoding: [chunked]
       X-Content-Type-Options: [nosniff]
       X-Frame-Options: [SAMEORIGIN]
       X-Pagination: ['{"total_entries":1,"total_pages":1,"previous_page":null,"current_page":1,"next_page":null}']
@@ -120,4 +116,32 @@ interactions:
       X-Runtime: ['0.040866']
       X-XSS-Protection: [1; mode=block]
     status: {code: 200, message: OK}
+- request:
+    body: '{}'
+    headers:
+      Accept: [application/vnd.regalii.v3.1+json]
+      Accept-Encoding: ['gzip, deflate']
+      Authorization: ['APIAuth 88879c1b066dc9aea6201f27be2bbba9:SSKSsvnBkqY8VYVDHAvOsuMCz0M=']
+      Connection: [keep-alive]
+      Content-Length: ['2']
+      Content-MD5: [mZFLkyvTelC5g8XnyQrpOw==]
+      Content-Type: [application/json]
+      Date: ['Sun, 21 Jul 2019 15:51:55 GMT']
+      User-Agent: [python-requests/2.21.0]
+    method: GET
+    uri: https://api.casiregalii.com/transactions?q[id_eq]=48586
+  response:
+    body: {string: '{"transactions":[{"type":"transaction","id":48586,"amount":666.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":34.7,"transaction_fee":3.0,"total_usd":34.85,"hours_to_fulfill":24,"created_at":"2019-02-20T18:04:02Z","status":"refunded"}]}'}
+    headers:
+      Cache-Control: ['max-age=0, private, must-revalidate']
+      Connection: [keep-alive]
+      Content-Type: [application/json; charset=utf-8]
+      Date: ['Sun, 21 Jul 2019 15:51:56 GMT']
+      ETag: [W/"4a3d10ed4c769d60d1962a9a0c8db0f2"]
+      Strict-Transport-Security: [max-age=31536000; includeSubDomains]
+      Transfer-Encoding: [chunked]
+      X-Pagination: ['{"total_entries":1,"total_pages":1,"previous_page":null,"current_page":1,"next_page":null}']
+      X-Request-Id: [ef112ef9-50eb-4358-bcec-3d6fd4426184]
+      X-Runtime: ['0.022131']
+    status: {code: 200, message: OK}
 version: 1
diff --git a/tests/resources/cassettes/test_transaction_refresh.yaml b/tests/resources/cassettes/test_transaction_refresh.yaml
new file mode 100644
index 0000000..5570622
--- /dev/null
+++ b/tests/resources/cassettes/test_transaction_refresh.yaml
@@ -0,0 +1,58 @@
+interactions:
+- request:
+    body: '{}'
+    headers:
+      Accept: [application/vnd.regalii.v3.1+json]
+      Accept-Encoding: ['gzip, deflate']
+      Authorization: ['APIAuth 88879c1b066dc9aea6201f27be2bbba9:1tGfs/dR+XN6rHkgzznlEqhNRC8=']
+      Connection: [keep-alive]
+      Content-Length: ['2']
+      Content-MD5: [mZFLkyvTelC5g8XnyQrpOw==]
+      Content-Type: [application/json]
+      Date: ['Sun, 21 Jul 2019 16:02:59 GMT']
+      User-Agent: [python-requests/2.21.0]
+    method: GET
+    uri: https://api.casiregalii.com/transactions
+  response:
+    body: {string: '{"transactions":[{"type":"transaction","id":34869,"amount":48.84,"amount_currency":"USD","fx_rate":1.0,"amount_usd":2.39,"transaction_fee":3.0,"total_usd":2.54,"hours_to_fulfill":72,"created_at":"2018-06-07T17:43:07Z","status":"fulfilled"},{"type":"transaction","id":34870,"amount":73.35,"amount_currency":"USD","fx_rate":1.0,"amount_usd":3.59,"transaction_fee":3.0,"total_usd":3.73,"hours_to_fulfill":72,"created_at":"2018-06-07T17:45:22Z","status":"fulfilled"},{"type":"transaction","id":34871,"amount":21.75,"amount_currency":"USD","fx_rate":1.0,"amount_usd":1.06,"transaction_fee":3.0,"total_usd":1.21,"hours_to_fulfill":72,"created_at":"2018-06-07T17:47:55Z","status":"fulfilled"},{"type":"transaction","id":34925,"amount":36.25,"amount_currency":"USD","fx_rate":1.0,"amount_usd":1.76,"transaction_fee":3.0,"total_usd":1.9,"hours_to_fulfill":72,"created_at":"2018-06-08T15:48:13Z","status":"fulfilled"},{"type":"transaction","id":34926,"amount":84.51,"amount_currency":"USD","fx_rate":1.0,"amount_usd":4.1,"transaction_fee":3.0,"total_usd":4.24,"hours_to_fulfill":72,"created_at":"2018-06-08T15:52:08Z","status":"fulfilled"},{"type":"transaction","id":34927,"amount":549.0,"amount_currency":"MXN","fx_rate":0.98,"amount_usd":26.63,"transaction_fee":3.0,"total_usd":26.77,"hours_to_fulfill":0,"created_at":"2018-06-08T16:01:08Z","status":"fulfilled"},{"type":"transaction","id":34928,"amount":549.0,"amount_currency":"MXN","fx_rate":0.98,"amount_usd":26.63,"transaction_fee":3.0,"total_usd":26.77,"hours_to_fulfill":0,"created_at":"2018-06-08T16:01:32Z","status":"fulfilled"},{"type":"transaction","id":34929,"amount":549.0,"amount_currency":"MXN","fx_rate":0.98,"amount_usd":26.63,"transaction_fee":3.0,"total_usd":26.77,"hours_to_fulfill":0,"created_at":"2018-06-08T16:07:59Z","status":"fulfilled"},{"type":"transaction","id":34931,"amount":537.0,"amount_currency":"MXN","fx_rate":0.98,"amount_usd":26.04,"transaction_fee":3.0,"total_usd":26.19,"hours_to_fulfill":24,"created_at":"2018-06-08T16:42:46Z","status":"refunded"},{"type":"transaction","id":34932,"amount":669.0,"amount_currency":"MXN","fx_rate":0.98,"amount_usd":32.45,"transaction_fee":3.0,"total_usd":32.59,"hours_to_fulfill":24,"created_at":"2018-06-08T16:49:50Z","status":"fulfilled"},{"type":"transaction","id":34933,"amount":539.0,"amount_currency":"MXN","fx_rate":0.98,"amount_usd":26.14,"transaction_fee":3.0,"total_usd":26.29,"hours_to_fulfill":24,"created_at":"2018-06-08T16:50:20Z","status":"refunded"},{"type":"transaction","id":34934,"amount":537.0,"amount_currency":"MXN","fx_rate":0.98,"amount_usd":26.04,"transaction_fee":3.0,"total_usd":26.19,"hours_to_fulfill":24,"created_at":"2018-06-08T16:54:20Z","status":"fulfilled"},{"type":"transaction","id":34939,"amount":782.0,"amount_currency":"MXN","fx_rate":0.98,"amount_usd":37.93,"transaction_fee":3.0,"total_usd":38.07,"hours_to_fulfill":24,"created_at":"2018-06-08T17:06:03Z","status":"refunded"},{"type":"transaction","id":34941,"amount":586.0,"amount_currency":"MXN","fx_rate":0.98,"amount_usd":28.42,"transaction_fee":3.0,"total_usd":28.57,"hours_to_fulfill":24,"created_at":"2018-06-08T17:10:40Z","status":"refunded"},{"type":"transaction","id":34942,"amount":862.0,"amount_currency":"MXN","fx_rate":0.98,"amount_usd":41.81,"transaction_fee":3.0,"total_usd":41.95,"hours_to_fulfill":24,"created_at":"2018-06-08T17:11:06Z","status":"refunded"},{"type":"transaction","id":34943,"amount":472.0,"amount_currency":"MXN","fx_rate":0.98,"amount_usd":22.89,"transaction_fee":3.0,"total_usd":23.04,"hours_to_fulfill":24,"created_at":"2018-06-08T17:12:02Z","status":"refunded"},{"type":"transaction","id":34945,"amount":549.0,"amount_currency":"MXN","fx_rate":0.98,"amount_usd":26.63,"transaction_fee":3.0,"total_usd":26.77,"hours_to_fulfill":0,"created_at":"2018-06-08T17:17:55Z","status":"fulfilled"},{"type":"transaction","id":34946,"amount":698.0,"amount_currency":"MXN","fx_rate":0.98,"amount_usd":33.85,"transaction_fee":3.0,"total_usd":34.0,"hours_to_fulfill":24,"created_at":"2018-06-08T17:17:58Z","status":"refunded"},{"type":"transaction","id":34947,"amount":549.0,"amount_currency":"MXN","fx_rate":0.98,"amount_usd":26.63,"transaction_fee":3.0,"total_usd":26.77,"hours_to_fulfill":0,"created_at":"2018-06-08T17:37:03Z","status":"fulfilled"},{"type":"transaction","id":34948,"amount":255.0,"amount_currency":"MXN","fx_rate":0.98,"amount_usd":12.37,"transaction_fee":3.0,"total_usd":12.51,"hours_to_fulfill":24,"created_at":"2018-06-08T17:37:06Z","status":"refunded"},{"type":"transaction","id":43613,"amount":549.0,"amount_currency":"MXN","fx_rate":0.98,"amount_usd":27.18,"transaction_fee":3.0,"total_usd":27.32,"hours_to_fulfill":0,"created_at":"2018-11-06T19:42:29Z","status":"fulfilled"},{"type":"transaction","id":43614,"amount":549.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":27.18,"transaction_fee":3.0,"total_usd":27.32,"hours_to_fulfill":0,"created_at":"2018-11-06T19:50:22Z","status":"fulfilled"},{"type":"transaction","id":43615,"amount":361.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":17.87,"transaction_fee":3.0,"total_usd":18.02,"hours_to_fulfill":24,"created_at":"2018-11-06T19:50:27Z","status":"refunded"},{"type":"transaction","id":44276,"amount":549.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":27.18,"transaction_fee":3.0,"total_usd":27.32,"hours_to_fulfill":0,"created_at":"2018-11-15T23:00:01Z","status":"fulfilled"},{"type":"transaction","id":44277,"amount":549.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":27.18,"transaction_fee":3.0,"total_usd":27.32,"hours_to_fulfill":0,"created_at":"2018-11-15T23:00:41Z","status":"fulfilled"},{"type":"transaction","id":44280,"amount":631.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":31.23,"transaction_fee":3.0,"total_usd":31.38,"hours_to_fulfill":24,"created_at":"2018-11-15T23:25:25Z","status":"fulfilled"},{"type":"transaction","id":44281,"amount":218.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":10.79,"transaction_fee":3.0,"total_usd":10.94,"hours_to_fulfill":24,"created_at":"2018-11-15T23:26:08Z","status":"refunded"},{"type":"transaction","id":44283,"amount":782.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":38.71,"transaction_fee":3.0,"total_usd":38.86,"hours_to_fulfill":24,"created_at":"2018-11-15T23:27:32Z","status":"refunded"},{"type":"transaction","id":44284,"amount":549.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":27.18,"transaction_fee":3.0,"total_usd":27.32,"hours_to_fulfill":0,"created_at":"2018-11-15T23:32:23Z","status":"fulfilled"},{"type":"transaction","id":44285,"amount":214.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":10.59,"transaction_fee":3.0,"total_usd":10.74,"hours_to_fulfill":24,"created_at":"2018-11-15T23:32:25Z","status":"refunded"},{"type":"transaction","id":44286,"amount":829.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":41.04,"transaction_fee":3.0,"total_usd":41.18,"hours_to_fulfill":24,"created_at":"2018-11-15T23:33:57Z","status":"refunded"},{"type":"transaction","id":44288,"amount":549.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":27.18,"transaction_fee":3.0,"total_usd":27.32,"hours_to_fulfill":0,"created_at":"2018-11-15T23:45:03Z","status":"fulfilled"},{"type":"transaction","id":44289,"amount":888.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":43.96,"transaction_fee":3.0,"total_usd":44.1,"hours_to_fulfill":24,"created_at":"2018-11-15T23:45:05Z","status":"refunded"},{"type":"transaction","id":44290,"amount":549.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":27.18,"transaction_fee":3.0,"total_usd":27.32,"hours_to_fulfill":0,"created_at":"2018-11-15T23:52:37Z","status":"fulfilled"},{"type":"transaction","id":44291,"amount":352.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":17.42,"transaction_fee":3.0,"total_usd":17.57,"hours_to_fulfill":24,"created_at":"2018-11-15T23:52:39Z","status":"refunded"},{"type":"transaction","id":44293,"amount":549.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":27.18,"transaction_fee":3.0,"total_usd":27.32,"hours_to_fulfill":0,"created_at":"2018-11-15T23:56:30Z","status":"fulfilled"},{"type":"transaction","id":44294,"amount":870.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":43.07,"transaction_fee":3.0,"total_usd":43.21,"hours_to_fulfill":24,"created_at":"2018-11-15T23:56:32Z","status":"refunded"},{"type":"transaction","id":44296,"amount":425.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":21.04,"transaction_fee":3.0,"total_usd":21.19,"hours_to_fulfill":24,"created_at":"2018-11-16T00:07:53Z","status":"refunded"},{"type":"transaction","id":44297,"amount":479.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":23.71,"transaction_fee":3.0,"total_usd":23.86,"hours_to_fulfill":24,"created_at":"2018-11-16T00:08:26Z","status":"refunded"},{"type":"transaction","id":44298,"amount":208.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":10.3,"transaction_fee":3.0,"total_usd":10.44,"hours_to_fulfill":24,"created_at":"2018-11-16T00:10:31Z","status":"refunded"},{"type":"transaction","id":44299,"amount":656.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":32.47,"transaction_fee":3.0,"total_usd":32.62,"hours_to_fulfill":24,"created_at":"2018-11-16T00:11:14Z","status":"refunded"},{"type":"transaction","id":44300,"amount":202.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":10.0,"transaction_fee":3.0,"total_usd":10.15,"hours_to_fulfill":24,"created_at":"2018-11-16T00:11:38Z","status":"refunded"},{"type":"transaction","id":44301,"amount":582.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":28.81,"transaction_fee":3.0,"total_usd":28.96,"hours_to_fulfill":24,"created_at":"2018-11-16T00:11:59Z","status":"refunded"},{"type":"transaction","id":44302,"amount":476.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":23.56,"transaction_fee":3.0,"total_usd":23.71,"hours_to_fulfill":24,"created_at":"2018-11-16T00:13:07Z","status":"refunded"},{"type":"transaction","id":44303,"amount":502.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":24.85,"transaction_fee":3.0,"total_usd":25.0,"hours_to_fulfill":24,"created_at":"2018-11-16T00:14:03Z","status":"refunded"},{"type":"transaction","id":44308,"amount":549.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":27.18,"transaction_fee":3.0,"total_usd":27.32,"hours_to_fulfill":0,"created_at":"2018-11-16T02:19:13Z","status":"fulfilled"},{"type":"transaction","id":44309,"amount":549.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":27.18,"transaction_fee":3.0,"total_usd":27.32,"hours_to_fulfill":0,"created_at":"2018-11-16T02:19:49Z","status":"fulfilled"},{"type":"transaction","id":44310,"amount":549.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":27.18,"transaction_fee":3.0,"total_usd":27.32,"hours_to_fulfill":0,"created_at":"2018-11-16T02:27:17Z","status":"fulfilled"},{"type":"transaction","id":44311,"amount":549.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":27.18,"transaction_fee":3.0,"total_usd":27.32,"hours_to_fulfill":0,"created_at":"2018-11-16T02:27:35Z","status":"fulfilled"},{"type":"transaction","id":44312,"amount":645.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":31.93,"transaction_fee":3.0,"total_usd":32.08,"hours_to_fulfill":24,"created_at":"2018-11-16T02:43:43Z","status":"fulfilled"},{"type":"transaction","id":44313,"amount":547.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":27.08,"transaction_fee":3.0,"total_usd":27.23,"hours_to_fulfill":24,"created_at":"2018-11-16T02:47:10Z","status":"fulfilled"},{"type":"transaction","id":44314,"amount":796.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":39.4,"transaction_fee":3.0,"total_usd":39.55,"hours_to_fulfill":24,"created_at":"2018-11-16T02:47:48Z","status":"fulfilled"},{"type":"transaction","id":44315,"amount":538.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":26.63,"transaction_fee":3.0,"total_usd":26.78,"hours_to_fulfill":24,"created_at":"2018-11-16T02:48:20Z","status":"fulfilled"},{"type":"transaction","id":44316,"amount":225.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":11.14,"transaction_fee":3.0,"total_usd":11.29,"hours_to_fulfill":24,"created_at":"2018-11-16T02:50:40Z","status":"fulfilled"},{"type":"transaction","id":44317,"amount":116.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":5.74,"transaction_fee":3.0,"total_usd":5.89,"hours_to_fulfill":24,"created_at":"2018-11-16T02:53:04Z","status":"fulfilled"},{"type":"transaction","id":44318,"amount":785.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":38.86,"transaction_fee":3.0,"total_usd":39.01,"hours_to_fulfill":24,"created_at":"2018-11-16T02:55:24Z","status":"refunded"},{"type":"transaction","id":44319,"amount":950.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":47.03,"transaction_fee":3.0,"total_usd":47.17,"hours_to_fulfill":24,"created_at":"2018-11-16T03:01:00Z","status":"refunded"},{"type":"transaction","id":44320,"amount":949.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":46.98,"transaction_fee":3.0,"total_usd":47.12,"hours_to_fulfill":24,"created_at":"2018-11-16T03:03:58Z","status":"refunded"},{"type":"transaction","id":44321,"amount":811.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":40.14,"transaction_fee":3.0,"total_usd":40.29,"hours_to_fulfill":24,"created_at":"2018-11-16T03:08:57Z","status":"refunded"},{"type":"transaction","id":44322,"amount":549.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":27.18,"transaction_fee":3.0,"total_usd":27.32,"hours_to_fulfill":0,"created_at":"2018-11-16T03:10:02Z","status":"fulfilled"},{"type":"transaction","id":44323,"amount":725.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":35.89,"transaction_fee":3.0,"total_usd":36.04,"hours_to_fulfill":24,"created_at":"2018-11-16T03:10:04Z","status":"refunded"},{"type":"transaction","id":44324,"amount":549.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":27.18,"transaction_fee":3.0,"total_usd":27.32,"hours_to_fulfill":0,"created_at":"2018-11-16T03:14:30Z","status":"fulfilled"},{"type":"transaction","id":44325,"amount":904.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":44.75,"transaction_fee":3.0,"total_usd":44.9,"hours_to_fulfill":24,"created_at":"2018-11-16T03:14:32Z","status":"refunded"},{"type":"transaction","id":44326,"amount":549.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":27.18,"transaction_fee":3.0,"total_usd":27.32,"hours_to_fulfill":0,"created_at":"2018-11-16T03:17:49Z","status":"fulfilled"},{"type":"transaction","id":44327,"amount":238.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":11.78,"transaction_fee":3.0,"total_usd":11.93,"hours_to_fulfill":24,"created_at":"2018-11-16T03:17:50Z","status":"refunded"},{"type":"transaction","id":44328,"amount":549.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":27.18,"transaction_fee":3.0,"total_usd":27.32,"hours_to_fulfill":0,"created_at":"2018-11-16T03:18:18Z","status":"fulfilled"},{"type":"transaction","id":44329,"amount":925.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":45.79,"transaction_fee":3.0,"total_usd":45.94,"hours_to_fulfill":24,"created_at":"2018-11-16T03:18:20Z","status":"refunded"},{"type":"transaction","id":44330,"amount":549.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":27.18,"transaction_fee":3.0,"total_usd":27.32,"hours_to_fulfill":0,"created_at":"2018-11-16T03:21:45Z","status":"fulfilled"},{"type":"transaction","id":44331,"amount":610.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":30.2,"transaction_fee":3.0,"total_usd":30.34,"hours_to_fulfill":24,"created_at":"2018-11-16T03:21:47Z","status":"refunded"},{"type":"transaction","id":44333,"amount":549.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":27.18,"transaction_fee":3.0,"total_usd":27.32,"hours_to_fulfill":0,"created_at":"2018-11-16T03:33:57Z","status":"fulfilled"},{"type":"transaction","id":44334,"amount":918.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":45.44,"transaction_fee":3.0,"total_usd":45.59,"hours_to_fulfill":24,"created_at":"2018-11-16T03:33:58Z","status":"refunded"},{"type":"transaction","id":44338,"amount":549.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":27.18,"transaction_fee":3.0,"total_usd":27.32,"hours_to_fulfill":0,"created_at":"2018-11-16T03:34:44Z","status":"fulfilled"},{"type":"transaction","id":44339,"amount":997.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":49.35,"transaction_fee":3.0,"total_usd":49.5,"hours_to_fulfill":24,"created_at":"2018-11-16T03:34:46Z","status":"refunded"},{"type":"transaction","id":44340,"amount":549.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":27.18,"transaction_fee":3.0,"total_usd":27.32,"hours_to_fulfill":0,"created_at":"2018-11-16T03:37:36Z","status":"fulfilled"},{"type":"transaction","id":44341,"amount":443.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":21.93,"transaction_fee":3.0,"total_usd":22.08,"hours_to_fulfill":24,"created_at":"2018-11-16T03:37:37Z","status":"refunded"},{"type":"transaction","id":44342,"amount":549.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":27.18,"transaction_fee":3.0,"total_usd":27.32,"hours_to_fulfill":0,"created_at":"2018-11-16T03:37:49Z","status":"fulfilled"},{"type":"transaction","id":44343,"amount":896.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":44.35,"transaction_fee":3.0,"total_usd":44.5,"hours_to_fulfill":24,"created_at":"2018-11-16T03:37:51Z","status":"refunded"},{"type":"transaction","id":44344,"amount":549.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":27.18,"transaction_fee":3.0,"total_usd":27.32,"hours_to_fulfill":0,"created_at":"2018-11-16T16:39:53Z","status":"fulfilled"},{"type":"transaction","id":44345,"amount":549.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":27.18,"transaction_fee":3.0,"total_usd":27.32,"hours_to_fulfill":0,"created_at":"2018-11-16T16:39:54Z","status":"fulfilled"},{"type":"transaction","id":44346,"amount":29.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":1.44,"transaction_fee":3.0,"total_usd":1.58,"hours_to_fulfill":24,"created_at":"2018-11-16T16:39:55Z","status":"refunded"},{"type":"transaction","id":44347,"amount":715.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":35.39,"transaction_fee":3.0,"total_usd":35.54,"hours_to_fulfill":24,"created_at":"2018-11-16T16:39:56Z","status":"refunded"},{"type":"transaction","id":44348,"amount":549.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":27.18,"transaction_fee":3.0,"total_usd":27.32,"hours_to_fulfill":0,"created_at":"2018-11-16T16:40:06Z","status":"fulfilled"},{"type":"transaction","id":44349,"amount":825.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":40.84,"transaction_fee":3.0,"total_usd":40.99,"hours_to_fulfill":24,"created_at":"2018-11-16T16:40:08Z","status":"refunded"},{"type":"transaction","id":44350,"amount":549.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":27.18,"transaction_fee":3.0,"total_usd":27.32,"hours_to_fulfill":0,"created_at":"2018-11-16T16:40:08Z","status":"fulfilled"},{"type":"transaction","id":44351,"amount":372.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":18.41,"transaction_fee":3.0,"total_usd":18.56,"hours_to_fulfill":24,"created_at":"2018-11-16T16:40:10Z","status":"refunded"},{"type":"transaction","id":44364,"amount":549.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":27.18,"transaction_fee":3.0,"total_usd":27.32,"hours_to_fulfill":0,"created_at":"2018-11-16T19:12:46Z","status":"fulfilled"},{"type":"transaction","id":44365,"amount":549.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":27.18,"transaction_fee":3.0,"total_usd":27.32,"hours_to_fulfill":0,"created_at":"2018-11-16T19:14:11Z","status":"fulfilled"},{"type":"transaction","id":44366,"amount":549.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":27.18,"transaction_fee":3.0,"total_usd":27.32,"hours_to_fulfill":0,"created_at":"2018-11-16T19:16:04Z","status":"fulfilled"},{"type":"transaction","id":44367,"amount":549.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":27.18,"transaction_fee":3.0,"total_usd":27.32,"hours_to_fulfill":0,"created_at":"2018-11-16T19:18:58Z","status":"fulfilled"},{"type":"transaction","id":44368,"amount":437.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":21.63,"transaction_fee":3.0,"total_usd":21.78,"hours_to_fulfill":24,"created_at":"2018-11-16T19:19:00Z","status":"refunded"},{"type":"transaction","id":44370,"amount":549.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":27.18,"transaction_fee":3.0,"total_usd":27.32,"hours_to_fulfill":0,"created_at":"2018-11-16T19:24:22Z","status":"fulfilled"},{"type":"transaction","id":44371,"amount":311.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":15.39,"transaction_fee":3.0,"total_usd":15.54,"hours_to_fulfill":24,"created_at":"2018-11-16T19:24:24Z","status":"refunded"},{"type":"transaction","id":44372,"amount":549.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":27.18,"transaction_fee":3.0,"total_usd":27.32,"hours_to_fulfill":0,"created_at":"2018-11-16T19:33:44Z","status":"fulfilled"},{"type":"transaction","id":44373,"amount":107.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":5.3,"transaction_fee":3.0,"total_usd":5.45,"hours_to_fulfill":24,"created_at":"2018-11-16T19:33:46Z","status":"refunded"},{"type":"transaction","id":44374,"amount":669.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":33.12,"transaction_fee":3.0,"total_usd":33.26,"hours_to_fulfill":24,"created_at":"2018-11-16T19:33:48Z","status":"refunded"},{"type":"transaction","id":44375,"amount":549.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":27.18,"transaction_fee":3.0,"total_usd":27.32,"hours_to_fulfill":0,"created_at":"2018-11-16T19:33:52Z","status":"fulfilled"},{"type":"transaction","id":44376,"amount":706.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":34.95,"transaction_fee":3.0,"total_usd":35.1,"hours_to_fulfill":24,"created_at":"2018-11-16T19:33:53Z","status":"refunded"},{"type":"transaction","id":44377,"amount":549.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":27.18,"transaction_fee":3.0,"total_usd":27.32,"hours_to_fulfill":0,"created_at":"2018-11-16T19:34:29Z","status":"fulfilled"},{"type":"transaction","id":44378,"amount":135.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":6.68,"transaction_fee":3.0,"total_usd":6.83,"hours_to_fulfill":24,"created_at":"2018-11-16T19:34:30Z","status":"refunded"},{"type":"transaction","id":44379,"amount":549.0,"amount_currency":"MXN","fx_rate":1.0,"amount_usd":27.18,"transaction_fee":3.0,"total_usd":27.32,"hours_to_fulfill":0,"created_at":"2018-11-16T19:35:31Z","status":"fulfilled"}]}'}
+    headers:
+      Cache-Control: ['max-age=0, private, must-revalidate']
+      Connection: [keep-alive]
+      Content-Type: [application/json; charset=utf-8]
+      Date: ['Sun, 21 Jul 2019 16:03:00 GMT']
+      ETag: [W/"c665dcb030127f12d904cf0524e4b5ff"]
+      Strict-Transport-Security: [max-age=31536000; includeSubDomains]
+      Transfer-Encoding: [chunked]
+      X-Pagination: ['{"total_entries":1054,"total_pages":11,"previous_page":null,"current_page":1,"next_page":2}']
+      X-Request-Id: [79965894-c633-4da0-aa95-c294b8c7511e]
+      X-Runtime: ['0.065089']
+    status: {code: 200, message: OK}
+- request:
+    body: '{}'
+    headers:
+      Accept: [application/vnd.regalii.v3.1+json]
+      Accept-Encoding: ['gzip, deflate']
+      Authorization: ['APIAuth 88879c1b066dc9aea6201f27be2bbba9:J0FY8UbURaVwBig0Qab8wdcr100=']
+      Connection: [keep-alive]
+      Content-Length: ['2']
+      Content-MD5: [mZFLkyvTelC5g8XnyQrpOw==]
+      Content-Type: [application/json]
+      Date: ['Sun, 21 Jul 2019 16:03:00 GMT']
+      User-Agent: [python-requests/2.21.0]
+    method: GET
+    uri: https://api.casiregalii.com/transactions?q[id_eq]=34869
+  response:
+    body: {string: '{"transactions":[{"type":"transaction","id":34869,"amount":48.84,"amount_currency":"USD","fx_rate":1.0,"amount_usd":2.39,"transaction_fee":3.0,"total_usd":2.54,"hours_to_fulfill":72,"created_at":"2018-06-07T17:43:07Z","status":"fulfilled"}]}'}
+    headers:
+      Cache-Control: ['max-age=0, private, must-revalidate']
+      Connection: [keep-alive]
+      Content-Type: [application/json; charset=utf-8]
+      Date: ['Sun, 21 Jul 2019 16:03:00 GMT']
+      ETag: [W/"79db0fea225ccbdfef30e4521fd6029b"]
+      Strict-Transport-Security: [max-age=31536000; includeSubDomains]
+      Transfer-Encoding: [chunked]
+      X-Pagination: ['{"total_entries":1,"total_pages":1,"previous_page":null,"current_page":1,"next_page":null}']
+      X-Request-Id: [d3ed0262-5979-46fc-8659-a2227e8e19c5]
+      X-Runtime: ['0.488987']
+    status: {code: 200, message: OK}
+version: 1
diff --git a/tests/resources/test_bills.py b/tests/resources/test_bills.py
index 715ad93..986af75 100644
--- a/tests/resources/test_bills.py
+++ b/tests/resources/test_bills.py
@@ -22,9 +22,12 @@ def test_invalid_biller_id(client):
 
 @pytest.mark.vcr
 def test_invalid_account_number(client):
+    biller_id = 40
     invalid_account_number = '501000000004'
-    with pytest.raises(exc.InvalidAccountNumber):
-        client.bills.create(40, invalid_account_number)
+    with pytest.raises(exc.InvalidAccountNumber) as excinfo:
+        client.bills.create(biller_id, invalid_account_number)
+    assert excinfo.value.account_number == invalid_account_number
+    assert excinfo.value.biller_id == biller_id
 
 
 @pytest.mark.vcr
@@ -36,6 +39,14 @@ def test_successful_payment(client):
     assert transaction.status == 'fulfilled'
 
 
+@pytest.mark.vcr
+def test_amount_too_low(client):
+    bill = client.bills.create(40, '501000000007')
+    assert bill == client.bills.get(bill.id)
+    with pytest.raises(exc.InvalidAmount):
+        bill.pay(.01)
+
+
 @pytest.mark.vcr
 def test_pay_with_int_amount(client):
     bill = client.bills.create(40, '501000000007')
@@ -50,6 +61,7 @@ def test_unexpected_error(client):
         client.bills.create(6900, '1111362009')
     e = excinfo.value
     assert e.code == 'R9'
+    str(e)
 
 
 @pytest.mark.vcr
@@ -63,6 +75,7 @@ def test_cancel_bill_success(client):
     updated_transaction = client.transactions.get(transaction.id)
     assert updated_transaction.id == transaction.id
     assert updated_transaction.status == 'refunded'
+    assert transaction.status == updated_transaction.status
 
 
 @pytest.mark.vcr
diff --git a/tests/resources/test_topups.py b/tests/resources/test_topups.py
index b84e37e..b0a99b6 100644
--- a/tests/resources/test_topups.py
+++ b/tests/resources/test_topups.py
@@ -1,6 +1,7 @@
 import pytest
 
-from arcus.exc import UnprocessableEntity
+from arcus.exc import InvalidAccountNumber
+from arcus.resources import Topup
 
 
 @pytest.mark.vcr
@@ -30,11 +31,11 @@ def test_topup_invalid_phone_number(client):
     biller_id = 13599
     account_number = '559999'
     amount = 100.0
-    with pytest.raises(UnprocessableEntity) as excinfo:
+    with pytest.raises(InvalidAccountNumber) as excinfo:
         client.topups.create(biller_id, account_number, amount)
     exc = excinfo.value
-    assert exc.code == 'R5'
-    assert exc.message == 'Invalid Phone Number'
+    assert exc.account_number == account_number
+    assert exc.biller_id == biller_id
 
 
 def test_topup_list(client):
@@ -54,3 +55,10 @@ def test_pay_invoice_with_name_on_account(client):
     assert topup.account_number == account_number
     assert topup.bill_amount == amount
     assert topup.ending_balance < topup.starting_balance
+
+
+def test_unimplemented():
+    with pytest.raises(NotImplementedError):
+        Topup.list()
+    with pytest.raises(NotImplementedError):
+        Topup.get(1)
diff --git a/tests/resources/test_transactions.py b/tests/resources/test_transactions.py
index 99ff443..1f56946 100644
--- a/tests/resources/test_transactions.py
+++ b/tests/resources/test_transactions.py
@@ -1,3 +1,5 @@
+import copy
+
 import pytest
 
 from arcus.resources import Transaction
@@ -9,3 +11,12 @@ def test_transactions_list(client):
     assert transactions
     assert type(transactions) is list
     assert all(isinstance(txn, Transaction) for txn in transactions)
+
+
+@pytest.mark.vcr
+def test_transaction_refresh(client):
+    transaction = client.transactions.list()[0]
+    copied = copy.deepcopy(transaction)
+    transaction.status = 'hey there'
+    transaction.refresh()
+    assert transaction == copied