This document defines the REST API specification implemented by public Go Daddy® APIs.
Our goal is to make APIs that are as easy to use as possible. Each service has documentation available, but this should be a supplement, not required reading. Armed with just the URL and credentials, a user should be able to navigate their way through the API in a web browser to learn about what resources and operations it has. In other words, the API should be discoverable. Once you're familar with what's available, requests can be made with simple tools like cURL or any basic HTTP request library.
Maybe you'd like to build your own tools that work with our services. Or maybe you want to build your own service that follows the same style as ours. We'd love it if you did either one and want to give you all the information you need. This is also the same documentation our internal teams use to build their APIs.
There is information about each API on our documentation page. We also have clients for various languages:
For questions, comments, corrections, suggestions, etc, you can use the usual tools in GitHub or email us at apispec@godaddy.com. Please use our normal support page for questions or problems about a specific API, product, or account.
Copyright © 2012 Go Daddy Operating Company, LLC
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Examples demonstrate a hypothetical file storage API. Only the relevant HTTP request and response information is shown, additional standard HTTP headers will be present in a real request. Examples generally show JSON request and responses, but several request types are available and other response types may be defined in the future.
REST: A REpresentational State Transfer service is a style of API where a client makes HTTP requests to manipulate resources identified by the request URL. RESTful services are stateless, so session state is stored on the server between requests. Each requests contains all the information needed to service that request.
Resource: A resource is an object or concept that can be manipulated by the API. In our file storage example, they will be things like a 'Folder' and a 'File'. Resources are the building blocks of an API, the nouns in the language describing the system. All operations in the API manipulate the resources or their state. Resources should be organized in a way that is useful to the client. This is the most important part of the design of an API; if your resources just match your database schema one-to-one, chances are your API is not going to be very easy to use.
Representation: REST APIs transfer representations of resources back and forth between the client and the service. These are documnents that describe resources. Representations are most commonly JSON-formatted, but can be of any type.
Attribute: Representations of resources consist of a series of attributes names and values as key-value pairs.
Collection: A collection is a special kind of resource that represents a group of related resources. It contains a representation of each resource, and some additional information for things like pagination and filtering.
Identifier: Every resource in a collection MUST have an identifier attribute with a value that is unique within that collection.
Side Effects: Requests that change the state of something in the service are said to have side effects. It is very important that certain types of requests not have side-effects.
Idempotent: An operation is idempotent if it can be applied multiple times without changing the result after the first application.
Opaque: Some pieces of information returned from a service are considered to be opaque. Opaque values are a black box that has meaning only to the service; clients should not rely on any particular format, length, or content in an opaque value. They should not change the value or try to parse any meaning out of it. Opaque values MAY change between API revisions or even individual requests, so they should never be stored or compared against. For example, pagination URLs contain a "marker" attribute that identifies the appropriate page to load.
Action: An action is an operation that can be performed on a resource but does not fit into one the standard create/read/update/delete operations. For example "sharing" or "encrypting" a file resource.
Discoverability: Discoverability is a method of self-documenting. Each API has a collection of schemas that define what resource types are available and what attributes they have. Each response contains information about how to find related resources and what actions are available.
Since this documentation is in a computer-readable form, it is easy to make a generic client library that will speak to any API that implements this specification, with no code related to a particular service. We provide several client libraries for different languages, and if you load the API in a browser we respond with a built-in JavaScript client that provides a friendly UI for experimentation.
Every HTTP response contains a status code. This is the primary mechanism that a client uses to determine the result of their request, so it is very important that they be clearly defined and used consistently. Requests that were successfully handled MUST return a response with a 2xx or 3xx status code. Requests that cannot be processed MUST return a 4xx or 5xx code.
| Code | Meaning |
|---|---|
| 2xx | Success |
| 200 OK | The request was successful. |
| 201 Created | Success, and a new resource has been created. • A Location header to the resource SHOULD be included. |
| 202 Accepted | The request has been received but has not completed. It MAY be completed in the future. • This is typically used for requests that produce a long-running process that will be performed asynchronously. |
| 204 No Content | The request was successful, and the response will have no body portion. |
| 3xx | Redirect 301 Moved Permanently | Permanent redirect. The requested resource is somewhere else now and will never be coming back.
• The new location MUST be specified in the Location header.
• The operative word here is permanent; clients may remember this and never request the old URL again.
• If in doubt, use 302. 302 Found | Temporary redirect. The requested resource isn't here right now.
• The new location MUST be specified in the Location header.
•The client will ask for the original URL if it wants this resource again in the future. 304 Not Modified | The client made a conditional GET request for a resource, and that resource matches the condition so the response body does not need to be sent. | 4xx | Client Error — The client did something wrong.
• Sending the same request again will result in the same error. 400 Bad Request | The request was malformed in some way or the input did not pass validation; the client should feel bad. 401 Unauthorized | Authentication information was not sent or is invalid. 403 Forbidden | Authentication information was validated, but does not give the client access to the requested resource. 404 Not Found | These are not the droids you are looking for. 405 Method Not Allowed | The requested HTTP method is not allowed for this URL. 406 Not Acceptable | The service does not support the representation content type that the client requested/sent. 409 Conflict | Resource versioning is enabled, and the requested operation conflicts with the current state. 410 Gone | The requested API version is no longer supported. 418 I'm a teapot | The request attempted to brew coffee with a teapot service that is not compliant with RFC2324. | 5xx | Service Error — Something bad happened within the service.
• There is nothing the client can do about this.
• The same request will succeed (or produce a 4xx error) if re-submitted in the future. 500 Internal Server Error | Something is broken on our side; the service should feel bad. 503 Service Unavailable | The request couldn't be handled due to maintenance or overload.
A representation is the way a resource is described/serialized in a HTTP request or response. All services MUST support:
- JSON (application/json) for both requests and responses.
- This is the primary representation used by all APIs.
- HTML (text/html; charset=utf8) for responses
- This is a small HTML wrapper around the JSON format which displays the HTML UI.
- The HTML response format is only intended for use in a web browser, not for clients to parse.
- Forms (multipart/form-data and application/x-www-form-urlencoded) for requests.
- These are needed for the HTML UI and are easy to create with browsers and command-line tools like cURL.
Other representation Content-Types that make sense for the particular application MAY also be supported.
When clients are sending a representation to the service, they MUST specify the format using the [Content-Type](http://tools.ietf.org/html/rfc2616#section-14.17 Content-Type) header. If the service does not support the specified Content-Type, it SHOULD return a 406 error.
Clients MAY specify their preferred representation by including an appropriate Accept header. Service SHOULD be lenient in mapping this to one of their acceptable formats. For example application/json, text/json;charset=utf-8, and text/json should all be interpreted as JSON.
JSON SHOULD be assumed as the preferred representation, unless the request is from a web browser.
- The suggested definiton of "a web browser" is that the Accept header contains "/" and the User-Agent header contains "mozilla".
- This matches all the common graphical web browsers but not HTTP request libraries or command-line browsers.
A query parameter of _format=json overrides any defaults or Accept header present and MUST make the response representation JSON.
In practice, if you only support HTML and JSON, your detection logic should look something like:
if ( query parameter "_format" is present and equals "json" ) respond with json else if ( accepts header contains "*/*" AND user-agent header to lowercase contains "mozilla" ) respond with html else respond with json JSON responses SHOULD be pretty-printed, at least to the extent of having occasional newlines. This adds minimal overhead and makes it much more readable.
Escaping the forward slash ("/") character is not required in the JSON specification
- When responding as raw JSON, slashes SHOULD NOT be escaped.
- When responding as HTML, strings in the JSON data portion MUST have forward slashes escaped, typically as "/".
- Failure to do this exposes the page to an XSS attack using strings that contain "</script>".
Dates SHOULD always be in UTC. If you have a very good reason to use something else, the attribute name SHOULD indicate that it is "local" or similar to avoid confusion.
For JSON, dates SHOULD should be returned in 2 formats:
- An ISO-8601 formatted UTC string.
- e.g. created: "2012-02-24T15:42:00Z"
- The number of milliseconds since 1/1/1970 (a "UNIX timestamp" or "epoch time") as the same name with "TS" appended
- e.g. createdTS: 1330098120000
- Note: The "TS" version SHOULD NOT appear in the schema and therefore cannot be writable.
Services provide a HTML version of their API by wrapping the JSON response with the snippet below. It includes JavaScript and CSS that pretty-prints the response and displays a bar that provides buttons for operations, actions, sorting, filtering, pagination, etc.
<!DOCTYPE html> <!-- If you are reading this, there is a good chance you would prefer sending an "Accept: application/json" header and receiving actual JSON responses. --> <link rel="stylesheet" type="text/css" href="https://cloud.secureserver.net/css.php?group=htmlapi" /> <script src="https://cloud.secureserver.net/js.php?group=htmlapi"></script> <script> var docs = "http://url-to-your-docs/site"; var data = { /* ... JSON response ... */ }; </script>Error responses MUST have a resource body which gives more information about the error. At a minimum, this MUST include:
type:"error"status:the HTTP status code of the responsecode:A short identifier for the error, suitable for identifying what specific kind of error this is with code.
Errors SHOULD also include:
message:A short description of the error for a human to readdetail:Additional detail about the error, if available- Any other application-specific information that is available.
Error responses MUST be returned in the representation appropriate for what the request asked for.
- It's rude to send an HTML error page back to a client that made a request for JSON.
- Also consider responses that might be returned from application servers and web proxies in your stack but outside your API code.
- If the error is with content negotiation itself, return in the default format (JSON).
{ "type": "error", "status": 404, "code": "FolderNotFound", "message": "The specified folder does not exist", /* ... more application-specific info ... */ }Resource representations MUST have several attributes:
type:A string that uniquely identifies the kind of resource this is.- Types SHOULD be singular, not plural, and MUST correspond to a schema id.
id:A string which uniquey identifies this resource.- MUST be unique among other resources of the same type and consist only of URL-safe characters.
- SHOULD be globally unique when practical.
- SHOULD NOT be an auto-incrementing id from a database. Exposing this value reveals information about the size and growth of the service, and easily allows attackers to iterate over the entire valid id range.
- In general something like a GUID is best if there will be many of the resource or they are dynamically created.
- If there is a very limited set of possible resources then a short readable string is good.
- e.g. "facebook", "twitter", "myspace", "googleplus" for a social network resource.
rev:A string identifying the resource revision, if resource versioning is implemented.links:A map with links to:self:The location of the resource itself.schemas:The location of the schemas collection.- This is required only at the root level of the response. If it contains nested resources (e.g. a collection) they do not need this link.
- Any related resources/collections, as appropriate.
actions:A map of action names → the URL that can be requested to perform them.- This MAY be omitted if the resource type has no actions.
{ "id": "b1b2e7006be", "type": "file", "rev": "rev0d41cb806a", "links": { /* see links */ }, "actions": { /* see actions */ }, "name": "ultimate_answer.txt", "size": 2, /* ... more application-specific attributes ... */ }Collections are a special case of resource. They do not need to have an identifier attribute, and have a "data" array that contains an array of resources.
Collection representations MUST have:
type:"collection"resourceType:The name of the primary schema type this collection holds.links:A map with links to:self:The location of the resource itself.schemas:The location of the schemas collection.- This is required only at the top level of the response. The resources within the collection do not need this link.
- Any related resources/collections, as appropriate.
data:An array containing resource representations- This MUST always be present and be an array, even if there are 0 or 1 entries in it.
And SHOULD have (when appropriate):
createTypes:A map of the names of types that can be created in this collection → the URL where the resource SHOULD be posted.- This SHOULD be present only if a type other than
resourceTypecan be created. - Each entry/type SHOULD be an "extension" the primary
resourceType. That is, it should have all the same fields and filters, plus additional info. - If the primary
resourceTypecan be created, it SHOULD also be present in the map. - The URL can just be the same as the "self" link, but MAY also be any other location, and different for each createType to provide additional flexibility.
createDefaults:A map of field names → their values.- This can be used to specify a context-specific default value for fields when the client is creating a new resource.
- This SHOULD be present only if a type other than
actions:A map of action names → the URL that can be requested to perform them.- This MAY be omitted if the resource type has no actions.
pagination:See pagination.sort:See sorting.filters:See filtering.
Collections MAY also include additional application-specific attributes.
{ "type": "collection", "resourceType": "file", "createTypes": { "file": "https://base/v1/files", "textFile": "https://base/v1/files", "imageFile": "https://base/v1/files", }, "links": { "self": "https://base/v1/files", "schemas": "https://base/v1/schemas" /* ... more links ... */ }, "actions": { /* see actions */ }, "pagination": { /* see pagination */ }, "sort": { /* see sorting */ }, "filters": { /* see filtering */ }, "data": [ {/* file resource */}, {/* file resource */}, /* ... more resources ... */ ], /* ... application-specific attributes ... */ }Links provide a trail for the client to follow to get to related information that is not included in the response. Clients SHOULD use the links to retrieve related information instead of hard-coding or constructing URLs from strings on their own. Services SHOULD provide the appropriate links so that clients don't have to resort to that sort of thing.
Links in responses MUST be absolute URLs, including the protocol (https), host, port (if not 443), and API Version.
- This prevents the client needing resolve relative URLs into absolute ones.
- HTTP compression will make the overhead of transmitting absolute URLs negligible.
Slashes:
- Trailing slashes SHOULD NOT be included on URLs in responses.
- But they SHOULD have no effect on the response produced if a client sends one.
- Multiple slashes in a URL SHOULD be treated the same as a single slash.
{ "links": { "self": "https://base/v1/files/b1b2e7006be", "schemas": "https://base/v1/schemas", "content": "https://base/v1/files/b1b2e7006be/content", "folder": "https://base/v1/folders/19c3932wef", "public": "http://documents.your-files.com/ultimate_answer.txt" /* ... more links ... */ }, /* ...other attributes... */ }See also: What to link
Actions perform an operation on a resource (or collection) and optionally returns a result. Actions may have several inputs and typically do something that requires application logic beyond what could be done with a simple create, update, or delete operation.
The schema for types that have actions available have an actions and/or collectionActions map in their schema detailing all the actions that are possible and their input/output schema. For example, there may be "share", "encrypt", and "decrypt" actions on a file. See schemas for more information.
Actions are defined by a map with 4 attributes:
input:The ID of the schema that the inputs will conform tooutput:The ID of the schema that the outputs will conform to
The appropriate pair MAY be omitted if there are no inputs or outputs to the action.
{ "id": "file", "type": "schema", "actions": { "share": { "input": "shareInput", }, "decrypt": { "input": "cryptInput", "output": "file", }, "encrypt": { "input": "cryptInput", "output": "file", }, /* ... other actions ... */ }, /* ... other schema attributes ... */ }Resources (and collections) of types that have actions defined have a actions attribute that details what actions are available for this particular resource, and what URL is to be accessed to perform them. For example if only one of "encrypt" and "decrypt" are possible for a given file, only the one currently available would appear in the resource:
{ "id": "b1b2e7006be", "type": "file", "actions": { "share": "https://base/v1/files/b1b2e7006be?share", "encrypt": "https://base/v1/files/b1b2e7006be?encrypt" }, /* ... other resource attributes ... */ }Each service MUST have a top-level collection called "schemas" which contains "schema" resource for each resource type. The information contained in the schema provides enough information to build a smart client that knows what actions are available, what fields make up a resource, etc.
The "schemas" collection MUST also have a link to the base URL of the API version.
- This makes the schema collection (https://base//v1/schemas) a single URL that provides a client everything they need to know about the service, similar to a WSDL in a SOAP service.
Each schema resource MUST describe:
id:: The name of the resource type (e.g. "files").type:"schema"resourceMethods:: An array of HTTP methods that are available to some (but not necessarily all) resources of this type.resourceFields:: A map of attribute names available in resources of this type → descriptions of that field (see fields).resourceActions:: A map detailing the actions available to resources of this type (see actions).collectionMethods:: An array of HTTP methods that are available to a collection of this type.collectionActions:: A map detailing the actions available to collections of this type (see actions).collectionFields:: A map detailing the non-standard attribute fields that the collection has, if any (see fields).collectionFilters:: A map detailing the filters that are available to collections of this type (see filters).links::self:: The URL for this schemacollection:If this type can be queried/listed, the URL for doing so (e.g. "http://base/v1/folders").- These links are used by API clients to generate object stubs and use this URL to fetch data.
- This SHOULD correspond to the collections that are linked at the version root.
Each field is defined by a map of properties. Fields MUST have a type:, which may be a "simple" type:
| type | description |
|---|---|
| "string" | UTF-8 string |
| "password" | String that should not be displayed |
| "float" | JavaScript uses double-precision IEEE 754 |
| "int" | "int"s are just floats in JavaScript, so the min/max safe values are ± 253 |
| "date" | As a string, see dates |
| "blob" | Binary data, encoded as a string |
| "boolean" | Boolean |
Or a non-simple type:
| type | description |
|---|---|
| "enum" | One choice out of an enumeration of possible values |
"reference[schema_name]" | The id of another resource with type schema_name |
"type[schema_name]" | The actual representation of a resource with type schema_name |
"array[another_type]" | An array of entries of type another_type |
"map[another_type]" | Key/value pairs. Values are of type another_type |
Additional metadata SHOULD be provided for each field when available:
| name | type | description |
|---|---|---|
default: | same as field | The default value that will be used if none is specified |
unique: | boolean | If true, this field's value must be unique with its resource type |
nullable: | boolean | If true, null is a valid value for this field |
create: | boolean | If true, this the field can be set when creating a resource |
required: | boolean | If true, this field must be set when creating a resource |
update: | boolean | If true, this field's value can be changed when updating a resource |
minLength: | int | For strings and arrays, the minimum length (inclusive) |
maxLength: | int | For strings and arrays, the maximum length (inclusive) |
min: | int | For ints and floats, the minimum allowed value (inclusive) |
max: | int | For ints and floats, the maximum allowed value (inclusive) |
options: | array[same as field] | For enums, the list of possible values |
validChars: | string | For strings, only these characters are allowed (see character ranges) |
invalidChars: | string | For strings, these characters are not allwoed (see character ranges) |
The additional fields above provide enough info for a client to do basic validation of values before sumbitting them to a service. They are not intended to be completly comprehensive; A service will often have additional restrictions on values that cannot be represented here. If the service is given a value that does not match all of it's conditions, it should return a 400 error with enough detail for the client to fix the problem and re-submit the reuqest.
The validChars: and invalidChars: are case-sensitive and may contain ranges as in a simple regular expression. For example alphanumerics may be represented as "a-zA-Z0-9". Unicode characters should be represented as \uXXXX or \uXXXXXX, where X are the hexadecimal representation of the codepoint.
{ "id": "file", "type": "schema", "resourceMethods": ["GET","DELETE"], "resourceFields": { "name": {"type": "string", "required": true, "create": true, "update": true}, "size": {"type": "int"}, "owner": {"type": "reference[user]"}, "access": { "type": "enum", "options": ["public","private","requirepassword"], "default": "private", "create": true, "update": true }, /* ... more fields ... */ }, "resourceActions": { "encrypt": { "input": "cryptInput", "output": "file", }, /* ...more actions... */ }, "collectionMethods": ["GET","POST"], "collectionActions": { "archive" { "input": "archiveInput", "output": "file", } /* ...more actions... */ }, "collectionFields": { "size": {"type": "int"} }, "collectionFilters": { "name": {"modifiers": ["ne","prefix","suffix"]}, "date": {"modifiers": ["lt","gt","lte","gte","prefix"]} "size": {"modifiers": ["lt","gt","lte","gte"] } "access": {"modifiers": ["eq","ne"], "options": ["public","private","requirepassword"]} } }| Operation | HTTP Method | Request URL | Description |
|---|---|---|---|
| Query | GET or HEAD | https://base/v1/{collection_name} | Retrieve a collection of resources |
| Read | GET or HEAD | https://base/v1/{collection_name}/{resource id} | Retrieve a single resource |
| Create | POST | https://base/v1/{collection_name} | Creates one or more resources |
| Update | PUT | https://base/v1/{collection_name}/{resource_id} https://base/v1/{collection_name} | Change one or more existing resources |
| Delete | DELETE | https://base/v1/{collection_name}/{resource_id} https://base/v1/{collection_name} | Delete one or more existing resources |
| Action | POST | https://base/v1/{collection_name}/{resource_id}?{action_name} https://base/v1/{collection_name}?{action_name} | Perform an action on a resource or collection |
The query operation allows a client to list the resources that are in a collection. Query operations MUST NOT incur side effects.
GET /v1/folders HTTP/1.1 Accept: application/json Authorization: Basic YWNjZXNzX2tleTpzZWNyZXRfa2V5 HTTP/1.1 200 OK Content-Type: application/json { "type": "collection", "resourceType": "folder", "links": { "self": "https://base/v1/folders", "schemas": "https://base/v1/schemas" /* ... more links ... */ }, "resourceType": "folder", "data": [ { "type": "folder", "id": "b1b2e7006be", "name": "Documents", "links": { /* see links */ }, "actions": { /* see actions */ } }, /* ... more folder resources ... */ ], "actions": { "deleteAll": "https://base/v1/folders?deleteAll", }, "pagination": { /* see pagination */ }, "sort": { /* see sorting */ }, "filters": { /* see filters */ } }Collections that may return a large number of results SHOULD paginate the response.
Pagination SHOULD be controlled by adding a marker={opaque_string} query string parameter.
- The implementation and meaning of the opaque string is left to the service.
- A MySQL-style numerical offset is simple, but can return the same entry on 2 subsequent pages if the result set changes between requests.
- A marker that specifically identifies the last row returned prevents this.
Services SHOULD allow the client to specify how many results they would like per page with a limit={integer} query string parameter.
- The service SHOULD enforce (and document) an upper limit on how high this is allowed to go. At least 1000 is suggested.
- Services SHOULD support
limit=0so that clients can get just the metadata for a collection (sort, filter, etc).
If the collection supports pagination, the response MUST contain a "pagination" object containing:
limit:The number of items that are returned in each result set.partial:Whether this result is the complete set or if it's been truncated.
If the result has been truncated, it SHOULD also contain:
first:The URL of a page containing the first resource in the result set (this SHOULD be the same URL, without a marker).previous:The URL of the page immediately preceding the current result set.next:The URL of the page immediately following the current result set.
And MAY additionally contain:
last:The page containing the last resource in the result set.- This may be impractical to implement, depending on your data source.
total:The total number of items in the result set, if available.- This may also be impractical, but is very useful information to a client if possible.
When the current result set contains the first resource, 'first' and 'previous' SHOULD NOT be returned. When the current result set contains the last resource, 'next' and 'last' SHOULD NOT be returned.
URLs included in this section SHOULD include all query parameters needed to maintain the current sort and filter.
{ /* ... other collection attributes ... */ "pagination": { "first": "https://base/v1/files", "previous": "https://base/v1/files?marker=opaque_string1", "next": "https://base/v1/files?marker=opaque_string2", "last": "https://base/v1/files?marker=opaque_string3", "limit": 100, "total": 342, "partial": true }, /* ... other collection attributes ... */ }Services SHOULD allow clients to request a sorted list of resources in a collection by adding sort={sort name} and order={asc or desc} query string parameters to the request. Clients MAY use these directly when constructing their query, but SHOULD use the links contained in results.
If a collection can be sorted, the response SHOULD contain a sortLinks: object, a mapping of attributes that can be sorted → the URL to produce that sort.
If the response was sorted by something, it SHOULD contain a sort: object containing:
name:The name of the current sort, so that the client knows which column to show as sorted.order:The direction of the current sort. This SHOULD be either"asc"or"desc".reverse:The URL for the same sort in the opposite order.
If no sort is specified by the client, services SHOULD either:
- Choose a default, and include the
sort:attribute as if it were requested - Or return results in an undefined/unstable order, with no
sort:attribute).
Sorts MUST be "stable". This means they must produce a unique and repeatable ordering so that the same query will always return results in the same order. This is what a client would expect, and is also necessary for pagination.
URLs included in this section SHOULD include all parameters needed to maintain the current filter, but SHOULD NOT include information about pagination. When folloing a link to a different sort order, the client SHOULD end up back on the first page of results again.
Multi-level sorting is not defined. Services SHOULD pick something reasonable to actually sort on. This may include sorting on multiple attributes for a single sort name. For example "size" of a file is not unique, so your implementation might actually sort by "size", then "name".
{ /* ... other collection attributes ... */ "sort": { "name": "size", "order": "asc", "reverse": "https://base/v1/files?sort=size&order=desc", }, "sortLinks": { "name": "https://base/v1/files?sort=name", "size": "https://base/v1/files?sort=size", "upload_date: "https://base/v1/files?sort=upload_date", /* ... more sort options ... */ }, /* ... other collection attributes ... */ }Services MAY support searching/filtering of the collection. Support for this is indicated by collectionFilters: in the schema, and the presence of a filters: map in the collection response.
In the schema, the value of each filter attribute SHOULD be an object describing:
modifiers:What modifiers are supported, if anyoptions:What specific values are allowed, if the attribute is enumerable
Modifiers allow things like "greater than" or "not equal to". The standard modifiers are:
| modifier | meaning |
|---|---|
"eq" | equal to (always available, the default if no modifier is specified) |
"ne" | not equal to |
"lt" | less than |
"lte" | less than or equal to |
"gt" | greater than |
"gte" | greater than or equal to |
"prefix" | starts with |
"like" | matches, as in SQL: • "_" for exactly one character • "%" for 0 or more characters |
"notlike" | does not match (as above) |
"null" | value is NULL |
"notnull" | value is not NULL |
Services MAY define (and document) their own modifiers.
{ /* ... other collection attributes ... */ "filters": { "name": {"modifiers": ["eq","ne","prefix","suffix"]}, "date": {"modifiers": ["eq","lt","gt","lte","gte","prefix"]} "size": {"modifiers": ["eq","lt","gt","lte","gte"] } "access": {"modifiers": ["eq","ne"], "options": ["public","private","requirepassword"]} /* ... more filters ... */ }, /* ... other collection attributes ... */ }The client performs a search by starting with the URL for a standard query request. If they've already done a query and want to filter the results, the self: link of the result can be used instead. Then the client adds on query string parameters for {filter name}{"_"+modifier}={value}.
- The underscore and modifier are optional if the desired modifier is
eq. - For example to search for files starting with "a" and greater than 1kb, the client would append:
name_prefix=a&size_gt=1024
- To search for non-image files, they could append:
name_notlike=%.jpg&name_notlike=%.png
- Note: % characters are shown here for clarity. In an actual request they need to be escaped into "%25" according ot normal URL-encoding rules.
There is no mechanism defined for OR-ing conditions. All filters are AND-ed together.
Collections that support filtering SHOULD have a filter: map in the response, with an attribute for each field that can be filtered on.
- If any filter was applied for that field, the value should be an array describing the filters.
- If no filters were applied for that field, the value should be null.
{ /* ... other collection attributes ... */ filters: { name: [ {"modifier": "prefix", "value":"a" } ], size: [ {"modifier": "gt", "value": 1024} ], date: null, access: null /* ... more filters ... */ } /* ... other collection attributes ... */ }{ /* ... other collection attributes ... */ filters: { name: [ {"modifier": "notlike", "value": "%.jpg"}, {"modifier": "notlike", "value": "%.png"} ], size: null, date: null, access: null /* ... more filters ... */ } /* ... other collection attributes ... */ }The read operation allows a client to get a single resource. Read operations MUST NOT incur side effects.
GETting the base URL of a service SHOULD return a collection of API version resources. It SHOULD include a link to the latest: stable version of the API. Links that point to a specific version at this level (e.g. schemas) SHOULD point to this latest version.
Versions that are not the latest MAY have a deprecated: true flag to indicate support for this version will be removed in the near future.
{ "type": "collection", "links": { "self": "https://base/", "latest": "https://base/v3", "schemas": "https://base/v3/schemas" }, "data": [ { "id": "v1", "type": "apiversion", "deprecated": true, "links": { "self": "https://base/v1", "file": "https://base/v1/files", "folder": "https://base/v1/folders" /* ... other collections and resources ... */ } }, { "id": "v2", "type": "apiversion", "deprecated": false, "links": { "self": "https://base/v2" "file": "https://base/v2/files", "folder": "https://base/v2/folders" /* ... other collections and resources ... */ } }, { "id": "v3", "type": "apiversion", "deprecated": false, "links": { "self": "https://base/v3", "file": "https://base/v3/files", "folder": "https://base/v3/folders" /* ... other collections and resources ... */ } } ] }GETting the root URL of a particular API version SHOULD return a resource containing links to all the collections and resources that are available. See API Versioning for more info.
GET /v1 HTTP/1.1 Accept: application/json Authorization: Basic YWNjZXNzX2tleTpzZWNyZXRfa2V5 HTTP/1.1 200 OK Content-Type: application/json { "id": "v1", "type": "apiversion", "deprecated": true, "links": { "self": "https://base/v1", "schemas": "https://base/v1/schemas", "file": "https://base/v1/files", "folder": "https://base/v1/folders" /* ... other collections and resources ... */ }, }GETting the URL of a resource SHOULD return the representation of that resource.
GET /v1/files/b1b2e7006be HTTP/1.1 Accept: application/json Authorization: Basic YWNjZXNzX2tleTpzZWNyZXRfa2V5 HTTP/1.1 200 OK Content-Type: application/json { "id": "b1b2e7006be", "type": "file", /* ... other resource attributes ... */ }Making a HEAD request to a URL SHOULD return the same response code and header information as a GET of the same URL would, except that it MUST NOT return any message body.
HEAD /v1/files/b1b2e7006be HTTP/1.1 Accept: application/json Authorization: Basic YWNjZXNzX2tleTpzZWNyZXRfa2V5 HTTP/1.1 200 OK Content-Type: application/json Content-Length: 234 HEAD /v1/files/non-existent-id HTTP/1.1 Accept: application/json Authorization: Basic YWNjZXNzX2tleTpzZWNyZXRfa2V5 HTTP/1.1 404 Not Found Content-Type: application/json Content-Length: 123 The create operation allows a client to create a new resource in a collection. The URL of the request SHOULD NOT contain a query component, to differentiate a create request from an action request.
The body of the request MUST contain a representation of the resource to be created. If any of the fields that are required by the schema for this resource are not included or are invalid, a 400 error SHOULD be returned, with information about what specifically is wrong.
If the created resource is immediately available, a 201 Created status code SHOULD be returned, and the body SHOULD be the representation of the new resource. If the resource cannot be created and read immediately, a 202 Accepted status SHOULD be returned instead. At least the resource id should be returned if at all possible.
For a single resource, the response SHOULD include a Location header with the URL for the new resource. This is likely the same as the self: link in the resource. Note that Location headers MUST always be an absolute URL.
POST /v1/folders HTTP/1.1 Accept: application/json Authorization: Basic YWNjZXNzX2tleTpzZWNyZXRfa2V5 Content-Type: application/json { "name": "Documents" }HTTP/1.1 201 Created Content-Type: application/json Location: https://base/v1/folders/ab391827x31 { "id": "ab391827x31", "type": "folder", /* ... more resource attributes ... */ }Services SHOULD also support create calls which are HTML Form encoded, Content-Type: multipart/form-data or Content-Type: application/x-www-form-urlencoded. These are easy for a client to construct with a HTML form or cURL, and also allow for simple uploading of binary data/files. A file management API might allow creating a file resource like:
curl -u access_key:secret_key \ -F name="ultimate_answer.txt" \ -F file="@mydatafile.txt" \ "http://base/v1/folders/ab391827x31"Which would make a request like:
POST /v1/folders/ab391827x31 HTTP/1.1 Accept: application/json Authorization: Basic YWNjZXNzX2tleTpzZWNyZXRfa2V5 Content-Length: 307 Content-Type: multipart/form-data; boundary=----------------------------9a41916dd20a ------------------------------9a41916dd20a Content-Disposition: form-data; name="name" ultimate_answer.txt ------------------------------9a41916dd20a Content-Disposition: form-data; name="file"; filename="mydatafile.txt" Content-Type: text/plain 42 ------------------------------9a41916dd20a--HTTP/1.1 201 Created Content-Type: application/json Location: https://base/v1/files/b1b2e7006be { "id": "b1b2e7006be", "type": "file", /* ... more resource attributes ... */ }Services MAY allow multiple resources to be created in one request by accepting an array of representations instead of a single one.
- A Location header SHOULD NOT be returned.
- The response SHOULD be a collection containing the created resources.
- The service MUST ensure that this operation is atomic:
- Either ALL the creates succeed and a 2xx response code is returned,
- or NONE of the changes are committed and a 4xx or 5xx code is returned.
- If this is not possible then the service SHOULD reject requests for multi-resource create with a 406 error.
POST /v1/folders HTTP/1.1 Accept: application/json Authorization: Basic YWNjZXNzX2tleTpzZWNyZXRfa2V5 Content-Type: application/json [ {"name": "Documents", /* ... more resource attributes ... */}, {"name": "Pictures", /*... more resource attributes ... */}, /* ... more resource representations ... */ ]HTTP/1.1 201 Created Content-Type: application/json { "type": "collection", "resourceType": "folder", "data": [ {"name": "Documents", /* ... more resource attributes ... */}, {"name": "Pictures", /* ... more resource attributes ... */}, /* ... more resource representations ... */ ] /* ... more collection attributes ... */ }The update operation allows a client to modify resources. Update operations MUST be idempotent; making the same update request again should have no effect.
- Any change which does not have this property is an action, not an update.
Clients may submit just the attributes that they wish to change, or the entire representation of a resource. The id:, and rev:(if resource versioning is enabled) attributes MUST always be included.
The response SHOULD include the entire updated resource representation(s), even if the request did not. If the resource is a potentially large binary file instead of a JSON document, a 204 status and no body SHOULD be returned.
PUT /v1/folders/b1b2e7006be HTTP/1.1 Accept: application/json Authorization: Basic YWNjZXNzX2tleTpzZWNyZXRfa2V5 Content-Type: application/json { "id": "b1b2e7006be", "rev": "8d2e54afd", "access": "private }HTTP/1.1 200 OK Content-Type: application/json { "id": "b1b2e7006be", "rev": "8d2e54afd", "name": "Documents", "access": "private" }When updating multiple resources, the service MUST ensure that the operation is atomic.
- Either ALL the changes succeed and a 2xx response code is returned,
- or NONE of the changes are committed and a 4xx or 5xx code is returned.
- If this is not possible, do not allow multiple updates.
- The service SHOULD document and limit the number of resources that may be updated in one request and return a 400 error if the limit is exceeded.
PUT /v1/folders HTTP/1.1 Accept: application/json Authorization: Basic YWNjZXNzX2tleTpzZWNyZXRfa2V5 Content-Type: application/json [ { "id": "b1b2e7006be", "rev": "8d2e54afd", "access": "private" }, { "id": "d5a80ee7", "type": "folder", "rev": "9586f36z", "name": "Pictures", "access": "public" } ]HTTP/1.1 200 OK Content-Type: application/json { "type": "collection", "resourceType": "folder", "data": [ { "id": "b1b2e7006be", "type": "folder", "rev": "8d2e54afd", "name": "Documents", "access": "private" }, { "id": "d5a80ee7", "type": "folder", "rev": "9586f36z", "name": "Pictures", "access": "public" } ] /* ... other collection attributes ... */ }The delete operation deletes the item given by the request URL.
DELETE /v1/folders/b1b2e7006be HTTP/1.1 Accept: application/json Authorization: Basic YWNjZXNzX2tleTpzZWNyZXRfa2V5 HTTP/1.1 204 No Content When deleting multiple resources, the service MUST ensure that the operation is atomic.
- Either ALL the deletes succeed and a 2xx response code is returned,
- or NONE of the deletes are committed and a 4xx or 5xx code is returned.
- If this is not possible, do not allow multiple deletes.
- The service SHOULD document and limit the number of resources that may be deletes in one request and return a 400 error if the limit is exceeded.
DELETE /v1/folders/ HTTP/1.1 Content-Type: text/json [ "b1b2e7006be", "another_folder_id", /* ... more resource IDs ... */ ]HTTP/1.1 204 No Content If appropriate for your service, collections MAY support:
- A "truncate" action to delete all the resources in the collection (but not the collection itself).
- A "recursiveDelete" action to truncate and then delete the collection itself.
Services MAY continue to return resources that have been recently deleted in query and read operations. This is a suggestion from RightScale; It is easier for some use cases for the client to explicitly see that a resource has been removed than it is to infer that it is gone because it no longer comes back in query responses.
Deleted resources:
- MUST have a
removed:or similar attribute that the client can use to differentiate them from resources that still exist. - SHOULD support filtering on that attribute so clients that don't want them can get results that omit removed results.
- SHOULD stop being returned in query results after a documented period of time on the order of a few hours to days.
The replace operation is an atomic combination of the query, delete, and create operations.
- The request URL is treated as a query operation.
- Any matching resources are deleted.
- New resources described in the request body are created.
Services MAY implement replace for any collections where they see fit. It is most useful when updating a many-to-many relationship. For example, associating a list of IP addresses to a firewall rule. Updating this list would require a client UI to:
- Perform a query to get the current associations.
- Diff the result against what the new entries should be.
- Issue delete operation(s) for the ones that need to be removed.
- Issue create operation(s) for the ones that need to be added.
- Somehow resolve being in an inconsistent state if an error occurs partway through this process.
Replace performs all this in one convenient and atomic action for the client.
- The service MUST ensure that this entire operation is atomic.
- Either ALL the changes succeed and a 2xx response code is returned,
- or NONE of the changes are committed and a 4xx or 5xx code is returned.
The response SHOULD return the list of newly created resources, just as if the request were a normal create.
Note: this operation uses a non-standard HTTP method. There's nothing wrong with that, but some clients may not support abitrary methods.
REPLACE /v1/firewalls/42/allow HTTP/1.1 Accept: application/json Authorization: Basic YWNjZXNzX2tleTpzZWNyZXRfa2V5 Content-Type: application/json [ {"ip": "172.16.234.12"}, {"ip": "10.1.2.3"} ] HTTP/1.1 200 OK Content-Type: application/json { "type": "collection", "data": [ {"id": "1234", "ip": "172.16.234.12"}, {"id": "1235", "ip": "10.1.2.3"}, } /* ... more collection attributes ... */ }The action operation allows a client to manipulate a resource or collection in a way that cannot be done with any of the other standard operations. The request MAY include a body with additional information (arguments), and the response MAY contain a response body with result info.
Actions MAY (and generally SHOULD) incur side effects. The request URL for an operation MUST contain a query component, to distinguish it from a create operation. The actions that may be possible for given a resource type are defined in its schema. The actions: attribute in a resource specifies which actions are actually available for this particular resource and the URL to request to perform them.
POST /v1/folders/b1b2e7006be?encrypt HTTP/1.1 Accept: application/json Authorization: Basic YWNjZXNzX2tleTpzZWNyZXRfa2V5 Content-Type: application/json { "password": "purple monkey dishwasher" }HTTP/1.1 202 Accepted Content-Type: application/json { /* ... updated representation of the resource ... */ }Resources and collections MAY be nested. For example, folders might be associated to files, and files to a collection of tags:
GET /v1/folders/d5a80ee7/files/b1b2e7006be/tags HTTP/1.1 Accept: application/json Authorization: Basic YWNjZXNzX2tleTpzZWNyZXRfa2V5 HTTP/1.1 200 OK Content-Type: application/json { "type": "collection", "resourceType": "tag", "data": [ {"type: "tag", /*... more tag attributes ... */}, /* ... more tag resources ... */ ] /* ... more collection attributes ... */ }Or the content of the files stored might be exposed as a sub-resource:
PUT /v1/files/b1b2e7006be/content HTTP/1.1 Accept: application/json Authorization: Basic YWNjZXNzX2tleTpzZWNyZXRfa2V5 Content-Type: text/plain Content-Length: 2 42HTTP/1.1 204 No Content Content-Type: application/json GET /v1/files/b1b2e7006be/content HTTP/1.1 Authorization: Basic YWNjZXNzX2tleTpzZWNyZXRfa2V5 HTTP/1.1 200 OK Content-Type: text/plain Conetent-Length: 2 42Some (or all) resources MAY implement resource versioning. Versioning allows for the client to perform multiple concurrent updates on a resource and resolve conflicts when they occur.
For resources that implement versioning:
- The service MUST return resource version in responses as the
rev:attribute in query and read operations. - The client MUST include the
rev:attribute in update, patch, and action operations.- If the revision given does not match the current revision when the request is processed, the service MUST return a 409 error.
- The service MUST change the
rev:attribute whenever a field in the resource changes.
The base URL that users access your API with SHOULD be of the form: https://api{-optional-region-code}.{your product domain}/
APIs SHOULD have a separate DNS record from the your web/app load balancers, so that the API can be scaled separately from the rest of your stack. The name can always point to the web/app servers if this scale is not needed yet
All APIs that require authentication MUST be accessible to the public only over HTTPS. Unauthenticated public APIs MAY be provided over HTTP, but SHOULD also offer HTTPS.
APIs MUST support more than one version of their implementation. Clients MUST specify the particular version they want, and the application MUST NOT make changes that are not backwards compatible to that version.
Breaking changes should be avoided when possible, but you are eventually going to have to make a breaking change so it is far better to have a way to handle this built in from the start. The suggested format for the version string is the letter "v" followed by a single integer which increases by one for each revision. The version SHOULD be treated as an opaque string to the client, so any other format MAY be used.
Versions resources MAY also have a "revision" string attribute that changes on each release. This can be useful to help debug issues caused by changes made within a version that are supposed to be compatible with each other.
Outdated versions SHOULD be deprecated and eventually removed from the service. A request for a version that has been removed SHOULD return a 410 error.
Clients MUST be able to make a GET request to the base URL (without a version fragment) to find out what versions are available. This request SHOULD NOT require authentication. Clients SHOULD check the "latest" link periodically and take action if they are no longer using the latest version.
See the root level and individual version read operation for more info.
Most APIs that do something useful will need some form of authentication to determine what user is making the request and validate that they should be allowed to make it. A user is identified by a set of credentials called an API Key pair.
An API Key consists of a pair of strings called an access key and secret key. These are randomly generated opaque strings assigned by the service to each API user. The access key is analogous to a username and the secret key to a password.
Services MUST support HTTP Basic authentication. In Basic auth, the client sends their access key and secret key in the Authorization header. The service then reads these and validates the keys.
Several keywords are reserved by this standard and have specific meanings. These words MUST ONLY be used for their documented purpose:
- In resources:
id:,type:,rev:links:,actions:
- In collections:
- (Everything reserved for resources)
filters:,pagination:,sort:,sortLinks:,createTypes:,createDefaults:data:
- In resource and collection
links::self:,schemas:
- In query strings:
- For pagination:
marker,limit - For sorting:
sort,order
- For pagination:
Some additional guidelines:
- Names and attribute keys should be a single word when practical.
- Single-word collection, resource, attribute names SHOULD be all lowercase.
- Multiple words SHOULD be interCaps (also known as camelCase), not dash-separated, under_scored, or TitleCase.
- Resource names SHOULD be singular, not plural.
- These appear in a resources's
type:and schema'sid:.
- These appear in a resources's
Guidelines for creating links:
- Every reference to the
id:of another resource SHOULD have a corresponding link.- For example if a file resource has a
folderId:field, there should be afolder:link.
- For example if a file resource has a
- Links to a single resource SHOULD be singular.
- e.g.
"content": "https://base/v1/files/b1b2e7006be/content"
- e.g.
- Links to a collection SHOULD be plural.
- e.g.
"files": "https://base/v1/folders/d5a80ee7/files"
- e.g.
- Limit your URL namespace as much as possible. The less surface area you have exposed the less there is that might need to change later.
- Path components and query parameter names SHOULD be short, meaningful words in all lowercase, easy for a human to read.
- Services SHOULD NOT change the format or construction of URLs within an API version
- In theory, everyone uses the discoverability features and follows links, so services may change URL formats at any time.
- But some clients will inevitably ignore disoverability and hardcode paths into their code.
- So if a URL needs to be changed, provide a 301/302 redirect or release a new API version.
Each resource SHOULD have a single canonical URL and the representation of that resource SHOULD NOT change depending on how the client got to it.
If a file resource is accessible at https://base/v1/files/b1b2e7006be and as a data item in a collection https://base/v1/folders/d5a80ee7/files, both representations SHOULD be exactly the same.
- The links inside the resource will reflect the canonical URL.
- This prevents the service from generating arbitrarily long link URLs that contain unnecessary history of how the client got to where they are.
- One exception is that the "schemas" link MUST be present in the former response, but does not have to be in the latter, as it is only required at the top-level of the response.
GET /v1/files/b1b2e7006be HTTP/1.1 Accept: application/json HTTP/1.1 200 OK Content-Type: application/json { "id": "b1b2e7006be", "type": "file", "links": { "self": "https://base/v1/files/b1b2e7006be", "schemas": "https://base/v1/schemas", "content": "https://base/v1/files/b1b2e7006be/content", "folder": "https://base/v1/folders/19c3932wef", "public": "http://documents.your-files.com/ultimate_answer.txt" }, "actions": { "encrypt": "htps://base/v1/files/b1b2e7006be?encrypt" }, "name": "ultimate_answer.txt", /* ... more attributes ... */ }GET /v1/folders/d5a80ee7/files HTTP/1.1 Accept: application/json HTTP/1.1 200 OK Content-Type: application/json { "type": "collection", "links": { "self": "https://base/v1/folders/d5a80ee7/files", "schemas": "https://base/v1/schemas" } /* ... more attributes ... */ "data": [ { "id": "b1b2e7006be", "type": "file", /* the same JSON for file b1b2e7006be, as above */ } /* ... more resources ... */ ] }Many services have resources that exist in multiple geographic regions.
To provide the easiest management for the user, APIs SHOULD provide a single unified endpoint that can manage resources in all regions. This endpoint MAY have servers in each region and use geographic load balancing to direct the requests to the closest region.
In applications where centralized management is not possible, each region MAY have a separate endpoint with a region code identified in the base URL.
Services SHOULD do everything they can to enable the clients to take advantage of caching as much as possible.
Read operations SHOULD return a HTTP ETag header with an opaque value. The opaque value MUST uniquely describe the entire resource, and change if any part of the resource is changed. This can often be done as a hash of the serialized resource representation, e.g. convert the resource to a JSON string and return a sha-sum of the string.
Query operations SHOULD also return an ETag. The opaque value MUST uniquely describe the entire result set and change if any of the resources or metadata are changed/added/removed.
Clients MAY send an If-None-Match header along with their query or read operation. The service SHOULD compute its response, and if that response has the same ETag value, return a 304 status instead of transmitting the entire response again.
Whenver possible, services SHOULD keep a last modified date and return a Last-Modified header on Read and Query operations.
Clients MAY send an If-Modified-Since header. The service SHOULD return a 304 status instead of transmitting the entire response again if it hasn't changed since the time given.
Read and Query operations SHOULD return a Cache-Control header with values that are appropriate for the information being returned. If the data changes infrequently, allow clients to cache it for a reasonable period of time.
API Services SHOULD support gzip and deflate compression and deliver responses with an appropriate Content-Encoding header according to the Accept-Encoding requested by the client.