API Documentation

StorageRoom is a service and platform to manage any kind of content online and to easily integrate that content into one or multiple mobile, web or desktop apps.

The StorageRoom Application Programming Interface (API) has been created to allow you to interact programmatically with StorageRoom. The StorageRoom API returns data in JSON, so that you can easily integrate the content into your application or web site. As a developer you can program a large variety of applications on top of the StorageRoom API. There are no thematic limitations, be creative and start developing for your favorite device or platform by using your programming language of choice.

API Summary

The StorageRoom API is designed in a RESTful fashion and is easy to use. It relies on simple unique tokens for access authorization and for the authentication of your application. All Resources support the JSON and JSONP Format. Open Source Libraries are available and make it even easier to use StorageRoom as the data backend for your application.

Almost all of StorageRoom's functionality can be used by your application. Some of the most important features are:

  • Search all your Entries to only get the content you require.
  • Create a new Collection that contains further Entries
  • Add new Entries (Import)
  • Update or delete any Entry
  • Load associated Entries through Relationships
  • Use Webhooks to respond to Entry modifications

Examples

Collections are the containers for your data. They are very flexible, a Collection might define the following Fields:

Restaurant

Field Description Type
Name The name of the restaurant String
Description A long description String
Stars A rating (1-5) Integer
Street Street address String
Postal Code Postal code String
City City String
Location Geo coordinate Location
Tags A list of many tags Array
Menu A PDF of the menu File
Logo Logo including auto-generated user-defined thumbnails Image
Category Association to a Category in another Collection (1:n) Association
Meta Data Additional meta data such as the date the Entry was created or last modified. Per default meta data is prefixed with "@", but you can change this.

Editors will get a simple but powerful interface to manage all those restaurants and you can query this data and display the content in your applications.

Table of Contents

The API documentation was written to be read from top to bottom. The top parts build upon each other and provide a good understanding of the API essentials.

  • Architecture: Explains the general architecture of the API and how the RESTful web service is modeled
  • Authentication: How to authenticate your application
  • Errors: HTTP Response Codes and error messages
  • Formats: Description of the various formats (JSON, JSONP)
  • Resources: What the various Resources do and what they look like
  • Embedded Resources: Explains the nested Embedded Resources
  • Search: How to find the Entries you are looking for
  • Endpoints: List of exposed Endpoints
  • Webhooks: Webhooks send a request to your own server and respond to changes
  • Demo: Browse some demo data
  • Libraries: Open Source StorageRoom libraries
  • Sample Code: Open Source example code
  • FAQ: Frequently asked questions
  • Support: What to do when you encounter problems

Getting Help

We tried our best to make the usage of our API as simple as possible. But if the API doesn't behave like you think it should, if documentation is missing or incorrect or if you have any questions, comments or suggestions, please read the support section.

Architecture

The StorageRoom API is designed in a RESTful fashion. REST (Representational State Transfer) is a set of design principles that state how Web resources can be described and manipulated via the HTTP protocol and URIs. As REST is leveraging existing Web standards it is very easy to consume RESTful web services with any programming language that can make HTTP requests. REST is an architectural style and not a formal protocol. There is no "official" way to build a RESTful web service. Our implementation focuses on simplicity and applicability.

In the next paragraphs we will briefly describe what the four key REST principles are and how they apply to the StorageRoom API. If you want to find out more about REST you can find links for further reading at the bottom of the page.

1. Every "thing" is a Resource with a unique identifier

All the "things" on StorageRoom are RESTful Resources. Resources are the nouns of the web service, they are holding all the data and they can be created, modified or removed.

All Resources need a unique identifier, so that they can be read or modified. The identifier of a Resource is not only unique within the StorageRoom API, it is globally unique in the Web by using URIs.

All the Resources within the StorageRoom API are identifiable by their full URI. Associations also depend on the full URIs to reference other Entries.

URI Description
http://api.storageroomapp.com/accounts/:account_id/collections All the Collections in an Account
http://api.storageroomapp.com/accounts/:account_id/collections/:collection_id/entries All the Entries of a Collection
http://api.storageroomapp.com/accounts/:account_id/collections/:collection_id/entries/:resource_id One specific Entry of a Collection

Take a special look at the first two URIs, as it is not a single "thing", it is an Array of "things", but the Array is still represented as a Resource with a unique URI. Everything that is worth being identified within the web service has such an URI.

If you want to refer to another element within the web service, use its full URI.

2. Resources are linked together

The Web is built out of pages, and all the pages contain links to other pages. The following is an HTML link to another page: Google's homepage. Resources in a REST web service contain links to other associated Resources, just like all the HTML pages in the Web contain links to other pages.

A link to another child Resource might look like this in the StorageRoom web service:

{
    "entry": {
        "@type": "Category",
        "@version": 3,
        "@updated_at": "2010-11-26T11:31:28Z",
        "@created_at": "2010-11-26T11:31:28Z",
        "@collection_url": "http://api.storageroomapp.com/accounts/:account_id/collections/:collection_id",
        "@url": "http://api.storageroomapp.com/accounts/:account_id/collections/:collection_id/entries/:entry_id",
        "name": "Music",          
    }
}

