Publish to Billings.

As of version 2.5, you can send information from your application to Billings pretty easily. All you need is a BEX file (which is a standard plist) and a simple AppleScript command.

Composing the ".bex"

Composing the plist in a Cocoa application is pretty easy. The root of the plist is a dictionary (NSDictionary or CFDictionary) with specifies the kind of object you are sending and array (NSArray or CFArray) of dictionaries representing those objects.

Each object can have related objects. For example, if you have a dictionary representing a Project, within it, you can have an array of EstimateSlips. See tge specificiation below for all the valid keys.

Once you've composed your BEX, simply save it out and specify ".bex" as the file extension.

Maintaining updatability

The BEX supports the concept of updability. You can send a BEX with the same info and it will just update the existing record instead of creating a new. For this to work correctly, you just specify 3 keys in an object: foreignAppName, foreignAppEntityName and foreignAppImportID.

foreignAppName is your application name - ie. Daylite
foreignAppEntityName is your object class or entity - ie. MySuperDuperProjectClass
foreignAppImportID is your unique ID for that class or entity

The combination of these 3 attributes helps us identity the original record you sent so we can update it.

Example BEX files

If you need to see what an actual BEX file looks like, simple select a project in Billings and export it using the File -> Export -> Export Project... command. If you need more help, feel free to contact us and we'll be happy to help.

The AppleScript command

tell application "Billings" ImportBEXFile filename "the full path to the BEX file with extension .bex" end tell
Billings Echange Format.

The following are the keys accepted by a BEX system. Currently the specification is at version 2.

Root Dictionary
KeyTypeDescription
entityNameStringeither TimeSlip, EstimateSlip or Project
objectsArraySlips where each slip is represented as a dictionary
promptUserForClientIfNoneBOOL[Optional] This will prompt a sheet for the user to choose a Client if no Client is provided

Project
KeyTypeDescription
useNicknameIntegerShould the nickname used by default
startDateDateStart date
client.derivedNameStringThe client’s full name
projectCodeStringProject code
poNumberStringPO Number
objectiveStringObjective of the project
nicknameStringNickname for the project
nameStringName of the project
extraField1StringExtra field
extraField2StringExtra field
extraField3StringExtra field
extraField4StringExtra field
dueDateDateDue date
completeDateDateComplete date
balanceRealBalance of the project
createDateDateCreate date
modifyDateDateModify date
appliedRetainerAmtRealApplied retainer amount
client.clientABRefStringThe Adresss Book Reference ID
state.stateCodeIntegerState code, Active = 1001, Completed = 1002, Cancelled = 1003, Estimate = 1004
activeTimeslipsArrayAn array of working slips
estimateSlipsArrayAn array of estimate slips
foreignAppNameStringThe name of the application this Project was imported from
foreignAppEntityNameStringThe entity which the project type corresponds to in the foreign app
foreignAppImportIDStringThe ID which corresponds to the ID managed in the foreign app
client.firstNameStringClient's first name
client.lastNameStringClient's last name
client.companyStringClient's company
client.emailStringClient's email

EstimateSlip
KeyTypeDescription
project.nameStringName of the project.
project.client.derivedNameStringThe client name.
unitsRealThe quantity for a Quantity Estimate Slip
startDateTimeDateThe start date/time
roundTimeIntegerThe time to round to when calculating amount owed. ex. 15 min increments.
rateRealBilling rate of the slip
natureIntegerThe nature of the slip. Billable = 101, My Eyes Only = 103
nameStringThe name of the slip.
mileageTypeIntegerThe mileage type. Miles = 0, Kilometers = 1
markupRealThe markup on the slip as a percent.
endDateTimeDateThe end date/time.
durationRealDuration in Seconds. For Timed and Flat slips.
dueDateDateThe due date/time.
distanceRealThe distance for a mileage slip measured in units specified by mileageType.
discountRealThe discount on the slip as a percent.
createDateDateThe create date/time.
commentStringComment
type.typeCodeIntegerThe type of slip. Timed = 101, Flat = 102, Quantity = 103, Expense = 104, Mileage = 105
category.nameStringName of the category.
foreignAppNameStringThe name of the application this Project was imported from
foreignAppEntityNameStringThe entity which the project type corresponds to in the foreign app
foreignAppImportIDStringThe ID which corresponds to the ID managed in the foreign app
project.client.firstNameStringClient's first name
project.client.lastNameStringClient's last name
project.client.clientABRefStringClient's Address Book UID
project.client.emailStringClient's email
project.client.companyStringClient's Company
project.foreignAppNameStringForeign App Name for project
project.foreignAppEntityNameStringForeign App Entity name for Project
project.foreignAppImportIDStringForeign App ID for Project

TimeSlip
KeyTypeDescription
project.nameStringName of the project.
project.client.derivedNameStringThe client name.
unitsRealThe quantity for a Quantity Estimate Slip
startDateTimeDateThe start date/time
roundTimeIntegerThe time to round to when calculating amount owed. ex. 15 min increments.
rateRealBilling rate of the slip
natureIntegerThe nature of the slip. Billable = 101, My Eyes Only = 103
nameStringThe name of the slip.
mileageTypeIntegerThe mileage type. Miles = 0, Kilometers = 1
markupRealThe markup on the slip as a percent.
endDateTimeDateThe end date/time.
dueDateDateThe due date/time.
distanceRealThe distance for a mileage slip measured in units specified by mileageType.
discountRealThe discount on the slip as a percent.
createDateDateThe create date/time.
commentStringComment
type.typeCodeIntegerThe type of slip. Timed = 101, Flat = 102, Quantity = 103, Expense = 104, Mileage = 105
category.nameStringName of the category.
activeForTimingBooleanYES = 1, NO = 0
timeEntriesArray of time entries
foreignAppNameStringThe name of the application this Project was imported from
foreignAppEntityNameStringThe entity which the project type corresponds to in the foreign app
foreignAppImportIDStringThe ID which corresponds to the ID managed in the foreign app
project.client.firstNameStringClient's first name
project.client.lastNameStringClient's last name
project.client.clientABRefStringClient's Address Book UID
project.client.emailStringClient's email
project.client.companyStringClient's Company
project.foreignAppNameStringForeign App Name for project
project.foreignAppEntityNameStringForeign App Entity name for Project
project.foreignAppImportIDStringForeign App ID for Project

TimeEntry
KeyTypeDescription
startDateTimeDateStart date/time
isManualBooleanWas this time entry created manually? YES = 1, NO = 0
endDateTimeDateEnd date/time
createDateDateCreate date/time
commentStringComment
foreignAppNameStringForeign App Name for TimeEntry (if foreign App does not have concept of Time Entries use same value as TimeSlip)
foreignAppEntityNameStringForeign App Entity name for TimeEntry (if foreign App does not have concept of Time Entries use same value as TimeSlip)
foreignAppImportIDStringForeign App ID for TimeEntry (if foreign App does not have concept of Time Entries use same value as TimeSlip)