Log in

Or connect using:

Introduction#

The FotoBilder client protocol is designed to provide client authors with a flexible, easy-to-use interface to the FotoBilder server. It supports a variety of ways to send and receive data via HTTP, so clients can use whichever method is best supported on their platform. There are interfaces for uploading pictures as well as retrieving useful account information and more functionality will likely be added as the need arises.

Contents of this Document#

History#

The protocol described in this document is actually the second generation of FotoBilder's original HTTP-based client protocol. The first generation worked, but was clunky and made writing clients difficult. The one 'upload' method became extremely overloaded and nothing was every fully documented or implemented. A complete rewrite was needed to make everything clean and spur more client development, so the new protocol is less of a revision and more of a complete rewrite. With the new protocol, we've focused on providing more functionality and eliminating client development obstacles.

Major design goals for the new protocol include:

Tutorial#

Data Transmission#

RPC Encoding (via HTTP transport)#

In order to pass data to the protocol, clients need to encode it in a specific way, to pass it over the network in an HTTP-standard way, in HTTP headers, query string or POST-data, or using HTTP PUT.

Valid RPC Combinations#

Sometimes more than one on the RPC encoding listed above can be employed at a time. Likewise, some RPC encodings may not be used together in the same request. For instance, a client could feasibly transmit information using HTTP headers, URL-Encoded GET arguments, as well as MIME-Encoded POST arguments, all at once. But transmitting URL-Encoded POST and MIME-Encoded POST at the same time would not work. The table below lists all possible combinations of RPC encodings.

  Headers GET PUT MIME-Enc. POST URL-Enc. POST
Headers   X X X X
GET X   X X X
PUT X X   X X
MIME-Enc. POST X X      
URL-Enc. POST X X      

Data Precedence#

The list below attempts to describe the precedence relationships between the different RPC encodings. Each data set in a single request will be processed in the order shown in the list, which should be read from top-to-bottom.

Variables and their values are read from each RPC Encoding type in the order in which they are received. As each variable is read, it will overwrite its previous value as described in the Data Structure Serialization section.

Data Structure Serialization#

HTTP is based on the idea of sending flat elements which usually consist of a key (or variable name) and a value. Since the FotoBilder protocol often uses complex data structures both in requests and responses, there needs to be a standard way to represent them in HTTP's flat space.

Here is how to represent different variable types in this key/value system:

Scalars

Encoded as "MethodName.VarName=value". So to pass the "MD5" variable to a call to the UploadPic method, while sending an Auth, you would send the following variables:

Auth = 0123456789abcdef:0123456789abcdef UploadPic.MD5 = 458601965397d1fe437d17fc359518b8 UploadPic.Size = 65535

When a scalar value is defined multiple times, it will be overwritten as each new definition is encountered according to the processing order defined in the list above.

Arrays

Arrays must be instantiated to a given size using the special '_size' attribute: "MethodName.ArrayName._size=array_size". After the initial instantiation with '_size', each element is filled in using numeric keys (which are special) based on location (indexed on 0): "MethodName.ArrayName.0=value".

To encode an array named "MyArray" with elements 0-4 (size 5) to UploadPic, you would send the following headers:

UploadPic.MyArray._size: 5 UploadPic.MyArray.0 = Value 1 UploadPic.MyArray.1 = Value 2 UploadPic.MyArray.2 = Value 3 UploadPic.MyArray.3 = Value 4 UploadPic.MyArray.4 = Value 5

When an array is defined multiple times via the '_size' key, it will be overwritten and re-instantiated as a new array of the given size. When a specific element is overwritten, it will follow the same rules as defined for scalars.

Structs

Everything is essentially a struct, so encoding them is easy:

UploadPic.MyStruct.Key1 = some value UploadPic.MyStruct.Key2 = another value UploadPic.MyStruct.Key3 = yet another value

Nesting & Combining#

Data structures can be nested in any fashion necessary. Some protocol modes require fairly complicated data structures to be represented, and these may be a little bit tricky to coerce into the encoding we use. Here's an example of a two-element array whose values are structs, each storing scalar values in a one-element array:

UploadPic.ParentArray._size = 2; UploadPic.ParentArray.0.Key1._size = 1 UploadPic.ParentArray.0.Key1.0 = Some Scalar Value UploadPic.ParentArray.1.Key2._size = 1 UploadPic.ParentArray.1.Key2.0 = Another Scalar Value

If you're a Perl person, it might be easier to visualize what's being represented above as a Perl hash:

%UploadPic = ( ParentArray => [ { Key1 => [ "Some Scalar Value" ] }, { Key2 => [ "Another Scalar Value" ] }, ] );

Encoding methods#

Our encoding method requires the passing serialized data structures to the FotoBilder server using the key/value pair representation (discussed in the Data Serialization section). Key/value pairs can be send using HTTP headers, GET requests, and either MIME or URL encoded POST requests. For information about valid combinations, see the Valid RPC Combinations section.

In addition to global restrictions on what RPC encodings can be used together, there are some per-request restrictions which are defined by individual protocol methods. Particularly, any request sending binary data must be either a MIME-encoded POST or an HTTP PUT, since URL-encoding binary data greatly bloats file size.

HTTP Headers#

Any non-binary variable can be encoded using a special HTTP header whose name is the prefix "X-FB-" followed by the name of the variable to be encoded. The header value is then the same as the desired value to be sent. Making a HTTP header to represent a variable you want to send is probably the simplest way to encode data, depending on how well your HTTP library supports modification of your request headers.

Here is an example request using HTTP headers in conjunction with PUT to upload a picture:

PUT http://pics.livejournal.com/interface/simple X-FB-Mode: UploadPic X-FB-User: bob X-FB-Auth: crp:0123456789abcdef:0123456789abcdef X-FB-UploadPic.Meta.Filename: somefile.jpg Content-length: 134332 <ImageData>

Note that due to requirements set forth by section 4.2 of RFC 2616, all variable names sent via HTTP header RPC encoding will be interpretted as case-insensitive. However, variable names in other encodings are case-sensitive.

GET args#