As you can see, the Resource contains a "@collection_url" to the Resource URI of the Collection of the Entry (http://api.storageroomapp.com/accounts/:account_id/collections/:collection_id). Associations also use Resource URIs to link to each other.

In general you should always follow the links within the documents that you receive via the API and not manually specify the appropriate URIs for Resources. This is in analogy to links that you follow on regular web pages instead of updating the address bar every time you want to surf somewhere else.

Use the links within the returned documents, it saves you the work of constructing the URI yourself and it makes your code less likely to break if an URI ever changes. This is especially true for Associations. Use the search functionality to get a response with links to many Entries.

3. Resources have different Representations

The examples above showed some JSON markup, but JSON is only one kind of representation of a Resource. Each Resource can be accessed in multiple different Representations, as shown in the following table:

URI Format
http://api.storageroomapp.com/accounts/:account_id/collections/:collection_id/entries/:entry_id.json JSON
http://api.storageroomapp.com/accounts/:account_id/collections/:collection_id/entries/:entry_id.js?callback=test JSONP
http://api.storageroomapp.com/accounts/:account_id/collections/:collection_id/entries/:entry_id Use HTTP Content-Type header

All of the above URIs represent the same data, but each time the Resource is shown in a different Format. Behind the curtain, it is always the same Resource. You can select the response format for each request that you make.

Usually you would stick with one format and always use the same parsing tool of your programming language to access the data.

There's more information about the different Resource Types in the Formats section.

4. Resources can be accessed with a set of standard methods

Great, I understood the URIs and it is nice to have the data in multiple formats, but how can I create new stuff or delete existing stuff?

There are no new URIs to create, update or delete Resources. The action that is performed on the Resource at the given URI is determined by the HTTP method that is used. So far we only created GET requests. The HTTP protocol defines more HTTP methods/verbs that can be used in a request.

Method URI Request Body Server Response Description
GET http://api.storageroomapp.com/accounts/:account_id/collections/:collection_id/entries/:entry_id empty Representation of Resource Get the Representation of the Resource in JSON
PUT http://api.storageroomapp.com/accounts/:account_id/collections/:collection_id/entries/:entry_id Modified JSON Representation of Resource Updated JSON Representation of Resource Update the Resource (change one or multiple attributes)
DELETE http://api.storageroomapp.com/accounts/:account_id/collections/:collection_id/entries/:entry_id empty empty Delete a Resource
POST http://api.storageroomapp.com/accounts/:account_id/collections/:collection_id/entries JSON Representation of the new Resource Representation of the new Resource Create a new Resource

Change the HTTP method by specifying a request method parameter in your programming language and therefore update, delete or create Resources whenever you want to. Please note that for the first three Requests the action is performed on an individual Resource URI, while the last Request to create a new Resource is sent to the collection URI.

When you want to create or update a Resource you have to send a Representation of the Resource to the web service endpoint in the JSON format. If your Request is accepted the web service will return the Representation of the new or updated Resource with additional attributes (e.g. the time it was created and child associations). If things don't work out the web service will respond with a special error message.

The HTTP methods translate nicely into the basic CRUD database operations:

HTTP method Database method Description
POST INSERT Create
GET SELECT Read
PUT UPDATE Update
DELETE DELETE Delete

GET Requests are "safe" requests, they never change anything on the server, you cannot break anything by doing a GET Request.

That's all there is on the methods. There is no collection.create_resource(value1, value2), instead, a new Resource is created with a POST request. REST is all about Resources and manipulating them with the simple HTTP methods mentioned above. This might seem limiting at first compared to RPC-style APIs, but actually the same functionality can be provided in a simpler interface. Let us know how it goes!

Further Reading

This was a basic explanation of REST and how it applies to StorageRoom. Enough for you to start exploring the StorageRoom API. The websites below will be a good starting point if you want to learn more about REST.

Authentication

Each application that you create contains a set of authentication credentials that you need to pass to our servers to authenticate yourself. A request to an Entry can only be made if the application has the corresponding access rights to the Collection. Access rights are defined through Roles in the web interface. You should keep your credentials secret, especially for Applications that have write-access to Collections.

There are two ways to pass the credentials, they are explained in the following.

Passing a query parameter

Just pass an additional query parameter called "auth_token" on all your requests to authenticate yourself. This comes in handy for situations where it is not possible to set HTTP headers.

curl "http://api.storageroomapp.com/accounts/:account_id/collections/:collection_id/entries?auth_token=YOUR_TOKEN"

Using HTTP Basic Auth

Another option is to use the same set of credentials with HTTP Basic Authentication. Just pass your token as the username and leave the password blank. This option might be easier to set up for all the HTTP requests in your HTTP library. Instead of a blank password it is possible to pass an "X".

curl --basic -u YOUR_TOKEN:X "http://api.storageroomapp.com/accounts/:account_id/collections/:collection_id/entries"

Error Handling and Error Codes

HTTP Status Codes

The HTTP protocol defines certain HTTP Status Codes that are used across the web. The table below provides an overview about the Status Codes used by the StorageRoom API. You can find a full list of all status codes on Wikipedia.

2xx Success
200 Ok Everything worked out
201 New Resource created A new Resource was created
204 No Content Everything worked out, but the server returned no content.
3xx Redirection
301 Moved Permanently The URL of the Resource changed permanently
303 Moved Temporarily The URL of the Resource is temporarily different
4xx Client Error
400 Bad Request The Request contains bad syntax or cannot be fulfilled, repeating the Request doesn't help
401 Unauthorized Authentication is possible, but has failed
402 Payment Required Your pricing plan doesn't have this feature enabled
403 Forbidden You cannot access this Resource
404 Not Found The Resource doesn't exist
405 Method Not Allowed You picked the wrong HTTP method
409 Conflict The request could not be processed because of an optimistic locking error.
422 Unprocessable Entity The Request was valid, but the Resource doesn't pass validation rules
5xx Server Error
500 Internal Server Error Something bad happened. We get notified automatically on those errors
503 Server Unavailable The system is currently down for maintenance

422 Unprocessable Entity

You wanted to create or update a Resource and received this error. This means, that the Request that you created was valid, but there were validation errors when the server tried to save the Resource. An example for this could be that you provided an invalid value for an attribute. You should show those messages to the user so that she can correct her Entry. You should not look into the elements and parse the error message, as the messages might change and they vary for different languages.

An example for an error message:

{
    "error": {
        "code": 422,
        "message": ["Name can't be empty", "Tags are not in a valid format"],
        "@type": "Error"
    }
}

Requests and Responses

All Requests to the StorageRoom API must be encoded in UTF-8. The server will return an UTF-8 encoded document.

Request Formats and how to select one is further described in the Formats section.

Optionally set the "Accept-Encoding" HTTP Header to "gzip, deflate" and we will return compressed Representations of all Resources. This is a trade-off, it requires more computing power on the client, but saves a lot of bandwidth. Your HTTP library of choice must support compression or you have to decompress the Request body manually.

Save processing power and bandwidth through caching by using HTTP ETags and the If-None-Match header.

Meta Prefix ("@")

You can change the meta data prefix for each request if you find that the "@" prefix is problematic when using your JSON or REST library of choice. An example for such a library is the excellent RestKit (Objective-C). It relies heavily on Apple's Key-Value-Coding (KVC), which doesn't allow the "@" in a key path.

Please be careful when changing the meta prefix and be certain that you use a prefix that doesn't cause collisions with the keys in your Entries. Good examples for alternative meta prefixes would be "meta_", "m_", "_" or "$".

It is possible to change the meta prefix in two ways. You should stick to one way and set this permanently in your code for all requests.

Add a Parameter to the Query String

To quickly change the meta prefix just append a parameter called "meta_prefix":

http://api.storageroomapp.com/accounts/4d13574cba05613d25000004.json?auth_token=DZHpRbsJ7VgFXhybKWmT&preview_api=1&meta_prefix=m_

Test this with our Demo Account

Set an HTTP Header

Another way to change the meta prefix is to send a custom HTTP header called "X-Meta-Prefix" with each request. An example with curl is shown below:

curl "http://api.storageroomapp.com/accounts/4d13574cba05613d25000004.json?auth_token=DZHpRbsJ7VgFXhybKWmT&preview_api=1" -H "X-Meta-Prefix: m_"

Formats

The StorageRoom API understands several different Formats, each useful in a variety of different programming contexts.

  • JSON: Easily parsed in many languages, lightweight, can be evaluated in JavaScript.
  • JSONP: Same structure as JSON, use it for cross-domain requests in older browsers
  • XML: On roadmap (Screw that, we will stick to JSON)

Specifying the Format

It is possible to specify the Format in two different ways:

  • Append the format to the URI
  • Set HTTP Headers

Append the format to the URI

This is especially useful for tools where it is not possible to set your own HTTP Headers.

To quickly view different Formats within your browser you can just surf on the StorageRoom website and click on the "JSON" buttons.

URI Format
http://api.storageroomapp.com/accounts/:account_id/collections Default format (JSON)
http://api.storageroomapp.com/accounts/:account_id/collections.json JSON (explicit)
http://api.storageroomapp.com/accounts/:account_id/collections.js?callback=test JSONP

Please notice that changing the extension just displays another Representation of the Resource. If you "delete" one Representation of the Resource all Representations will be deleted.

The format extensions can only be used to read data. If you want to modify Resources you have to set HTTP Headers as well, otherwise our Request Forgery Protection kicks in and will block your query, resulting in a returned HTML page with an HTTP Status Code of 400 (Bad Request).

Set HTTP Headers

The HTTP protocol uses HTTP Headers to specify which media type is used in a request and which media types are supported by the client for the response.

The StorageRoom web service uses the HTTP Headers to let you pick a Format. This is a translation of our Formats to the media types you should use in HTTP Headers:

Fromat Media Type
JSON application/json
JSONP application/javascript
Model your code in a way that allows you to set those HTTP Headers at one central point, so that they are included in all Requests to the StorageRoom API. This way, you will never have to worry about the headers again.

HTTP Accept Header

The HTTP protocol uses the "Accept" Header to let the client specify which media types it supports and prefers. This can be used to specify the Format of the response without using a format extension. The command line tool curl, which is available and pre-installed on many platforms, can be used to test this.

# this will return the JavaScript Representation
curl "http://api.storageroomapp.com/accounts/:account_id/collections/:collection_id/entries/:entry_id?callback=test" -H "Accept: application/javascript" 

The server will always respond in the Format that you specify in the HTTP Accept Header. However, the format extension has a higher priority than the Accept Header.

The server will specify the current media type of the response in the HTTP Content-Type Header.

HTTP Content-Type Header

The HTTP Content-Type Header specifies which format the current request or response is in. The server will set the Content-Type header in response to your requests to show which Format is returned.

If you are sending data to the StorageRoom API with a POST or PUT Request you also have to specify the Content-Type of your current request, so that the server knows how to parse the data. If you don't set the Content-Type our Request Forgery Protection kicks in and will block your query, resulting in a returned HTML page with an HTTP Status Code of 400 (Bad Request).

The JSON Format

JSON is a lightweight data format that can be parsed in all programming languages. It can be evaluated directly in JavaScript, making it easy to build widgets or web applications.

This is an example of a Resource Representation in JSON:

{
    "entry": {
        "@type": "Category",
        "@updated_at": "2010-11-26T11:31:28Z",
        "@created_at": "2010-11-26T11:31:28Z",
        "@collection_url": "http://api.storageroomapp.com/accounts/:account_id/collections/:collection_id",
        "@url": "http://api.storageroomapp.com/accounts/:account_id/collections/:collection_id/entries/:entry_id",
        "name": "Music",
        "field1": 1.1,
        "field2": "value",
        "parent_category": {
          "@type": "Category",
          "url": "http://api.storageroomapp.com/accounts/:account_id/collections/:collection_id/entries/:entry_id"
        }
    }
}

The output above is nicely formatted so that it is easier to read. The JSON output of the StorageRoom API does not contain white-spaces. Use JSON Lint to prettify JSON output, which can be useful for debugging purposes.

All elements that start with an at sign ("@") are meta data that are added by our system. Those keys are readable but cannot be modify directly. It is possible to change this prefix to another string.

The following contains an example in JavaScript. JSON can be parsed in many languages, but as JSON is a subset of JavaScript is very simple to use it in JavaScript.

var jsonString = "..."; // the String contains the content of the JSON example above
var entry = JSON.parse(jsonString).entry;
alert(entry.name); // returns the name
alert(entry["@url"]); // returns the unique URI

JavaScript cross-domain AJAX Requests with CORS

Regular JavaScript AJAX requests are subject to the same origin policy of the browser, which forbids cross-domain AJAX requests. Cross-Origin Resource Sharing (CORS) is a relatively new specification which defines ways for a web server to allow its resources to be accessed by web pages from a different domain.

Our API is configured with CORS to allow cross-domain requests. All of the latest browsers (yes, even Internet Explorer) support CORS, you don't have to do anything to get it to work. Just use regular AJAX requests from your web application to our API.

Check if your browser supports CORS.

CORS with jQuery

jQuery's ajax function facilitates AJAX requests across the different browser implementations. Take a look at the following example on how to make cross-domain AJAX requests with jQuery. More documentation on the $.ajax method can be found in the jQuery Documentation.

  $('#jquery-cors-link').click(function() {
    $.ajax({
        url: 'http://api.storageroomapp.com/accounts/:account_id/collections/:collection_id/entries.json',
        data: {
          auth_token: 'YOUR_AUTH_TOKEN',
          // meta_prefix: 'm_' // optionally set the meta prefix
          per_page: 1
        },
        dataType: 'json',
        success: function(data) {
          var entry = data.array.resources[0];
          alert("The Entry was created at: " + entry["@created_at"]);
        },
        error: function() {
          alert("An error occurred.");
        }
    });

    return false;
  });

<a href="#" id="jquery-cors-link">When was the last Entry in Demo account created? (jQuery)</a>

Try it: When was the last Entry in the Demo account created? (CORS)

If you need to support older browsers and still want to use the JSON Format for cross-domain requests you should use the JSONP Format. It is very similar to the JSON Format but allows cross-domain communication for older browsers.

The JSONP Format

The JSONP Format (JSONP) passes the JSON Response to a JavaScript callback function that you specify in a query parameter in the request. JavaScript code on a page is subject to the same-origin policy of the browser (for an exception see CORS above), so you cannot directly fetch the JSON Representation from our API with AJAX. JSONP allows cross-domain JSON Requests.

All Endpoints that can be directly fetched in the JSON Format can also be requested with JSONP by adding a callback parameter. Your callback function can display the returned JSON on your web page or process it in another way without using a proxy.

Just change the format to JSONP and add a "callback" parameter to the query parameters, which specifies the JavaScript function to use. Optionally set the "_" parameter to a random value to prevent caching, this is what jQuery is doing by default.

You don't have to use JSONP if you know your application is only accessed by modern browsers. Instead, you should use our CMS with the JSON Format and Cross-Origin Resource Sharing (CORS).

JSONP with plain old JavaScript

A simple example in plain JavaScript is following and illustrates how JSONP works:

function outputEntry(data) {
  var entry = data.array.resources[0];
  alert("The Entry was created at: " + entry["@created_at"]);
}

function getEntryWithJSONP() {
  var script = document.createElement('script');
  var url = "http://api.storageroomapp.com/accounts/:account_id/collections/:collection_id/entries.js?callback=outputEntry&per_page=1";
  script.setAttribute('src', url);

  document.getElementsByTagName('head')[0].appendChild(script); // load the script
}
<a href="#" onclick="getEntryWithJSONP(); return false;">When was the last Entry in Demo account created? (Plain JS)</a>

Try it: When was the last Entry in the Demo account created? (Plain JS)

JSONP with jQuery

The jQuery library provides handy methods that abstract JSONP requests. Take a look at the following example on how to make cross-domain JSONP requests with jQuery. More documentation on the $.ajax method can be found in the jQuery Documentation.

  $('#jquery-jsonp-link').click(function() {
    $.ajax({
        url: 'http://api.storageroomapp.com/accounts/:account_id/collections/:collection_id/entries.js',
        data: {
          auth_token: 'YOUR_AUTH_TOKEN',
          // meta_prefix: 'm_' // optionally set the meta prefix
          per_page: 1
        },
        dataType: 'jsonp',    
        success: function(data) {
          var entry = data.array.resources[0];
          alert("The Entry was created at: " + entry["@created_at"]);            
        },
        error: function() {
          alert("An error occurred.");
        }
    });
    
    return false;
  });

<a href="#" id="jquery-jsonp-link">When was the last Entry in Demo account created? (jQuery)</a>

Try it: When was the last Entry in the Demo account created? (jQuery)

Resources

Resources are all the "things" on StorageRoom that you can access and modify by using the StorageRoom API. Resources consist out of simple data types and other Embedded Resources (compound data types).

This section explains how a Resource is structured in general so that it is easier for you to parse the data. The individual Resource sections contain more information about each Resource and what it is used for.

Simple Data Types

On the lowest level Resources exist out of simple data types.

  • Strings
  • Integers
  • Floating point numbers
  • ISO8601 timestamps
  • Booleans

Compound Data Types

All Resources in the StorageRoom API are compound data types. They exist of multiple simple data types and/or contain other compound data types. Compound data types always contain a "@type" attribute that describes which data type you are dealing with.

The table below shows all primary Resources that are used in the StorageRoom API.

Type Description
Account Describes your Account
Collection Defines the structure of Entries and contains all of those Entries
Entry A piece of content
Deleted Entry Log of deleted Entries.
Array A container for multiple other compound data types.
Use the "@type" attribute to distinguish different Resources or attributes and parse them accordingly.

Optimistic Locking

The API uses Optimistic Locking to prevent lost updates when two Users edit the same Resource simultaneously.

If you want to update an existing Resource through the API you must send the "@version" key back exactly as it was sent to you from the API, otherwise you will receive an HTTP 409 status code and the Resource won't be updated. If you sent the "@version" key and you still receive this error then the Resource was just updated by another user. You should show an error to the user of your application and reload the Resource.

Creating new Resources

Create a new Resource by POSTing a Representation of the new Resource to the Base URL of the Resource.

The following example shows what to do to create a new Entry in the Guidebook Collection.

Step 1: Where do I have to send a POST request to if I want to create a new Guidebook?

Get the list of all the Collections from http://api.storageroomapp.com/accounts/:account_id/collections

{
    "array": {
        "@type": "Array",
        "@url": "http://api.storageroomapp.com/accounts/:account_id/collections",
        "resources": [
            {
                "@type": "Collection",
                "@url": "http://api.storageroomapp.com/accounts/:account_id/collections/:categories_id",
                "@created_at": "2010-11-26T11:31:27Z",
                "@updated_at": "2010-11-26T11:31:27Z",
                "@entries_url": "http://api.storageroomapp.com/accounts/:account_id/collections/:categories_id/entries",
                "name": "Categories",
                "entry_type": "Category",
                "fields": [
                  ...
                ]
            },
            {
                "@type": "Collection",
                "@url": "http://api.storageroomapp.com/accounts/:account_id/collections/:guidebooks_id",
                "@created_at": "2010-11-26T11:31:28Z",
                "@updated_at": "2010-11-26T11:31:28Z",
                "@entries_url": "http://api.storageroomapp.com/accounts/:account_id/collections/:guidebooks_id/entries",
                "name": "Guidebooks",  
                "entry_type": "Guidebook",                
                "fields": [
                  ...
                ]
            }
        ]
    }
}

The URL to create a new Guidebook would be the @entries_url:

http://api.storageroomapp.com/accounts/:account_id/collections/:guidebooks_id/entries 
Step 2: What do I have to POST?

Optional: If you want to associate the Guidebook to a Category find a Category and save the Resource URI of this Category.

You would have to POST the following to the above URL to create a new Guidebook that belongs to a specific Category. Don't add the "category" key if you don't want to add a relationship:

{  
  "entry": {
      "name": "My Guidebook",
      "category": {
        "url": "http://api.storageroomapp.com/accounts/:account_id/collections/:categories_id/entries/:category_id"
      }
  }
}

Please note that you can but don't have to include any meta data (keys beginning with the @ sign). They will be added automatically.

As a response to your successful POST request you will receive a representation of the resource including all attributes. Find out more about relationships in the Entry section.

Array

Arrays are important as they are used frequently and contain an array of many Resources. If you make a GET request on the Base URL of a Resource you will get an Array in response. The Array will always have the same structure, but - depending on the endpoint - contain different Resources in the "resources" attribute.

Methods

Read Create Update Delete
yes no no no

Attributes

Name Type Description
resources array Contains an array of all the Resources
@type String Type of the Resource
@url String URL of this Array
@total_resources Integer Count of Resources in this Array
@pages Integer Total amount of pages with the current per_page setting
@per_page Integer How many Resources were returned per page
@next_page_url String The URL to the next page of this Array if it exists
@previous_page_url String The URL to the previous page of this Array if it exists

Example

{
    "array": {
        "@type": "Array",
        "@url": "http://api.storageroomapp.com/accounts/:account_id/collections",
        "@next_page_url": "http://api.storageroomapp.com/accounts/:account_id/collections?page=2",
        "@per_page": 10,
        "@page": 1,
        "@pages": 3,
        "@total_resources": 29,
        "resources": [
            {
                "@type": "Collection",
                "@url": "http://api.storageroomapp.com/accounts/:account_id/collections/:collection_id"
                "@created_at": "2010-11-26T11:31:27Z",
                "@updated_at": "2010-11-26T11:31:27Z",
                "@entries_url": "http://api.storageroomapp.com/accounts/:account_id/collections/:collection_id/entries",
                "name": "Categories",
                "fields": [
                  ...
                ]
            },
            {
                "@type": "Collection",
                "@url": "http://api.storageroomapp.com/accounts/:account_id/collections/:collection_id",
                "@created_at": "2010-11-26T11:31:28Z",
                "@updated_at": "2010-11-26T11:31:28Z",
                "@entries_url": "http://api.storageroomapp.com/accounts/:account_id/collections/:collection_id/entries",
                "name": "Guidebooks",
                "fields": [
                  ...
                ]
            }
        ]
    }
}

Account

Accounts are at the root of the hierarchy and provide an entry point to browse the API.

Methods

Read Create Update Delete
yes no no no

Attributes

Name Type Description
name String Name of the Account
subdomain String Subdomain of the Account
@type String Type of the Resource
@url String URL of this Account
@collections_url String URL with an Array of all Collections for this Account
@deleted_entries_url String URL with an Array of all Deleted Entries for this Account
@created_at String (ISO8601) When this Account was created
@updated_at String (ISO8601) When this Account was updated

Examples

{
    "account": {
        "@type": "Account",
        "@url": "http://api.storageroomapp.com/accounts/:account_id",
        "@created_at": "2010-11-26T11:31:24Z",
        "@updated_at": "2010-11-26T11:31:49Z",
        "@collections_url": "http://api.storageroomapp.com/accounts/:account_id/collections",
        "@deleted_entries_url": "http://api.storageroomapp.com/accounts/:account_id/deleted_entries",
        "name": "Demo",
        "subdomain": "demo"
    }
}

Collection

Think of Collections as tables in a database. Collections define the structure of your data with Fields and contain all the individual Entries. You can query a Collection and find Entries by many different search criteria.

Methods

Read Create Update Delete
yes yes yes yes

Attributes

Name Type Description
name String Name of the Collection
entry_type String String that is used as the @type attribute for Entries of the Collection
fields array Array of all the Fields that describe the Collection
webhook_definitions array Array of all the Webhook Definitions
primary_field_identifier String The identifier of the main field that is used to display Entries in the interface
@updated_at String (ISO8601) When the Collection was updated
@created_at String (ISO8601) When the Collection was created
@url String URL of this Collection
@entries_url String URL to an Array of all the Entries
@deleted_entries_url String URL to an Array of all the Deleted Entries in the Collection
@type String The type of this Resource
@version Integer The key used for Optimistic Locking

Examples

{
    "collection": {
        "@type": "Collection",
        "@url": "http://api.storageroomapp.com/accounts/:account_id/collections/:collection_id"
        "@created_at": "2010-11-26T11:31:27Z",
        "@updated_at": "2010-11-26T11:31:27Z",
        "@entries_url": "http://api.storageroomapp.com/accounts/:account_id/collections/:collection_id/entries",
        "@deleted_entries_url": "http://api.storageroomapp.com/accounts/:account_id/deleted_entries?collection_url=:collection_url",
        "@version": 1,
        "name": "Categories",
        "entry_type": "Category",
        "primary_field_identifier": "name",
        "fields": [
            {
                "@type": "StringField",
                "name": "Name",
                "required": true,
                "default_value": null,
                "include_blank_choice": false,
                "input_type": "text_field",
                "hint": null,
                "identifier": "name"
            }
        ],
        "webhook_definitions": []
    }
}

Entry

Collections define how an Entry looks like. Entries are the actual content. You can add as many Fields as you want to an Entry by updating the Collection. A Field can also be an Association to another Entry.

Methods

Read Create Update Delete
yes yes yes yes

Attributes

Name Type Description
@updated_at String (ISO8601) When the Entry was updated
@created_at String (ISO8601) When the Entry was created
@url String URL of this Entry
@collection_url String URL to the Collection of the Entry
@type String The type of this Resource
@version Integer The key used for Optimistic Locking
... Anything All other keys are defined in the Collection

Examples

{
    "entry": {
        "@type": "News",
        "@url": "http://api.storageroomapp.com/accounts/:account_id/collections/:collection_id/entries/:entry_id",
        "@created_at": "2010-11-26T11:31:28Z",
        "@updated_at": "2010-11-26T11:31:28Z",
        "@collection_url": "http://api.storageroomapp.com/accounts/:account_id/collections/:collection_id",
        "@version": 1,
        "title": "Test Title",
        "body": "Neque rem maiores molestiae debitis magnam et provident.",
        "category": {
          "@type": "Category",
          "url": "http://api.storageroomapp.com/accounts/:account_id/collections/:categories/entries/:category_id"
        }
    }
}

Creating new Entries

Entries are created like all other Resources. This is described in the Resources section.

Associations

Frequently relationships between Entries in different Collections are required. Let's say you have a Collection of trivia questions for a game and each TriviaQuestion should be categorized. You could directly add the Category as a simple StringField in the TriviaQuestion Collection, but then you would not be able to add additional information to each Category.

If you want a relationship where a Category holds further information you can create a Category Collection with as many Fields as you want. In the TriviaQuestion Collection you would then add an OneAssociationField or a ManyAssociationField.

To-One Association

This means that each TriviaQuestion belongs to one Category (OneAssociationField). Fetch a Category and all its TriviaQuestions with the Search API or get the Category for a TriviaQuestion that you already loaded from the API. Please note that the "category" key below is a single subdocument with the Resource URI of the associated Category.

{
    "entry": {
        "question": "Question with *one* Category",
        "category": {
          "@type": "Category",
          "url": "http://api.storageroomapp.com/accounts/:account_id/collections/:categories/entries/:category_id"
        },
        ...
    }
}

To-Many Association

This means that each TriviaQuestion belongs to many Categories (ManyAssociationField). Fetch a Category and all its TriviaQuestions with the Search API or get all the Categories for a TriviaQuestion that you already loaded from the API. Please note that the "categories" key below is an array with many subdocuments that contain the Resource URIs of all associated Categories.

{
    "entry": {
        "question": "Question with *many* Categories",
        "categories": [
          {
            "@type": "Category",
            "url": "http://api.storageroomapp.com/accounts/:account_id/collections/:categories/entries/:category1_id"
          },
          {
            "@type": "Category",
            "url": "http://api.storageroomapp.com/accounts/:account_id/collections/:categories/entries/:category2_id"
          }      
        ]
        ...
    }
}

Creating Associations through the API

To create a To-One or To-Many Association between Entries through an API call you need to transmit the documents as they are shown in the examples above. You always need to send the full Resource URI of the other Entry to create an Association.

File and Image Attachments

Arbitrary Files and Images can be attached to Entries through FileFields and ImageFields. ImageFields also support the generation of images from the source image (e.g. thumbnails or lower resolution artwork) through Image Versions. To following gives instructions on how to upload and remove Files and Images through the API.

1. Uploads

The following request must be made to add or to replace an attached File or Image with the identifier "file" for a "Post" Entry:

{
    "entry": {
        "name": "Name of the Post",
        "file": {
          "content_type": "image/png",
          "filename": "post.png",
          "data": "LARGE_BLOCK_OF_BASE64_ENCODED_DATA"
        }
        ...
    }
}

Take the file you want to attach, Base64 encode it and nest it in the POST or PUT request as seen above. If you PUT and don't add any data for the "file" Field then the uploaded File will just stay the same. This avoids multiple unnecessary uploads of the same file if you just want to update some other attributes.

2. Removals

There must be another way to remove Files or Images as they cannot be removed by not including the identifier in the updated Resource representation. To remove a File or Image with the identifier "file" you need to PUT the following:

{
    "entry": {
        "name": "New Name of the Post",
        "file": {
          "remove": true
        }
        ...
    }
}

Deleted Entry

An Entry is removed permanently when you delete it. If you want to synchronize a local database in your app with StorageRoom it can be hard to find out which Entries have been deleted from the remote Collection on StorageRoom.

Each Entry therefore leaves a trace on removal. A new DeletedEntry Resource is created automatically when you delete an Entry.

Methods

Read Create Update Delete
yes no no no

Attributes

Name Type Description
@type String The type of this Resource
@url String URL of this Deleted Entry
@account_url String URL to the Account of the Entry
@collection_url String URL to the Collection of the Entry
@entry_url String URL to the original Entry that was deleted
@deleted_at String (ISO8601) When the original Entry was deleted

Examples

{
  "@type": "DeletedEntry",
  "@url": "http://api.storageroomapp.com/accounts/4e1e9c234250712eba000052/deleted_entries/4e269c0f42507106fc000001",
  "@account_url": "http://api.storageroomapp.com/accounts/4e1e9c234250712eba000052",
  "@collection_url": "http://api.storageroomapp.com/accounts/4e1e9c234250712eba000052/collections/4e1e9c234250712eba000056",
  "@entry_url": "http://api.storageroomapp.com/accounts/4e1e9c234250712eba000052/collections/4e1e9c234250712eba000056/entries/4e269c2742507106fc000004",
  "@deleted_at": "2011-07-20T09:13:13Z"
}

Webhook Call

Webhook Calls are what StorageRoom will POST to the URL in a Webhook Definition. Parse Webhook Calls on the server and respond to changes to your Entries.

The Ruby Gem, which you can use on your server, supports parsing of Webhook Calls (example).

Attributes

Name Type Description
@type String The type of this Resource
@event String Type of the event (create, update, delete)
@attempts Integer How many times have we tried to deliver the webhook call
@last_attempt_at String (ISO8601) When we tried to deliver the last webhook call
@last_status_code Integer The HTTP status code your server returned on the last webhook call
@created_at String (ISO8601) When the webhook call was created
@entry Entry The JSON representation of the Entry at the time the webhook call was created

Examples

{
  "@type": "WebhookCall",
  "@event": "update", 
  "@attempts": 2,     
  "@last_attempt_at": "2011-07-15T11:04:49Z", 
  "@last_status_code": 500,    
  "@created_at": "2011-07-15T11:04:48Z",     
  "@entry": {
    "@collection_url": "http://api.storageroomapp.com/accounts/4e1e9c234250712eba000052/collections/4e1e9c234250712eba000062", 
    "@created_at": "2011-07-14T07:35:26Z", 
    "@trash": false, 
    "@type": "Announcement", 
    "@updated_at": "2011-07-15T11:04:48Z", 
    "@url": "http://api.storageroomapp.com/accounts/4e1e9c234250712eba000052/collections/4e1e9c234250712eba000062/entries/4e1e9c3e4250712eba000093", 
    "@version": 2, 
    "text": "changed text"
  }
}

Embedded Resources

Besides the primary Resources described above there are also embedded Resources. Those Resources don't have their own URL and are always part of one of the primary Resources. The embedded Resources are:

Field

Fields are part of Collections and are used to describe the structure of a "column". They don't have their own URL as they are always part of a Collection.

Field Types

A Field will have different options depending on the chosen Field type. A list of all available Field types follows.

  • Atomic
    • BooleanField
    • DateField
    • TimeField
    • FloatField
    • IntegerField
    • StringField
  • Compound
    • FileField
    • ImageField
    • LocationField
    • ArrayField
    • JsonField
  • Association
    • OneAssociationField (To-One)
    • ManyAssociationField (To-Many)

Attributes

Name Type Description
name String Name of the Field
identifier String Unique identifier of the Field
collection_url String The associated Collection for Association Fields
interface Boolean Is this Field shown in the editing interface?
required Boolean Is this Field mandatory and must be filled out?
unique Boolean This Field's value must be unique within the Collection
regexp String The regular expression against the string must match
minimum_length Integer The minimum length of a String Field
maximum_length Integer The maximum length of a String Field
minimum_number Float The minimum value of an Integer or Float Field.
maximum_number Float The maximum value of an Integer or Float Field.
minimum_size Integer The minimum size in Megabytes of an uploaded File
maximum_size Integer The maximum size in Megabytes of an uploaded File
included_in Array The value must be within the Array.
excluded_of Array The value is not allowed to be within the Array.
default_value Dependent on Field What is the default value
include_blank_choice Boolean Can this Field be left blank?
input_type String Which form of input to use in the interface
hint String The hint to display when entering data
choices Array The hint to display when entering data
@type String The type of this Field
versions Array Definitions of type Image Version (ImageField)

Examples

{
    "@type": "StringField",
    "name": "Name",
    "identifier": "name",
    "interface": true,
    "required": true,
    "default_value": "Unnamed Category",
    "include_blank_choice": false,
    "input_type": "text_field",
    "hint": "The name of the Category"
}

Location

Use a LocationField to add one or many locations to your Entries. Locations have a special format and can also be searched with radius and bounding box queries.

Attributes

Name Type Description
lat Float Latitude
lng Float Longitude
@type String The type of this Resource

Examples

{
  "@type": "Location",
  "lat": 12.3333,
  "lng": -33.123
}

File

Attach one or multiple files to each Entry and download them from your applications. Examples of files are images, PDFs, MP3s, etc.

Attributes

Name Type Description
@url String URL to download the file
@type String The type of this Resource

Examples

{
  "@type": "File",
  "@url": "http://files.storageroomapp.com/accounts/:account_id/collection/:collection_id/entries/:entry_id/fields/:field_id/:filename"
}

Image

The Image Resource provides additional support for automatically generating thumbnail images of your uploaded image through Image Versions.

Attributes

Name Type Description
@url String URL to download the image
@processing Boolean Are Image Versions currently being processed?
@type String The type of this Resource
@versions Array Details for all Image Versions

Examples

{
  "@type": "Image",
  "@url": "http://files.storageroomapp.com/accounts/:account_id/collection/:collection_id/entries/:entry_id/fields/:field_id/:filename",
  "@processing": false,
  "@versions": {
    "thumb_small": {
      "@url": "http://files.storageroomapp.com/accounts/:account_id/collection/:collection_id/entries/:entry_id/fields/:field_id/:thumb_small_filename"
    },
    "thumb_large": {
      "@url": "http://files.storageroomapp.com/accounts/:account_id/collection/:collection_id/entries/:entry_id/fields/:field_id/:thumb_large_filename"
    }      
  }

}

Image Version

Image Versions are embedded within Image Fields and define which thumbnails should be generated from the original source image.

Attributes

Name Type Description
identifier String Identifier for the Image Version
format String The image format (png, jpg or gif)
resize_mode String The resize mode (none, fill, fit, relative)
height Integer Height in pixel for fill/fit resize modes
width Integer Width in pixel for fill/fit resize modes
scale Integer Scale in percent for relative resize mode

Examples

{
  "@type": "ImageVersion",
  "identifier": "thumbnail",
  "format": "png",
  "resize_mode": "fit",
  "width": 100,
  "height": 200
}

Webhook Definition

A Webhook Definition is part of a Collection and configures one of many Webhooks that are called when an Entry is modified.

Attributes

Name Type Description
@type String The type of this Resource
url String URL where POST requests are sent to
on_create Boolean Execute for new Entries?
on_update Boolean Execute for updated Entries?
on_delete Boolean Execute for deleted Entries?
api Boolean Execute for changes coming through the API
web_interface Boolean Execute for changes coming through the web interface
username String Optional HTTP Basic username (not readable)
password String Optional HTTP Basic password (not readable)

Examples

{
    "@type": "WebhookDefinition"
    "url": "http://www.myserver.com/webhooks/storage_room"
    "on_create": true
    "on_update": true
    "on_delete": true
    "api": true
    "web_interface": false
}

Endpoints

As all the Resources provide further links to other Resources you should not build URLs manually. Just follow the existing links. Building links manually is more effort and might break if we ever change our URL structure.

However, for a small script or widget it might be interesting to know what Endpoints are available.

This is an overview about all the available Endpoints. You should only use the Endpoints that are documented in this list. There might be some other undocumented Endpoints, but those might change without upfront notice.

Resource Method Endpoint Request Response Description
Account GET /accounts/:account_id Account Representation Get details about your Account
Collection GET /accounts/:account_id/collections Array of Collections in Account Get all Collections in your Account
Collection GET /accounts/:account_id/collections/new Collection Template Template to create a new Collection
Collection GET /accounts/:account_id/collections/:collection_id Collection Representation Get details about a Collection
Collection DELETE /accounts/:account_id/collections/:collection_id Delete a Collection and all its Entries
Collection PUT /accounts/:account_id/collections/:collection_id Collection Representation Collection Representation Update a Collection
Collection POST /accounts/:account_id/collections Collection Representation Collection Representation Create a new Collection
Entry GET /accounts/:account_id/collections/:collection_id/entries Array of Entries in Collection Get all Entries in a Collection
Entry GET /accounts/:account_id/collections/:collection_id/entries/new Entry Template Template to create a new Entry
Entry GET /accounts/:account_id/collections/:collection_id/entries/:entry_id Entry Representation Get details about an Entry
Entry DELETE /accounts/:account_id/collections/:collection_id/entries/:entry_id Trash an Entry
Entry PUT /accounts/:account_id/collections/:collection_id/entries/:entry_id Entry Representation Entry Representation Update an Entry
Entry POST /accounts/:account_id/collections/:collection_id/entries Entry Representation Entry Representation Create a new Entry
Deleted Entry GET /accounts/:account_id/deleted_entries Array of DeletedEntries in Account Get all DeletedEntries in your Account
Deleted Entry GET /accounts/:account_id/deleted_entries/:deleted_entry_id DeletedEntry Representation Get details about a DeletedEntry

Webhooks

Webhooks

StorageRoom supports Webhooks, so that a HTTP POST request is performed on a custom URL every time Entries are modified. You get notified about changes to your content when they happen and don't need to poll the API constantly to find out if a change occurred.

Use Webhooks to update certain Fields of an Entry on your server, create push notifications with a 3rd party service or use it to synchronize content with another CMS. The opportunities are endless, limited only by your imagination, as you can do anything you want with the data you receive.

Define up to 5 different Webhooks per Collection in our web interface and specify if you want to get notified on new, updated or deleted Entries. In addition, define if you want the callback to be triggered by all changes or only by changes through the web interface or the API.

For each change StorageRoom will send a POST request with a JSON Payload to your custom URL. Your service should respond with a HTTP Status Code of 200 or 201 when it processed the Webhook successfully. In case of failure StorageRoom will retry the request to your server multiple times after some delay. Your endpoint should be prepared for this and use the timestamps in the POST body, and not rely on the time the POST is executed.

Please be careful when updating content with a Webhook, as this could produce infinite loops, where your Webhook and the StorageRoom servers ping each other about changed content forever. Set the "skip_webhooks" parameter to "1" in the query string to prevent any Webhooks from being executed.

Configure a Postbin as your Webhook URL to test how Webhooks work and check out our Ruby on Rails Webhook Example.

Demo

Take a look at our demo account and browse the API with a read-only API key that we provide.

Use the following URL to start at the Account level:

Or take a direct look at a Collection:

  • Restaurants: Shows many of the available Fields in action
  • Wallpapers: Shows automatically generated thumbnail images
  • Posts: Associations between Entries

Browser Extensions

To browse the JSON-API in your browser use one of the following plugins:

Libraries

It is not hard to consume the StorageRoom web service as soon as you have figured out how to use your HTTP library of choice. But it is even easier to use the StorageRoom API if you don't have to take care about stuff like parsing JSON responses yourself.

StorageRoomKit (iOS)

StorageRoomKit is a library for iOS and Mac OS that provides helper methods and classes that make it very simple to use the StorageRoom API.

Feature summary:

  • Works with NSObjects and NSManagedObjects
  • Supports the GET, POST, PUT and DELETE HTTP methods
  • Comes with classes and mappings for all StorageRoom Resources
  • Helper methods to generate StorageRoom paths
  • ... and many more features that the underlying RestKit provides

You can find the code and usage examples on http://github.com/thriventures/StorageRoomKit.

Ruby Gem

To test our web service in every aspect we developed a Ruby Gem. We released it as an open source tool and everybody can use in their applications. It might also give you some inspiration on how to model a library for another programming language.

Importing content from another CMS or Excel sheet can be done in minutes with the Gem (Example).

Feature summary:

  • ActiveRecord/ActiveModel like interface.
  • Automatic creation of Entry Classes from a Collection, you don’t have to configure anything
  • Supports lazy-loading of associations (e.g. post.category will fetch a category transparently if it has not yet been loaded)
  • Supports caching through an identity map, so that Resources don’t have to be loaded multiple times
  • File uploads and removals
  • Model Callbacks
  • Webhook Processing

Find the gem on http://github.com/thriventures/storage_room_gem.

sudo gem install storage_room
# Create an Entry
collection = StorageRoom::Collection.find('4ddaf68b4d085d374a000003')
Guidebook = collection.entry_class # the class is automagically configured from the Collection
entry = Guidebook.new(:name => 'Foo', :price => 1.23)

if entry.save
  puts "Guidebook created"
else
  puts "Guidebook could not be created: #{entry.errors.join(', ')}"
end

# Search for Entries
array = Guidebook.search(:name => 'Bar')

puts "Guidebooks with name 'Bar':"

array.resources.each do |g|
  puts "- #{g.name}"
end

# More examples on Github

JavaScript

It is very easy to use the RESTful JSON-API of our CMS in JavaScript (through cross-domain AJAX requests with CORS or JSONP). There is a plethora of great open-source JavaScript libraries for building web-based desktop & mobile applications that work great with our Content Management System (CMS) and make you even more productive:

Pick your weapon of choice and start building great content-based web applications!

Sample Code

To make using our API even easier we provide some sample code. Feel free to reuse parts of the examples.

iPhone

Restaurants are loaded from the StorageRoom CMS, saved locally with Core Data and displayed in a UITableView and a MKMapView. Details can be seen on a secondary page. The restaurants are cached for offline use until the user manually decides to load the Resources again from the web.

This example is kept simple on purpose and focuses on the downloading and parsing of the JSON data.

The code is on GitHub: https://github.com/thriventures/simple_iphone_example

  • 5853375296_847cafb1d9_m
  • 5853368406_a49d81f84d_m
  • 5852815813_6f5e733f25_m

Android

Restaurants and announcements are loaded from the CMS with the JSON API. They are saved locally in a SQLite database and displayed in an Activity with a ListView and an Activity with a MapView. Details can be accessed in a separate activity. The images in the ListView and in the DetailsView are downloaded in the background and cached locally for the application life-time. Special thanks go to Till Simon for providing the code.

The code is on GitHub: https://github.com/TillSimon/storage_room_android_example

  • 5852900499_bb292d6fb8_m
  • 5852899963_8da71c437d_m
  • 5853454018_f50fb092f1_m

Your code here

Please get in touch with us if you have an open-source project that's based on our API that you wish to see here.

FAQ

Is StorageRoom an application generator that spits out a templated mobile application?

Nope. You develop the app yourself or in cooperation with an agency. We only provide libraries to make your life easier. This is an advantage as you have the freedom to do whatever you want with the content in your app.

Can I use StorageRoom for Offline Content?

Yes. You can use StorageRoom to manage content, and then export the content and deliver it for offline use with your app. It is even possible to do delta-synchronization to keep the content up to date in your applications without releasing a new version.

How do I import content from my existing CMS?

There are so many different data formats that it would be hard for us to provide an universal importer. But content can be imported in a snap with our Ruby Gem.

How do I create relationships between my Entries?

If you have a "Posts" Collection and a "Category" Collection and you want to link each Post to a Category then you should create an AssociationField. You can model one-to-one and one-to-many relationships this way.

I have some content that doesn't fit into your Fields?

Use a JSON Field. You can add any custom deeply nested JSON data to this Field, there just won't be a nice interface to edit this content.

What is an Authenticity Token error?

Our servers have a protection against Cross-site request forgery. The protection is only activated for Requests that were made by a browser. Only the POST/PUT/DELETE HTTP Methods are checked.

If you receive this error in your application you probably forgot to set the correct HTTP Content-Type and Accept Header. See Formats for more information.

How do I use StorageRoom on iOS?

Give our StorageRoomKit library a try.

My JSON library doesn't like the "@meta_data" attributes?

Just change the default meta prefix to something else.

Support

We want your feedback! Did you find a bug or encounter a problem while using the API? Do you have feedback or suggestions that you would like to share? Did you find an error in the API documentation?

Maybe the answer to your question is already posted on our help & discussions page. If not, please post your question there.

If you want to contact us directly, send us an email: team@storageroomapp.com.