{ "info": { "author": "Dan Black", "author_email": "dyspop@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 3 - Alpha", "Environment :: Console", "Environment :: MacOS X", "Framework :: Flake8", "Framework :: Pytest", "Intended Audience :: Developers", "Intended Audience :: End Users/Desktop", "Intended Audience :: Information Technology", "License :: OSI Approved :: MIT License", "Natural Language :: English", "Programming Language :: Python :: 3.7", "Topic :: Communications :: Email", "Topic :: Software Development :: Libraries :: Python Modules" ], "description": "# Responsys Interact REST API python client #\n\nA python library providing access to the Responsys Interact API. Currently supports version 1.3 Release 6.33 E65150-15.\n\nAs this is Alpha software many features remain to be implemented. Here's a list of every feature based on its Responsys documentation name (not the internal function names) and its implementation status:\n\n| Feature | Implementation | Notes |\n|---|---|---|\n| Login with username and certificates | Missing | |\n| Retrieving all profile lists for an account | Complete | |\n| Merge or update members in a profile list table | Partial | While you can override merge rules, they are applied globally to the merge, not set per record. |\n| Get all EMD email campaigns | Complete | |\n| Get all Push campaigns | Complete | |\n| Retrieve a member of a profile list using RIID | Complete | |\n| Retrieve a member of a profile list based on query attribute | Complete | |\n| Retrieve all profile extensions of a profile list | Complete | |\n| Retrieve a member of a profile extension table based on RIID | Complete | |\n| Retrieve a member of a profile extension table based on a query attribute | Complete | |\n| Trigger email message | Complete | |\n| Delete Profile List Recipients based on RIID | Complete | |\n| Create a new supplemental table | Complete | |\n| List the contents of a folder | Complete | |\n| Create a new folder in /contentlibrary/ | Complete | |\n| Create a document in /contentlibrary/ | Complete | |\n| Get a document from /contentlibrary/ | Complete | |\n| Update a document that's already in /contentlibrary/ | Complete | |\n| Delete a document in /contentlibrary/ | Complete | Could be improved |\n| Delete a folder in /contentlibrary/ | Complete | Could be improved |\n| Create a profile extension table | Missing | |\n| Update a profile extension table | Missing | |\n| Update a supplemental table | Missing | |\n| Get a record from a supplemental table | Missing | |\n| Delete a record from a supplemental table | Missing | |\n| Update a list and then send an email message | Missing | |\n| Update a list and send an email message | Missing | |\n| Update a list and send an sms | Missing | |\n| Send a push message | Missing | |\n| Trigger a custom event | Missing | |\n| Schedule a campaign | Missing | |\n| Get the schedule IDs for a campaign | Missing | |\n| Get the schedule for a campaign | Missing | |\n| Update a campaign schedule | Missing | |\n| Unschedule a campaign | Missing | |\n| Create a media file | Missing | |\n| Get a media file | Missing | |\n| Update a media file | Missing | |\n| Delete a media file | Missing | |\n| Copy a media file | Missing | |\n| Set the image data for media that are referenced in a document | Missing | |\n| Get the image data for media that are referenced in a document | Missing | |\n\n\n## Requirements\n\n1. A Responsys Interact account (see How-to).\n2. A valid Responsys Interact API user name and password.\n3. Python (see How-to)\n4. pip (see How-to)\n\n### How-to\n\nSign up for Responsys Interact at https://www.oracle.com/marketingcloud/products/cross-channel-orchestration/index.html (not free).\n\nInstall Python3 and Python Package Index. \n * OS X: It is recommended to install Python3 this way: http://docs.python-guide.org/en/latest/starting/install3/osx/ which should alias your Python3 to separate command `python3`.\n\nThis package is developed for Python3.x but should work on 2.7 if you're so inclined.\n\n## Install ##\n\n### Standard install for using in your application\n\n pip install responsysrest\n\n### Development install via repository clone\n\nIf you want to help developing this package:\n\n1. Clone this repo:\n git clone git@github.com:dyspop/responsysrest.git\n2. Create Virtual Environment\n cd responsysrest && python -m venv venv && source venv/bin/activate\n2. Install via source package in development mode:\n```\n pip install -e .\n```\n\n## Usage ##\n\n1. Import the responsysrest package\n2. Configure your Interact connection settings and credentials\n3. Instantiate the client\n4. Use the client\n\nThe quickest way to get started is to create a `config.json` file and a `secret.json` file with your configuration and credentials information in them. The package comes with the `config.json` file but you'll need to create your own `secret.json` file. You can call the auto function from the package sub modules `configuration` and `credentials` which will traverse the root looking for the json files.\n\nconfig.json boilerplate:\n\n {\n \"pod\": \"5\",\n \"api_version\": \"1.3\",\n \"api_folder\": \"___api-generated\",\n \"api_list\": \"___api-list\",\n \"profile_extension_table_alias\": \"_pet\",\n \"supplemental_table_alias\": \"_supp\",\n \"primary_key_alias\": \"_primary_key\",\n \"riid_generator_length\": 11,\n \"caste_nonstr_to_str\": false,\n \"local_content_library_folder\": \"\",\n \"remote_content_library_folder\": \"___api-generated-cl\",\n \"test_campaign_name\": \"test_api_classic\",\n \"test_local_content_library_folder\": \"responsysrest/tests/documents/\",\n \"test_remote_content_library_folder\": \"___api-generated-test\"\n }\n\nsecret.json boilerplate:\n\n {\n \"user_name\": \"team_member\",\n \"password\": \"1!Aa\",\n \"email_address\": \"team_member@company.com\"\n }\n\nthen if they're local to where you're running python from:\n\n import responsysrest as r\n client = r.Client(r.configuration.auto(), r.credentials.auto())\n\nIf not then the package can import them from json files:\n\n config = r.configuration.from_json('path/to/config.json')\n creds = r.credentials.from_json('path/to/secret.json')\n\nThen instantiate the client:\n\n client = r.Client(config, creds)\n\n| Property | Value | What it is |\n|---|---|---|\n| pod | string, `2` or `5` | Oracle subdomain server group, found in the endpoint URL |\n| api_folder | string | The default location within your instance you want to store non-content assets |\n| api_list | string | The default list within your instance to populate to |\n| profile_extension_table_alias | string | What to append to PET names by default |\n| supplemental_table_alias | string | What to append to Supplemental Table names by default |\n| primary_key_alias | string | What to append to primary key fields by default |\n| riid_generator_length | integer | How long the builtin RIIDs should be, mostly used for tests |\n| caste_nonstr_to_str | bool | True if you want the wrapper to convert data to strings |\n| local_content_library_folder | string | Location of content library local to code execution |\n| remote_content_library_folder | string | Location of the content library on your instance. It's not wise to use the Content Library root |\n| test_campaign_name | string | Name of the campaign that tests will fire to. You'll have to set this up manually for now |\n| test_local_content_library_folder | string | Where the test suite documents are. Doubtful you'll want to change it. |\n| test_remote_content_library_folder | string | Where the test suite points to remotely. It should be created and deleted when integrations tests are run, so don't plan on using this location in production. |\n\n\n## Client functions usage:\n\nGenerally the library wants lists of records per function call where appropriate. To apply a method to a series of records do this:\n\n imported_csv_data = [\n ['EMAIL_ADDRESS_', 'COUNTRY_'],\n ['hey@test.com', 'US']\n ]\n fields = imported_csv_data[0]\n records = imported_csv_data[1:]\n client.some_method(fields, records)\n\nDon't do this:\n\n for record in records:\n client.some_method(fields, [record])\n\n\n### Managing Profile List Tables\n\n\n#### Retrieving all profile lists for an account\n\n client.get_profile_lists()\n\nReturns a list of dictionaries of all profile lists:\n\n [\n {\n 'fields': [\n {'fieldName': 'RIID_', 'fieldType': 'INTEGER'},\n {'fieldName': 'CREATED_SOURCE_IP_', 'fieldType': 'STR255'},\n {'fieldName': 'CUSTOMER_ID_', 'fieldType': 'STR255'},\n {'fieldName': 'EMAIL_ADDRESS_', 'fieldType': 'STR500'},\n {'fieldName': 'EMAIL_DOMAIN_', 'fieldType': 'STR255'},\n {'fieldName': 'EMAIL_ISP_', 'fieldType': 'STR255'},\n {'fieldName': 'EMAIL_FORMAT_', 'fieldType': 'CHAR'},\n {'fieldName': 'EMAIL_PERMISSION_STATUS_', 'fieldType': 'CHAR'},\n {'fieldName': 'EMAIL_DELIVERABILITY_STATUS_', 'fieldType': 'CHAR'},\n {'fieldName': 'EMAIL_PERMISSION_REASON_', 'fieldType': 'STR255'},\n {'fieldName': 'MOBILE_NUMBER_', 'fieldType': 'STR25'},\n {'fieldName': 'MOBILE_COUNTRY_', 'fieldType': 'STR25'},\n {'fieldName': 'MOBILE_PERMISSION_STATUS_', 'fieldType': 'CHAR'},\n {'fieldName': 'MOBILE_DELIVERABILITY_STATUS_', 'fieldType': 'CHAR'},\n {'fieldName': 'MOBILE_PERMISSION_REASON_', 'fieldType': 'STR255'},\n {'fieldName': 'POSTAL_STREET_1_', 'fieldType': 'STR255'},\n {'fieldName': 'POSTAL_STREET_2_', 'fieldType': 'STR255'},\n {'fieldName': 'CITY_', 'fieldType': 'STR50'},\n {'fieldName': 'STATE_', 'fieldType': 'STR50'},\n {'fieldName': 'POSTAL_CODE_', 'fieldType': 'STR25'},\n {'fieldName': 'COUNTRY_', 'fieldType': 'STR50'},\n {'fieldName': 'POSTAL_PERMISSION_STATUS_', 'fieldType': 'CHAR'},\n {'fieldName': 'POSTAL_DELIVERABILITY_STATUS_', 'fieldType': 'CHAR'},\n {'fieldName': 'POSTAL_PERMISSION_REASON_', 'fieldType': 'STR255'},\n {'fieldName': 'CREATED_DATE_', 'fieldType': 'TIMESTAMP'},\n {'fieldName': 'MODIFIED_DATE_', 'fieldType': 'TIMESTAMP'},\n {'fieldName': 'MY_CUSTOM_FIELD', 'fieldType': 'STR500'}\n ],\n 'folderName': 'UIfolderNotContentLibraryFolder',\n 'name': 'LIST_NAME'\n },\n {\n 'fields': [\n {'fieldName': 'RIID_', 'fieldType': 'INTEGER'},\n {'fieldName': 'CREATED_SOURCE_IP_', 'fieldType': 'STR255'},\n {'fieldName': 'CUSTOMER_ID_', 'fieldType': 'STR255'},\n {'fieldName': 'EMAIL_ADDRESS_', 'fieldType': 'STR500'},\n {'fieldName': 'EMAIL_DOMAIN_', 'fieldType': 'STR255'},\n {'fieldName': 'EMAIL_ISP_', 'fieldType': 'STR255'},\n {'fieldName': 'EMAIL_FORMAT_', 'fieldType': 'CHAR'},\n {'fieldName': 'EMAIL_PERMISSION_STATUS_', 'fieldType': 'CHAR'},\n {'fieldName': 'EMAIL_DELIVERABILITY_STATUS_', 'fieldType': 'CHAR'},\n {'fieldName': 'EMAIL_PERMISSION_REASON_', 'fieldType': 'STR255'},\n {'fieldName': 'MOBILE_NUMBER_', 'fieldType': 'STR25'},\n {'fieldName': 'MOBILE_COUNTRY_', 'fieldType': 'STR25'},\n {'fieldName': 'MOBILE_PERMISSION_STATUS_', 'fieldType': 'CHAR'},\n {'fieldName': 'MOBILE_DELIVERABILITY_STATUS_', 'fieldType': 'CHAR'},\n {'fieldName': 'MOBILE_PERMISSION_REASON_', 'fieldType': 'STR255'},\n {'fieldName': 'POSTAL_STREET_1_', 'fieldType': 'STR255'},\n {'fieldName': 'POSTAL_STREET_2_', 'fieldType': 'STR255'},\n {'fieldName': 'CITY_', 'fieldType': 'STR50'},\n {'fieldName': 'STATE_', 'fieldType': 'STR50'},\n {'fieldName': 'POSTAL_CODE_', 'fieldType': 'STR25'},\n {'fieldName': 'COUNTRY_', 'fieldType': 'STR50'},\n {'fieldName': 'POSTAL_PERMISSION_STATUS_', 'fieldType': 'CHAR'},\n {'fieldName': 'POSTAL_DELIVERABILITY_STATUS_', 'fieldType': 'CHAR'},\n {'fieldName': 'POSTAL_PERMISSION_REASON_', 'fieldType': 'STR255'},\n {'fieldName': 'CREATED_DATE_', 'fieldType': 'TIMESTAMP'},\n {'fieldName': 'MODIFIED_DATE_', 'fieldType': 'TIMESTAMP'},\n {'fieldName': 'MY_CUSTOM_FIELD', 'fieldType': 'STR500'}\n ],\n 'folderName': 'UIfolderNotContentLibraryFolder',\n 'name': 'LIST_NAME_2'\n }\n ]\n\nThis comes bundled with the folder location and all of the field names too, so to retrieve just a list of the lists:\n\n profile_lists = client.get_profile_lists()\n [list[\"name\"] for list in profile_lists] \n\nreturns: \n\n ['LIST_NAME', 'LIST_NAME_2']\n\nor a list of the lists with their respective folders:\n\n [(list[\"name\"], list[\"folderName\"]) for list in profile_lists]\n\nreturns:\n\n [('LIST_NAME', 'UIfolderNotContentLibraryFolder'), ('LIST_NAME_2', 'UIfolderNotContentLibraryFolder')]\n\n\n#### Update profile list\n\nThis is the \"Merge or update members in a profile list table\" feature. \n\n list_name = 'myTestList'\n fields = ['EMAIL_ADDRESS_', 'FIRST_NAME']\n records = ['bob@somesite.com', 'bob']\n client.update_profile_list(list_name, fields, records)\n\nIt requires three positional arguments: `list_name`, `fields`, and `records`. The library doesn't do any checking on the input. If the client can connect to Responsys you'll get a somewhat helpful error from the API:\n\n```\nclient.update_profile_list(\n 'fakelist', ['notafield'], ['notarecord'])\n```\n```\n{\n 'type': '', \n 'title': 'List not found', \n 'errorCode': 'LIST_NOT_FOUND', \n 'detail': 'fakelist List Not Found', \n 'errorDetails': []\n}\n```\n\nResponsys wants a lot of contextual information to merge records into an existing list, so this library has chosen defaults for you. \n\nThese can be changed with keyword arguments. Here are all the keyword arguments with all of the default values passed in redundantly. You don't need to set any of these unless you're changing them from the default values below:\n\n client.update_profile_list(\n list_name,\n fields,\n records)\n html_value='H',\n optin_value='I',\n text_value='T',\n insert_on_no_match=True,\n insert_on_match='REPLACE_ALL',\n match_column_name1='RIID_',\n match_column_name2=None,\n match_operator='NONE',\n opt_out_value='O',\n reject_records_if_channel_empty=None,\n default_permission_status='OPTIN')\n\nNote that whatever records you send in must contain a field in the fields list equal to the `match_column_name1` value (`RIID_` by default). For that reason a common profile list update might look like:\n\n client.update_profile_list(\n list_name,\n fields,\n records,\n match_column_name1='EMAIL_ADDRESS_')\n\nor\n\n client.update_profile_list(\n list_name,\n fields,\n records,\n match_column_name1='CUSTOMER_ID_')\n\nFor single records you can just pass in a string:\n\n client.update_profile_list(\n 'test@test.com', 'FIRST_NAME', 'Mister Mime', match_column_name1='EMAIL_ADDRESS_')\n\n\n#### Retrieve a member of a profile list using RIID\n\n client.get_member_of_list_by_riid(list_name, riid)\n\nReturns a full record if it's in the list.\n\n\n#### Retrieve a member of a profile list based on query attribute\n\n client.get_member_of_list_by_attribute(\n list_name, record_id, query_attribute, fields)\n\nReturns the record data for the record provided. Requires `list_name`, `record_id`. The list name is that which you want to find the record from within your Responsys Interact instance. The record id is the specific id you wish to use to identify the record. The query attribute is the type of id that you are using to retreive the record. If you don't specify it's assumed to be Customer ID. The available options are:\n\n| Option | Meaning |\n|---|---|\n| r | RIID |\n| e | Email Address |\n| c | Customer ID |\n| m | Mobile Number |\n\nThe fields to return should be a python list data object, if left blank it will return all the fields:\n\n fields = ['EMAIL_DOMAIN_, FIRST_NAME']\n query_attribute = 'e'\n record_id = 'test@test.com'\n client.get_member_of_list_by_attribute(\n list_name, record_id, query_attribute, fields)\n\n\n\n#### Delete Profile List Recipients based on RIID\n\n client.delete_from_profile_list(list_name, riid)\n\nDeletes a record from a profile list. Examples:\n\n client.delete_from_profile_list('CONTACTS_LIST', 'a@b.c')\n\n\n\n### Managing Profile Extension Tables\n\n\n#### Retrieve all profile extentions of a profile list\n\n client.get_profile_extensions_for_list(list_name)\n\nReturns the profile extension tables (also known as profile extensions, profile extenion lists, or PETs) associated with a given list. This comes bundled with the folder location and all of the field names too, so to retrieve just a list of the lists, or a list of the lists with their respective folders use:\n\n pets = client.get_profile_extensions_for_list(list_name)\n [list['profileExtension']['objectName'] for list in pets]\n [(list['profileExtension']['objectName'],\n list['profileExtension']['folderName']) for list in pets]\n\n\n#### Create a new profile extension table\n\nCreates a new profile extension table. Requires only the list name you wish to extend, but this will create a blank profile extension table using default a folder locations and name (from on your client configuration).\n\n client.create_profile_extension(list_name)\n\nExamples:\n\n client.create_profile_extension('CONTACTS_LIST')\n\nIf you've used the defaults from the boilerplate config this creates a `CONTACTS_LIST_pet` profile extension table extending `CONTACTS_LIST` in the UIfolder specified by your client configuration (default is `___api-generated`) with no records and no non-default fields.\n\nYou can also specify the extension you want to use, but this function is opinionated and will only let you create a profile extension table that begins with the name of the profile list that is being extended.\n\nThis example will create an empty profile extension table extending `CONTACTS_LIST` called `CONTACTS_LIST-Profile_Extension`:\n\n client.create_profile_extension(\n 'CONTACTS_LIST', extension_name='-Profile_Extension')\n\nYou can specify the folder to place it in to override your client configuration:\n\n client.create_profile_extension(\n 'CONTACTS_LIST', folder_name='OtherFolder')\n\nAdditionally you can supply fields as a list:\n\n client.create_profile_extension(\n 'CONTACTS_LIST', fields=['LTV_v1', 'LTV_v2', 'decile'])\n\nIf you don't specify a (Responsys Interact) data type for each it will default to `STR4000`. This default data type can be overridden with one of `STR500`, `STR4000`, `INTEGER`, `NUMBER`, or `TIMESTAMP`:\n\n fields = ['last_purchased_date', 'first_purchased_date']\n client.create_profile_extension(\n 'CONTACTS_LIST', fields=fields, default_field_type='TIMESTAMP')\n\nYou can also specify the field type of each within the list if you supply it as a list or tuple:\n\n fields = [\n ('last_purchased_date','TIMESTAMP'),\n ('lifetime_purchases', 'INTEGER')\n ]\n client.create_profile_extension(\n 'CONTACTS_LIST', fields=fields)\n\nThe default field type override can be supplied alongside individual fields without their own field type specifications:\n\n fields = [\n ('probability_of_login', 'NUMBER'),\n 'CUSTOMER_ID_',\n ('ARTICLE_CONTENTS','STR4000')\n ]\n client.create_profile_extension(\n 'CONTACTS_LIST', fields=fields, default_field_type='STR500')\n\n\n\n#### Retrieve a member of a profile extension table based on RIID\n\nReturns a full record if it's in the profile extension table.\n\n client.get_member_of_profile_extension_by_riid(\n list_name, pet_name, riid)\n\nAlso takes an optional argument `fields` which defaults to `all` if not specified. Examples:\n\n client.get_member_of_profile_extension_by_riid(\n 'CONTACTS_LIST', 'CONTACTS_LIST_pet', '101234567890')\n\nor\n\n client.get_member_of_profile_extension_by_riid(\n 'CONTACTS_LIST',\n 'CONTACTS_LIST_pet',\n '101234567890',\n fields='FIRST_NAME, LAST_PURCHASE_DATE')\n\n\n#### Retrieve a member of a profile extension table based on a query attribute\n\n client.get_member_of_profile_extension_by_attribute(\n list_name, pet_name record_id, query_attribute, fields)\n\nTakes five arguments, but requires `list_name`, `pet_name` and `record_id`. The list name is that which you want to find the record from in your Responsys Interact instance. The record id is the specific id you wish to use to identify the record. The query attribute is the type of id that you are using to retreive the record. The available options are `r` for RIID, `e` for EMAIL_ADDRESS, `c` for CUSTOMER_ID and `m` for MOBILE_NUMBER. The fields to return python list data object of the fields in the list, if left blank it will return all the fields.\n\nExamples:\n\n client.get_member_of_profile_extension_by_attribute(\n 'AFFILIATES', '1234251', 'c', ['email_address_', 'first_name'])\n\n\n#### Delete a member of a profile extension table based on RIID\n\nDeletes a member of a profile extension table based on RIID if it exists.\n\n client.delete_member_of_profile_extension_by_riid(\n list_name, pet_name, riid):\n\n\n\n### Managing Supplemental Tables\n\n\n#### Create a new supplemental table\n\n\nCreates a new supplemental table. Requires only a table name, but this will create a blank supplemental table using default a folder location and name.\n\nExamples:\n\n client.create_supplemental_table(\n 'CONTACTS_LIST', fields=['field1','field2'])\n\nThis creates a `CONTACTS_LIST_supp` supplemental table in a folder named from your client configuration (default is `___api-generated`) with no records and no non-default fields. You must specify either a list with at least one field or a primary key that is one of the Responsys internal field names. If you do not specify a primary key the wrapper will use the first field in the input list because the API requires a primary key field. You can also specify an optional data extraction key.\n\n client.create_supplemental_table(\n supplemental_table_name, folder_name, fields=fields)\n\nor\n\n client.create_supplemental_table(\n supplemental_table_name, folder_name, primary_key=primary_key)\n\nThe wrapper writes all fields with a default field type, which is `STR500` unless another type is specified. If the default type is specified it will use that type for all fields.\n\nExamples:\n\n client.create_supplemental_table(\n 'my_supp_table',\n 'API_testing',\n fields=['field1', 'field2'],\n default_field_type='STR25',\n data_extraction_key='field2',\n primary_key='field1')\n\n\n\n\n### Managing Campaigns\n\n\n#### Get all EMD Campaigns\n\n client.get_campaigns()\n\nReturns a dictionary of campaigns and their data, along with links and their data:\n\n 'campaigns': [\n {\n 'id': 12345678, \n 'name': 'API_Test', \n 'folderName': '___api-generated-cl', \n 'type': 'EMAIL', \n 'purpose': 'PROMOTIONAL', \n 'listName': 'CONTACTS_LIST', \n 'proofListPath': 'testing/Prooflist', \n 'seedListPath': 'testing/Seedlist', \n 'htmlMessagePath': '/contentlibrary/campaigns/___api-generated-cl/document.htm', \n 'enableLinkTracking': False, \n 'enableExternalTracking': False, \n 'subject': 'This is a test message', \n 'fromName': 'Company', \n 'fromEmail': 'email@company.com', \n 'replyToEmail': 'support@company.com', \n 'useUTF8': True, \n 'locale': 'en', \n 'trackHTMLOpens': True, \n 'trackConversions': True, \n 'sendTextIfHTMLUnknown': False, \n 'unsubscribeOption': 'OPTOUT_SINGLE_CLICK', \n 'autoCloseOption': 'AUTO_CLOSE_X_DAYS_AFTER_LAST_RESPONSE', \n 'autoCloseValue': '30', \n 'links': [\n {\n 'rel': 'self', \n 'href': '/rest/api/v1.3/campaigns/API_Test', \n 'method': 'GET'\n }\n , \n {\n 'rel': 'update', \n 'href': '/rest/api/v1.3/campaigns/API_Test', \n 'method': 'PUT'\n }\n , \n {\n 'rel': 'create', \n 'href': '/rest/api/v1.3/API_Test', \n 'method': 'POST'\n }\n ]\n }\n ]\n\n\nTo see a list of just campaigns:\n\n campaigns = client.get_campaigns()['campaigns']\n [campaign['name'] for campaign in campaigns]\n\n\nor a list of campaigns and their respective folders:\n campaigns = client.get_campaigns()['campaigns']\n [(campaign['name'], campaign['folderName']) for campaign in campaigns]\n\n#### Get all Push Campaigns\n\n client.get_push_campaigns()\n\nReturns a list of push campaigns and their associated data.\n\n\n### Managing Content\n\nYou'll notice the files we use are `.htm`. Responsy changes `.html` to `.htm` silently on upload, and appends `.htm` to `.html` files creted in the UI. It is recommended to simply create all of your files with `.htm` to comply, otherwise you might end up with duplicates in your local copies if you're pulling files out. In fact, the wrapper won't allow `.html` files (though you'll have to rename them yourself).\n\n\n\n#### Create Folder\n\nCreates a folder in the content library (`/contentlibary/`).\n\n client.create_folder('new_folder')\n\nCreates a folder `/contentlibarary/new_folder` in the Content Library.\n\nIf you don't specify a folder the wrapper will default to the API folder name configured for your client. The boilerplate default is `___api-generated`. \n\n\n#### Delete Folder\n\nDeletes a folder if it exists in the content library (`/contentlibary/`). \n\n client.delete_folder('folder_name')\n\nThis recursively deletes all files in the folder as well.\n\n\n#### Create Content Library Document\n\nCreates a document in the content library (`/contentlibary/`). It uses your configuration local and remote paths if no paths are specified:\n\n client.create_document('document.htm')\n\nYou can also specify the local and/or remote contentlibrary subfolder:\n\n client.update_document(\n document='document.htm',\n remote_path='path/to/interact/contentlibrary/subfolder/',\n local_path='../../relative/local/path/')\n\nThis should create (if you're on pod 5):\n\n https://interact5.responsys.net/suite/c#!liveViewEditor/%2Fcontentlibrary%2Farbitrary%2Ffolder%2Fpath/document%2Ehtm\n\n\n#### Get Content Library Document\n\nGets the document path, content, and REST CRUD links for a content library document. It uses your configuration local and remote paths if no paths are specified:\n\n client.get_document('document.htm')\n\nYou can also specify the local and/or remote contentlibrary subfolder:\n\n client.update_document(\n document='document.htm',\n remote_path='path/to/interact/contentlibrary/subfolder/',\n local_path='../../relative/local/path/')\n\nreturns:\n\n {\n 'documentPath': '/contentlibrary/___api-generated-cl/document.htm', \n 'content': '\\n
\\n