Help: API

e6AI offers a simple API to make scripting easy. All you need is a way to send GET, POST, PATCH and DELETE calls to URLs. The ability to parse JSON is nice but not critical. The simplicity of the API means you can write scripts using JavaScript, Perl, Python, Ruby, and even shell languages like bash or tcsh.

This documentation is not exhaustive. A good rule of thumb is that if you can do it in the UI you can also do it via the API. Take a look at the network requests your browser is making, adding .json will work most of the time. Only select endpoints have json responses disabled.

Basics | Posts | Favorites | Tags | Tag aliases | Tag implications | Notes | Pools | API Endpoint Summary

Basics

Return to top ↑

HTTP defines four request methods: GET, POST, PATCH and DELETE. You'll be using these four methods to interact with the e6AI API. Most API calls that create a new database entry use POST, calls that update an existing entry use PATCH and calls that only retrieve data use GET.

In the e6AI API, a URL is analogous to a function name. You pass in the function parameters as a query string. Here's an extremely simple example:

/posts?limit=10

Here we're retrieving a list of posts. Finally, the json part describes what format we want the response in. You can specify .json for JSON responses and nothing at all for HTML responses.

HTTP POST request bodies should be urlencoded or use multipart form data content encoding, and you should set the content-type header to the appropriate value for the encoding used. urlencoded POST bodies cannot contain files, you must use multipart form data encoding if you are uploading a file.

Almost all HTTP request libraries will included routines to do all of this encoding automatically for you, and you SHOULD use them.

User Agents

A non-empty User-Agent header is required for all requests. Please pick a descriptive User-Agent for your project. You are encouraged to include your e6AI username so that you may be contacted if your project causes problems. DO NOT impersonate a browser user agent, as this will get you blocked. An example user-agent would be MyProject/1.0 (by username on e6AI)
Due to frequent abuse, default user agents for programming languages and libraries are usually blocked. Please make sure that you are defining a user agent that is in line with our policy.

If you are using a javascript based method for requests, such as creating a userscript, a browser extension, or are otherwise unable to set a custom header from inside a browser, please attach an additional url query parameter named _client and set it based on how you would have set your user-agent.

Rate Limiting

e6AI has a hard rate limit of two requests per second. This is a hard upper limit and if you are hitting it, you are already going way too fast. Hitting the rate limit will result in a 503 HTTP response code. You should make a best effort not to make more than one request per second over a sustained period.

Responses

All API calls that change state will return a single element response. They are formatted like this:
{success: false, reason: "duplicate"}

While you can usually determine success or failure based on the response object, you can also figure out what happened based on the HTTP status code. In addition to the standard ones, e6AI uses some custom status codes in the 4xx and 5xx range.

Status CodeMeaning
200 OKRequest was successful
204 No ContentRequest was successful, nothing will be returned. Most often encountered when deleting a record
403 ForbiddenAccess denied. May indicate that your request lacks a User-Agent header (see Notice #2 above)
404 Not FoundNot found
412 Precondition failed
420 Invalid RecordRecord could not be saved
421 User ThrottledUser is throttled, try again later
422 LockedThe resource is locked and cannot be modified
423 Already ExistsResource already exists
424 Invalid ParametersThe given parameters were invalid
500 Internal Server ErrorSome unknown error occurred on the server
502 Bad GatewayA gateway server received an invalid response from the e6AI servers
503 Service UnavailableServer cannot currently handle the request or you have exceeded the request rate limit. Try again later or decrease your rate of requests
520 Unknown ErrorUnexpected server response which violates protocol
522 Origin Connection Time-outCloudFlare's attempt to connect to the e6AI servers timed out
524 Origin Connection Time-outA connection was established between CloudFlare and the e6AI servers, but it timed out before an HTTP response was received
525 SSL Handshake FailedThe SSL handshake between CloudFlare and the e6AI servers failed

Logging In

The API requires that API access be enabled on the account before it can log in using the API. To enable API access, you must go to your profile page (Account > My profile) and generate an API key. Then, and only then will the below method of logging in work. If you do not have an API key generated, you will receive a failed login, even if the details are correct.

Some actions may require you to log in. For any action you can always specify two parameters to identify yourself:

  • login Your username.
  • api_key Your API key.

HTTP Basic Auth is also available, which should be used on GET requests that need authentication, to avoid having login parameters sent in the URL.

CORS

The API allows simple requests as defined in the MDN Web Docs. You might also optionally send the Authorization header in order to login and prevent sending the login parameters in the URL directly.

What this means for you is that GET and POST requests are possible cross-origin while PATCH, PUT and DELETE are not.

Posts

Return to top ↑
Create | Update | List | Flag | Vote | Favorite

Create

Return to category top ↑

The base URL is /uploads.json called with POST.
There are only four mandatory fields: you need to supply the file (either through a multipart form or through a source URL), the tags, a source (even if blank), and the rating.

  • upload[tag_string] A space delimited list of tags.
  • upload[file] The file data encoded as a multipart form.
  • upload[rating] The rating for the post. Can be: s, q or e for safe, questionable, and explicit respectively.
  • upload[direct_url] If this is a URL, e6AI will download the file.
  • upload[source] This will be used as the post's 'Source' text. Separate multiple URLs with %0A (url-encoded newline) to define multiple sources. Limit of ten URLs
  • upload[description] The description for the post.
  • upload[parent_id] The ID of the parent post.
  • upload[referer_url]
  • upload[md5_confirmation]
  • upload[as_pending]

If the call fails, the following response reasons are possible:

  • MD5 mismatch This means you supplied an MD5 parameter and what e6AI got doesn't match. Try uploading the file again.
  • duplicate This post already exists in e6AI (based on the MD5 hash). An additional attribute called location will be set, pointing to the (relative) URL of the original post.
  • other Any other error will have its error message printed.
Response:

Success:
HTTP 200 OK

{
    "success":true",
    ”location":"/posts/<Post_ID>",
    "post_id":<Post_ID>
}

Failed due to the post already existing:
HTTP 412

{
    "success":false,
    "reason":"duplicate",
    "location":"/posts/<Post_ID>",
    "post_id":<Post_ID>}
}

