Developer Documentation

Introduction

The CASH Music platform gives all musicians access to tools that let them manage, promote, and sell their music online — all owned and controlled themselves.

Everything is modular. We built up around a PHP core. The admin app, API, and each element are separate applications that work together to form a full platform. We've built around the concept of cooperation, so we've abstracted all third party services so artists can easily change mailing providers, payment processors, etc. And we've kept dependencies as lightweight as possible so functionality can play well with other apps like WordPress, Drupal, etc.

We host a free (now and forever) version of the CASH Music platform at cashmusic.org or the whole thing can be downloaded and installed on your own server. A few simple changes to settings switch the platform from single-user mode to mutli-user (hosted) mode.

In short: the CASH Music platform was built to create possibilies for artists on the open web.

In these docs we'll cover:

  • Working directly with the PHP Core
  • Our APIs (verbose and RESTful)
  • Defining connections to third party services
  • Building elements (custom workflow for embeds)
  • Working with our admin app

Useful Links

Github / Twitter / Facebook / Development Group


Introduction: Setup

One of our goals is for this to run in as many places as possible, so we've worked hard to keep the requirements minimal:

  • PHP 5.4+
  • PDO (a default) and MySQL OR SQLite
  • mod_rewrite (for admin app)
  • fopen wrappers OR cURL

For local testing and development all you need to get started is VirtualBox, Vagrant 1.4+, and this repo. Just fork, install VirtualBox and Vagrant, then open a terminal window and in the repo directory type:

vagrant up

Vagrant will fire up a VM, set up Apache, install the platform, and start serving a special dev website with tools, docs, and a live instance of the platform — all mapped right to http://localhost:8888.

Dev site included in repo

If you want to go beyond the basic setup included wth our vagrant scripts, you'll nbeed to edit the /framework/settings/cashmusic.ini.php file. We include a template (cashmusic_template.ini.php) and the settings are pretty straightforward. You can change database settings, modify default system salt for password security, set timezone and email settings, and switch between single or multi-user mode.

Introduction: Code Standards

When in doubt, code for legibility and easy adoption. Capitalization and CamelCase should be used for class names, camelCase starting with lowercase for function names, and variable names in snake_case (lowercase and underscores.) Indentation has been kept simple — a single hard tab for each level, with curly brackets on the same line as the control statement.

So a simplified file will look something like:

Each class should have a file of it's own.

No class is final without formatted comments.

PHP Core

All functionality of the platform is accessed through a consistent request/response model at the heart of the PHP Core. No direct function calls should be made — instead data should be accessed and set through a secure and standard request/response model.

The request/response model lets us build consistency from PHP to API and into elements and connections. It mimics a REST-style API and standardizes calls and responses across the methods.

Every request is made with a specific type and action, plus any required or optional parameters. It's response will contain an http-esque status code, a uid containing type/action/code, a human-readable status message, a more detailed contextual message, an echo of the request type and action, a payload with the full response data or false if the request failed, the api version, and a timestamp.

Initiating a PHP Request looks like this:

An example of a failed response object:

Or on success:

The payload is returned as an associative array. Most basic data requests will include creation and modification dates which are standard and automated in the system. Requests to create new resources will return an id number on success.

All core files are located in the repo at /framework/classes/core with requests divided by type and organized into individual plant classes at /framework/classes/plants. Most new functionality is defined at the plant level, with the core classes used to route requests, to plants, abstract database connections, etc.

Each plant includes a routing table for requests that points to internal functions and defines the authentication context under which they're allowed. See below for a complete list of requests exposed by the core.

PHP Core: System requests

All actions defined for 'system' type requests:

system / addlogin

Allowed methods: direct
Parameters:
  • address (REQUIRED)
  • password (REQUIRED)
  • is_admin (default: 0)
  • username (default: '')
  • display_name (default: 'Anonymous')
  • first_name (default: '')
  • last_name (default: '')
  • organization (default: '')
  • address_country (default: '')
  • force52compatibility (default: false)
  • data (default: '')

Adds a new user to the system, setting login details

@param {string} $address - the email address in question
@param {string} $password - the password
@return array|false

system / addlockcode

Allowed methods: direct
Parameters:
  • scope_table_alias (REQUIRED)
  • scope_table_id (REQUIRED)
  • user_id (default: 0)

Creates a new lock/unlock code for and asset

@param {integer} $element_id - the element for which you're adding the lock code
@return string|false

system / deletelogin

Allowed methods: direct
Parameters:
  • address (REQUIRED)

Removes user to the system

@param {string} $address - the email address in question
@return bool

system / deletesettings

Allowed methods: direct
Parameters:
  • user_id (REQUIRED)
  • type (REQUIRED)

Removes system settings of the given type for a user — be careful with wild cards. (Don't use them unless you want to delete all system settings for a user. So, you know, don't.)

@return bool

system / deletetemplate

Allowed methods: direct
Parameters:
  • template_id (REQUIRED)
  • user_id (default: false)

Removes a user page/embed template

@return bool

system / getapicredentials

Allowed methods: direct
Parameters:
  • user_id (REQUIRED)

Gets API credentials for a user id

@param {int} $user_id - the user
@return array|false

system / getlockcodes

Allowed methods: direct
Parameters:
  • scope_table_alias (REQUIRED)
  • scope_table_id (REQUIRED)
  • user_id (default: false)

Gets all lock codes for a given resource.

@return array|false

system / getnewesttemplate

Allowed methods: direct
Parameters:
  • user_id (REQUIRED)
  • type (default: 'page')
  • all_details (default: false)

Gets the latest page/embed template for a given user.

@return string|false

system / getsettings

Allowed methods: direct
Parameters:
  • user_id (REQUIRED)
  • type (REQUIRED)
  • return_json (default: false)

Gets settings of the given type for a user. Set return_json to true and the system will return the stored JSON without decoding.

@return string|array|false

system / gettemplate

Allowed methods: direct
Parameters:
  • template_id (REQUIRED)
  • user_id (default: false)
  • all_details (default: false)

Gets a user page/embed template for display.

@return string|false

system / gettemplatesforuser

Allowed methods: direct
Parameters:
  • user_id (REQUIRED)
  • type (default: false)

Gets all user page/embed template for display.

@return string|false

system / migratedb