In most situations, GET arguments are the simplest way to pass arguments. Simply URL-Encode a string of "key=value" pairs, separated by "&" and attach it to the end of the request URI.

Though it is easy, this RPC encoding is only good for sending small amounts of data. For this reason, GET arguments are perfect for protocol methods like GetChallenge which require very few variables to be sent and poor for methods like UploadPrepare which require many variables to be sent. In fact, binary data cannot be sent using the GET method, so if a protocol method requires binary data, you'll either have to use a different RPC encoding such as MIME-Encoded POST or PUT.

Here's a simple example of using GET arguments to fetch a challenge:

GET http://pics.livejournal.com/interface/simple?GetChallenge=1 HTTP/1.x

PUT#

PUT requests are allowed exclusively in conjunction with any method that accepts binary data. This is useful for the UploadPic and UploadTempFile protocol methods when a client is being written in a language that supports PUT better than MIME-encoded POST.

The binary image data received will be implicitly interpretted as the "ImageData" variable on the primary method specified by the "Mode" variable. Since the body of a PUT request is simply the binary value of one piece of information being sent, all other included variables will need to be encoded using either GET arguments or HTTP Headers.

PUT http://pics.livejournal.com/interface/simple X-FB-Mode: UploadPic X-FB-User: bob X-FB-Auth: crp:0123456789abcdef:0123456789abcdef X-FB-UploadPic.Meta.Filename: somefile.jpg Content-length: 134332 <ImageData>

POST args (URL-encoded)#

A URL-encoded POST request is another simple way to send data to the server. It's very similar to using a GET request in that you simply URL-encode a string of "key=value" pairs to represent the data you want to send. The difference comes in the way it's transmitted. Rather than being tacked onto the end of the request URI, it's sent in the body of the document you are "post"ing to the server, along with a "Content-Length" header which specifies how long your data will be.

URL-encoded POST requests are well-supported by most HTTP libraries and work great for any protocol method which doesn't require the sending of binary data. Though it is technically possible to transmit binary data using this RPC encoding, doing so bloats the size of the information being sent. Since there are several alternative methods for sending binary data to FotoBilder, it is explicitly disallowed in POST requests.

POST http://pics.livejournal.com/interface/simple HTTP/1.x Content-length: 18 GetChallenge=1

POST args (mime-encoded)#

MIME-encoded POSTs are the only RPC encoding which is valid in all protocol methods. It can transmit binary data to the server with no problems. In fact, this is how most web browsers do we uploads via HTTP. That said, it is not the most efficient method for transmitting large numbers of non-binary variables. Since each variable has to be encoded in a new MIME part of the POSTed document, there is a lot of overhead in "setting up" a new variable and sending it.

The best usage of MIME-Encoded POST requests is when making a call to the UploadPic or UploadTempFile protocol methods. All others are somewhat wasteful, but still allowed.

Here's an example of a simple request to the UploadPic protocol method:

POST http://pics.livejournal.com/interface/simple HTTP/1.x Content-Type: multipart/form-data; boundary=---------------------------115756643718031969371809661030 Content-Length: 34662 -----------------------------115756643718031969371809661030 Content-Disposition: form-data; name="Mode" UploadPic -----------------------------115756643718031969371809661030 Content-Disposition: form-data; name="User" bob -----------------------------115756643718031969371809661030 Content-Disposition: form-data; name="Auth" crp:0123456789abcdef:0123456789abcdef -----------------------------115756643718031969371809661030 Content-Disposition: form-data; name="ImageData"; filename="somefile.jpg" Content-Type: image/jpeg <ImageData>

Simple Responses#

The document returned from any "Simple" request will always be well-formed XML which you should be able to parse with your favorite XML library. Data will be enclosed in the <FBResponse> ... </FBResponse> parent element, which will contain sub-elements describing the data returned by one or more protocol methods which were invoked in your request.

Here is an example of the logical structure of what would be returned from request which contained calls to the GetChallenge and GetSecGroups protocol methods:

<FBResponse> <GetChallengeResponse> <Challenge>crp:230948209384902843</Challenge> </GetChallengeResponse> <GetSecGroupsResponse> <SecGroup id='1'> <Name>Privileged People</Name> <GroupMembers> <GroupMember id='1' user='someuser' /> <GroupMember id='2' user='otheruser' /> </GroupMembers> </SecGroup> </GetSecGroupsResponse> </FBResponse>

For information on what specific information will be contained in the XML blocks returned by each individual protocol method, see the RPC Method Documentation section.

Writing a FotoBilder Client#

Authentication#

Challenge-Response Authentication#

Instead of sending user passwords in the clear (where they can be intercepted) or using SSL (which is costly on the server end, and not always as well supported on the client side), the FotoBilder protocol uses challenge-response authentication.

The way challenge-response works, in a nutshell, is that you have to first ask for a "challenge" (which is just some opaque string, valid for one-time use within the next 14 days). Then when you go to do the real request, you include both the original challenge and the "response", which is typically a cryptographic hash the client computes made up of the challenge combined with the user's password and an optional "auth verifier" string (discussed later).

The server then verifies the challenge is legit, hasn't been used before, and the cryptographic response is computed correctly. The password never goes across the network, and the challenges can only be used once, preventing replay attacks.

Normally a challenge-response system would make the number of HTTP requests double (each request requiring fetching a challenge, and then doing the real request), but the FotoBilder protocol lets the client fetch a new challenge along with each request. So if you're doing 20 protocol requests, it only takes 21 total HTTP requests, the first one to get the process going.

Retrieving a Challenge#

In order to calculate a response, you first need to retrieve a challenge by making a call to the GetChallenge protocol mode. This can be done with a single GET request a new challenge alone or by combining the GetChallenge with an existing request (Say, an UploadPic for the previous image if uploading in serial).

Here is an example of getting a challenge using a simple GET request:

GET /interface/simple HTTP/1.x Host: pics.livejournal.com X-FB-User: bob X-FB-Mode: GetChallenge

The server will respond with a challenge for you to use:

<FBResponse> <GetChallengeResponse> <Challenge>230948209384902843</Challenge> </GetChallengeResponse> </FBResponse>
Retrieving Multiple Challenges#

