Andrew, I have not looked into the express checkout solution - but i think that is because i wanted full cart functionality.
sorry about my sloppy code on the slice. guess i did not sanitize it well enough... sitesettings is a table that i have that is just name, value pairs (the following is in my db.py): # a table of settings. db.define_table('settings', SQLField('name', 'text', notnull=True, unique=True, requires=[IS_NOT_EMPTY(), IS_NOT_IN_DB(db,'settings.name')]), SQLField('value', 'text'), migrate=migrate) sitesettings = buildDict(db.settings, "value") #@TODO: create global dictionaries that have the lookup tables, and don't # reload them on every page hit. def buildDict(table, field="id"): """ Creates a dictionary, actually a L{gluon.sql.SQLStorage} object from a lookup table. @type table: SQLTable @param table: the SQLTable to make into a SQLStorage object. The table is expected to have an ID and a name field. @rtype: SQLStorage @return: SQLStorage object with the names of the rows as keys, and id's as values. """ rows = db(db[table].id>0).select() enum_dict = SQLStorage() for r in rows: enum_dict[r.name] = r[field] return enum_dict I put the full_url() method in a file in the models directory so it is available to all controllers. the song_purchases table is where i track what users have purchased: #a table of purchases, one record per user per cue_point(song) purchased db.define_table('song_purchases', SQLField('cue_point', db.cue_point, ondelete='RESTRICT', requires=IS_NULL_OR(IS_IN_DB(db, db.cue_point.id, '%(name)s')), notnull=False), SQLField('song_media', db.song_media, notnull=False, ondelete='RESTRICT', requires=IS_NULL_OR(IS_IN_DB(db,db.song_media.id,'%(name)s'))), SQLField('auth_user', db.auth_user, ondelete='RESTRICT', requires=IS_IN_DB(db, db.auth_user.id, '%(first_name)s %(last_name)s'), notnull=True), SQLField('date', 'datetime', notnull=True, default=now), #when the download expires. #@TODO: make the default expires time configurable. SQLField('expires', 'datetime', notnull=True, default=now + datetime.timedelta(2)), #the paypal transaction id in case we need to look this up SQLField('transaction_id', 'text', notnull=True, requires=IS_NOT_EMPTY()), migrate=migrate) I hope that helps. let me know if you decide to go this route and are still having problems. christian