Allowed methods: direct
Parameters:
  • todriver (REQUIRED)
  • tosettings (REQUIRED)

Wrapper for CASHData migrateDB call. Currently used for SQLite -> MySQL migrations but any from/to should be possible. More tests need to be written for full support.

@return bool

system / redeemlockcode

Allowed methods: direct, get, post
Parameters:
  • code (REQUIRED)
  • scope_table_alias (default: false)
  • scope_table_id (default: false)
  • user_id (default: false)

Attempts to redeem a given lock code, returning all details for the code on success or false on failure. The code is tied to a scope_table_alias and scope_table_id pointing to a specific asset, element, etc.

Pass a specific scope_table_alias, scope_table_id, or user_id to limit results to only matching returns.

This will continue to return true for four hours after initial redemption — in the case of a failed download this will give a user a second try without risking any long-term breach.

@return array|false

system / setapicredentials

Allowed methods: direct
Parameters:
  • user_id (REQUIRED)

Sets or resets API credentials for a user

@param {int} $user_id - the user
@return array|false

system / setlogincredentials

Allowed methods: direct
Parameters:
  • user_id (REQUIRED)
  • address (default: false)
  • password (default: false)
  • username (default: false)
  • is_admin (default: false)
  • display_name (default: false)
  • url (default: false)

Resets email/password credentials for a user

@param {int} $user_id - the user
@return array|false

system / setresetflag

Allowed methods: direct
Parameters:
  • address (REQUIRED)

Sets or resets the password reset for a user

@return key(md5 hash)|false

system / setsettings

Allowed methods: direct
Parameters:
  • user_id (REQUIRED)
  • type (REQUIRED)
  • value (REQUIRED)

Sets data for the given type for a user. This is basically a single key/value, so if the type already exists this call with overwrite the existing value.

@return bool

system / settemplate

Allowed methods: direct
Parameters:
  • user_id (REQUIRED)
  • type (default: false)
  • name (default: false)
  • template (default: false)
  • template_id (default: false)

Adds/edits a user page/embed template

@return bool

system / startjssession