If you are in a situation where you know you will eventually need a certain number of challenges, but constraints keep you from piggy-backing one challenge from each protocol request you will be making, then you can use the GetChallenges protocol method to retrieve up to 100 challenges at a time. Though the plural GetChallenges method is provided, the preferred method of requesting challenges is to make an initial request, then piggy-back more challenges on subsequent requests.

Here is an example of getting 3 challenges using a GET request:

GET /interface/simple HTTP/1.x Host: pics.livejournal.com X-FB-User: bob X-FB-Mode: GetChallenges X-FB-GetChallenges.Qty: 3

The server will respond GetChallenges.Qty challenges:

<FBResponse> <GetChallengesResponse> <Challenge>ToOEY9OegNjvdI6Q0WmrZZ72aBqcsbtsi9azsWqt</Challenge> <Challenge>Tc2zWP1hIHZPYUJCdjWDjIwsmBTkvBYr5334GmJo</Challenge> <Challenge>v3OppsYmzLDgN7giAsAMJGyAunph7ePzZkdzNpLt</Challenge> </GetChallengesResponse> </FBResponse>
Calculating a Response#

Once you have a challenge from the server, you'll need to combine it with some "secret" data that only you and the FotoBilder know. This is done using the MD5 Hash Algorithm to compute a hash of your password and the authentication challenge. Most languages have libraries to do this for you, so it's not nearly as scary as it sounds.

In the simplest case, you need to compute the following. The output will be your "Auth" token which can be sent to the server along with any protocol request for the next 30 seconds. Note the "crp:" prefix before the computed string. This is just to indicate to the server that the authentication string is of type challenge-response

crp:challenge_string:MD5(challenge_string, MD5(user_password))
Validating Username/Passwords#

To check if a username and password pair is valid without performing any action, you can make a protocol request without a 'Mode' argument. The server will respond with an empty FBResponse if successful, or one with an error to indicate failure. Alternatively, you can just send a Login request immediately after the first GetChallenge.

Login#

Much like the LiveJournal API, FotoBilder's client protocol has a login mode, even though it is stateless. The reason for this, rather than to establish a new stateful session, is to providate a way for clients to announce their ClientVersion as well as retrieve useful user information and server broadcast messages.

Though the name "login" is somewhat of a misnomer, the name was chosen for a number of reasons:

A typical client chain of method calls should go something like this:

  1. GetChallenge: Retrieve a bootstrap challenge
  2. Login: Check the challenge and get quota info / announcements
  3. Optionally GetPics, GetGals, GetSecGroups, etc., to refresh gallery and picture information stored locally.
  4. UploadPrepare: See which images need to be uploaded
  5. UploadPic: Upload pictures

Obviously actual client flows will vary and many calls can be piggy-backed with others in the same request, but the point is that a Login request should generally be done directly after the first GetChallenge. Here is an example of what a request might look like:

GET /interface/simple HTTP/1.x Host: pics.livejournal.com X-FB-User: bob X-FB-Mode: Login X-FB-Auth: crp:0123456789abcdef:0123456789abcde X-FB-Login.ClientVersion: MyClient/1.0

The response will look something like this:

<FBResponse> <LoginResponse> <Message>hola</Message> <Quota> <Remaining>4291553280</Remaining> <Total>4294966272</Total> <Used>3412992</Used> </Quota> </LoginResponse> </FBResponse>

As a final note, the nature of the Login protocol mode lends itself to frequent change. We may change the protocol in the future to provide some other useful information in Login responses. Since the contents may change, you should be careful to handle unexpected or missing data gracefully in your client application.

Uploading#

Uploading a Single Picture#

Uploading a single picture requires exactly two HTTP requests. One is required to fetch a challenge from the server, then a second is needed to actually send the image data to the server. Here is an example:

First Request

GET /interface/simple HTTP/1.x Host: pics.livejournal.com X-FB-User: bob X-FB-Mode: GetChallenge

Second Request

PUT /interface/simple HTTP/1.x Host: pics.livejournal.com X-FB-User: bob X-FB-Mode: UploadPic X-FB-Auth: crp:<challenge_string>:<response> X-FB-AuthVerifier: md5=bbf4cf5c9c38f3b3c0ff13f0216cd275&mode=UploadPic X-FB-UploadPic.MD5: bbf4cf5c9c38f3b3c0ff13f0216cd275 X-FB-UploadPic.PicSec: 255 X-FB-UploadPic.Meta.Filename: DSCN1205.JPG X-FB-UploadPic.Gallery._size: 1 X-FB-UploadPic.Gallery.0.GalName: My New Gallery X-FB-UploadPic.Gallery.0.GalSec: 255 Content-Length: 234324

Uploading Multiple Pictures#

Uploading multiple pictures is a little different from uploading just one. One request is still required to fetch the initial challenge, but there's an optional second step which allows the client to declare what files it is about to upload and get receipts to send with the subsequent upload requests. This gives the server a chance to say if it already has the image data. In the case that an image is already "known" by the server, the client will not need to send the image data in the UploadPic request for that image.

The advantage of going through the UploadPrepare step is that if many images are to be uploaded and there's a possibility that the user already has one of the images uploaded, the sending of image data for duplicate images can be skipped by just including a receipt with the UploadPic request when the time comes. This is extremely useful in the case of an interrupted upload that needs to be resumed, so the extra one HTTP request per transaction is well worth it.

After step 1 and the optional step 2, UploadPic requests are most likely made in serial, each requesting a new challenge for the next request, until all of the images have been uploaded. Here is a sample set of requests for uploading 3 images:

First Request: Get Challenge #1

GET /interface/rest/GetChallenge HTTP/1.x Host: pics.livejournal.com X-FB-User: bob

Second Request: Get Upload Receipts and Challenge #2