Update

Return to category top ↑

The base URL is /posts/<Post_ID>.json called with PATCH.
Leave parameters blank if you don't want to change them.

  • post[tag_string_diff] A space delimited list of tag changes such as dog -cat. This is a much preferred method over the old version.

(The old method of updating a post’s tags still works, with post[old_tag_string] and post[tag_string], but post[tag_string_diff] is preferred.)

  • post[source_diff] A (URL encoded) newline delimited list of source changes. This works the same as post[tag_string_diff] but with sources.

(The old method of updating a post’s sources still works, with post[old_source] and post[source], but post[source_diff] is preferred.)

  • post[parent_id] The ID of the parent post.
  • post[old_parent_id] The ID of the previously parented post.
  • post[description] This will be used as the post's 'Description' text.
  • post[old_description] Should include the same descriptions submitted to post[description] minus any intended changes.
  • post[rating] The rating for the post. Can be: s, q or e for safe, questionable, and explicit respectively.
  • post[old_rating] The previous post’s rating.
  • post[is_rating_locked] Set to true to prevent others from changing the rating.
  • post[is_note_locked] Set to true to prevent others from adding notes.
  • post[edit_reason] The reason for the submitted changes. Inline DText allowed.
  • post[has_embedded_notes] (True/False)

List

Return to category top ↑ [ Example JSON output ]

The base URL is /posts.json called with GET.
Deleted posts are returned when status:deleted/status:any is in the searched tags.

The most efficient method to iterate a large number of posts is to search use the page parameter, using page=b<ID> and using the lowest ID retrieved from the previous list of posts. The first request should be made without the page parameter, as this returns the latest posts first, so you can then iterate using the lowest ID. Providing arbitrarily large values to obtain the most recent posts is not portable and may break in the future.

Note: Using page=<number> without a or b before the number just searches through pages. Posts will shift between pages if posts are deleted or created to the site between requests and page numbers greater than 750 will return an error.

  • limit How many posts you want to retrieve. There is a hard limit of 320 posts per request. Defaults to the value set in user preferences.
  • tags The tag search query. Any tag combination that works on the website will work here.
  • page The page that will be returned. Can also be used with a or b + post_id to get the posts after or before the specified post ID. For example a13 gets every post after post_id 13 up to the limit. This overrides any ordering meta-tag, order:id_desc is always used instead.