Allowed methods: direct, get, post, api_public
Parameters:

    system / validateapicredentials

    Allowed methods: direct
    Parameters:
    • api_key (REQUIRED)
    • api_secret (default: false)

    Verifies API credentials and returns authorization type (api_key || api_fullauth || none) and user_id

    @param {int} $user_id - the user
    @return array|false

    system / validatelogin

    Allowed methods: direct
    Parameters:
    • address (REQUIRED)
    • password (REQUIRED)
    • require_admin (default: false)
    • verified_address (default: false)
    • browserid_assertion (default: false)
    • element_id (default: NULL)
    • keep_session (default: false)

    Logins are validated using the email address given with a salted sha256 hash of the given password. Blowfish is unavailable to PHP 5.2 (reliably) so we're limited in hashing. The system salt is stored in /framework/settings/cashmusic.ini.php outside the database for additional security.

    In addition to the standard email/pass we also validate against Mozilla's Browser ID standard using the browserid_assetion which can be passed in. This works with the CASHSystem Browser ID calls to determine a positive login status for the user, get the email address, and compare it to the system to return the correct user and login status.

    Pass require_admin to only return true for admin-level users. Pass an element_id if you want the login analytics to be tied to a specific element.

    @return array|false

    system / validateresetflag

    Allowed methods: direct, get, post
    Parameters:
    • address (REQUIRED)
    • key (REQUIRED)

    Verifies that the password reset is valid

    @return bool

    PHP Core: Asset requests

    All actions defined for 'asset' type requests:

    asset / addasset

    Allowed methods: direct
    Parameters:
    • title (REQUIRED)
    • description (REQUIRED)
    • user_id (REQUIRED)
    • location (default: '')
    • connection_id (default: 0)
    • hash (default: '')
    • size (default: 0)
    • public_url (default: '')
    • type (default: 'file')
    • tags (default: false)
    • metadata (default: false)
    • parent_id (default: 0)
    • public_status (default: 0)

    asset / addlockcode

    Allowed methods: direct
    Parameters:
    • asset_id (REQUIRED)

    Wrapper for system lock code call

    @param {integer} $element_id - the element for which you're adding the lock code
    @return string|false

    asset / claim

    Allowed methods: get, post, direct
    Parameters:
    • id (REQUIRED)
    • element_id (default: 0)
    • session_id (default: false)

    Reads asset details and redirects to the file directly. The success Response is set here rather than in processRequest(), allowing it to exist in the session

    @param {integer} $id - the asset you are trying to retrieve
    @return string

    asset / deleteasset

    Allowed methods: direct
    Parameters:
    • id (REQUIRED)
    • user_id (default: false)
    • connection_id (default: false)

    asset / editasset

    Allowed methods: direct
    Parameters:
    • id (REQUIRED)
    • hash (default: false)
    • size (default: false)
    • location (default: false)
    • title (default: false)
    • description (default: false)
    • public_url (default: false)
    • connection_id (default: false)
    • type (default: false)
    • parent_id (default: false)
    • public_status (default: false)
    • user_id (default: false)
    • tags (default: false)
    • metadata (default: false)

    asset / finalizeupload

    Allowed methods: direct
    Parameters:
    • connection_id (REQUIRED)
    • filename (REQUIRED)

    asset / findassets

    Allowed methods: direct
    Parameters:
    • query (REQUIRED)
    • user_id (REQUIRED)
    • page (default: 1)
    • max_returned (default: 10)

    asset / getanalytics

    Allowed methods: direct
    Parameters:
    • analtyics_type (REQUIRED)
    • user_id (REQUIRED)

    Pulls analytics queries in a few different formats

    @return array

    asset / getasset

    Allowed methods: direct
    Parameters:
    • id (REQUIRED)
    • user_id (default: false)

    Gets all details for a specific asset id (or array of ids) — pass in a single id and get the asset details associative array, pass in an array of asset ids and get an array of asset detail arrays.

    @return void

    asset / getassetsforconnection

    Allowed methods: direct
    Parameters:
    • connection_id (REQUIRED)

    asset / getassetsforparent

    Allowed methods: direct
    Parameters:
    • parent_id (REQUIRED)

    asset / getassetsforuser

    Allowed methods: direct
    Parameters:
    • user_id (REQUIRED)
    • type (default: false)
    • parent_id (default: false)

    asset / getasseturl

    Allowed methods: direct
    Parameters:
    • connection_id (REQUIRED)
    • user_id (REQUIRED)
    • asset_location (REQUIRED)
    • params (default: false)

    asset / getfulfillmentassets

    Allowed methods: direct
    Parameters:
    • asset_details (REQUIRED)
    • type (default: 'fulfillment')
    • session_id (default: false)

    asset / getuploadparameters

    Allowed methods: direct
    Parameters:
    • connection_id (REQUIRED)
    • user_id (REQUIRED)
    • acl (default: false)

    asset / getpublicurl

    Allowed methods: direct
    Parameters:
    • id (REQUIRED)
    • user_id (default: false)

    asset / makepublic

    Allowed methods: direct
    Parameters:
    • id (REQUIRED)
    • user_id (default: false)
    • commit (default: false)

    asset / redeemcode

    Allowed methods: direct, get, post
    Parameters:
    • code (REQUIRED)
    • user_id (default: false)
    • element_id (default: false)

    Wrapper for system lock code call

    @param {string} $code - the code
    @return bool

    asset / unlock

    Allowed methods: direct
    Parameters:
    • id (REQUIRED)
    • session_id (default: false)

    Adds an unlock state to platform session persistent store

    @return boolean

    PHP Core: People requests

    All actions defined for 'people' type requests:

    people / addaddresstolist

    Allowed methods: direct
    Parameters:
    • address (REQUIRED)
    • list_id (REQUIRED)
    • do_not_verify (default: false)
    • initial_comment (default: '')
    • additional_data (default: '')
    • name (default: 'Anonymous')
    • force_verification_url (default: false)
    • request_from_service (default: false)
    • service_opt_in (default: true)
    • extra_querystring (default: '')
    • first_name (default: '')
    • last_name (default: '')

    Adds a user to a list. If no user exists for the email address passed, a new user will be created then added to the list.

    @param {string} $address - the email address in question
    @param {int} $list_id - the id of the list
    @param {bool} $verified - 0 for unverified, 1 to skip verification and mark ok
    @param {string} $initial_comment - a comment passed with the list signup
    @param {string} $additional_data - any extra data (JSON, etc) a dev might pass with signup for later use
    @param {string} $name - if the user doesn't exist in the system this will be used as their display name
    @return bool

    people / addcontact

    Allowed methods: direct
    Parameters:
    • email_address (REQUIRED)
    • user_id (REQUIRED)
    • first_name (default: '')
    • last_name (default: '')
    • organization (default: '')
    • address_line1 (default: '')
    • address_line2 (default: '')
    • address_city (default: '')
    • address_region (default: '')
    • address_postalcode (default: '')
    • address_country (default: '')
    • phone (default: '')
    • notes (default: '')
    • links (default: '')

    Adds a new contact to the system

    @return id|false

    people / addmailing

    Allowed methods: direct
    Parameters:
    • user_id (REQUIRED)
    • list_id (REQUIRED)
    • connection_id (REQUIRED)
    • subject (REQUIRED)
    • template_id (default: 0)
    • html_content (default: '')
    • text_content (default: '')
    • from_name (default: '')

    Adds/edits a mailing

    @return bool

    people / addlist

    Allowed methods: direct
    Parameters:
    • name (REQUIRED)
    • user_id (REQUIRED)
    • description (default: '')
    • connection_id (default: 0)

    Adds a new list to the system

    @param {int} $list_id - the list
    @param {int} $name - a name given to the list for easy recognition
    @param {int} $description - a description, in case the name is terrible and offers no help
    @param {int} $connection_id - a third party connection with which the list should sync
    @return id|false

    people / buildmailingcontent

    Allowed methods: direct
    Parameters:
    • template_id (REQUIRED)
    • html_content (REQUIRED)
    • title (REQUIRED)
    • subject (REQUIRED)
    • template (default: 'user_email')

    people / checkverification

    Allowed methods: direct
    Parameters:
    • address (REQUIRED)
    • list_id (REQUIRED)

    Returns true/false as to whether a user is verified for a specific list

    @param {string} $address - the email address in question
    @param {int} $list_id - the id of the list
    @return bool

    people / deletelist

    Allowed methods: direct
    Parameters:
    • list_id (REQUIRED)
    • user_id (default: false)

    Removes an entire list and all member records. Use with caution.

    @param {int} $list_id - the list
    @return bool

    people / editcontact

    Allowed methods: direct
    Parameters:
    • id (REQUIRED)
    • email_address (default: false)
    • first_name (default: false)
    • last_name (default: false)
    • organization (default: false)
    • address_line1 (default: false)
    • address_line2 (default: false)
    • address_city (default: false)
    • address_region (default: false)
    • address_postalcode (default: false)
    • address_country (default: false)
    • phone (default: false)
    • notes (default: false)
    • links (default: false)
    • user_id (default: false)

    people / editlist

    Allowed methods: direct
    Parameters:
    • list_id (REQUIRED)
    • name (default: false)
    • description (default: false)
    • connection_id (default: false)
    • user_id (default: false)

    Edits the details of a given list

    @param {int} $list_id - the list
    @param {int} $name - a name given to the list for easy recognition
    @param {int} $description - a description, in case the name is terrible and offers no help
    @param {int} $connection_id - a third party connection with which the list should sync
    @return id|false

    people / editmailing

    Allowed methods: direct
    Parameters:
    • mailing_id (REQUIRED)
    • send_date (default: false)
    • subject (default: false)
    • html_content (default: false)
    • text_content (default: false)
    • user_id (default: false)
    • from_name (default: false)

    people / getaddresslistinfo

    Allowed methods: direct
    Parameters:
    • address (REQUIRED)
    • list_id (REQUIRED)

    Returns email address information for a specific list / address

    @param {string} $address - the email address in question
    @return array|false

    people / getanalytics

    Allowed methods: direct
    Parameters:
    • analtyics_type (REQUIRED)
    • user_id (default: 0)
    • list_id (default: false)

    Pulls analytics queries in a few different formats

    @return array

    people / getcontact

    Allowed methods: direct
    Parameters:
    • id (REQUIRED)
    • user_id (default: false)

    people / getcontactsbyinitials

    Allowed methods: direct
    Parameters:
    • user_id (REQUIRED)
    • initial (REQUIRED)

    people / getcontactinitials

    Allowed methods: direct
    Parameters:
    • user_id (REQUIRED)

    people / getlistsforuser

    Allowed methods: direct
    Parameters:
    • user_id (REQUIRED)

    Returns all lists owned by a user

    @param {int} $user_id - the user
    @return array|false

    people / getlist

    Allowed methods: direct, api_key
    Parameters:
    • list_id (REQUIRED)
    • user_id (default: false)

    Returns basic information about a list

    @param {int} $list_id - the id of the list
    @return array|false

    people / getmailing

    Allowed methods: direct
    Parameters:
    • mailing_id (REQUIRED)
    • user_id (default: false)

    people / getmailinganalytics

    Allowed methods: direct
    Parameters:
    • mailing_id (REQUIRED)
    • user_id (default: false)

    people / getrecentactivity

    Allowed methods: direct
    Parameters:
    • user_id (REQUIRED)
    • since_date (default: 0)

    Get recent activity for a given user. (list joins and orders) — if since_date isn't set it will default to two weeks from now.

    @return bool

    people / getuser

    Allowed methods: direct
    Parameters:
    • user_id (REQUIRED)

    Gets details for an individual user

    people / getuseridforaddress

    Allowed methods: direct
    Parameters:
    • address (REQUIRED)
    • with_security_credentials (default: false)

    Returns user id for a given email address

    @param {string} $address - the email address in question
    @return id|false

    people / getuseridforusername

    Allowed methods: direct
    Parameters:
    • username (REQUIRED)

    Returns user id for a given username

    @param {string} $address - the email address in question
    @return id|false

    people / processwebhook

    Allowed methods: direct, api_key, get, post
    Parameters:
    • origin (REQUIRED)
    • user_id (REQUIRED)
    • list_id (default: 0)
    • type (default: false)
    • data (default: false)
    • mandrill_events (default: false)

    Used with the verbose API for remote webhook calls — incoming data into the system from third parties, etc.

    people / recordmailinganalytics

    Allowed methods: direct
    Parameters:
    • mailing_id (REQUIRED)
    • sends (default: 0)
    • opens_total (default: 0)
    • opens_mobile (default: 0)
    • opens_country (default: false)
    • opens_id (default: false)
    • click_url (default: false)
    • failures (default: 0)
    • user_id (default: false)

    people / removeaddress

    Allowed methods: direct, post, get, api_key
    Parameters:
    • address (REQUIRED)
    • list_id (REQUIRED)

    Sets a user inactive for a given list. If the user is not present on the list it returns true.

    @param {string} $address - the email address in question
    @param {int} $list_id - the id of the list
    @return bool

    people / sendmailing

    Allowed methods: direct
    Parameters:
    • mailing_id (REQUIRED)
    • user_id (default: false)

    people / signintolist

    Allowed methods: post, get, direct, api_key
    Parameters:
    • address (REQUIRED)
    • password (REQUIRED)
    • list_id (REQUIRED)
    • browserid_assertion (default: false)
    • element_id (default: NULL)

    people / signup

    Allowed methods: direct, post, get, api_key
    Parameters:
    • list_id (REQUIRED)
    • address (REQUIRED)
    • user_id (default: false)
    • comment (default: '')
    • name (default: 'Anonymous')
    • element_id (default: false)
    • first_name (default: '')
    • last_name (default: '')
    • additional_data (default: '')

    Adds an email address to an existing list — optionally tie to a specific element for analytics

    people / storeuserdata

    Allowed methods: direct
    Parameters:
    • user_id (REQUIRED)
    • key (REQUIRED)
    • value (REQUIRED)

    Store keyed data in a user's data field

    @return bool

    people / verifyaddress

    Allowed methods: direct, post, get
    Parameters:
    • address (REQUIRED)
    • list_id (REQUIRED)
    • verification_code (REQUIRED)

    people / viewlist

    Allowed methods: direct
    Parameters:
    • list_id (REQUIRED)
    • unlimited (default: false)
    • user_id (default: false)

    PHP Core: Commerce requests

    All actions defined for 'commerce' type requests:

    commerce / additem

    Allowed methods: direct
    Parameters:
    • user_id (REQUIRED)
    • name (REQUIRED)
    • description (default: '')
    • sku (default: '')
    • price (default: 0)
    • flexible_price (default: 0)
    • available_units (default: -1)
    • digital_fulfillment (default: 0)
    • physical_fulfillment (default: 0)
    • physical_weight (default: 0)
    • physical_width (default: 0)
    • physical_height (default: 0)
    • physical_depth (default: 0)
    • variable_pricing (default: 0)
    • fulfillment_asset (default: 0)
    • descriptive_asset (default: 0)
    • shipping (default: '')

    commerce / additemvariants

    Allowed methods: direct
    Parameters:
    • item_id (REQUIRED)
    • variants (REQUIRED)

    commerce / addorder

    Allowed methods: direct
    Parameters:
    • user_id (REQUIRED)
    • order_contents (REQUIRED)
    • transaction_id (default: -1)
    • physical (default: 0)
    • digital (default: 0)
    • cash_session_id (default: '')
    • element_id (default: 0)
    • customer_user_id (default: 0)
    • fulfilled (default: 0)
    • canceled (default: 0)
    • notes (default: '')
    • country_code (default: '')
    • currency (default: 'USD')
    • data (default: '')

    commerce / addtocart

    Allowed methods: get, post, direct, api_public
    Parameters:
    • item_id (REQUIRED)
    • element_id (REQUIRED)
    • item_variant (default: false)
    • price (default: false)
    • session_id (default: false)

    commerce / addtransaction

    Allowed methods: direct
    Parameters:
    • user_id (REQUIRED)
    • connection_id (REQUIRED)
    • connection_type (REQUIRED)
    • service_timestamp (default: '')
    • service_transaction_id (default: '')
    • data_sent (default: '')
    • data_returned (default: '')
    • successful (default: -1)
    • gross_price (default: 0)
    • service_fee (default: 0)
    • status (default: 'abandoned')
    • currency (default: 'USD')
    • parent (default: 'order')
    • parent_id (default: '0')

    commerce / cancelorder

    Allowed methods: direct
    Parameters:
    • order_id (REQUIRED)
    • user_id (default: false)

    commerce / cancelsubscription

    Allowed methods: direct
    Parameters:
    • user_id (REQUIRED)
    • connection_id (REQUIRED)
    • id (REQUIRED)

    commerce / createsubscriptionplan

    Allowed methods: direct
    Parameters:
    • user_id (REQUIRED)
    • connection_id (REQUIRED)
    • plan_name (REQUIRED)
    • description (REQUIRED)
    • sku (REQUIRED)
    • amount (default: 0)
    • flexible_price (default: false)
    • recurring (default: true)
    • suggested_price (default: false)
    • physical (default: false)
    • interval (default: 'month')
    • interval_count (default: 12)
    • currency (default: 'usd')

    commerce / createcompedsubscription

    Allowed methods: direct
    Parameters:
    • user_id (REQUIRED)
    • plan_id (REQUIRED)
    • first_name (REQUIRED)
    • last_name (REQUIRED)
    • email_address (REQUIRED)

    commerce / deleteitem

    Allowed methods: direct
    Parameters:
    • id (REQUIRED)
    • user_id (default: false)

    commerce / deleteitemvariant

    Allowed methods: direct
    Parameters:
    • id (REQUIRED)
    • user_id (default: false)

    commerce / deleteitemvariants

    Allowed methods: direct
    Parameters:
    • item_id (REQUIRED)
    • user_id (default: false)

    commerce / deletesubscription

    Allowed methods: direct
    Parameters:
    • id (REQUIRED)
    • subscription_id (REQUIRED)

    commerce / deletesubscriptionplan

    Allowed methods: direct
    Parameters:
    • user_id (REQUIRED)
    • id (REQUIRED)

    commerce / editcartquantity

    Allowed methods: get, post, direct, api_public
    Parameters:
    • item_id (REQUIRED)
    • element_id (REQUIRED)
    • qty (REQUIRED)
    • item_variant (default: '')
    • session_id (default: false)

    commerce / editcartshipping

    Allowed methods: get, post, direct, api_public
    Parameters:
    • element_id (REQUIRED)
    • region (default: 'r1')
    • session_id (default: false)

    commerce / editfulfillmentorder

    Allowed methods: direct
    Parameters:
    • id (REQUIRED)
    • name (default: false)
    • email (default: false)
    • shipping_address_1 (default: false)
    • shipping_address_2 (default: false)
    • shipping_city (default: false)
    • shipping_province (default: false)
    • shipping_postal (default: false)
    • shipping_country (default: false)
    • complete (default: false)
    • fulfilled (default: false)
    • price (default: false)
    • tier_id (default: false)
    • order_data (default: false)
    • notes (default: false)
    • data_sent (default: false)

    commerce / edititem

    Allowed methods: direct
    Parameters:
    • id (REQUIRED)
    • name (default: false)
    • description (default: false)
    • sku (default: false)
    • price (default: false)
    • flexible_price (default: false)
    • available_units (default: false)
    • digital_fulfillment (default: false)
    • physical_fulfillment (default: false)
    • physical_weight (default: false)
    • physical_width (default: false)
    • physical_height (default: false)
    • physical_depth (default: false)
    • variable_pricing (default: false)
    • fulfillment_asset (default: false)
    • descriptive_asset (default: false)
    • user_id (default: false)
    • shipping (default: false)

    commerce / edititemvariant

    Allowed methods: direct
    Parameters:
    • id (REQUIRED)
    • quantity (REQUIRED)
    • item_id (REQUIRED)
    • user_id (default: false)

    commerce / editorder

    Allowed methods: direct
    Parameters:
    • id (REQUIRED)
    • fulfilled (default: false)
    • canceled (default: false)
    • notes (default: false)
    • country_code (default: false)
    • customer_user_id (default: false)
    • order_contents (default: false)
    • transaction_id (default: false)
    • physical (default: false)
    • digital (default: false)
    • user_id (default: false)
    • data (default: '')

    commerce / edittransaction

    Allowed methods: direct
    Parameters:
    • id (REQUIRED)
    • service_timestamp (default: false)
    • service_transaction_id (default: false)
    • data_sent (default: false)
    • data_returned (default: false)
    • successful (default: false)
    • gross_price (default: false)
    • service_fee (default: false)
    • status (default: false)

    commerce / emailbuyersbyitem

    Allowed methods: direct
    Parameters:
    • user_id (REQUIRED)
    • connection_id (REQUIRED)
    • item_id (REQUIRED)
    • subject (REQUIRED)
    • message (REQUIRED)
    • include_download (default: false)

    commerce / emptycart

    Allowed methods: get, post, direct, api_public
    Parameters:
    • element_id (REQUIRED)
    • session_id (default: false)

    commerce / formatvariantname

    Allowed methods: direct
    Parameters:
    • name (REQUIRED)

    commerce / getanalytics

    Allowed methods: direct
    Parameters:
    • analtyics_type (REQUIRED)
    • user_id (REQUIRED)
    • date_low (default: false)
    • date_high (default: false)

    Pulls analytics queries in a few different formats @return array

    commerce / getcart

    Allowed methods: direct
    Parameters:
    • element_id (REQUIRED)
    • session_id (default: false)

    commerce / getfulfillmentjobbytier

    Allowed methods: direct
    Parameters:
    • tier_id (REQUIRED)

    commerce / getfulfillmentorder

    Allowed methods: direct
    Parameters:
    • id (REQUIRED)
    • user_id (default: false)

    commerce / getitem

    Allowed methods: direct
    Parameters:
    • id (REQUIRED)
    • user_id (default: false)
    • with_variants (default: true)

    commerce / getitemvariants

    Allowed methods: direct
    Parameters:
    • item_id (REQUIRED)
    • exclude_empties (default: false)
    • user_id (default: false)

    commerce / getitemsforuser

    Allowed methods: direct
    Parameters:
    • user_id (REQUIRED)
    • with_variants (default: true)

    commerce / getorder

    Allowed methods: direct
    Parameters:
    • id (REQUIRED)
    • deep (default: false)
    • user_id (default: false)

    commerce / getordersforuser

    Allowed methods: direct
    Parameters:
    • user_id (REQUIRED)
    • include_abandoned (default: false)
    • max_returned (default: false)
    • since_date (default: 0)
    • unfulfilled_only (default: 0)
    • deep (default: false)
    • skip (default: 0)

    commerce / getordersbycustomer

    Allowed methods: direct
    Parameters:
    • user_id (REQUIRED)
    • customer_email (REQUIRED)

    commerce / getordersbyitem

    Allowed methods: direct
    Parameters:
    • user_id (REQUIRED)
    • item_id (REQUIRED)
    • max_returned (default: false)
    • skip (default: 0)

    commerce / getordertotals

    Allowed methods: direct
    Parameters:
    • order_contents (REQUIRED)

    commerce / getsubscriptiondetails

    Allowed methods: direct
    Parameters:
    • id (REQUIRED)

    commerce / getsubscriptionplan

    Allowed methods: direct
    Parameters:
    • id (REQUIRED)
    • user_id (default: false)

    commerce / getsubscriptionplanbysku

    Allowed methods: direct
    Parameters:
    • sku (REQUIRED)

    commerce / getallsubscriptionsbyplan

    Allowed methods: direct
    Parameters:
    • id (REQUIRED)
    • limit (default: false)

    commerce / getsubscriptionplans

    Allowed methods: direct
    Parameters:
    • user_id (REQUIRED)
    • limit (default: false)

    commerce / getsubscriptionstats

    Allowed methods: direct
    Parameters:
    • plan_id (REQUIRED)

    commerce / getsubscribercount

    Allowed methods: direct
    Parameters:
    • plan_id (REQUIRED)

    commerce / getsubscriptiontransactions

    Allowed methods: direct
    Parameters:
    • id (REQUIRED)

    commerce / gettransaction

    Allowed methods: direct
    Parameters:
    • id (REQUIRED)
    • user_id (default: false)

    commerce / finalizepayment

    Allowed methods: get, post, direct
    Parameters:
    • order_id (REQUIRED)
    • token (REQUIRED)
    • email_address (default: false)
    • customer_name (default: false)
    • shipping_info (default: false)
    • session_id (default: false)
    • total_price (default: false)
    • description (default: false)
    • finalize_url (default: false)

    commerce / initiatecheckout

    Allowed methods: get, post, direct, api_public
    Parameters:
    • element_id (default: false)
    • shipping_info (default: false)
    • paypal (default: false)
    • stripe (default: false)
    • origin (default: false)
    • email_address (default: false)
    • customer_name (default: false)
    • session_id (default: false)
    • geo (default: false)
    • finalize_url (default: false)

    initiateCheckout @param bool $element_id @param bool $shipping_info @param bool $paypal @param bool $stripe @param bool $origin @param bool $email_address @param bool $customer_name @param bool $session_id @return bool

    commerce / initiatesubscription

    Allowed methods: get, post, direct, api_public
    Parameters:
    • element_id (default: false)
    • price (default: false)
    • stripe (default: false)
    • origin (default: false)
    • email_address (default: false)
    • subscription_plan (default: false)
    • customer_name (default: false)
    • session_id (default: false)
    • geo (default: false)
    • shipping_info (default: false)
    • finalize_url (default: false)

    commerce / loginsubscriber

    Allowed methods: get, post, direct, api_public
    Parameters:
    • email (default: false)
    • password (default: false)
    • plans (default: false)

    commerce / processwebhook

    Allowed methods: direct, api_public, public, get, post
    Parameters:
    • origin (REQUIRED)
    • type (default: false)
    • data (default: false)

    commerce / sendorderreceipt

    Allowed methods: direct
    Parameters:
    • id (default: false)
    • order_details (default: false)
    • finalize_url (default: false)

    commerce / updatesubscriptionplan

    Allowed methods: direct
    Parameters:
    • user_id (REQUIRED)
    • connection_id (REQUIRED)
    • id (REQUIRED)
    • sku (REQUIRED)
    • name (REQUIRED)
    • description (REQUIRED)
    • flexible_price (default: false)
    • suggested_price (default: false)
    • physical (default: false)

    commerce / updatesubscription

    Allowed methods: direct
    Parameters:
    • id (REQUIRED)
    • status (default: false)
    • total (default: false)
    • start_date (default: false)
    • update_plan_id (default: false)

    commerce / validatesubscription

    Allowed methods: get, post, direct, api_public
    Parameters:
    • user_id (REQUIRED)
    • plans (REQUIRED)

    Simple lookup to check if a user is an active subscriber @param $user_id @param $plan_id @return bool

    PHP Core: Calendar requests

    All actions defined for 'calendar' type requests:

    calendar / addevent

    Allowed methods: direct
    Parameters:
    • date (REQUIRED)
    • user_id (REQUIRED)
    • venue_id (REQUIRED)
    • purchase_url (default: '')
    • comment (default: '')
    • published (default: 0)
    • cancelled (default: 0)

    calendar / addvenue

    Allowed methods: direct
    Parameters:
    • name (REQUIRED)
    • city (REQUIRED)
    • address1 (REQUIRED)
    • address2 (REQUIRED)
    • region (REQUIRED)
    • country (REQUIRED)
    • postalcode (REQUIRED)
    • url (REQUIRED)
    • phone (REQUIRED)
    • user_id (REQUIRED)

    calendar / deleteevent

    Allowed methods: direct
    Parameters:
    • event_id (REQUIRED)

    calendar / deletevenue

    Allowed methods: direct
    Parameters:
    • venue_id (REQUIRED)

    calendar / editevent

    Allowed methods: direct
    Parameters:
    • event_id (REQUIRED)
    • date (default: false)
    • venue_id (default: false)
    • purchase_url (default: false)
    • comment (default: false)
    • published (default: false)
    • cancelled (default: false)
    • user_id (default: false)

    calendar / editvenue

    Allowed methods: direct
    Parameters:
    • venue_id (REQUIRED)
    • name (default: false)
    • address1 (default: false)
    • address2 (default: false)
    • city (default: false)
    • region (default: false)
    • country (default: false)
    • postalcode (default: false)
    • url (default: false)
    • phone (default: false)

    calendar / findvenues

    Allowed methods: direct
    Parameters:
    • query (REQUIRED)
    • user_id (REQUIRED)
    • page (default: 1)
    • max_returned (default: 12)

    calendar / getallvenues

    Allowed methods: direct
    Parameters:
    • user_id (REQUIRED)
    • visible_event_types (REQUIRED)

    calendar / getevent

    Allowed methods: direct
    Parameters:
    • event_id (REQUIRED)

    calendar / getevents

    Allowed methods: direct
    Parameters:
    • user_id (REQUIRED)
    • offset (default: 0)
    • published_status (default: 1)
    • cancelled_status (default: 0)
    • cutoff_date_low (default: false)
    • cutoff_date_high (default: false)
    • visible_event_types (default: 'upcoming')

    calendar / geteventsnostatus

    Allowed methods: direct
    Parameters:
    • user_id (REQUIRED)
    • visible_event_types (default: 'upcoming')
    • cutoff_date_low (default: false)
    • cutoff_date_high (default: false)

    calendar / getvenue

    Allowed methods: direct
    Parameters:
    • venue_id (REQUIRED)

    PHP Core: Element requests

    All actions defined for 'element' type requests:

    element / addelementtocampaign

    Allowed methods: direct
    Parameters:
    • element_id (REQUIRED)
    • campaign_id (REQUIRED)

    element / addcampaign

    Allowed methods: direct
    Parameters:
    • title (REQUIRED)
    • description (REQUIRED)
    • user_id (REQUIRED)
    • elements (default: '[]')
    • metadata (default: '{}')

    element / addelement

    Allowed methods: direct
    Parameters:
    • name (REQUIRED)
    • type (REQUIRED)
    • options_data (REQUIRED)
    • user_id (REQUIRED)

    element / addlockcode

    Allowed methods: direct
    Parameters:
    • element_id (REQUIRED)

    Wrapper for system lock code call

    @param {integer} $element_id - the element for which you're adding the lock code
    @return string|false

    element / checkuserrequirements

    Allowed methods: direct
    Parameters:
    • user_id (REQUIRED)
    • element_type (REQUIRED)

    Feed in a user id and element type (string) and this function returns either true, meaning the user has defined all the required bits needed to set up an element of the type; or an array containing codes for what's missing.

    A boolean return of false means there was an error reading the JSON

    @param {int} $user_id - the user
    @param {string} $element_type - element type name
    @return true|false|array

    element / deletecampaign

    Allowed methods: direct
    Parameters:
    • id (REQUIRED)
    • user_id (default: false)

    element / deleteelement

    Allowed methods: direct
    Parameters:
    • id (REQUIRED)
    • user_id (default: false)

    element / editelement

    Allowed methods: direct
    Parameters:
    • id (REQUIRED)
    • name (REQUIRED)
    • options_data (REQUIRED)
    • user_id (default: false)

    element / editcampaign

    Allowed methods: direct
    Parameters:
    • id (REQUIRED)
    • user_id (default: false)
    • title (default: false)
    • description (default: false)
    • elements (default: false)
    • metadata (default: false)
    • template_id (default: false)

    element / getanalytics

    Allowed methods: direct
    Parameters:
    • analtyics_type (REQUIRED)
    • user_id (REQUIRED)
    • element_id (default: 0)

    Pulls analytics queries in a few different formats

    @return array

    element / getanalyticsforcampaign

    Allowed methods: direct
    Parameters:
    • id (REQUIRED)

    element / getcampaign

    Allowed methods: direct
    Parameters:
    • id (REQUIRED)
    • user_id (default: false)

    element / getelement

    Allowed methods: direct
    Parameters:
    • id (REQUIRED)
    • user_id (default: false)

    element / getcampaignsforuser

    Allowed methods: direct
    Parameters:
    • user_id (REQUIRED)

    element / getcampaignforelement

    Allowed methods: direct
    Parameters:
    • id (REQUIRED)

    element / getelementsforcampaign

    Allowed methods: direct
    Parameters:
    • id (REQUIRED)

    element / getelementsforuser

    Allowed methods: direct
    Parameters:
    • user_id (REQUIRED)

    element / getelementtemplate

    Allowed methods: direct
    Parameters:
    • element_id (REQUIRED)
    • return_template (default: false)

    element / getmarkup

    Allowed methods: direct
    Parameters:
    • id (REQUIRED)
    • status_uid (REQUIRED)
    • original_request (default: false)
    • original_response (default: false)
    • access_method (default: 'direct')
    • location (default: false)
    • geo (default: false)
    • donottrack (default: false)

    element / getsupportedtypes

    Allowed methods: direct
    Parameters:
    • force_all (default: false)

    element / redeemcode

    Allowed methods: direct, get, post
    Parameters:
    • code (REQUIRED)
    • element_id (REQUIRED)

    Wrapper for system lock code call

    @param {string} $code - the code
    @param {integer} $element_id - the element for which you're adding the lock code
    @return bool

    element / removeelementfromcampaign

    Allowed methods: direct
    Parameters:
    • element_id (REQUIRED)
    • campaign_id (REQUIRED)

    element / setelementtemplate

    Allowed methods: direct
    Parameters:
    • element_id (REQUIRED)
    • template_id (REQUIRED)
    • user_id (default: false)

    API

    Our API is a standalone app located in the repo at /interfaces/api/ and available at the /api/ URL at cashmusic.org and locally for testing. Like the admin app, all configuration is handled by the constants.php file located in the app root, and all requests are routed through the controller.php script via mod_rewrite.

    The main API functionality is handled by the APICore class, located at /interfaces/api/classes/APICore.php.

    The API returns JSON objects for any request. Simply requesting / at the /api gives a basic hello with version number:

    A bad request returns a more standard format with status code and messages:

    We'll detail succesful requests in the verbose and RESTful docs below.

    API: Verbose API

    The verbose API is a direct wrapper for all requests that allow the apipublic or apikey access methods. At the moment those are mostly limited to list signups and initiating new transactions, but we're working on a full authorization scheme to expand scope.

    The response object and payload are nearly identical to the return from the PHP core, except returned as JSON. Making a request that doesn't allow API access will give you a forbidden status, but here's an example endpoint:

    /api/verbose/asset/getasset/id/2
    

    The format is simple: /verbose/plant/request/{parameter name}/{parameter value} — it'll parse as many parameters as you throw at it and respond:

    More about authorization methods coming soon.

    API: RESTful API

    The RESTful version of the API is still a work in progress.

    Connections

    Connections are basically API wrappers — an abstracted way for us to connect to third party services, categorize their offering, and define the data we need to store to make each one work. (Tokens, settings, etc.)

    Defining a connection happens in two different files:

    1. A definition JSON in /framework/settings/connections
    2. A Seed Class in /framework/classes/seeds

    The connection is defined in JSON and should look something like this:

    It needs a name, description, unique type, and you must define the classname of the seed used with the connection. There's an option for scope. This lets us narrow the connection type so we can show connections contextually in the admin app and beyond. (Currently, the scope types have been chosen fairly arbitrarily, though we need to define them better going forward.) Lastly, there's an array listing compatibility — does the connection work in single-user mode, multi-user mode, or both?

    Note that you can define different data needed for single-user and multi-user versions of the connection. (We frown on storing keys/secrets in multi-user mode.)

    The Seed class

    In the larger scheme of the platform, Plants handle requests while Seeds handle specific functionality — mostly in the form of connecting to third party APIs. Because seeds are supposed to be flexible, they're pretty arbitrary in structure, but you'll notice a bunch of common functions between similar seeds — check seeds for S3 and Google Drive.

    We'll be defining this more concretely on a scope-by-scope basis soon, but for now please look for similar services and pattern after them. We want as much uniformity as we can get at the seed level so we can abstract as much as possible at the plant level.

    Any connection supporting an OAuth style redirect (generally in multi-user mode) will need to have these two functions defined:

    • getRedirectMarkup($data=false)
    • handleRedirectReturn($data=false)

    The getRedirectMarkup will handle any logic needed to present the user with a redirect link, and the handleRedirectReturn will deal with the returned token and complete the connection process.

    Any data like application-level keys that need to be stored to initiate OAuth requests can be stored in /framework/settings/connections.json. See template at /framework/settings/_connections.json for a quick example.

    Elements

    Elements bundle unique workflows in the CASH Music platform. Think of them as apps accessing the core the same way apps access APIs on a phone. We took inspiration from app stores in the idea of creating a simple bundle that's easy to use and configure.

    Each element has a PHP class that follows a set pattern, mustache templates for markup, an image for thumbs, a LICENSE, and an accompanying JSON definition file. The rest is handled automatically. All settings forms are generated by the admin app itself (and could even be set manually from PHP if you feel like going gusto.)

    The main element class defines and responds to various states — usually triggered by GET or POST request via embed. The element listens for its own id and reacts to all matching CASH Responses.

    An element is embedded with a single function call, and will respond automatically when interacted with. The whole idea being that it's a simple to use structure that can be powerful and flexible enough to innovate on top of the PHP core.

    Elements: Structure

    Each element is essentially a bundle all to itself, with three main parts:

    1. An app.json definition file that defines element messages and data to be stored
    2. A Class file with logic and states for the element
    3. A folder of mustache templates (markup views for every state)

    Data and settings for each instance of an element are stored as encrypted JSON in the database, and defined in an element's app.json file. The app.json file defines all details like title and description of the element, instructions, and the data structure along with labels, messages, etc. A detailed sample file is better than a description here:

    The options define what can be set in the element admin, what options will be present and expected, and provide default values, etc.

    The allowed types for options are:

    • select
      • values (required)
    • boolean
    • number
    • text
    • markup

    And every option can also contain:

    • required
    • default
    • displaysize
    • helptext
    • placeholder

    The main element class

    The main element class file extends the ElementBase class, automating most of the state management and template selection you'll need. The logic can be as complex as necessary,
    but in the end the goal is to define some data into $this->element_data and return it as the output of the getData() function. Whatever you define will be added to the stored data and accessible in your mustache templates.

    In the example below, note that we use the $this->setTemplate() function to choose a template other than the (required) default.mustache file. This is based on filenames in the template folder, and controlled by state — the CASH Response UID returned the the last request. So if the element contains a form that triggers a CASH Request via GET or POST the element responds, sets its internal state, and your getData() function does some magic based on state before returning the data needed to render your embed.

    By separating the getData from rendering output we allow elements to work at all states on a purely data level — leaving room in the future for mobile app support, etc. But for now the data is combined with the mustache template you choose to render HTML in the browser.

    This is just a starting point. For more examples see the /framework/classes/elements directory in the main platform repo.

    Elements: Embedding

    We use our (tiny) custom javascript library, cashmusic.js, to create iframe embeds for elements. They can be styled to match any site with full user control over CSS and markup. Embedding is pretty straightforward and happens with a single copy and paste code.

    In a basic example, an element is embedded in place by id only:

    Endpoint and id are always required, but you can also choose to have the element appear in an overlay (lightboxed.) A lightboxed element will create a link inline with the caption passed in to the window.cashmusic.embed function. You can also pass in an object specifying size and position of the element inside the overlay.

    For embed calls after page load, provide a target element as the final argument to window.cashmusic.embed. This will place the embed, iframe or lightbox link, inside the first matching element. The target should be a string that will work with document.querySelector, like "#id", "#id .class", or similar.

    For styling, all iframe embeds are placed in a <div> classed with "cashmusic embed" and lightboxed embed links are placed in a <span> classed "cashmusic embed".

    An example with all options:

    We're also working on a new JSON object based embed call. It's mostly for clear formatting, but you'll notice a new CSS override option not available by the standard method. More on that soon...

    Admin app

    The admin app for the platform (/interfaces/admin) is a fairly straight-forward MVC-style webapp built with a front controller, individual controllers for each route, mustache views, and using the framework for the model instead of a traditional database layer. Basically it's dog-fooding the PHP core but building a much more complex app than a simple element.

    In terms of structure, it's fairly simple:

    • Settings are stored in the constants.php file
    • The .htaccess pushes all traffic through the controller.php file
    • Each route has a controller in /components/pages/controllers and after doing any logic the controller calls a mustache template view from /components/pages/views
    • The main page UI is stored in mustache templates in /ui/default

    It shouldn't be lost that the admin app is structured to mirror the CASH Request/Response types — this is very much on purpose with the goal of getting musicians and developers speaking the same language.