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.
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:
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.
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 |
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.
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:
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 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.
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
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" ] },
]
);
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.
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.
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 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>
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
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>
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.
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.
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>
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>
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))
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.
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:
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 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 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.
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.
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.
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).
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.
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 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.
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:
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.
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.
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
These methods can be invoked all in one RPC request; you cannot, however, invoke the same method twice in one request.
Create one or more galleries.
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:
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.
<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>
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.
GET /interface/simple HTTP/1.x
Host: pics.livejournal.com
X-FB-Mode: GetChallenge
Arguments: this method doesn't take arguments.
<FBResponse>
<GetChallengeResponse>
<Challenge>xBEP6yMKmyHO8vS8edbDJCjeKREBouH3pBEOFNoYakKgEH0FFC-1361188800-6228f485345a637ee16d2e2015035c32</Challenge>
</GetChallengeResponse>
</FBResponse>
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.
GET /interface/simple HTTP/1.x
Host: pics.livejournal.com
X-FB-Mode: GetChallenges
X-FB-GetChallenges.Qty: 3
Arguments:
<FBResponse>
<GetChallengesResponse>
<Challenge>gb2WGYtnHbqOYIOtpZ4L5ZZhoNJHbtwJQOeVMbQb6xyLhqmavh-1361188800-dc740afb224a4506b7f55f21aa24a38a</Challenge>
<Challenge>ghFSXIIO2FXHsSagINi7165QmvnTzN0bk5T2567U4cDphK6gKY-1361188800-528e6da94235bd65137abda3a645a3a9</Challenge>
<Challenge>DEyf9ggybI4uvdI5InAcUzbfWUykHNfhCcTvpxvlGERKptdKLh-1361188800-7e69ef65a87aaaaf7bf902f35798bcd5</Challenge>
</GetChallengesResponse>
</FBResponse>
Get information about the user's galleries.
GET /interface/simple
Host: pics.livejournal.com
X-FB-User: bob
X-FB-Mode: GetGals
X-FB-Auth: crp:0123456789abcdef:0123456789abcdef
Arguments:
<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.
OBSOLETE: Get gallery information in a tree-like structure, considering nested galleries (but effectively the same as GetGals).
GET /interface/simple
Host: pics.livejournal.com
X-FB-User: bob
X-FB-Mode: GetGalsTree
X-FB-Auth: crp:0123456789abcdef:0123456789abcdef
Arguments:
<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.
Retrieve information about all of a user's currently stored pictures.
GET /interface/simple
Host: pics.livejournal.com
X-FB-User: bob
X-FB-Mode: GetPics
X-FB-Auth: crp:0123456789abcdef:0123456789abcdef
Arguments:
<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>
Get information about security groups and their members.
GET /interface/simple
Host: pics.livejournal.com
X-FB-User: bob
X-FB-Mode: GetSecGroups
X-FB-Auth: crp:0123456789abcdef:0123456789abcdef
Arguments:
<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" 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.
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:
<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>
Declare intent to upload one or more files, get receipts used to upload them, do quota checks, and do duplicate file checks.
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:
An array of picture info to be checked. Values of each array element are hashes with the following keys:
<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>
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.
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:
<FBResponse>
<UploadTempFileResponse>
<Receipt>[opaque-receipt]</Receipt>
</UploadTempFileResponse>
</FBResponse>
or:
<FBResponse>
<UploadTempFileResponse>
<Error code='402'>Insufficient disk space remaining</Error>
</UploadTempFileResponse>
</FBResponse>
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.
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:
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.
A struct of meta-data to attach to the image. Only the following supported keys are recognized:
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.
<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>
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>
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 | |
| 100 | User error |
| 101 | No user specified |
| 102 | Invalid user |
| 103 | Unknown user |
| 2xx: Client Errors | |
| 200 | Client error |
| 202 | Invalid mode |
| 211 | Invalid argument |
| 212 | Missing required argument |
| 213 | Invalid image for upload |
| 3xx: Access Errors | |
| 300 | Access error |
| 301 | No auth specified |
| 302 | Invalid auth |
| 303 | Account status does not allow upload |
| 4xx: Limit Errors | |
| 400 | Limit error |
| 401 | No disk space remaining |
| 402 | Insufficient disk space remaining |
| 5xx: Server Errors | |
| 500 | Internal Server Error |
| 510 | Error creating gpic |
| 512 | Error creating gallery |
Brad Whitaker <whitaker@danga.com>, Danga Interactive
Andrey Ilyin <ailyin@sup.com>, SUP Media