This returns a JSON array, for each post it returns:

  • id The ID number of the post.
  • created_at The time the post was created in the format of YYYY-MM-DDTHH:MM:SS.MS+00:00.
  • updated_at The time the post was last updated in the format of YYYY-MM-DDTHH:MM:SS.MS+00:00.
  • file (array group)
    • width The width of the post.
    • height The height of the post.
    • ext The file’s extension.
    • size The size of the file in bytes.
    • md5 The md5 of the file.
    • url The URL where the file is hosted on e6AI
  • preview (array group)
    • width The width of the post preview.
    • height The height of the post preview.
    • url The URL where the preview file is hosted on e6AI
  • sample (array group)
    • has If the post has a sample/thumbnail or not. (True/False)
    • width The width of the post sample.
    • height The height of the post sample.
    • url The URL where the sample file is hosted on e6AI.
  • score (array group)
    • up The number of times voted up.
    • down A negative number representing the number of times voted down.
    • total The total score (up + down).
  • tags (array group)
    • general A JSON array of all the general tags on the post.
    • species A JSON array of all the species tags on the post.
    • character A JSON array of all the character tags on the post.
    • invalid A JSON array of all the invalid tags on the post.
    • meta A JSON array of all the meta tags on the post.
  • locked_tags A JSON array of tags that are locked on the post.
  • change_seq An ID that increases for every post alteration on E6 (explained below)
  • flags (array group)
    • pending If the post is pending approval. (True/False)
    • flagged If the post is flagged for deletion. (True/False)
    • note_locked If the post has it’s notes locked. (True/False)
    • status_locked If the post’s status has been locked. (True/False)
    • rating_locked If the post’s rating has been locked. (True/False)
    • deleted If the post has been deleted. (True/False)
  • rating The post’s rating. Either s, q or e.
  • fav_count How many people have favorited the post.
  • sources The source field of the post.
  • pools An array of Pool IDs that the post is a part of.
  • relationships (array group)
    • parent_id The ID of the post’s parent, if it has one.
    • has_children If the post has child posts (True/False)
    • has_active_children
    • children A list of child post IDs that are linked to the post, if it has any.
  • approver_id The ID of the user that approved the post, if available.
  • uploader_id The ID of the user that uploaded the post.
  • description The post’s description.
  • comment_count The count of comments on the post.
  • is_favorited If provided auth credentials, will return if the authenticated user has favorited the post or not. HTTP Basic Auth is recommended over login and api_key parameters in the URL.

change_seq is a number that is increased every time a post is changed on the site. It gets updated whenever a post has any of these values change:

tag_string
source
description
rating
md5
parent_id
approver_id
is_deleted
is_pending
is_flagged
is_rating_locked
is_pending
is_flagged
is_rating_locked

Flag

Return to category top ↑
Listing | Creating

Listing

The base URL is /post_flags.json called with GET.

  • search[post_id] The ID of the flagged post.
  • search[creator_id] The user’s ID that created the flag.
  • search[creator_name] The user’s name that created the flag.

Returns:

  • id The flag’s ID
  • created_at The time the flag was created in the format of YYYY-MM-DDTHH:MM:SS.MS+00:00.
post_id

The ID of the post that the flag applies to.
reason The reason submitted for the flag.
is_resolved If the flag has been handled (True/False)
updated_at The time the flag was last updated in the format of YYYY-MM-DDTHH:MM:SS.MS+00:00.

  • is_deletion If the flag is a flag for deletion.
  • category The category of the flag.
Creating

The base URL is /post_flags.json and called with POST. Both fields are required.

  • post_flag[post_id] The ID of the flagged post.
  • post_flag[reason_name] The reason submitted along with the flag, eg. "inferior".
  • post_flag[parent_id] ID of the superior post when flagging an image as inferior.

If successful it will return the added note in the same format as the Listing section above.

Vote

Return to category top ↑
The base URL is /posts/<Post_ID>/votes.json called with POST.

  • score Set to 1 to vote up and -1 to vote down. Repeat the request to remove the vote.
  • no_unvote Set to true to have this score replace the old score. Repeat votes will not remove the vote.
Response:

Success:
HTTP 200

{
   "score":<total>,
   "up":<up>,
   "down":<down>,
   "our_score":x
}

Where our_score is 1, 0, -1 depending on the action.
Failure:
HTTP 422

{
    "success": false,
    "message": "An unexpected error occurred.",
    "code": null
}

Favorites

Return to top ↑
Listing | Create | Delete

Listing

The base URL is /favorites.json called with GET.

  • user_id Optional, the user to fetch the favorites from. If not specified will fetch the favorites from the currently logged in user.
Response:

Success:
HTTP 200

See #posts_list for post data specification.

{
    "posts": [
        <post data>
    ]
}

Error:
HTTP 403 if the user has hidden their favorites.
HTTP 404 if the specified user_id does not exist or user_id is not specified and the user is not logged in.

Create

The base URL is /favorites.json called with POST.

  • post_id The post id you want to favorite.
Response:

Success:
HTTP 200

See #posts_list for post data specification.

{
   "post": <post data>
}

Delete

The base URL is /favorites/<post_id>.json called with DELETE.

There is no response.

Tags

Return to top ↑
Listing

Listing