POST /interface/simple HTTP/1.x Host: pics.livejournal.com X-FB-User: bob X-FB-Mode: UploadPrepare X-FB-Auth: crp:0123456789abcdef:0123456789abcdef X-FB-AuthVerifier: mode=UploadPrepare X-FB-GetChallenge: 1 X-FB-UploadPrepare.Pic._size: 3 X-FB-UploadPrepare.Pic.0.MD5: 258601965397d1fe437d17fc359518b8 X-FB-UploadPrepare.Pic.0.Magic: 2f3a4fccca6406e35bcf X-FB-UploadPrepare.Pic.0.Size: 224234 X-FB-UploadPrepare.Pic.1.MD5: 158601965397d1fe437d17fc359518b8 X-FB-UploadPrepare.Pic.1.Magic: 1f3a4fccca6406e35bcf X-FB-UploadPrepare.Pic.1.Size: 124234 X-FB-UploadPrepare.Pic.2.MD5: 358601965397d1fe437d17fc359518b8 X-FB-UploadPrepare.Pic.2.Magic: 3f3a4fccca6406e35bcf X-FB-UploadPrepare.Pic.2.Size: 324234 Content-Length: 0 <Content-Length is zero because we encoded all of our variables in headers, so the POST has no content in this case.>

Third Request: Upload Image #1, Get Challenge #3

PUT /interface/simple HTTP/1.x Host: pics.livejournal.com X-FB-User: bob X-FB-Mode: UploadPic X-FB-Auth: crp:0123456789abcdef:0123456789abcdef X-FB-AuthVerifier: md5=258601965397d1fe437d17fc359518b8&mode=UploadPic X-FB-GetChallenge: 1 X-FB-UploadPic.MD5: 258601965397d1fe437d17fc359518b8 X-FB-UploadPic.ImageSize: 324234 X-FB-UploadPic.Sec: 255 X-FB-UploadPic.Meta.Filename: DSCN1205.JPG X-FB-UploadPic.Gallery._size: 1 X-FB-UploadPic.Gallery.0.GalName: My Existing Gallery Content-Length: 234324 <ImageData>

Fourth Request: Upload Image #2, Get Challenge #4

POST /interface/simple HTTP/1.x Host: pics.livejournal.com X-FB-User: bob X-FB-Mode: UploadPic X-FB-Auth: crp:<challenge_string>:<response> X-FB-AuthVerifier: md5=158601965397d1fe437d17fc359518b8&mode=UploadPic X-FB-GetChallenge: 1 X-FB-UploadPic.Receipt: 0123456789abcdef X-FB-UploadPic.MD5: 158601965397d1fe437d17fc359518b8 X-FB-UploadPic.Sec: 255 X-FB-UploadPic.Meta.Filename: DSCN1205.JPG X-FB-UploadPic.Gallery._size: 1 X-FB-UploadPic.Gallery.0.GalName: My Existing Gallery Content-Length: 0 [no content sent, we have a receipt and the server already has the data]

Fifth Request: Upload Image #3

PUT /interface/simple HTTP/1.x Host: pics.livejournal.com X-FB-User: bob X-FB-Mode: UploadPic X-FB-Auth: crp:<challenge_string>:<response> X-FB-AuthVerifier: md5=358601965397d1fe437d17fc359518b8&mode=UploadPic X-FB-GetChallenge: 1 X-FB-UploadPic.MD5: 358601965397d1fe437d17fc359518b8 X-FB-UploadPic.ImageSize: 324234 X-FB-UploadPic.Sec: 255 X-FB-UploadPic.Meta.Filename: DSCN1205.JPG X-FB-UploadPic.Gallery._size: 1 X-FB-UploadPic.Gallery.0.GalName: My Existing Gallery Content-Length: 324234 [no receipt for this image, send full ImageData in POST content]

As you can see, uploading n pictures requires either n+1 or n+2 HTTP requests.

Uploading Temporary Files#

The FotoBilder protocol has a method called "UploadTempFile" which allows clients to upload an image via HTTP PUT or MIME-Encoded POST to be stored for 30 seconds, then receive a recipt to upload it via a subsequent request later.

Below is an example of how to upload a temporary file using HTTP PUT:

PUT /interface/rest/UploadTempFile HTTP/1.x Host: pics.livejournal.com X-FB-User: bob X-FB-Auth: crp:<challenge_string>:<response> X-FB-AuthVerifier: md5=358601965397d1fe437d17fc359518b8&mode=UploadTempFile Content-Length: 324234 <ImageData>

The server will respond with a receipt for the image just uploaded, which will be good for 30 seconds. This can be used in any subsequent UploadPic request to "upload" the temporary file with given gallery membership and security.

Fetching#

Fetching Galleries#

In order to provide a gallery selection widget to users, you'll likely want to fetch a list of galleries from the server. To do this, use the GetGals protocol mode. It returns a flat representation of all the galleries a user has, as well as pictures in each gallery. Here's an example of how this method works:

GET /interface/simple HTTP/1.x Host: pics.livejournal.com X-FB-User: bob X-FB-Mode: GetGals X-FB-Auth: crp:<challenge_string>:<response> X-FB-AuthVerifier: md5=358601965397d1fe437d17fc359518b8&mode=GetGals

See the GetGals method page for a reference to the structure of the XML response from the server.

Each Gal block returned contains individual attributes of the gallery (Name, Sec, Date, etc), and a list of all pictures in the gallery.

Fetching User's Pictures#

You may wish to retrieve a list of all pictures a user has uploaded. This can be useful in a number of situations:

The ideas above are just that, ideas. Really there is no specific purpose for the GetPics method, but it's bound to be useful in a number of situations that only the oh-so-clever client authors of the world will foresee. Here's an example of how to use it:

GET /interface/simple HTTP/1.x Host: pics.livejournal.com X-FB-User: bob X-FB-Mode: GetPics X-FB-Auth: crp:<challenge_string>:<response> X-FB-AuthVerifier: md5=358601965397d1fe437d17fc359518b8&mode=GetPics

Account for the possibility that the server response returned by this method will likely be very large, so you'll want to limit calls to it and perhaps give the user some sort of status indicator. Also remember that data in the 'Meta' response element is just that: meta-data. So though meta-data elements such as 'title', 'description', and 'filename' are extremely useful, you'll need to always be sure to account for the possibility that they are completely undefined; both when parsing server responses and planning UI (if you have one).

Getting Image Content#

