Compare commits

...

19 Commits

Author SHA1 Message Date
Hailey Clark ffacf89c01 Updated requirements 3 years ago
William Osborne 5d3b75f252
Merge pull request #17 from kevinhippert/patch-1 5 years ago
kevinhippert 1da0588351
Fix module import problems 5 years ago
Chris Lacina a7c3f63f45
Merge pull request #13 from denisemauldin/cdr_api 6 years ago
Denise Mauldin e38a12b56b Add CDR Export API v2.0 to the SDK 6 years ago
Maria Bermudez 7d28a9279d
Update README.md 7 years ago
Maria Bermudez 46a925d501 Add CNAM Storage Rules 7 years ago
Maria Bermudez 78936e1c09
Merge pull request #12 from flowroute/doc-updates 7 years ago
Maria Bermudez 922906ee80
Merge branch 'master' into doc-updates 7 years ago
Maria Bermudez 66267cb2f7 Fix documentation bugs 7 years ago
Maria Bermudez 885e6be2cc Documentation bug fixes 7 years ago
Maria Bermudez 5eac92f9ea Merge branch 'master' of github.com:flowroute/flowroute-sdk-v3-python 7 years ago
Maria Bermudez e3f6dc62ea Update E911 address to be validated 7 years ago
Chris Lacina 0d5578e096
Merge pull request #11 from flowroute/e911_addr 7 years ago
Maria Bermudez 917a12edfd Remove duplicate messaging functions list 7 years ago
Maria Bermudez d7d2532262 Merge branch 'master' of https://github.com/flowroute/flowroute-sdk-v3-python 7 years ago
Maria Bermudez 8581d9d7f9 Update URL for E911 and CNAM reference pages - conform to old resource URIs 7 years ago
Maria Bermudez 05dc4e6562 Merge branch 'doc-updates' of https://github.com/flowroute/flowroute-sdk-v3-python into doc-updates 7 years ago
Maria Bermudez bd3f9be48b Update CNAM anchor links 7 years ago
  1. 357
      README.md
  2. 64
      cdr_demo.py
  3. 5
      flowroutenumbersandmessaging/controllers/__init__.py
  4. 226
      flowroutenumbersandmessaging/controllers/cdrs_controller.py
  5. 6
      flowroutenumbersandmessaging/flowroutenumbersandmessaging_client.py
  6. 6
      requirements.txt