The base URL is /tags.json called with GET.

  • search[name_matches] A tag name expression to match against, which can include * as a wildcard.
  • search[category] Filters results to a particular category. Default value is blank (show all tags). See below for allowed values.
  • search[order] Changes the sort order. Pass one of date (default), count, or name.
  • search[hide_empty] Hide tags with zero visible posts. Pass true (default) or false.
  • search[has_wiki] Show only tags with, or without, a wiki page. Pass true, false, or blank (default).
  • limit Maximum number of results to return per query. Default is 75. There is a hard upper limit of 320.
  • page The page that will be returned. Can also be used with a or b + tag_id to get the tags after or before the specified tag ID. For example a13 gets every tag after tag_id 13 up to the limit. This overrides the specified search ordering, date is always used instead.
Categories:

The following values can be specified.

  • 0 general
  • 4 character
  • 5 species
  • 6 invalid
  • 7 meta

See here for a description of what different types of tags are and do.

Response:

Success:
HTTP 200

[{
   "id":<numeric tag id>,
   "name":<tag display name>,
   "post_count":<# matching visible posts>,
   "related_tags":<space-delimited list of tags>,
   "related_tags_updated_at":<ISO8601 timestamp>,
   "category":<numeric category id>,
   "is_locked":<boolean>,
   "created_at":<ISO8601 timestamp>,
   "updated_at":<ISO8601 timestamp>
},
...
]

If your query succeeds but produces no results, you will receive instead the following special value:

{ "tags":[] }

Tag Aliases

Return to top ↑
Listing

Note: Everything here also applies to Tag Implications, you just need to swap out tag_aliases with tag_implications when constructing urls.

Listing

The base URL is /tag_aliases.json called with GET.

  • search[name_matches] A tag name expression to match against, which can include * as a wildcard. Both the aliased-to and the aliased-by tag are matched.
  • search[antecedent_name] Supports multiple tag names, comma-separated.
  • search[consequent_name] Supports multiple tag names, comma-separated.
  • search[antecedent_tag_category] Pass a valid tag category. Supports multiple values, comma-separated.
  • search[consequent_tag_category] Pass a valid tag category. Supports multiple values, comma-separated.
  • search[creator_name] Name of the creator.
  • search[approver_name] Name of the approver.
  • search[status] Filters aliases by status. Pass one of approved, active, pending, deleted, retired, processing, queued, or blank (default).
  • search[order] Changes the sort order. Pass one of status (default), created_at, updated_at, name, or tag_count.
  • limit Maximum number of results to return per query.
  • page The page that will be returned. Can also be used with a or b + alias_id to get the aliases after or before the specified alias ID. For example a13 gets every alias after alias_id 13 up to the limit. This overrides the specified search ordering, created_at is always used instead.

* Some aliases have a status which is an error message, these show up in searches where status is omitted but there is no way to search for them specifically.

Response:

Success:
HTTP 200

[{
   "id": <numeric alias id>,
   "status": <status string>,
   "antecedent_name": <aliased-by tag name>,
   "consequent_name": <aliased-to tag name>,
   "post_count": <# matching posts>,
   "reason": <explanation>,
   "creator_id": <user id>,
   "approver_id": <user id>
   "created_at": <ISO8601 timestamp>,
   "updated_at": <ISO8601 timestamp>,
   "forum_post_id": <post id>,
   "forum_topic_id": <topic id>,
},
...
]

If your query succeeds but produces no results, you will receive instead the following special value:

{ "tag_aliases":[] }

Notes