Once a list or tree of pictures has been fetched using GetPics, the <URL> element of each image gives the URL at which the full-resolution image can be obtained using HTTP GET. Typically this takes the following form:

http://ic.pics.livejournal.com/username/9409131/557209/557209_original.jpg

"557209" is an identifier for the image (and 9409131 is an identifier for the user). The image will only be available if the proper credentials are present -- either a web session cookie or the X-FB-Auth header.

Gallery Formatting#

To get to the gallery page of the image, remove the 'basename' from the above URL:

http://ic.pics.livejournal.com/username/9409131/557209/
Thumbnails#

Thumbnails can be obtained for any image by replacing the 'original' part in the URL in the XML response by specific pre-defined numbers:

An example thumbnail URL:

http://ic.pics.livejournal.com/username/9409131/557209/557209_900.jpg

These would return thumbnails of the image resized to fit into a square of the corresponding size, maintaining the aspect ratio. The '100' resize here is an exception - requesting that would return an image cropped to a square and then resized to 100×100 exactly.

Fetching Security Groups#

Pictures and galleries have securities independent of one another. For a particular picture or album, the security is determined by a 'security number', ranging from 0 to 255. The 'security number' breakdown is as follows:

0: Private
Viewable only by the owner
1-30: User-Defined Security Groups
Arbitrary user-defined list of trusted users
31-252: Reserved for system use
These security groups reserved for future system use. Ignore them for now.
254: All friends
Viewable all users listed as friends by the owner
253, 255: Public
Public, for the whole world to see

The server will return proper names and IDs for each security group, so you don't really need to worry too much about the different types. However, if you want to break them up into different categories or give special icons to different groups (in a drop-down, for instance) you'll need to understand the significance of the security IDs.

Creating#

Creating Galleries#

There are two methods provided for creating galleries. Which one to use depends on the flow of your client application and what is most convenient.

UploadPic
When uploading a picture via the UploadPic protocol method, you have the option of specifying which galleries the picture should be added to by a combination of GalName and Path down the gallery tree from the root. When Specifying either a GalName or Path + GalName, new galleries will be created as necessary in order to create the gallery structure you specify. For more details about how this works, see the uploading tutorial and UploadPic method documentation.
CreateGals
There is a protocol method intended explicitly for creating one or more new galleries. You may specify a ParentID to create each new gallery under, or a list of GalNames to be auto-vivified as a path from the gallery root. In any case, you must specify a GalName for the new gallery to be created. If both Path and ParentID are ommitted, then the gallery will be created top-level.

The following is an example of a CreateGals request which creates two galleries.

GET /interface/simple HTTP/1.x Host: pics.livejournal.com X-FB-User: bob X-FB-Mode: CreateGals X-FB-Auth: crp:<challenge_string>:<response> X-FB-CreateGals.Gallery._size: 2 X-FB-CreateGals.Gallery.0.ParentID: 0 X-FB-CreateGals.Gallery.0.GalName: End of the World Party, 2001 X-FB-CreateGals.Gallery.0.GalSec: 0 X-FB-CreateGals.Gallery.1.GalDate: 2002-09-17 X-FB-CreateGals.Gallery.1.GalName: End of the World Party, 2002 X-FB-CreateGals.Gallery.1.GalSec: 255

Technical Information#

RPC Method Documentation#

These methods can be invoked all in one RPC request; you cannot, however, invoke the same method twice in one request.

CreateGals
Create one or more galleries.
GetChallenge
Get an authentication challenge for future usage in other methods requiring authentication.
GetChallenges
Get up to 100 authentication challenges for future usage in other methods requiring authentication.
GetGals
Get information about the user's galleries.
GetGalsTree
OBSOLETE: Get gallery information in a tree-like structure, considering nested galleries (but effectively the same as GetGals).
GetPics
Get information about the user's pictures.
GetSecGroups
Get information about the user's defined security groups.
Login
"Login" via the client protocol and retrieve any messages from the system, quota information, etc.
UploadPrepare
Declare intent to upload one or more files, get receipts used to upload them, do quota checks, and do duplicate file checks.
UploadTempFile
Upload a file for temporary storage and get a receipt back to use in a subsequent UploadPic request.
UploadPic
Upload a picture and place it in a new or existing galllery.

CreateGals#

Create one or more galleries.

Request#

GET /interface/simple Host: pics.livejournal.com X-FB-User: bob X-FB-Mode: CreateGals X-FB-Auth: crp:0123456789abcdef:0123456789abcdef X-FB-CreateGals.Gallery._size: 3 X-FB-CreateGals.Gallery.0.ParentID: 0 X-FB-CreateGals.Gallery.0.GalName: End of the World Party, 2002 X-FB-CreateGals.Gallery.0.GalSec: 0 X-FB-CreateGals.Gallery.1.GalName: End of the World Party, 2003 X-FB-CreateGals.Gallery.1.GalSec: 0 X-FB-CreateGals.Gallery.2.Path._size: 2 X-FB-CreateGals.Gallery.2.Path.0: Parties X-FB-CreateGals.Gallery.2.Path.1: End of the World X-FB-CreateGals.Gallery.2.GalName: End of the World Party, 2004 X-FB-CreateGals.Gallery.2.GalSec: 255

Arguments:

User
Username to authenticate as
Auth
Valid challenge/response authentication token
Gallery (array)

An array of Gallery structs describing the galleries to be created. Each struct must contain a GalName and optionally a ParentID or Path, but not both.

GalName
A string specifying the name of the gallery to be created.
GalSec (optional)
The security level of the gallery to be created. Defaults to 255 (public).

Response#

<FBResponse> <CreateGalsResponse> <Gallery> <GalID>30828</GalID> <GalName>End of the World Party, 2002</GalName> <GalURL>http://username.livejournal.com/pics/catalog/30828</GalURL> </Gallery> <Gallery> <GalID>31117</GalID> <GalName>End of the World Party, 2003</GalName> <GalURL>http://username.livejournal.com/pics/catalog/31117</GalURL> </Gallery> <Gallery> <GalID>31396</GalID> <GalName>End of the World Party, 2004</GalName> <GalURL>http://username.livejournal.com/pics/catalog/31396</GalURL> </Gallery> </CreateGalsResponse> </FBResponse>