@ -1,7 +1,7 @@
Flowroute Python Library v3
=====================
The Flowroute Python Library v3 provides methods for interacting with [Numbers v2](https://developer.flowroute.com/api/numbers/v2.0/) and [Messages v2.1](https://developer.flowroute.com/api/messages/v2.1/) of the [Flowroute](https://www.flowroute.com) API.
The Flowroute Python Library v3 provides methods for interacting with [Numbers v2](https://developer.flowroute.com/api/numbers/v2.0/) &endash; which includes inbound voice routes, E911 addresses, CNAM storage &endash; and [Messages v2.1](https://developer.flowroute.com/api/messages/v2.1/) and [CDR v2.0](https://developer.flowroute.com/api/cdrs/v2.0/) of the [Flowroute](https://www.flowroute.com) API.
**Topics**
@ -54,10 +54,12 @@ The Flowroute Python Library v3 provides methods for interacting with [Numbers v
* [unassociate_cnam](#unassociate_cnamnumber_id)
* [remove_cnam](#remove_cnamcnam_id)
* [Messaging](#messaging)
* [send_a_message](#send_a_messagemessage_body)
* [look_up_a_set_of_messagesstart_date](#look_up_a_set_of_messagesstart_date)
* [look_up_a_message_detail_record](#look_up_a_message_detail_recordmessage_id)
* [Call Detail Record (CDR)](#call-detail-record)
* [list_cdr_exports](#list_cdr_exports)
* [create_cdr_export](#create_cdr_export)
* [get_cdr_export_status](#get_cdr_export_status)
* [download_cdr_export](#download_cdr_export)
* [Errors](#errors)
* [Testing](#testing)
@ -91,7 +93,7 @@ Depending on your `pip` permissions, you may be required to preface each `pip` c
* * *
Usage
------------
In Flowroute's approach to building the Python Library v3, HTTP requests are handled by controllers named after the API resources they represent: **Numbers**, **Routes**, **E911s**, **CNAMs**, and **Messages**. These controllers contain the methods used to perform messaging, number management, route management, E911 address management, and CNAM record management within the Python library.
In Flowroute's approach to building the Python Library v3, HTTP requests are handled by controllers named after the API resources they represent: **Numbers**, **Routes**, **E911s**, **CNAMs**, and **Messages**. These controllers contain the methods used to perform messaging, number management, route management, E911 address management, and CNAM record management within the Python library.
## Controllers
@ -142,11 +144,22 @@ Contains all of the methods necessary to create, update, and validate new and ex
Contains all of the methods necessary to create and delete CNAM records, view all of the CNAM records associated with your account, filter for specific CNAM records by status, review CNAM record details, and assign and unassign CNAM records to your Flowroute long code phone numbers.
* [list\_cnams()](#list_cnams) \- Returns a list of all CNAM records on your account by default. You can apply search filters using any of the available query parameters.
* [get\_cnam(cnam\_id)](#get_cnamcnam_id) \- Returns details pertaining to a specific CNAM record on your account, including long code numbers that are associated with the record.
* [create\_cnam\_record(cnam\_value)](#create_cnam_recordcnam_value) \- Lets you create a Caller ID record for your account which can then be assigned to any of your long code numbers. To assign a CNAM record to your number, see the [associate\_cnam](#associate_cnam) method.
* [create\_cnam\_record(cnam\_value)](#create_cnam_recordcnam_value) \- Lets you create a Caller ID record for your account which can then be assigned to any of your long code numbers. To assign a CNAM record to your number, see the [associate\_cnam](#associate_cnamcnam_id-number_id) method.
* [associate\_cnam(cnam\_id, number\_id)](#associate_cnamcnam_id-number_id) \- Lets you associate a CNAM record with a specified long code number on your account. Note that a CNAM record takes 1-2 days to be approved.
* [unassociate(number\_id)](#unassociate_cnamnumber_id) \- Lets you unassign a CNAM record associated with a specified long code number on your account without deleting the CNAM record itself.
* [remove\_cnam(cnam\_id)](#remove_cnamcnam_id) \- Lets you delete a CNAM record from your account. Note that this will automatically disassociate all numbers associated with the deleted CNAM record.
### CDRsController
Contains all of the methods necessary to create and retrieve CDR exports.
* [list\_cdr\_exports](#list_cdr_exports) \- Returns a list of all CDR Exports that have been created on your account.
* [create\_cdr\_export](#create_cdr_export) \- Create a CDR Export with a list of filter parameters. When this asynchronous job is done running,
Flowroute's servers will post to a callback URL if one is provided.
* [get\_cdr\_export\_status(cdr\_export\_id)](#get_cdr_export_status) \- Returns details pertaining to a specific CDR Export, including the download_url that
is required to retrieve the CDR Export data.
* [download\_cdr\_export(cdr\_export\_id)](#download_cdr_export) \- Downloads the CDR Export CSV file or GZIPPED CSV file from the Flowroute servers.
The following shows an example of a single Python file that imports the Flowroute API client and all the required modules. The Python Library v3 comes with three example demo files — **number_route_message_demo.py**, **e911_demo.py**, **cnam_demo.py** — files that you can edit and run for demonstration and testing purposes.
```python
@ -896,13 +909,9 @@ The Flowroute Python Library v3 allows you to make HTTP requests to the `e911s`
All of the E911 address management methods are encapsulated in `e911_demo.py`.
| API Reference Pages |
| ------------------- |
| The E911 and CNAM API reference pages are currently restricted to our beta customers, which means that all API reference links below currently return a `404 Not Found`. They will be publicly available during our E911 and CNAM APIs GA launch in a few weeks. |
#### list\_e911s()
The method accepts `limit`, `offset`, and `state` as parameters which you can learn more about in the [API reference](https://developer.flowroute.com/api/e911s/v2.0/list-account-e911-addresses/).
The method accepts `limit`, `offset`, and `state` as parameters which you can learn more about in the [API reference](https://developer.flowroute.com/api/numbers/v2.0/list-account-e911-addresses/).
##### Example Request
```python
@ -951,9 +960,9 @@ On success, the HTTP status code in the response header is `200 OK` and the resp
'self': 'https://api.flowroute.com/v2/e911s?limit=2&offset=0'}}
```
#### get\_e911(e911_id)
#### get\_e911(e911\_id)
The method accepts an `e911_id` as a path parameter which you can learn more about in the [API reference](https://developer.flowroute.com/api/e911s/v2.0/list-e911-record-details/).
The method accepts an `e911_id` as a path parameter which you can learn more about in the [API reference](https://developer.flowroute.com/api/numbers/v2.0/list-e911-record-details/).
##### Example Request
```python
@ -975,25 +984,33 @@ On success, the HTTP status code in the response header is `200 OK` and the resp
```
--Get Details for a specific E911 Record
{'data': {'attributes': {'address_type': 'L',
'address_type_number': '12',
'city': 'Seattle',
'country': 'USA',
'first_name': 'Maria',
'label': 'Example E911',
'last_name': 'Bermudez',
'state': 'WA',
'street_name': '20th Ave SW',
'street_number': '7742',
'zip': '98106'},
'id': '20930',
'links': {'self': 'https://api.flowroute.com/v2/e911s/20930'},
'type': 'e911'}}
{
"data": {
"attributes": {
"address_type": "Suite",
"address_type_number": "333",
"city": "Seattle",
"country": "US",
"first_name": "Albus",
"label": "Office Space III",
"last_name": "Rasputin, Jr.",
"state": "WA",
"street_name": "Main St",
"street_number": "666",
"zip": "98101"
},
"id": "21845",
"links": {
"self": "https://api.flowroute.com/v2/e911s/21845"
},
"type": "e911"
}
}
```
#### validate_address(e911_attributes)
The method accepts the different attributes of an E911 address as parameters: `label`, `first_name`, `last_name`, `street_name`, `street_number`, `city`, `state`, `country`, and `zipcode`. Learn more about the different E911 attributes in the [API reference](https://developer.flowroute.com/api/e911s/v2.0/validate-e911-address/). Note that this method doesn't accept the `address_type` and `address_type_number` which are acceptable but not required E911 address attributes by the API.
The method accepts the different attributes of an E911 address as parameters: `label`, `first_name`, `last_name`, `street_name`, `street_number`, optional `address_type` and `address_type_number`, `city`, `state`, `country`, and `zipcode`. Learn more about the different E911 attributes in the [API reference](https://developer.flowroute.com/api/e911s/v2.0/validate-e911-address/).
##### Example Request
```
@ -1025,7 +1042,7 @@ HTTP response not OK.
```
#### create_address(e911_attributes)
The method accepts the different attributes of an E911 address as parameters: `label`, `first_name`, `last_name`, `street_name`, `street_number`, `city`, `state`, `country`, and `zipcode`. Learn more about the different E911 attributes in the [API reference](https://developer.flowroute.com/api/e911s/v2.0/create-and-validate-new-e911-address/). Note that this method doesn't accept the `address_type` and `address_type\_number` which are acceptable but not required E911 address attributes by the API.
The method accepts the different attributes of an E911 address as parameters: `label`, `first_name`, `last_name`, `street_name`, `street_number`, optional `address_type` and `address_type_number`, `city`, `state`, `country`, and `zipcode`. Learn more about the different E911 attributes in the [API reference](https://developer.flowroute.com/api/e911s/v2.0/create-and-validate-new-e911-address/).
##### Example Request
```
@ -1068,7 +1085,7 @@ On success, the HTTP status code in the response header is `201 Created` and the
```
#### update_address(e911_id, e911_attributes)
The method accepts an E911 record id and the different attributes of an E911 address as parameters: `label`, `first_name`, `last_name`, `street_name`, `street_number`, `city`, `state`, `country`, and `zipcode`. Learn more about the different E911 attributes that you can update in the [API reference](https://developer.flowroute.com/api/e911s/v2.0/update-and-validate-existing-e911-address/). Note that this method doesn't accept the `address_type` and `address_type_number` which are acceptable but not required E911 address attributes by the API. In the following example, we will retrieve the record ID of our newly created E911 address and assign it to a variable, `record_id`. We then update the `last_name` of our selected E911 address to "Wiley".
The method accepts an E911 record id and the different attributes of an E911 address as parameters: `label`, `first_name`, `last_name`, `street_name`, `street_number`, optional `address_type` and `address_type_number`, `city`, `state`, `country`, and `zipcode`. Learn more about the different E911 attributes that you can update in the [API reference](https://developer.flowroute.com/api/e911s/v2.0/update-and-validate-existing-e911-address/). In the following example, we will retrieve the record ID of our newly created E911 address and assign it to a variable, `record_id`. We then update the `last_name` of our selected E911 address to "Wiley".
##### Example Request
```
@ -1105,7 +1122,7 @@ On success, the HTTP status code in the response header is `200 OK` and the resp
```
#### associate(e911_id, number_id)
The method accepts an E911 record id and a phone number as parameters which you can learn more about in the [API reference](https://developer.flowroute.com/api/e911s/v2.0/assign-valid-e911-address-to-phone-number/). In the following example, we call the [list_account_phone_numbers](#list_account_phone_numbers) covered under Number Management and [list_e911s](#list_e911s), extract the values of the first items in the returned JSON arrays into variables `e911_id` and `did` then make the association between them.
The method accepts an E911 record id and a phone number as parameters which you can learn more about in the [API reference](https://developer.flowroute.com/api/numbers/v2.0/assign-valid-e911-address-to-phone-number/). In the following example, we call the [list_account_phone_numbers](#list_account_phone_numbers) covered under Number Management and [list_e911s](#list_e911s), extract the values of the first items in the returned JSON arrays into variables `e911_id` and `did` then make the association between them.
##### Example Request
```
@ -1130,11 +1147,14 @@ except Exception as e:
On success, the HTTP status code in the response header is `204 No Content` which means that the server successfully processed the request and is not returning any content.
`204: No Content`
```
--Associate an E911 Record and a DID
204: No Content
```
#### list_dids_for_e911(e911_id)
The method accepts an E911 record id as a parameter which you can learn more about in the [API reference](https://developer.flowroute.com/api/e911s/v2.0/list-phone-numbers-associated-with-e911-record/). In the following example, we retrieve the list of phone numbers associated with our previously assigned `e911_id`.
The method accepts an E911 record id as a parameter which you can learn more about in the [API reference](https://developer.flowroute.com/api/numbers/v2.0/list-phone-numbers-associated-with-e911-record/). In the following example, we retrieve the list of phone numbers associated with our previously assigned `e911_id`.
##### Example Request
```
@ -1168,7 +1188,7 @@ On success, the HTTP status code in the response header is `200 OK` and the resp
#### disconnect(number_id)
The method accepts a phone number as a parameter which you can learn more about in the [API reference](https://developer.flowroute.com/api/e911s/v2.0/deactivate-e911-service-for-phone-number/). In the following example, we deactivate the E911 service for our previously assigned `did`.
The method accepts a phone number as a parameter which you can learn more about in the [API reference](https://developer.flowroute.com/api/numbers/v2.0/deactivate-e911-service-for-phone-number/). In the following example, we deactivate the E911 service for our previously assigned `did`.
##### Example Request
```
@ -1190,7 +1210,7 @@ On success, the HTTP status code in the response header is `204 No Content` whic
```
#### delete_address(e911_id)
The method accepts an E911 record ID as a parameter which you can learn more about in the [API reference](https://developer.flowroute.com/api/e911s/v2.0/remove-e911-address-from-account/). Note that all phone number associations must be removed first before you are able to delete the specified `e911_id`. In the following example, we will attempt to delete the previously assigned `e911_id`.
The method accepts an E911 record ID as a parameter which you can learn more about in the [API reference](https://developer.flowroute.com/api/numbers/v2.0/remove-e911-address-from-account/). Note that all phone number associations must be removed first before you are able to delete the specified `e911_id`. In the following example, we will attempt to delete the previously assigned `e911_id`.
##### Example Request
```
@ -1215,13 +1235,9 @@ The Flowroute Python Library v3 allows you to make HTTP requests to the `cnams`
All of the CNAM record management methods are encapsulated in `cnam_demo.py`.
| API Reference Pages |
| ------------------- |
| The E911 and CNAM API reference pages are currently restricted to our beta customers, which means that all API reference links below currently return a `404 Not Found`. They will be publicly available during our E911 and CNAM APIs GA launch in a few weeks. |
#### list\_cnams()
The method accepts `limit`, `offset`, and `is_approved` as parameters which you can learn more about in the [API reference](https://developer.flowroute.com/api/cnams/v2.0/list-account-cnam-records/).
The method accepts `limit`, `offset`, and `is_approved` as parameters which you can learn more about in the [API reference](https://developer.flowroute.com/api/numbers/v2.0/list-account-cnam-records/).
##### Example Request
```python
@ -1300,7 +1316,7 @@ On success, the HTTP status code in the response header is `200 OK` and the resp
```
#### get_cnam(cnam_id)
The method accepts a CNAM record ID as a parameter which you can learn more about in the [API reference](https://developer.flowroute.com/api/cnams/v2.0/list-cnam-record-details/). In the following example, we query for approved CNAM records on your account and then extract the ID of the first record returned and retrieve the details of that specific CNAM record.
The method accepts a CNAM record ID as a parameter which you can learn more about in the [API reference](https://developer.flowroute.com/api/numbers/v2.0/list-cnam-record-details/). In the following example, we query for approved CNAM records on your account and then extract the ID of the first record returned and retrieve the details of that specific CNAM record.
##### Example Request
```
@ -1330,7 +1346,17 @@ On success, the HTTP status code in the response header is `200 OK` and the resp
```
#### create_cnam_record(cnam_value)
The method accepts a Caller ID value as a parameter which you can learn more about in the [API reference](https://developer.flowroute.com/api/cnams/v2.0/create-a-new-cnam-record/). In the following example, we reuse the `random_generator()` function to generate a four-character random string which we will concatenate with FR and assign as our CNAM value.
The method accepts a Caller ID value as a parameter which you can learn more about in the [API reference](https://developer.flowroute.com/api/numbers/v2.0/create-a-new-cnam-record/). In the following example, we reuse the `random_generator()` function to generate a four-character random string which we will concatenate with FR and assign as our CNAM value.
| CNAM Storage Rules |
| ------------------- |
| You can enter up to 15 characters for your CNAM value at least one of which is a letter. |
| While most CNAM presets can be approved, the following are not allowed and must be rejected: |
| - Consist of curse words and/or is inappropriate. |
| - A phone number (CNAM must be a name not a number) |
| - If the CNAM preset which the customer has submitted appears to be misleading such as: |
| - Political Figures or Places (Obama, Barack or The White House) |
| - False or fake CNAM (Seattle Police) |
##### Example Request
```
@ -1347,7 +1373,7 @@ print("\nNOTE: Newly created CNAM records need to be approved first before they
##### Example Response
On success, the HTTP status code in the response header is `201 Created` and the response body contains the newly created cnam object in JSON format.
On success, the HTTP status code in the response header is `201 Created` and the response body contains the newly created cnam object in JSON format. Note that CNAM records take up to 48 hours to be approved on your account and further association with a phone number takes 5-7 business days.
```
--Create a CNAM Record
@ -1365,7 +1391,7 @@ NOTE: Newly created CNAM records need to be approved first before they can be as
```
#### associate_cnam(cnam_id, number_id)
The method accepts a CNAM record ID and a phone number as parameters which you can learn more about in the [API reference](https://developer.flowroute.com/api/cnams/v2.0/assign-cnam-record-to-phone-number/). In the following example, we will call `list_account_phone_numbers()` and associate the first number in the returned array with our previously assigned `cnam_id`.
The method accepts a CNAM record ID and a phone number as parameters which you can learn more about in the [API reference](https://developer.flowroute.com/api/numbers/v2.0/assign-cnam-record-to-phone-number/). In the following example, we will call `list_account_phone_numbers()` and associate the first number in the returned array with our previously assigned `cnam_id`.
##### Example Request
```
@ -1391,7 +1417,7 @@ On success, the HTTP status code in the response header is `202 Accepted` and th
```
#### unassociate_cnam(number_id)
The method accepts a phone number as a parameter which you can learn more about in the [API reference](https://developer.flowroute.com/api/cnams/v2.0/unassign-a-cnam-record-from-phone-number/). In the following example, we will disassociate the same phone number that we've used in `associate_cnam()`.
The method accepts a phone number as a parameter which you can learn more about in the [API reference](https://developer.flowroute.com/api/numbers/v2.0/unassign-a-cnam-record-from-phone-number/). In the following example, we will disassociate the same phone number that we've used in `associate_cnam()`.
##### Example Request
```
@ -1411,7 +1437,7 @@ On success, the HTTP status code in the response header is `202 Accepted` and th
```
#### remove_cnam(cnam_id)
The method accepts a CNAM record ID as a parameter which you can learn more about in the [API reference](https://developer.flowroute.com/api/cnams/v2.0/remove-cnam-record-from-account/). In the following example, we will be deleting our previously extracted `cnam_id` from the "List Approved CNAM Records" function call.
The method accepts a CNAM record ID as a parameter which you can learn more about in the [API reference](https://developer.flowroute.com/api/numbers/v2.0/remove-cnam-record-from-account/). In the following example, we will be deleting our previously extracted `cnam_id` from the "List Approved CNAM Records" function call.
##### Example Request
```
@ -1428,6 +1454,239 @@ On success, the HTTP status code in the response header is `204 No Content` whic
''
```
### Call Detail Record Export API
The Flowroute Python Library v3 allows you to make HTTP requests to the `cdrs` resource of Flowroute API v2: `https://api.flowroute.com/v2/cdrs`.
All of the CDR export methods are encapsulated in `cdr_demo.py`.
#### list_cdr_exports
The method accepts `status`, `limit`, and `offset` as parameters which you can learn more about in the [API reference](https://developer.flowroute.com/api/cdrexports/v2.0/list-cdrs/).
##### Example Request
```python
print("--List Completed CDR Exports")
status = 'completed'
limit = 10
offset = None
result = cdrs_controller.list_cdr_exports(status, limit, offset)
pprint.pprint(result)
```
##### Example Response
On success, the HTTP status code in the response header is `200 OK` and the response body contains an array of CDR Export objects in JSON format.
```
{
"data": [
{
"data": {
"attributes": {
"billed_minutes": 0,
"callback_url": null,
"ccrf": "0.0",
"created_at": "2019-03-18T23:20:30+00:00",
"download_url": "https://s3.us-west-2.amazonaws.com/flowroute-cdrexports/40375/2019/3/18/e55f474c3154a14cd2cec842f79ca6a8000.gz?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential;=ASIA2DG5LFSOIDMMFUVW%2F20190318%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date;=20190318T232030Z&X-Amz-Expires;=259200&X-Amz-SignedHeaders;=host&X-Amz-Security-Token;=FQoGZXIvYXdzEJz%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaDBB4u7fdwDGKfgWUSyKZBF6fKcf16poJprJr9imLeVtLmQCcWKWnJjmmkRLz%2FQKjaMUvHTnTo4drHg8KWAbvvbpwoC3NOgFsn28nw1fHlgBjVODuIDeMJxFHROUZAPTbayDsUttyO%2BqbcluTENh3ESJoZGoXi3sGwHDvvtcYTtHr0MQMw7cvEEKgKvaMp7KgliTpwJzzquAPeMQg2LD5C%2FR36nI%2BZNXrqp64ZovMrtVV1IR9KLXTkRZs3%2Ft%2Bvt7CzhM8Fopc96cKhu%2FpX7eVR%2BBJfTeUD%2FPvz19KWuKWsM9V%2FEqNptPTADIg6LtupuainAJVhvBaatHOdGe7aUt2ABkvsCZVs5uFbdy79aHVMMtZgN886E1TsVR%2FDwbg1AhfsxLBujEumIn9bJAkr1RJpHakrC67gm%2FyTsU64huC%2BGCqQrd5CHIAQsbDCV8tMPw5K%2B3SonWV2TLusiOg%2FWZikSMqgDrexj7KQo7utXWGAAt2W4INKGSpwY1BoOWJGl6rBMJ1rWpERJ2lxagHeAPd8tOPiKVvkytscHH1vEgM4S1wOApspud5tMsvtkhyAWGwfsbkn1ZiF5PoqUbBjHXH9m%2Bq8p4oLUEI2aozdrLEqdQxELSlleQna0U1VsxyRa%2BXRjxDU7oOpmqETzUEx3NKELDGOb%2FwzO%2F8HH%2BqPcC8OVaox2KdLvAFwHGulKLwRrtSlblZopzZqrBmd0R5X60tZ4u2KIUH3lLeiSiGvb%2FkBQ%3D%3D&X-Amz-Signature;=beb0e34bbd48cac63ce1db887de6f783238acddcfd7675b3a525ae49003d2cb7",
"expires_at": "2019-03-21T23:20:30+00:00",
"filter_parameters": {
"number_aliases": [
"Home Phone"
],
"start_call_end_time": "2019-01-01T00:00:00+00:00",
"start_call_start_time": "2018-12-01T00:00:00+00:00"
},
"num_calls": 0,
"requested_at": "2019-03-18T23:20:17+00:00",
"status": "completed",
"total_cost": "0.0",
"call_subtotal": "0.0",
"connect_fees": "0.0",
"cnamlookup_fees": "0.0",
"usf_fees": "0.0"
},
"id": 203485,
"type": "cdrexport"
}
},
{
"data": {
"attributes": {
"billed_minutes": 0,
"callback_url": null,
"ccrf": "0.0",
"created_at": "2019-03-18T23:16:47+00:00",
"download_url": "https://s3.us-west-2.amazonaws.com/flowroute-cdrexports/40375/2019/3/18/8294b10fd18846d61ab1de8535f05b55000.gz?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential;=ASIA2DG5LFSOIDMMFUVW%2F20190318%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date;=20190318T231647Z&X-Amz-Expires;=259200&X-Amz-SignedHeaders;=host&X-Amz-Security-Token;=FQoGZXIvYXdzEJz%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaDBB4u7fdwDGKfgWUSyKZBF6fKcf16poJprJr9imLeVtLmQCcWKWnJjmmkRLz%2FQKjaMUvHTnTo4drHg8KWAbvvbpwoC3NOgFsn28nw1fHlgBjVODuIDeMJxFHROUZAPTbayDsUttyO%2BqbcluTENh3ESJoZGoXi3sGwHDvvtcYTtHr0MQMw7cvEEKgKvaMp7KgliTpwJzzquAPeMQg2LD5C%2FR36nI%2BZNXrqp64ZovMrtVV1IR9KLXTkRZs3%2Ft%2Bvt7CzhM8Fopc96cKhu%2FpX7eVR%2BBJfTeUD%2FPvz19KWuKWsM9V%2FEqNptPTADIg6LtupuainAJVhvBaatHOdGe7aUt2ABkvsCZVs5uFbdy79aHVMMtZgN886E1TsVR%2FDwbg1AhfsxLBujEumIn9bJAkr1RJpHakrC67gm%2FyTsU64huC%2BGCqQrd5CHIAQsbDCV8tMPw5K%2B3SonWV2TLusiOg%2FWZikSMqgDrexj7KQo7utXWGAAt2W4INKGSpwY1BoOWJGl6rBMJ1rWpERJ2lxagHeAPd8tOPiKVvkytscHH1vEgM4S1wOApspud5tMsvtkhyAWGwfsbkn1ZiF5PoqUbBjHXH9m%2Bq8p4oLUEI2aozdrLEqdQxELSlleQna0U1VsxyRa%2BXRjxDU7oOpmqETzUEx3NKELDGOb%2FwzO%2F8HH%2BqPcC8OVaox2KdLvAFwHGulKLwRrtSlblZopzZqrBmd0R5X60tZ4u2KIUH3lLeiSiGvb%2FkBQ%3D%3D&X-Amz-Signature;=8b4dab6a349ecc98905d949d026889035101ee8acb34055efb87ca2c299e4ba4",
"expires_at": "2019-03-21T23:16:47+00:00",
"filter_parameters": {
"number_aliases": [
"Home Phone"
],
"start_call_end_time": "2018-10-01T00:00:00+00:00",
"start_call_start_time": "2018-10-01T00:00:00+00:00"
},
"num_calls": 0,
"requested_at": "2019-03-18T23:16:46+00:00",
"status": "completed",
"total_cost": "0.0",
"call_subtotal": "0.0",
"connect_fees": "0.0",
"cnamlookup_fees": "0.0",
"usf_fees": "0.0"
},
"id": 203484,
"type": "cdrexport"
}
}
],
"links": {
"next": "http://cdr-api/cdrs/exports?offset=2&limit;=2",
"self": "http://cdr-api/cdrs/exports?offset=0&limit;=2"
}
}
```
#### create_cdr_export
The method accepts a many query parameters, such as `start_call_start_time`, `start_call_end_time`, and `number_aliases`. Learn more about the different CDR export filter parameters in the [API reference](https://developer.flowroute.com/api/cdrexports/v2.0/query-cdrs/).
##### Example Request
```
print("\n--Create a CDR Export where the call started between a certain time from a list of number alises")
try:
filters = {
"start_call_start_time": "2019-01-01 00:00:00",
"start_call_end_time": "2019-02-01 00:00:00",
"number_aliases": ["Office 221", "Office 888"]
}
callback_url = "https://myserver.com/cdrs"
result = cdrs_controller.create_cdr(filters, callback_url)
pprint.pprint(result)
except Exception as e:
print(str(e))
print(e.context.response.raw_body)
```
##### Example Response
On success, the HTTP status code in the response header is `201 Created` and the response body contains the newly created CDR export object in JSON format. On error, a printable representation of the detailed API response is displayed.
```
{
"data": {
"type": "cdrexport",
"id": "38647",
"links": {
"self": "https://api.flowroute.com/v2/cdrs/exports/38647"
},
"attributes": {
"number_aliases": [
"Office 221",
"Office 888"
],
"start_call_start_time": "2019-01-01 00:00:00",
"start_call_end_time": "2019-02-01 00:00:00",
"callback_url": "https://myserver.com/cdrs",
"status": "processing",
"download_url": None,
"requested_at": "2019-03-18T16:43:00+00:00",
"created_at": "2019-03-18T16:43:01+03:00",
"expires_at": None,
"total_cost": None,
"call_subtotal": None,
"connect_fees": None,
"cnamlookup_fees": None,
"usf_fees": None,
"ccrf": None,
"billed_minutes": None,
"filter_parameters": {
"number_aliases": [
"Office 221",
"Office 888"
],
}
}
}
}
```
#### get_cdr_export_status(cdrexport_id)
The method accepts a CDR Export ID as a parameter which you can learn more about in the [API reference](https://developer.flowroute.com/api/cdrexports/v2.0/cdr-status/). In the following example, we will be retrieving the Detail Status of the CDR Export we created in the previous query.
##### Example Request
```
print("\n--Get CDR Export Detail Status")
result = cdrs_controller.get_cdr_export_status(cdrexport_id)
pprint.pprint(result)
```
##### Example Response
On success, the HTTP status code in the response header is `200 OK` and the response body contains a CDR export JSON object.
```
{'data':
'type': 'cdrexport',
'id': '38647',
'attributes': {
'callback_url': 'http://myserver.com/webhook',
'status': 'completed',
'download_url': ('https://s3.us-east-2.amazonaws.com/uiuc-presigned-url-example/secret.'
'txt?X-Amz-Date=20170720T182534Z&X-Amz-SignedHeaders;=host&X-Amz-Creden;'
'tial=ASIAIYLQNVRRFNZOCFBA%2F20170720%2Fus-east-2%2Fs3%2Faws4_request&'
'X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires;=604800&X-Amz-Security-;'
'Token=FQoDYXdzEJP%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaDOLWx95j90zPxGh7WSL'
'dAVnoYoKC4gjrrR1xbokFWRRwutmuAmOxaIVcQqOy%2Fqxy%2FXQt3Iz%2FohuEEmI7%2'
'FHPzShy%2BfgQtvfUeDaojrAx5q8fG9P1KuIfcedfkiU%2BCxpM2foyCGlXzoZuNlcF8o'
'hm%2BaM3wh4%2BxQ%2FpShLl18cKiKEiw0QF1UQGj%2FsiEqzoM81vOSUVWL9SpTTkVq8'
'EQHY1chYKBkBWt7eIQcxjTI2dQeYOohlrbnZ5Y1%2F1cxPgrbk6PkNFO3whAoliSjyRC8'
'e4TSjIY2j3V6d9fUy4%2Fp6nLZIf9wuERL7xW9PjE6eZbKOHnw8sF&X-Amz-Signature;'
'=a14b3065ab822105e8d7892eb5dcc455ddd603c61e47520774a7289178af9ecc'),
'requested_at': '2018-09-11T23:21:20+00:00'
'created_at': '2018-09-11T23:23:23+00:00'
'expires_at': '2018-09-14T23:23:29+00:00',
'total_cost': '34.321300',
'usf_fees': '5.93190',
'ccrf': '0.0',
'num_calls': 301,
'billed_minutes': 10,
'filter_parameters': {
"start_call_start_time": "2019-01-01 00:00:00",
"start_call_end_time": "2019-02-01 00:00:00",
"number_aliases": "['Office 221', 'Office 888']"
}
},
'links': {
'self': 'http://cdr-api/cdrs/exports/38647'
}
}
```
#### #download_cdr_export(cdrexport_id)
The method accepts a CDR Export ID as a parameter which you can learn more about in the [API reference](https://developer.flowroute.com/api/cdrexports/v2.0/cdr-status/). In the following example, we will be retrieving the file of the CDR Export we created in the previous query.
You can learn more about the format of the CDR Export Data in the [API results reference](https://developer.flowroute.com/api/cdrexports/v2.0/cdr-results/).
##### Example Request
```
print("\n--Get CDR Export Data")
result = cdrs_controller.download_cdr_export(cdrexport_id, filename)
pprint.pprint(result)
```
##### Example Response
On success, the HTTP status code in the response header is `200 OK` and a file is written to the local computer using the provided filename.
```
direction,start_time,end_time,destination,number_alias,callerid,total_cost,destination_name,callerid_country,line_information,result,call_fail_sip_code,call_fail_reason,duration,billed_duration,rate,first_increment,subsequent_increment,cost_subtotal,connect_fee,usf_fee,ccrf,cnam_lookup_fee,custom_x_tag,customer_ip
Outbound,2019-06-25 18:18:54+00,2019-06-25 18:19:31+00,18774551500,Office Line 2,+12063389999,0.00000000,UNITED STATES - TOLL FREE,N/A,,completed,200,OK,37,42,0.000000,6,6,0.00000000,0.0000,0.00000000,0.00000000,0.00000000,,53.186.152.52:5080
Inbound,2019-06-25 18:18:00+00,2019-06-25 18:18:29+00,12063389999,Office Line 2,+12069928999,0.00474784,UNITED STATES,UNITED STATES,61,completed,200,OK,29,30,0.001500,6,6,0.00075000,0.0000,0.00000000,0.00009784,0.00390000,,53.186.152.52
Outbound,2019-06-25 18:15:38+00,2019-06-25 18:17:24+00,12069928999,Office Line 1,+12063389998,0.01994112,UNITED STATES,N/A,,completed,200,OK,106,108,0.009800,6,6,0.01764000,0.0000,0.00000000,0.00230112,0.00000000,,53.186.151.52:5080
```
#### Errors
In cases of method errors, the Python library raises an exception which includes an error message and the HTTP body that was received in the request.
@ -1437,6 +1696,8 @@ In cases of method errors, the Python library raises an exception which includes
## Testing
Once you are done configuring your Flowroute API credentials and updating the function parameters, you can run any of the demo files to see them in action. The Flowroute library demo files are named after the resource they represent: <resource_name>_demo.py.
Once you are done configuring your Flowroute API credentials and updating the function parameters, you can run any of the demo files to see them in action. The Flowroute library demo files are named after the resource they represent: `<resource_name>_demo.py`.
` python cnam_demo.py `
` python e911_demo.py `
` python cdrs_demo.py `

@ -0,0 +1,64 @@
#!/usr/bin/env python
import pprint
import os
import random
import string
from flowroutenumbersandmessaging.flowroutenumbersandmessaging_client \
import FlowroutenumbersandmessagingClient
# Helper function for random strings
def random_generator(size=4, chars=string.ascii_uppercase + string.digits):
return ''.join(random.choice(chars) for x in range(size))
# Set up your api credentials and test mobile number for outbound SMS or MMS
basic_auth_user_name = os.environ.get('FR_ACCESS_KEY')
basic_auth_password = os.environ.get('FR_SECRET_KEY')
# Instantiate API client and create controllers for Numbers and E911s
client = FlowroutenumbersandmessagingClient(basic_auth_user_name,
basic_auth_password)
numbers_controller = client.numbers
cdrs_controller = client.cdrs
cdr_id = None
print("\n--Create a CDR Export Record")
filters = {
"start_call_start_time": "2019-01-01 00:00:00",
"start_call_end_time": "2019-02-01 00:00:00",
"number_aliases": ["Office 221", "Office 888"]
}
callback_url = "https://myserver.com/cdrs"
result = cdrs_controller.create_cdr_export(filters, callback_url)
pprint.pprint(result)
print("--List CDR Records")
limit = 10
offset = None
result = cdrs_controller.list_cdrs(limit, offset)
pprint.pprint(result)
print("\n--List Completed CDR Exports")
result = cdrs_controller.list_cdrs(limit, offset, "completed")
pprint.pprint(result)
if len(result['data']):
cdr_id = result['data'][0]['data']['id']
print("\n--List CDR Export Detail {}".format(cdr_id))
result = cdrs_controller.get_cdr_export_status(cdr_id)
pprint.pprint(result)
filename = "temp_cdr_file.csv"
print("\n--Download CDR Export Data {} to {}".format(cdr_id, filename))
result = cdrs_controller.download_cdr_export(cdr_id, filename)
print("\n--Downloaded CDR Export data to {}".format(result['filename']))
# https://developer.flowroute.com/api/cdrexports/v2.0/cdr-results/
fileinfo = cdrs_controller.parse_cdr_export(filename)
for row in fileinfo:
print("{} called {} for {} starting at {}".format(
row['callerid'], row['destination'], row['total_cost'], row['start_time'])
)

@ -1,6 +1,7 @@
__all__ = [
__all__ = [
'base_controller',
'cdrs_controller',
'numbers_controller',
'routes_controller',
'messages_controller',
'messages_controller',
]

@ -0,0 +1,226 @@
# -*- coding: utf-8 -*-
"""
flowroutenumbersandmessaging.controllers.cdrs_controller
"""
from csv import DictReader
import gzip
import json
#import StringIO
from io import StringIO
#import urllib2
from urllib.request import urlopen
from .base_controller import BaseController
from ..api_helper import APIHelper
from ..configuration import Configuration
from .numbers_controller import NumbersController
from ..exceptions.api_exception import APIException
class CDRsController(BaseController):
"""A Controller to access Endpoints in the CDR API."""
def list_cdrs(self,
limit=None,
offset=None,
status=None):
"""Does a GET request to /v2/cdrs/exports.
Returns a list of all CDR Exports created by the user.
Args:
limit (int, optional): Limits the number of items to retrieve. A
maximum of 200 items can be retrieved.
offset (int, optional): Offsets the list of CDR exports by your
specified value. For example, if you have 4 CDR exports and
you entered 1 as your offset value, then only 3 of your
CDR exports will be displayed in the response.
status: Display only requests whose status matches the specified
value. Possible values are processing, completed or failed
Returns:
mixed: Response from the API. A JSON object of CDR Export Records
that satisfy your search criteria.
Raises:
APIException: When an error occurs while fetching the data from
the remote API. This exception includes the HTTP Response
code, an error message, and the HTTP body that was received in
the request.
"""
# Prepare query URL
_query_builder = Configuration.base_uri
_query_builder += '/v2/cdrs/exports'
_query_parameters = {
'limit': limit,
'offset': offset
}
if status is not None:
_query_parameters['status'] = status
_query_builder = APIHelper.append_url_with_query_parameters(
_query_builder,
_query_parameters,
Configuration.array_serialization)
_query_url = APIHelper.clean_url(_query_builder)
# Prepare and execute request
_request = self.http_client.get(_query_url)
return self.handle_request_and_response(_request)
def get_cdr_export_status(self, cdrexport_id):
"""Does a GET request to /v2/cdrs/exports/<cdrexport_id>.
Returns a record detail for the CDR Export Record Id specified
Args:
cdrexport_id (int, required): The ID of the CDR Export to retrieve
Returns:
mixed: Response from the API. A JSON object of of an CDR Export record
that satisfy your search criteria.
Raises:
APIException: When an error occurs while fetching the data from
the remote API. This exception includes the HTTP Response
code, an error message, and the HTTP body that was received in
the request.
"""
# Prepare query URL
_query_builder = Configuration.base_uri
_query_builder += '/v2/cdrs/exports/{}'.format(cdrexport_id)
_query_url = APIHelper.clean_url(_query_builder)
# Prepare and execute request
_request = self.http_client.get(_query_url)
return self.handle_request_and_response(_request)
def create_cdr_export(self, filters, callback_url=None):
"""Does a POST request to /v2/cdrs/export.
Searches for CDR Records that match the criteria
Args:
filters (dictionary, required): The dictionary of filter parameters
https://developer.flowroute.com/api/cdrexports/v2.0/query-cdrs/
callback_url (string, optional): A string to use as a URI for sending
callback events
Returns:
mixed: Response from the API. A JSON object of of a CNAM record
with the new data
Raises:
APIException: When an error occurs while fetching the data from
the remote API. This exception includes the HTTP Response
code, an error message, and the HTTP body that was received in
the request.
"""
body = {
"data": {
"type": "cdrexport",
"attributes": {
"filter_parameters": filters
}
}
}
if callback_url is not None:
body['data']['attributes']['callback_url'] = callback_url
json_body = json.dumps(body)
# Prepare query URL
_query_builder = Configuration.base_uri
_query_builder += '/v2/cdrs/exports'
_query_url = APIHelper.clean_url(_query_builder)
# Prepare headers
_headers = {
'Accept': 'application/vnd.api+json',
'Content-Type': 'application/vnd.api+json'
}
# Prepare and execute request
_request = self.http_client.post(_query_url, headers=_headers,
parameters=json_body)
return self.handle_request_and_response(_request)
def download_cdr_export(self, cdrexport_id, filename):
"""Does a GET request to /v2/cdrs/exports/<cdrexport_id>.
Returns the filename that was written
Args:
cdrexport_id (int, required): The ID of the CDR Export to retrieve
filename (string, required): The filename to write the CDR Export data
Returns:
mixed: Response from the API and filename
Raises:
APIException: When an error occurs while fetching the data from
the remote API. This exception includes the HTTP Response
code, an error message, and the HTTP body that was received in
the request.
"""
# Prepare query URL
_query_builder = Configuration.base_uri
_query_builder += '/v2/cdrs/exports/{}'.format(cdrexport_id)
_query_url = APIHelper.clean_url(_query_builder)
# Prepare and execute request
_request = self.http_client.get(_query_url)
_response = self.handle_request_and_response(_request)
if (_response.get('data') and _response['data'].get('attributes') and _response['data']['attributes'].get('download_url')):
print("fetching {}".format(_response['data']['attributes']['download_url']))
export_url = _response['data']['attributes']['download_url']
#urllib.urlretrieve(export_url, filename)
try:
response = urlopen(export_url)
compressedFile = StringIO.StringIO(response.read())
decompressedFile = gzip.GzipFile(fileobj=compressedFile)
with open(filename, 'w') as outfile:
outfile.write(decompressedFile.read())
return {'filename': filename}
except Exception as e:
raise APIException("Error fetching CDR Export data {}".format(e),
_response.context)
def parse_cdr_export(self, filename):
"""Parses a CDR export file and returns a dictionary
Args:
filename (string, required): The filename to write the CDR Export data
Returns:
mixed: dictionary of file contents
Raises:
Exception: When an error occurs parsing data
"""
try:
with open(filename, 'r') as infile:
fileinfo = DictReader(infile)
return list(fileinfo)
except Exception as e:
raise Exception("Error parsing CDR Export data {}".format(e))

@ -13,7 +13,7 @@ from .controllers.messages_controller import MessagesController
from .controllers.e911s_controller import E911sController
from .controllers.cnams_controller import CNAMsController
from .controllers.porting_controller import PortingController
from .controllers.cdrs_controller import CDRsController
class FlowroutenumbersandmessagingClient(object):
@ -43,6 +43,10 @@ class FlowroutenumbersandmessagingClient(object):
def porting(self):
return PortingController()
@lazy_property
def cdrs(self):
return CDRsController()
def __init__(self,
basic_auth_user_name = None,
basic_auth_password = None):

@ -1,4 +1,4 @@
requests==2.9.1
jsonpickle==0.7.1
requests>=2.21.0
jsonpickle>=0.9.6
cachecontrol==0.11.7
python-dateutil==2.5.3
python-dateutil==2.5.3

Loading…
Cancel
Save