Return to top ↑
Listing | Create | Update | Delete | [[#notes_revert|Revert]

Listing

The base URL is /notes.json called with GET.

  • search[body_matches] The note's body matches the given terms. Use a * in the search terms to search for raw strings.
  • search[post_id]
  • search[post_tags_match] The note's post's tags match the given terms. Meta-tags are not supported.
  • search[creator_name] The creator's name. Exact match.
  • search[creator_id] The creator's user id.
  • search[is_active] Can be: true, false
  • limit Limits the amount of notes returned to the number specified.

This returns a JSON array, for each note it returns:

  • id The Note’s ID
  • created_at The time the note was created in the format of YYYY-MM-DDTHH:MM:SS.MS+00:00.
  • updated_at The time the mote was last updated in the format of YYYY-MM-DDTHH:MM:SS.MS+00:00.
  • creator_id The ID of the user that created the note.
  • x The X coordinate of the top left corner of the note in pixels from the top left of the post.
  • y The Y coordinate of the top left corner of the note in pixels from the top left of the post.
  • width The width of the box for the note.
  • height The height of the box for the note.
  • version How many times the note has been edited.
  • is_active If the note is currently active. (True/False)
  • post_id The ID of the post that the note is on.
  • body The contents of the note.
  • creator_name The name of the user that created the note.

If no results are returned:

{"notes":[]}

Create

Return to category top ↑

The base URL is /notes.json called with POST.

  • note[post_id] The ID of the post you want to add a note to.
  • note[x] The X coordinate of the top left corner of the note in pixels from the top left of the post.
  • note[y] The Y coordinate of the top left corner of the note in pixels from the top left of the post.
  • note[width] The width of the box for the note.
  • note[height] The height of the box for the note.
  • note[body] The contents of the note.

All fields are required.

If successful it will return the added note in the same format as the Listing section above.

Update

Return to category top ↑

The base URL is /notes/<Note_ID>.json called with PUT.

  • note[x] The X coordinate of the top left corner of the note in pixels from the top left of the post.
  • note[y] The Y coordinate of the top left corner of the note in pixels from the top left of the post.
  • note[width] The width of the box for the note.
  • note[height] The height of the box for the note.
  • note[body] The contents of the note.

All fields are required.

If successful it will return the added note in the same format as the Listing section above.

Delete

Return to category top ↑

The base URL is /notes/<Note_ID>.json called with DELETE.

There is no response.

Revert

Return to category top ↑

The base URL is /notes/<Note_ID>/revert.json called with PUT.

  • version_id The note version id to revert to.

Pools

Return to top ↑
Listing | Create | Update | Revert

Listing

The base URL is /pools.json called with GET.

  • search[name_matches] Search pool names.
  • search[id] Search for a pool ID, you can search for multiple IDs at once, separated by commas.
  • search[description_matches] Search pool descriptions.
  • search[creator_name] Search for pools based on creator name.
  • search[creator_id] Search for pools based on creator ID.
  • search[is_active] If the pool is active or hidden. (True/False)
  • search[category] Can either be “series” or “collection”.
  • search[order] The order that pools should be returned, can be any of: name, created_at, updated_at, post_count. If not specified it orders by updated_at
  • limit The limit of how many pools should be retrieved.

This returns a JSON array, for each pool it returns:

  • id The ID of the pool.
  • name The name of the pool.
  • created_at The time the pool was created in the format of YYYY-MM-DDTHH:MM:SS.MS+00:00.
  • updated_at The time the pool was updated in the format of YYYY-MM-DDTHH:MM:SS.MS+00:00.
  • creator_id the ID of the user that created the pool.
  • description The description of the pool.
  • is_active If the pool is active and stillg etting posts added. (True/False)
  • category Can be “series” or “collection”.
  • post_ids An array group of posts in the pool.
  • creator_name The name of the user that created the pool.
  • post_count the amount of posts in the pool.

Create

The base URL is /pools.json called with POST.

The pool’s name and description are required, though the description can be empty.

  • pool[name] The name of the pool.
  • pool[description] The description of the pool.
  • pool[category] Can be either “series” or “collection”.
  • pool[is_locked] 1 or 0, whether or not the pool is locked. Admin only function.

Success will return the pool in the format shown in the Listing section above.

Update

The base URL is /pools/<Pool_ID>.json called with PUT.

Only post parameters you want to update.

  • pool[name] The name of the pool.
  • pool[description] The description of the pool.
  • pool[post_ids] List of space delimited post ids in order of where they should be in the pool.
  • pool[is_active] Can be either 1 or 0
  • pool[category] Can be either “series” or “collection”.

Success will return the pool in the format shown in the Listing section above.

Revert

Return to category top ↑

The base URL is /pools/<Pool_ID>/revert.json called with PUT.

  • version_id The version ID to revert to.

API Endpoint Summary

Return to top ↑

Function Endpoint Method
Search posts /posts.json GET
Upload a new post /uploads.json POST
Update a post /posts/<Post_ID>.json PATCH
Search flags /post_flags.json GET
Create a new flag /post_flags.json POST
Vote on a post /posts/<Post_ID>/votes.json POST
Favorite a post /favorites.json POST
Delete a favorite /favorites/<Post_ID>.json DELETE
Search notes /notes.json GET
Create a new note /notes.json POST
Update an existing note /notes/<Note_ID>.json PUT
Delete a note /notes/<Note_ID>.json DELETE
Revert a note to a previous version /notes/<Note_ID>/revert.json PUT
Search pools /pools.json GET
Create a new pool /pools.json POST
Update pool /pools/<Pool_ID>.json PUT
Revert pool to some previous version /pools/<Pool_ID>/revert.json PUT