GetChallenge#

Get an authentication challenge for future usage in other methods requiring authentication.

Note: Challenge is an opaque string. Its length may change in future, but there will be a single-line of text always, without whitespace. There could possibly be special characters that should be URL-escaped when sending later. Challenge is valid for one-time use and expire 14 days after creation.

Request#

GET /interface/simple HTTP/1.x Host: pics.livejournal.com X-FB-Mode: GetChallenge

Arguments: this method doesn't take arguments.

Response#

<FBResponse> <GetChallengeResponse> <Challenge>xBEP6yMKmyHO8vS8edbDJCjeKREBouH3pBEOFNoYakKgEH0FFC-1361188800-6228f485345a637ee16d2e2015035c32</Challenge> </GetChallengeResponse> </FBResponse>

GetChallenges#

Get up to 100 authentication challenges for future usage in other methods requiring authentication.

Note: Challenge is an opaque string. Its length may change in future, but there will be a single-line of text always, without whitespace. There could possibly be special characters that should be URL-escaped when sending later. Challenge is valid for one-time use and expire 14 days after creation.

Request#

GET /interface/simple HTTP/1.x Host: pics.livejournal.com X-FB-Mode: GetChallenges X-FB-GetChallenges.Qty: 3

Arguments:

Qty
The quantity of challenges being requested. At least 1 is required, max is 100.

Response#

<FBResponse> <GetChallengesResponse> <Challenge>gb2WGYtnHbqOYIOtpZ4L5ZZhoNJHbtwJQOeVMbQb6xyLhqmavh-1361188800-dc740afb224a4506b7f55f21aa24a38a</Challenge> <Challenge>ghFSXIIO2FXHsSagINi7165QmvnTzN0bk5T2567U4cDphK6gKY-1361188800-528e6da94235bd65137abda3a645a3a9</Challenge> <Challenge>DEyf9ggybI4uvdI5InAcUzbfWUykHNfhCcTvpxvlGERKptdKLh-1361188800-7e69ef65a87aaaaf7bf902f35798bcd5</Challenge> </GetChallengesResponse> </FBResponse>

GetGals#

Get information about the user's galleries.

Request#

GET /interface/simple Host: pics.livejournal.com X-FB-User: bob X-FB-Mode: GetGals X-FB-Auth: crp:0123456789abcdef:0123456789abcdef

Arguments:

User
Username to authenticate as
Auth
Valid challenge/response authentication token

Response#

<FBResponse> <GetGalsResponse> <Gal id='31117' sortorder='31117' incoming='1'> <Name>My Gallery</Name> <Sec>255</Sec> <Date>2004-01-01 01:01:01</Date> <TimeUpdate>1096989775</TimeUpdate> <URL>http://username.livejournal.com/pics/catalog/31117</URL> <GalMembers> <GalMember id='1' /> <GalMember id='2' /> </GalMembers> <ParentGals></ParentGals> <ChildGals></ChildGals> </Gal> <Gal id='31396' sortorder='31396'> ... </Gal> </GetGalleriesResponse> </FBResponse>

Note: ParentGals and ChildGals here are returned empty for backwards-compatibility; fotobilder used to have nested galleries before but this is now obsolete.

GetGalsTree#

OBSOLETE: Get gallery information in a tree-like structure, considering nested galleries (but effectively the same as GetGals).

Request#

GET /interface/simple Host: pics.livejournal.com X-FB-User: bob X-FB-Mode: GetGalsTree X-FB-Auth: crp:0123456789abcdef:0123456789abcdef

Arguments:

User
Username to authenticate as
Auth
Valid challenge/response authentication token

Response#

<FBResponse> <GetGalsResponse> <RootGals> <Gal id='31117' sortorder='31117' incoming='1'> <Name>My Gallery</Name> <Sec>255</Sec> <Date>2004-01-01 01:01:01</Date> <TimeUpdate>1096989775</TimeUpdate> <URL>http://username.livejournal.com/pics/catalog/31117</URL> <GalMembers> <GalMember id='1' /> <GalMember id='2' /> </GalMembers> <ParentGals></ParentGals> <ChildGals></ChildGals> </Gal> <Gal id='31396' sortorder='31396'> ... </Gal> </RootGals> <UnreachableGals></UnreachableGals> </GetGalleriesResponse> </FBResponse>

Note: ParentGals and ChildGals here are returned empty for backwards-compatibility; fotobilder used to have nested galleries before but this is now obsolete. Similarly, UnreachableGals is returned empty because all galleries are considered top-level now.

GetPics#

Retrieve information about all of a user's currently stored pictures.

Request#

GET /interface/simple Host: pics.livejournal.com X-FB-User: bob X-FB-Mode: GetPics X-FB-Auth: crp:0123456789abcdef:0123456789abcdef

Arguments:

User
Username to authenticate as
Auth
Valid challenge/response authentication token

Response#

<FBResponse> <GetPicsResponse> <Pic id='557209'> <Sec>0</Sec> <Width>2048</Width> <Height>3072</Height> <Bytes>1280381</Bytes> <Format>image/jpeg</Format> <MD5>458601965397d1fe437d17fc359518b8</MD5> <URL>http://ic.pics.livejournal.com/username/9409131/557209/557209_original.jpg</URL> <Meta name='filename'>557209_original.jpg</Meta> <Meta name='title'>This is my test file!</Meta> <Meta name='description'>OMG This is a description of my first image LOL!!!</Meta> </Pic> <Pic> ... </Pic> </GetPicsResponse> <FBResponse>

GetSecGroups#

Get information about security groups and their members.

Request#

GET /interface/simple Host: pics.livejournal.com X-FB-User: bob X-FB-Mode: GetSecGroups X-FB-Auth: crp:0123456789abcdef:0123456789abcdef

Arguments:

User
Username to authenticate as
Auth
Valid challenge/response authentication token

Response#

