⌈⌋ branch:  freshcode

Freecode JSON API

State: obsolete, replaced

See API2 for a newer proposal.

Freshcode reimplements the Freecode JSON API to allow for project and release updating per command line (freecode-submit).

Old URL scheme

The request URLs and data formats are broadly compatible:

method URL path function 1:1
GET /projects/<name>.json query YES
PUT /projects/<name>.json update_core YES
CREATE /projects/<name>.json new_project NEW
POST /projects/<name>/releases.json publish YES
GET /projects/<name>/releases/pending.json pending YES
DELETE /projects/<name>/releases/<int>.json withdraw YES
GET /projects/<name>/urls.json urls NEW
PUSH /projects/<name>/urls.json update_urls NEW

See also http://web.archive.org/web/20130412231142/http://help.freecode.com/kb/api-7/data-api-releases for the original reference.

There are semantic differences in that freshcode.club does not currently require pre-moderation and approvals. Still the API is unchanged apart from the URL updating.


GET requests append an ?auth_code= which contains the plain auth_token / password.

POST/PUT instead wrap the "auth_code" in the outermost layer of the JSON content body.

Query GET/projects/<name>.json

Retrieves general project information. The original Freecode.com included:

   "project": {
      "id": "424902329",
      "permalink": "project_name",
      "oneliner": "First sentence of description.",
      "license_list": "BSDL",
      "approved_urls": [
         { "label": "src", "redirector": "http://example.org" }

Additionally the extended Freshcode.club feed fields are present (tags, homepage, image, urls, etc.).

If the GET request also includes an ?auth_code=, then the raw database contents are even returned (lock, submitter, submitter_openid, hidden, flags, social_links, regex, ...)

Update_core PUT /projects/<name>.json

To edit the general project information, send the basic fields via PUT wrapped in a JSON dict containing:

   "auth_code": "plain_pw_123",
   "project": {
      "description": "Project does foo and bar.",
      "oneliner": "__will_be_ignored__",
      "license_list": "GNU GPL",
      "project_tag_list": "desktop,end-user,browser,gtk",

In addition freshcode honors any included homepage and download URL, or updating the state (alpha, beta, stable, etc.)

Publish POST /projects/<name>/releases.json

Submitting a new release is just as straightforward. The POST body ought to list:

   "auth_code": "pw123",
   "project": {
      "version": "3.0",
      "changelog": "User-friendly summary of changes..",
      "tag_list": "major,bugfix,security,stable",
      "hidden_from_frontpage": false,

The tag_list is split into our scope and state fields, and the special tag hidden sets the hidden_from_frontpage flag implicitly. A new download URL can also be submitted herein.

URLs dict GET/PUSH /projects/<name>/urls.json

The URL retrieval and storage methods have been simplified. Freecode used oddly nested JSON (see the Query example). It required the update process to first GET a list, then tediously PUTing in updated entries, POSTing new ones, and DELETEing stale ones each. Which is not only a long-winded implementation for API server and client, but would incur around 15 database revisions when updating just 3 URLs. ^^

Instead we'll just pass around an associative urls dictionary/array.
For GET requests on /projects/<name>/urls.json you receive:

   "urls": {
      "src": "http://example.org/pkg-src.txz",
      "release-notes": "http://example.org/proj-blog/"

Updating all URLs at once takes the same format, but requires an auth_code of course. The API is indifferent to PUT or POST or even PUSH here.

   "auth_code": "plain_pw_123",
   "urls": {
      "txz": "http://example.org/pkg-$version.txz",

Notice that all URLs may contain a $version placeholder as usual. Which somewhat alleviates the need to update URLs anyway. Links names are free-form, can be mixed-cased, should be dash-delimited.

withdraw_release DELETE

The doubly versioned database scheme is meant to be somewhat immutable. As such there is no actual deleting taking place. Withdrawing a release is still possible. It'll just be marked as hidden, and/or flagged for moderator attention, (or somewhen use the deleted flag even).

It takes two steps:

  1. GET /projects/<name>/releases/pending.json to uncover the associated id for a version.

        "release": {
          "id": "1403557288",
          "version": "3.15.1",
          "approved_at": "2014-06-28T22:51:00+0000"
        "release": {
          "id": "1403995977",
          "version": "3.15.2",
          "created_at": "2014-06-28T22:52:57+0000"

    (There are more fields, absent from this example.)

  2. Send a DELETE request onto /projects/<name>/releases/<id>.json?auth_code=.. to remove that project revision.

    The id is always numeric. Also it's basically just the t_published timestamp.

Because there is no pending/approval stage on freshcode.club anymore, this even works for previous releases, not just the current one.

New_project CREATE /projects/<name>.json

For submitting an entirely new project, send a CREATE request onto /projects/<newname>.json. Basically this request scheme is just an extension over the PUT method (Update_core).

   "auth_code": "your_new_pw_123",
   "project": {
      "title": "My project",
      "description": "...",
      "image": "http://example.org/screenshot.png",
      "submitter": "Your Name, username@gravatar",
      "scope": "stable",
      "version": "2.0.0-current",
      "autoupdate_url": "http://example.org/NEWS.txt",
      "license_list": "MITL",
      "project_tag_list": "desktop,end-user,browser,gtk",

This method accepts way more fields than other request schemes. (Since this is a diversion from the old freecode API, it might as well be more convenient). Please note that most fields are entirely optional still:

  • The project name is derived from the /projects/name.json request URL.
  • If the project title is omitted, the project basename will be used simply.
  • A project description text could also be submitted via PUT (update_core) later.
  • The image can contain an application screenshot URL. If left out, a homepage screenshot will be generated automatically / as usual.
  • With submitter you could define an author name. Or a gravatar email address, or user@github, user@launchpad, user@sourceforge icon. Both are optional.
  • Optionally declare the current version.
  • Or submit the current changelog right along.
  • And of course you can submit all the fields that "update_core" already accepts:
    • Project homepage
    • and download URL
    • the license
    • and tags
    • release state (alpha, beta, stable)
    • and scope (minor bugfix, major feature)
  • CREATE basically can make a subsequent PUT redundant. (The additional fields should probably be made accessible via PUT/update_core too..)

Auth_code: A project can only be created once. Which is because this request populates the project authorization hash. The unencrypted auth_code from the CREATE payload is used for that. (It's bcrypt-hashed internally, and stored in our lock database field..)

SSL Authorization: Still undecided. CREATE requests require a client SSL certificate to be sent along.

  • This is not a security feature. Just obscures the API access to avert spambot submissions. (Perhaps redundant, because <form> spam is more likely, and the API is complicated enough as it is. But enforcing a SSL cert pretty much rules out typical Windows trojan botnets.)
  • And there's no need for custom SSL certs. A single publically-known private cert can be used. It's available under fossil:doc/trunk/doc/submit.pem (f18b1aba613ac804).
  • If you want to use a custom cert, just mail in the serial number (openssl x509 -noout -text -in s.pem) for registration.

Response JSON

When operations succeeded, the response will usually come with HTTP code 200 or 201, and include a JSON body of {"success": true}.

Whereas errors can result in HTTP codes 503, 500, 401 with a message body of {"error": "details..."}.


If you just want to browse trough projects, then the plain freshcode feed is simpler to deal with. It's available as http://freshcode.club/feed/xfer or per-project with http://freshcode.club/feed/<name>.

Password setup

To utilize remote updates, you just need an extra password in your project listing. Add at least one OpenID handle and a password hash in the Lock field. (Trust me, you need both!). As of now, projects can be registered with a password lock right away. The /login page provides for a per-project password login.

Otherwise, you can manually adapt the lock field in the submit form. To use OpenID and/or a password:

 http://your.openid.com/, $1$rua41x5V$mZHrJHKySV0uXfLA4EjEz0

You can generate a password hash using:

For freshcode-submit list the plain password in your ~/.netrc file:

machine freshcode
  account pw123
  password none

Afterwards submitting release updates is as simple as

freecode-submit -P name -v 2.0 -c "Changes.."

A complete patch is currently in preparation.