<FBResponse> <GetSecGroupsResponse> <SecGroup id='1'> <Name>Privileged People</Name> <GroupMembers> <GroupMember id='1' user='someuser' /> </GroupMembers> </SecGroup> <SecGroup id='254'> <Name>All Friends</Name> <GroupMembers> <GroupMember id='1' user='someuser' /> </GroupMembers> </SecGroup> </GetSecGroupsResponse> </FBResponse>

Login#

"Login" via the client protocol and retrieve any messages from the system, quota information, etc.

Note: Since the FotoBilder client protocol is stateless, this login method is optional, though encouraged as it allows clients to display system broadcast messages to the user and retrieve other useful information.

As described in the notes section above, this mode is completely optional due to the stateless nature of the protocol. The name is somewhat of a misnomer, but it still makes a lot of sense and there is precedent in the LiveJournal client protocol.

The Login method is meant to be an extensible method which can return useful data that client authors request. Initially, quota information will be returned in the same way it is returned via the UploadPrepare method:

Due to the extensible nature of this method, it is recommended that you take extra care to make sure that you properly handle cases where new data may be present, or expected data may be missing.

Request#

GET /interface/simple HTTP/1.x Host: pics.livejournal.com X-FB-User: bob X-FB-Mode: Login X-FB-Auth: crp:0123456789abcdef:0123456789abcdef X-FB-Login.ClientVersion: MyFBClient/1.0

Arguments:

User
Username to fetch challenge for
Auth
Valid challenge/response authentication token

Response#

<FBResponse> <LoginResponse> <ServerTime>2005-06-10 16:25:23</ServerTime> <Message>hola</Message> <Quota> <Remaining>4291553280</Remaining> <Total>4294966272</Total> <Used>3412992</Used> </Quota> </LoginResponse> </FBResponse>

UploadPrepare#

Declare intent to upload one or more files, get receipts used to upload them, do quota checks, and do duplicate file checks.

Request#

GET /interface/simple HTTP/1.x Host: pics.livejournal.com X-FB-User: bob X-FB-Mode: UploadPrepare X-FB-Auth: crp:0123456789abcdef:0123456789abcdef X-FB-UploadPrepare.Pic._size: 2 X-FB-UploadPrepare.Pic.0.MD5: 458601965397d1fe437d17fc359518b8 X-FB.UploadPrepare.Pic.0.Magic: 2f3a4fccca6406e35bcf X-FB.UploadPrepare.Pic.0.Size: 324234234 X-FB-UploadPrepare.Pic.1.MD5: 158601965397d1fe437d17fc359518b8 X-FB-UploadPrepare.Pic.1.Magic: 1f3a4fccca6406e35bcf X-FB-UploadPrepare.Pic.1.Size: 124234234

Arguments:

User
Username to authenticate as
Auth
Valid challenge/response authentication token
Pic (array)

An array of picture info to be checked. Values of each array element are hashes with the following keys:

MD5
A hex MD5 hash of the image
Magic
The first 10 bytes, encoded in hex.
Size
The size of the image

Response#

<FBResponse> <UploadPrepareResponse> <Quota> <Total>1048576</Total> <Used>524288</Used> <Remaining>524288</Remaining> </Quota> <Pic known='0'> <MD5>458601965397d1fe437d17fc359518b8</md5> </Pic> <Pic> <MD5>458601965397d1fe437d17fc359518b8</MD5> <Error code='213'>Invalid image for upload</Error> </Pic> </UploadPrepareResponse> </FBResponse>

UploadTempFile#

Upload a file for temporary storage and get a receipt back to use in a subsequent UploadPic request.

Note: This method may either be done via a MIME-Encoded POST request or an HTTP PUT. URL-Encoded requests will not be accepted.

Request#

PUT /interface/simple HTTP/1.x Host: pics.livejournal.com X-FB-User: bob X-FB-Mode: UploadTempFile X-FB-Auth: crp:0123456789abcdef:0123456789abcdef Content-Length: 12345 <image data>

Arguments:

User
Username to authenticate as
Auth
Valid challenge/response authentication token
ImageData
The actual data of the image being uploaded. This variable is implicitly filled in with any data sent via HTTP PUT, but needs to be explicitly defined if using MIME-encoded POST.
ImageLength
The size of file being uploaded, if any. This variable is implicitly filled in via the request "Content-Length" header for HTTP PUT requests, but must be explicitly defined if using MIME-encoded POST.

Response#

<FBResponse> <UploadTempFileResponse> <Receipt>[opaque-receipt]</Receipt> </UploadTempFileResponse> </FBResponse>

or:

<FBResponse> <UploadTempFileResponse> <Error code='402'>Insufficient disk space remaining</Error> </UploadTempFileResponse> </FBResponse>

UploadPic#

Upload a picture and place it in a new or existing galllery.

Note: Can't do a photo upload through GET args or URL-encode post args without first retrieving an upload receipt via the UploadTempFile method.

Request#

Simple example using HTTP PUT:

PUT /interface/simple HTTP/1.x Host: pics.livejournal.com X-FB-User: bob X-FB-Mode: UploadPic X-FB-Auth: crp:0123456789abcdef:0123456789abcdef X-FB-AuthVerifier: md5=bbf4cf5c9c38f3b3c0ff13f0216cd275&mode=UploadPic X-FB-UploadPic.MD5: bbf4cf5c9c38f3b3c0ff13f0216cd275 X-FB-UploadPic.ImageLength: 234324 X-FB-UploadPic.PicSec: 255 X-FB-UploadPic.Meta.Filename: DSCN1205.JPG X-FB-UploadPic.Gallery._size: 3 X-FB-UploadPic.Gallery.0.GalName: End of the World Party, 2002 X-FB-UploadPic.Gallery.0.GalSec: 255 X-FB-UploadPic.Gallery.1.GalID: 233 X-FB-UploadPic.Gallery.2.GalID: 23 Content-Length: 234324 <image-data>

Arguments:

User
Username to authenticate as
Auth
Valid challenge/response authentication token
ImageData
The actual data of the image being uploaded. This variable is implicitly filled in with any data sent via HTTP PUT, but needs to be explicitly defined if using MIME-encoded POST.
ImageLength
The size of file being uploaded, if any. This variable is implicitly filled in via the request "Content-Length" header for HTTP PUT requests. Although this variable is not required, it is good practice to always fill this variable in. If present, it will be sanity-checked against the received data to make sure there was no error in transmission or in client libraries.
Receipt
A receipt given from the UploadPrepare method indicating that the data you wish to upload is already stored somewhere on our servers, so there's no need to retransmit the data. If this is the case, simply send the receipt as the 'Receipt' variable and omit ImageLength and ImageData.
Gallery (array)

An array containing not more than one gallery struct specifying the gallery to add this image to. The struct should contain either a "GalID" or "GalName" member, not both.

If this array is empty, the image will be added to the default "Unsorted" gallery.

GalName
Put in the gallery named exactly the value you give. If the gallery doesn't exist, it will be created.
GalID
Put uploaded image in the gallery specified by the GalID. If gallery doesn't exist, an error will be returned.
GalSec
When creating a new gallery, the security level of the gallery. Defaults to 255 (public). If a gallery with the specified name already exists, its security level is not changed.
PicSec
Security value of picture. If not supplied, the default is public.
Meta

A struct of meta-data to attach to the image. Only the following supported keys are recognized:

Title
Optional user-specified title for the picture. Maximum of 255 bytes.
Description
Optional user-specified description for the picture. Maximum of 65535 bytes.

Note: you are required to pass either an ImageReceipt or a combination of ImageData and ImageLength (which may be implicit) for this method to actually have data to process. You cannot specify both ImageReceipt and ImageData - trying to do so will result in an error.

Response#

<FBResponse> <UploadPicResponse> <URL>http://ic.pics.livejournal.com/username/9409131/557209/557209_original.jpg</URL> <PicID>23</PicID> <Width>640</Width> <Height>480</Height> <Bytes>33902</Bytes> </UploadPicResponse> </FBResponse>

or

<FBResponse> <UploadPicResponse> <Error code='402'>Insufficient disk space remaining</Error> </UploadPicResponse> </FBResponse>

Response Error Messages#

Error messages are returned from protocol requests in an "Error" element under the narrowest block to which they apply. For instance, general errors with the request itself (auth, username, etc) are top-level within the "FBResponse" block:

<FBResponse> <Error code="101">No user specified</Error> </FBResponse>

Simiarly, errors with a specific method call will exist within the response block of that method:

<FBResponse> <GetChallengesResponse> <Error code="212">Missing required argument: Qty</Error> </GetChallengesResponse> </FBResponse>

Error codes in one method's block do not imply success or error in other method's block. So it is completely feasible to have a mix of errors and successes, depending on how many methods you call:

<FBResponse> <GetChallengesResponse> <Challenge>FoksLvkdbkLSZM4geSyO0UwGn0YC4dmN8DEGcB2s</Challenge> <Challenge>9k4Lj2VcDmfvuWmdllvjZzs5q6OsvzR2rFtkE1u1</Challenge> <Challenge>7CVYhnQZsV1JD67HUSb3aNzm3FGWvAC6HFozKNZC</Challenge> </GetChallengesResponse> <CreateGalsResponse> <Error code="512">Error creating gallery: Gallery aready exists: End of the World Party, 2002</Error> </CreateGalsResponse> <GetGalsResponse> <Gal id="52"> <ChildGals> </ChildGals> <Date></Date> <GalMembers> </GalMembers> <Name>End of the World Party, 2003</Name> <ParentGals> <ParentGal id="0" sortorder="0" /> </ParentGals> <Sec>0</Sec> <TimeUpdate></TimeUpdate> <URL>http://pics.whitaker.lj/whitaker/gallery/0001w99c</URL> </Gal> <Gal id="56" incoming="1"> <ChildGals> </ChildGals> <Date></Date> <GalMembers> <GalMember id="229" /> <GalMember id="230" /> </GalMembers> <Name>Unsorted</Name> <ParentGals> <ParentGal id="0" sortorder="0" /> </ParentGals> <Sec>0</Sec> <TimeUpdate>1114205993</TimeUpdate> <URL>http://pics.whitaker.lj/whitaker/gallery/00020fz2</URL> </Gal> </GetGalsResponse> <UploadPicResponse> <Error code="211">Invalid argument: PicSec</Error> </UploadPicResponse> </FBResponse>

Error Codes and Meanings#

Below is a table of possible error codes and their meanings. Note that the first number represents the class of the error, and also that the error codes are completely separate from the HTTP response codes on the request.

1xx: User Errors
100User error
101No user specified
102Invalid user
103Unknown user
 
2xx: Client Errors
200Client error
202Invalid mode
211Invalid argument
212Missing required argument
213Invalid image for upload
 
3xx: Access Errors
300Access error
301No auth specified
302Invalid auth
303Account status does not allow upload
 
4xx: Limit Errors
400Limit error
401No disk space remaining
402Insufficient disk space remaining
 
5xx: Server Errors
500Internal Server Error
510Error creating gpic
512Error creating gallery

Author#

Brad Whitaker <whitaker@danga.com>, Danga Interactive

Andrey Ilyin <ailyin@sup.com>, SUP Media

Welcome to the new LiveJournal

Some changes have been made to LiveJournal, and we hope you enjoy them! As we continue to improve the site on a daily basis to make your experience here better and faster, we would greatly appreciate your feedback about these changes. Please let us know what we can do for you!

Send feedback

Switch back to old version

LiveJournal Feedback

See a bug? Let us know! Here you can also share your thoughts and ideas about updates to LiveJournal

Your request has been filed. You can track the progress of your request at:
If you have any other questions or comments, you can add them to that request at any time.

Send another report Close feedback form

If you're a LiveJournal user, you will be logged in after submitting your request.

(optional, if you're a LiveJournal user only)

(optional, if you're a LiveJournal user only)

(not shown to the public)

If you have a billing inquiry, please go here to submit your question.

Provide a link to the page where you are experiencing the error

Do not include any sensitive information, such as your password or phone number. No HTML allowed.

If you can't pass the human test, email your inquiry to: support@livejournal.com

Welcome to LiveJournal

Create an account