Skip to content
Browse files

Initial commit of the new docs

  • Loading branch information...
1 parent dae9c73 commit f76183fb77567b51eff76a7437e0146e70819d52 Andrew Knapp committed Dec 12, 2012
Showing with 7,886 additions and 0 deletions.
  1. +9 −0 Gemfile
  2. +32 −0 Gemfile.lock
  3. +45 −0 Rules
  4. +81 −0 config.yaml
  5. +21 −0 content/docs/authentication/flows/app-access-token.md
  6. +55 −0 content/docs/authentication/flows/password.md
  7. +66 −0 content/docs/authentication/flows/web.md
  8. +106 −0 content/docs/authentication/identity-delegation.md
  9. +98 −0 content/docs/authentication/index.md
  10. +92 −0 content/docs/authentication/token.md
  11. +16 −0 content/docs/basics/data-formats.md
  12. +59 −0 content/docs/basics/migrations.md
  13. +77 −0 content/docs/basics/rate-limits.md
  14. +123 −0 content/docs/basics/responses.md
  15. +45 −0 content/docs/index.md
  16. +651 −0 content/docs/meta/annotations.md
  17. +194 −0 content/docs/meta/entities.md
  18. +119 −0 content/docs/other/feeds.md
  19. +32 −0 content/docs/other/web-intents.md
  20. +567 −0 content/docs/resources/filter/index.md
  21. +456 −0 content/docs/resources/index.md
  22. +164 −0 content/docs/resources/interaction/index.md
  23. +236 −0 content/docs/resources/post/creation.md
  24. +449 −0 content/docs/resources/post/index.md
  25. +134 −0 content/docs/resources/post/lookup.md
  26. +82 −0 content/docs/resources/post/replies.md
  27. +187 −0 content/docs/resources/post/reposts.md
  28. +256 −0 content/docs/resources/post/stars.md
  29. +465 −0 content/docs/resources/post/streams.md
  30. +95 −0 content/docs/resources/stream-marker/index.md
  31. +472 −0 content/docs/resources/stream/index.md
  32. +307 −0 content/docs/resources/subscription/index.md
  33. +485 −0 content/docs/resources/user/following.md
  34. +380 −0 content/docs/resources/user/index.md
  35. +243 −0 content/docs/resources/user/lookup.md
  36. +271 −0 content/docs/resources/user/muting.md
  37. +189 −0 content/docs/resources/user/post-interactions.md
  38. +331 −0 content/docs/resources/user/profile.md
  39. +108 −0 layouts/default.html
  40. +2 −0 lib/default.rb
  41. +55 −0 lib/static.rb
  42. +31 −0 static/css/style.css
View
9 Gemfile
@@ -0,0 +1,9 @@
+source "http://rubygems.org"
+
+gem 'nanoc'
+gem 'adsf'
+gem 'fssm'
+gem 'kramdown'
+gem 'coderay'
+gem 'pygments.rb'
+gem 'nokogiri'
View
32 Gemfile.lock
@@ -0,0 +1,32 @@
+GEM
+ remote: http://rubygems.org/
+ specs:
+ adsf (1.1.1)
+ rack (>= 1.0.0)
+ coderay (1.0.8)
+ colored (1.2)
+ cri (2.3.0)
+ colored (>= 1.2)
+ fssm (0.2.9)
+ kramdown (0.14.0)
+ nanoc (3.4.2)
+ cri (~> 2.2)
+ nokogiri (1.4.7)
+ posix-spawn (0.3.6)
+ pygments.rb (0.3.2)
+ posix-spawn (~> 0.3.6)
+ yajl-ruby (~> 1.1.0)
+ rack (1.4.1)
+ yajl-ruby (1.1.0)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ adsf
+ coderay
+ fssm
+ kramdown
+ nanoc
+ nokogiri
+ pygments.rb
View
45 Rules
@@ -0,0 +1,45 @@
+#!/usr/bin/env ruby
+
+# A few helpful tips about the Rules file:
+#
+# * The string given to #compile and #route are matching patterns for
+# identifiers--not for paths. Therefore, you can’t match on extension.
+#
+# * The order of rules is important: for each item, only the first matching
+# rule is applied.
+#
+# * Item identifiers start and end with a slash (e.g. “/about/” for the file
+# “content/about.html”). To select all children, grandchildren, … of an
+# item, use the pattern “/about/*/”; “/about/*” will also select the parent,
+# because “*” matches zero or more characters.
+
+compile '/static/*' do
+end
+
+compile '*' do
+ if item.binary?
+ # don’t filter binary items
+ else
+ filter :erb
+ filter :kramdown
+ filter :colorize_syntax,
+ :colorizers => {:javascript => :pygmentsrb}
+ layout 'default'
+ end
+end
+
+route '/static/*' do
+ '/assets'+item.identifier[7..-2]
+end
+
+route '*' do
+ if item.binary?
+ # Write item with identifier /foo/ to /foo.ext
+ item.identifier.chop + '.' + item[:extension]
+ else
+ # Write item with identifier /foo/ to /foo/index.html
+ item.identifier + 'index.html'
+ end
+end
+
+layout '*', :erb
View
81 config.yaml
@@ -0,0 +1,81 @@
+# A list of file extensions that nanoc will consider to be textual rather than
+# binary. If an item with an extension not in this list is found, the file
+# will be considered as binary.
+text_extensions: [ 'coffee', 'css', 'erb', 'haml', 'handlebars', 'hb', 'htm', 'html', 'js', 'less', 'markdown', 'md', 'ms', 'mustache', 'php', 'rb', 'sass', 'scss', 'txt', 'xhtml', 'xml' ]
+
+# The path to the directory where all generated files will be written to. This
+# can be an absolute path starting with a slash, but it can also be path
+# relative to the site directory.
+output_dir: output
+
+# A list of index filenames, i.e. names of files that will be served by a web
+# server when a directory is requested. Usually, index files are named
+# “index.html”, but depending on the web server, this may be something else,
+# such as “default.htm”. This list is used by nanoc to generate pretty URLs.
+index_filenames: [ 'index.html' ]
+
+# Whether or not to generate a diff of the compiled content when compiling a
+# site. The diff will contain the differences between the compiled content
+# before and after the last site compilation.
+enable_output_diff: false
+
+prune:
+ # Whether to automatically remove files not managed by nanoc from the output
+ # directory. For safety reasons, this is turned off by default.
+ auto_prune: false
+
+ # Which files and directories you want to exclude from pruning. If you version
+ # your output directory, you should probably exclude VCS directories such as
+ # .git, .svn etc.
+ exclude: [ '.git', '.hg', '.svn', 'CVS' ]
+
+# The data sources where nanoc loads its data from. This is an array of
+# hashes; each array element represents a single data source. By default,
+# there is only a single data source that reads data from the “content/” and
+# “layout/” directories in the site directory.
+data_sources:
+ -
+ # The type is the identifier of the data source. By default, this will be
+ # `filesystem_unified`.
+ type: filesystem_unified
+
+ # The path where items should be mounted (comparable to mount points in
+ # Unix-like systems). This is “/” by default, meaning that items will have
+ # “/” prefixed to their identifiers. If the items root were “/en/”
+ # instead, an item at content/about.html would have an identifier of
+ # “/en/about/” instead of just “/about/”.
+ items_root: /
+
+ # The path where layouts should be mounted. The layouts root behaves the
+ # same as the items root, but applies to layouts rather than items.
+ layouts_root: /
+
+ # Whether to allow periods in identifiers. When turned off, everything
+ # past the first period is considered to be the extension, and when
+ # turned on, only the characters past the last period are considered to
+ # be the extension. For example, a file named “content/about.html.erb”
+ # will have the identifier “/about/” when turned off, but when turned on
+ # it will become “/about.html/” instead.
+ allow_periods_in_identifiers: false
+
+ -
+ type: static
+ items_root: /static
+
+# Configuration for the “watch” command, which watches a site for changes and
+# recompiles if necessary.
+watcher:
+ # A list of directories to watch for changes. When editing this, make sure
+ # that the “output/” and “tmp/” directories are _not_ included in this list,
+ # because recompiling the site will cause these directories to change, which
+ # will cause the site to be recompiled, which will cause these directories
+ # to change, which will cause the site to be recompiled again, and so on.
+ dirs_to_watch: [ 'content', 'layouts', 'lib' ]
+
+ # A list of single files to watch for changes. As mentioned above, don’t put
+ # any files from the “output/” or “tmp/” directories in here.
+ files_to_watch: [ 'config.yaml', 'Rules' ]
+
+ # When to send notifications (using Growl or notify-send).
+ notify_on_compilation_success: true
+ notify_on_compilation_failure: true
View
21 content/docs/authentication/flows/app-access-token.md
@@ -0,0 +1,21 @@
+# App Access Token Flow
+
+The App Access Token Flow is used to request a token that is tied to your application instead of a specific user. **App access tokens cannot be distributed and must only be used from a server. You should consider them secret.** If you would like a client (i.e. mobile) application to use an app access token, that app must connect to a server you control that stores the app access token.
+
+To retrieve an app access token, your app must make the following request:
+
+ POST https://alpha.app.net/oauth/access_token
+
+with URL-encoded POST body:
+
+ client_id=[your client ID]
+ &client_secret=[your client secret]
+ &grant_type=client_credentials
+
+> Note: we also accept the `client_id` and `client_secret` parameters via the Authorization header, as described in [section 2.3.1 of the spec](http://tools.ietf.org/html/draft-ietf-oauth-v2-31#section-2.3.1).
+
+App.net will respond with a JSON-encoded token:
+
+ {"access_token": "[app access token]"}
+
+You can use this access_token to make authenticated calls to the App.net API on behalf of your app.
View
55 content/docs/authentication/flows/password.md
@@ -0,0 +1,55 @@
+# Password Flow
+
+This is referred to as the Resource Owner Password Credential flow in the OAuth 2.0 spec. However, in order to protect the integrity of `client_secret`s, we require the use of a separate token to be included with flows.
+
+This flow is useful for obtaining an access token authorized for specific scopes when pushing the user into a browser-based flow is impractical for technical or user-experience reasons.
+
+## Important notes
+
+**Security of user accounts is the most important thing.** When in doubt, err on the side of securing user password information, rather than optimizing for user experience.
+
+**Your application must be specifically approved to use this flow.** To obtain authorization, please email password-auth@app.net from your user account's email address and include your application's `client_id`, your username, and an explanation of your situation.
+
+## Additional rules
+
+> Some of these rules might limit what you can do with your app. Please do not attempt to circumvent them, or we will disable your application token. That may sound harsh, but it is of utmost importance that we protect the integrity of the service and the security of user accounts.
+
+1. **NEVER** store user password information, no matter how securely. Users should be able to disable access to your application at any time by revoking authorization. Access tokens are designed not to expire unless users take explicit action, so there is no need to build in a mechanism to reauthenticate that would require storing passwords.
+1. Do not send user password information over the network, except to the prescribed App.net OAuth endpoint.
+1. **NEVER** log user password information, even debug logging to your app or device's console. It is too easy to accidentally leak password information this way.
+1. These flows should only be used in cases where browser-based authentication is impractical. For one-off applications, shell scripts, please use the pre-generated access token available in the "Apps" section of App.net.
+1. Users must have a way to see which scopes are being requested by an application. This can be behind a "more info" button, but must at least be exposed on the login screen, before users are required to enter their password information to coninue.
+1. By default, **users will receive an email each time they authorize an application with this flow**, listing the name of the application, the scopes requested and the time that authorization was performed.
+1. If an error is returned from the OAuth endpoint, it MUST be displayed to users verbatim.
+1. If these rules are updated, application developers must make reasonable attempts to comply with new regulations wherever possible.
+
+## Procedure
+
+Once approved, it's pretty straightforward:
+
+1. From your client, make a request to the token endpoint:
+
+ POST https://alpha.app.net/oauth/access_token
+
+ with URL-encoded POST body:
+
+ client_id=[your client ID]
+ &password_grant_secret=[your password grant secret, not your client secret]
+ &grant_type=password
+ &username=[user's email or username]
+ &password=[user's password]
+ &scope=[scopes separated by spaces]
+
+ > Note: The use of `password_grant_secret` diverges from the OAuth 2.0 specificaion. `password_grant_secret` is a special token that we'll send you when your use of the password flow is approved.
+
+1. If the authorization was successful, App.net will respond with a JSON-encoded token:
+
+ {"access_token": "[user access token]"}
+
+ You can use this access_token to make authenticated calls to the App.net API on behalf of a user.
+
+1. If authentication failed or there was another error, App.net will respond with an error:
+
+ {"error": "Authentication failed"}
+
+ If the `error_text` key is present in this dictionary, you **MUST** show a modal dialog or equivalent containing this text. If possible, you should include value of the `error_title` key as a title in your dialog.
View
66 content/docs/authentication/flows/web.md
@@ -0,0 +1,66 @@
+# Web Flows
+
+## Server-side Flow
+
+This is the easiest way to get an access token—we recommend it to most users of the API. If you're writing an app on a server using a language like Ruby, Python, PHP, Java, etc. you should use this flow.
+
+**You must keep your client_secret confidential**. That means that you may not include it in the source code or binary of an application that you ship to end-users, even in obscured form.
+
+1. Direct the user that you want to authenticate to this URL:
+
+ https://alpha.app.net/oauth/authenticate
+ ?client_id=[your client ID]
+ &response_type=code
+ &redirect_uri=[your redirect URI]
+ &scope=[scopes separated by spaces]
+
+ > To avoid cross-site scripting attacks, we also support the **state** parameter. If you include a state parameter, we will append it to the query parameters when redirecting the user to your **Redirection URI**.
+
+ > To comply with Apple's App Store Guidelines, you can add the query string parameter `adnview=appstore` to hide all signup links on the authentication pages.
+
+ We'll request that the user log in to App.net and show them a permissions dialog allowing them to choose whether to authorize your application.
+
+1. If the user decides to authorize your application, they will be redirected to: `https://[your registered redirect URI]/?code=CODE`
+
+ > If you included a query string in your redirect URI, the `code` parameter will be appended. Likewise, the scheme of your redirect URI will be respected, though we strongly recommend sending all traffic over HTTPS.
+
+1. On your server, your application should then make the following request: `POST https://alpha.app.net/oauth/access_token`
+
+ with URL-encoded POST body:
+
+ client_id=[your client ID]
+ &client_secret=[your client secret]
+ &grant_type=authorization_code
+ &redirect_uri=[your registered redirect URI]
+ &code=[code received from redirect URI]
+
+ > Note: we also accept the `client_id` and `client_secret` parameters via the Authorization header, as described in [section 2.3.1 of the spec](http://tools.ietf.org/html/draft-ietf-oauth-v2-31#section-2.3.1).
+
+1. App.net will respond with a JSON-encoded token: `{"access_token": "[user access token]"}`
+
+ You can use this access_token to make authenticated calls to the App.net API on behalf of a user.
+
+## Client-side Flow
+
+If you're building a client-side Javascript app or a mobile app that doesn't have an associated back-end server, you'll find that you need to take some special steps to keep your `client_secret` confidential.
+
+1. Direct the user that you want to authenticate to this URL:
+
+ https://alpha.app.net/oauth/authenticate
+ ?client_id=[your client ID]
+ &response_type=token
+ &redirect_uri=[your redirect URI]
+ &scope=[scopes separated by spaces]
+
+ > To avoid cross-site scripting attacks, we also support the **state** parameter. If you include a state parameter, we will append it to the query parameters when redirecting the user to your **Redirection URI**.
+
+ > To comply with Apple's App Store Guidelines, you can add the query string parameter `adnview=appstore` to hide all signup links on the authentication pages.
+
+ We'll request that the user log in to App.net and show them a permissions dialog allowing them to choose whether to authorize your application.
+
+1. If the user decides to authorize your application, they will be redirected to: `https://[your registered redirect URI]/#access_token=[user access token]`
+
+ > If you included a query string in your redirect URI, the `code` parameter will be appended. Likewise, the scheme of your redirect URI will be respected, though we strongly recommend sending all traffic over HTTPS.
+
+ The access_token will be appended to the URI in the fragment section, encoded as if it were a query string. Your client-side code should parse this for the access_token.
+
View
106 content/docs/authentication/identity-delegation.md
@@ -0,0 +1,106 @@
+# Identity Delegation
+
+The purpose of this specification is to define a method by which one App.net app is able to verifiably prove to another application that it has access to a specific user's account without sharing any secret credentials.
+
+## Definitions
+
+> Unless otherwise defined here, terms should have the same approximate usage as the OAuth 2.0 draft specification.
+
+* **delegate client**: The client to which the identity delegation is made (e.g., a photo hosting service)
+* **authorized client**: The client wishing to make a request to the delegate client (e.g., an App.net mobile client application)
+
+## Scope
+
+Intentionally not addressed in this document are the following:
+
+* Authorization of delegate client to make requests to the request server on behalf of the resource owner
+* Discovery of delegate client `client_id`
+* Discovery of user identity endpoints
+* Format of user identity endpoint
+
+## Steps
+
+1. The authorized client completes an OAuth authorization flow and obtains an access token from the resource server. This is outside the scope of this document.
+
+1. The authorized client makes an authenticated POST request to the resource server OAuth token endpoint:
+
+ POST /oauth/access_token HTTP/1.1
+ Host: alpha.app.net
+ Authorization: Bearer [access_token]
+ Content-Length: 59
+ Content-Type: application/x-www-form-urlencoded
+
+ grant_type=delegate&delegate_client_id=[delegate client_id]
+
+ which returns in the body of the reply:
+
+ {"delegate_token": "[delegate token]"}
+
+ > For App.net, the OAuth token endpoint is: `https://alpha.app.net/oauth/access_token`
+
+1. The authorized client makes a request to the delegate client with two additional headers, `Identity-Delegate-Token` and `Identity-Delegate-Endpoint`:
+
+ POST /protected/resource HTTP/1.1
+ Host: delegate-client.example.com
+ Identity-Delegate-Token: [delegate_token]
+ Identity-Delegate-Endpoint: https://alpha-api.app.net/stream/0/token
+ Content-Length: 100
+ Content-Type: application/x-www-form-urlencoded
+
+ do_some_stuff=1&fo_reals=1
+
+ The Authorization header is purposefully not used, as another mechanism may be in place for authentication.
+
+ > The delegate token and delegate endpoint may also be sent as delegate_token and delegate_endpoint in the query string or POST body.
+
+1. The delegate client identifies the resource server by using the `Identity-Delegate-Endpoint` header and makes a request to that endpoint with the Authorization header set.
+
+ > The query string parameters `delegate_token`, `client_id` and `client_secret` may be used in place of HTTP headers if desired.
+
+ GET /stream/0/token HTTP/1.1
+ Host: alpha-api.app.net
+ Authorization: Basic [base64(client_id + ":" + client_secret)]
+ Identity-Delegate-Token: [delegate_token]
+
+ which returns in the body of the reply:
+
+ {
+ "data": {
+ "app": {
+ "client_id": "udxGzAVBdXwGtkHmvswR5MbMEeVnq6n4",
+ "link": "http://foo.example.com",
+ "name": "Bryan's app for testing"
+ },
+ "client_id": "udxGzAVBdXwGtkHmvswR5MbMEeVnq6n4",
+ "scopes": [
+ "follow",
+ "write_post",
+ "stream"
+ ],
+ "user": {
+ "created_at": "2012-07-30T18:57:05Z",
+ "id": "16",
+ "locale": "en_US",
+ "name": "Bryan Berg",
+ "timezone": "America/Los_Angeles",
+ "type": "human",
+ "username": "bryan"
+ [... truncated for the sake of brevity ...],
+ },
+ },
+ "meta": {
+ "code": 200
+ }
+ }
+
+ The resource server replies with an implementation-dependent description of the current user, which must include the client_id the authorized client. In the case of App.net, this is the Token object of the authorizing client's access_token as returned by the [Retrieve current Token](../resources/token.md#retrieve-current-token) endpoint.
+
+ The delegate client may verify that the authorized client matches some external authentication scheme and/or list of authorized applications. If the delegate token is not valid for the delegate client's client_id, this call will return a `401 Unauthorized`.
+
+ > For App.net, the identity delegation endpoint is: `https://alpha-api.app.net/stream/0/token`
+
+## Notes
+
+1. `delegate_token`s are valid as long as their associated `access_token`s are valid.
+1. The delegate client may cache the return value of the identity delegate endpoint for a short period of time.
+1. Feedback on this draft is welcomed. Please open an issue on the [api-spec GitHub repo](https://github.com/appdotnet/api-spec/issues). Private or security-sensitive commentary can be sent to [bryan@app.net](mailto:bryan@app.net).
View
98 content/docs/authentication/index.md
@@ -0,0 +1,98 @@
+# Authentication
+
+As a developer working with App.net, you are required to follow some simple rules to ensure that the privacy and security of user data is protected. To help you achieve that, we've put together this document on how to authenticate with App.net.
+
+All requests to the API—authenticated or not—must be made over HTTPS. We use the [OAuth 2.0 protocol](http://tools.ietf.org/html/draft-ietf-oauth-v2-31) for API authentication, but only certain portions of the specification. For instance, we only support the use of bearer tokens as access tokens. The specification is a little dense on the standards-speak, but we encourage you to take a look. We'll explain our specific use of OAuth 2 in this document.
+
+## Initial Developer Setup
+
+Once you have signed up as a developer, you will be able to create an app from the [App.net developer dashboard](https://account.app.net/developer/apps/). You will need to pre-register a **redirection URI**. This is where we will redirect users after they have successfully authorized your application.
+
+Once you have created an application, you will be assigned a **client ID** and **client secret**. You will use these in the authentication flow. The client ID may be publicly shared (e.g., included in a compiled binary or in the source code of a web page), but the client secret **must** be kept confidential.
+
+You authenticate to our API by use of an **access token**. There are two types of access tokens: client tokens and user tokens. **Client tokens** represent access to API resources on behalf of the application and **user tokens** represent access to API resources on behalf of a specific user. Some resources are only accessible to client or user tokens.
+
+It should go without saying, but for the sake of user privacy and security, please ensure that your App.net account has a **strong password**.
+
+## How do I get an access token?
+
+If you want a **user token**, you must use one of these flows:
+
+* **[Web flow (server-side)](flows/web/#server-side-flow)** - use this if you're building a web application backed by a server. (The OAuth 2.0 internet-draft calls this the [Authorization Code Flow](http://tools.ietf.org/html/draft-ietf-oauth-v2-31#section-4.1).)
+* **[Web flow (client-side)](flows/web/#client-side-flow)** - use this if you're building an application without a central server, like a mobile app or a client-side Javascript app. (The OAuth 2.0 internet-draft calls this the [Implicit Grant Flow](http://tools.ietf.org/html/draft-ietf-oauth-v2-31#section-4.2).)
+* **[Password flow](flows/password/)** - use this if you're building a native application (or an application where it is difficult to use a web browser) and want to avoid implementing a web-based authentication flow. This flow requires special permission to use and comes with a bunch of extra rules and requirements to protect user security.
+
+If you're only interested in obtaining a **client token** (sometimes called an "App token"), you can use the **[app access token flow](flows/app_access_token)**. (The OAuth 2.0 internet-draft calls this this [Client Credentials Grant](http://tools.ietf.org/html/draft-ietf-oauth-v2-31#section-4.4).)
+
+We also intend to provide a SDK you can embed into your mobile applications to provide seamless authentication with App.net to your application's users.
+
+### Errors
+
+If an error occurs while obtaining an access token, we'll notify you by redirecting the user to the **Redirection URI** with the following additional query string or fragment parameters:
+
+* `error` — a single error code from [this list](http://tools.ietf.org/html/draft-ietf-oauth-v2-31#section-4.1.2.1)
+* `error_description` — a human readable error description.
+* `error_uri` — a URI identifying a human-readable webpage with information about the error.
+
+If a user is redirected to your application with an error code, you should be sure to give your user an informative error message.
+
+### Scopes
+
+Scopes are how an application specifies what kind of data it wants from a User. They are specified on the initial access token request. A user will be able to see a list of the permissions you are requesting with explanations of what each of the permissions means. They will be able to authorize any permissions they choose. Your app should not assume that an access token has all the requested scopes.
+
+When using an OAuth token, App.net will include an extra HTTP headers so the app knows what scopes that token has authorized. For example:
+
+> X-OAuth-Scopes: email,follow
+
+means that the current token has permission to see the user's email and to follow new users.
+
+Here is the current list of scopes on App.net:
+
+* **basic**: see basic information about this user
+* **stream**: read this user's stream
+* **email**: access this user's email address
+* **write_post**: create a new post as this user
+* **follow**: add or remove follows (or mutes) for this user
+* **messages**: send and receive private messages as this user
+* **update_profile**: update a user's name, images, and other profile information
+* **export**: bulk export all of this user's App.net data. This is intended only for backup services, not day-to-day App.net client use. Users will be shown an extra warning when this scope is requested due to the sensitivity of this data.
+
+The **basic** scope will always be granted on creation of access token, even if the token request omits it.
+
+## Making Authenticated API Requests
+
+All requests to the API—authenticated or not—must be made over HTTPS.
+
+When making a call to one of our API resources, there are three ways to include authentication information.
+
+> In all of these examples, `[access token]` is the user's access token, free of any JSON framing or query string parameters.
+
+* Adding an Authorization header (**preferred**)
+
+ Add the following header to your request:
+ `Authorization: Bearer [access token]`
+ where `[access token]` is the value of the user's access token.
+
+ Here's an example:
+
+ curl -H 'Authorization: Bearer [access token]' \
+ -F 'text=Test post' \
+ https://alpha-api.app.net/stream/0/posts
+
+* Add `access_token` to query string
+
+ curl https://alpha-api.app.net/stream/0/posts/1?access_token=[access token]
+
+* Add `access_token` to HTTP body.
+
+ > Note: this method will only work with the `PUT`, `POST`, and `PATCH` methods. `GET` and `DELETE` do not accept an HTTP body.
+
+ curl -F 'access_token=[access token]' \
+ -F 'text=Test post' \
+ https://alpha-api.app.net/stream/0/posts
+
+## How can I authenticate between App.net apps?
+
+We call this Identity Delegation. The detailed [Identity Delegation
+specification](identity_delegation/) has its own page.
+
View
92 content/docs/authentication/token.md
@@ -0,0 +1,92 @@
+# Token
+
+## Retrieve current Token
+
+Returns info about the current OAuth Token and current <a href="../objects/user.md">User</a> object.
+
+> This endpoint is currently migrated by the ```response_envelope``` migration. Please refer to the [Migrations documentation](/appdotnet/api-spec/blob/master/migrations.md#current-migrations) for more info.
+
+### URL
+> https://alpha-api.app.net/stream/0/token
+
+### Parameters
+
+None.
+
+### Example
+
+> GET https://alpha-api.app.net/stream/0/token
+```js
+{
+ "data": {
+ "client_id": "udxGzAVBdXwGtkHmvswR5MbMEeVnq6n4",
+ "app": {
+ "client_id": "udxGzAVBdXwGtkHmvswR5MbMEeVnq6n4",
+ "link": "http://foo.example.com",
+ "name": "Bryan's app for testing"
+ },
+ "scopes": [
+ "stream",
+ "messages",
+ "export",
+ "write_post",
+ "follow",
+ "email"
+ ],
+ "user": {
+ "id": "1", // note this is a string
+ "username": "mthurman",
+ "name": "Mark Thurman",
+ "description": {
+ "text": "Hi, I'm Mark Thurman and I'm teaching you about the @appdotnet Stream #API.",
+ "html": "Hi, I'm Mark Thurman and I'm <a href=\"https://github.com/appdotnet/api_spec\" rel=\"nofollow\">teaching you</a> about the <span itemprop=\"mention\" data-mention-name=\"appdotnet\" data-mention-id=\"3\">@appdotnet</span> Stream #<span itemprop=\"hashtag\" data-hashtag-name=\"api\">API</span>.",
+ "entities": {
+ "mentions": [{
+ "name": "appdotnet",
+ "id": "3",
+ "pos": 52,
+ "len": 10
+ }],
+ "hashtags": [{
+ "name": "api",
+ "pos": 70,
+ "len": 4
+ }],
+ "links": [{
+ "text": "teaching you",
+ "url": "https://github.com/appdotnet/api-spec",
+ "pos": 29,
+ "len": 12
+ }]
+ }
+ },
+ "timezone": "US/Pacific",
+ "locale": "en_US",
+ "avatar_image": {
+ "height": 512,
+ "width": 512,
+ "url": "https://example.com/avatar_image.jpg"
+ },
+ "cover_image": {
+ "height": 118,
+ "width": 320,
+ "url": "https://example.com/cover_image.jpg"
+ },
+ "type": "human",
+ "created_at": "2012-07-16T17:23:34Z",
+ "counts": {
+ "following": 100,
+ "followers": 200,
+ "posts": 24,
+ "stars": 76
+ },
+ "follows_you": false,
+ "you_follow": true,
+ "you_muted": false,
+ }
+ },
+ "meta": {
+ "code": 200
+ }
+}
+```
View
16 content/docs/basics/data-formats.md
@@ -0,0 +1,16 @@
+## Notes on data formats
+
+### Dates
+
+Dates will be formatted as a **strict** subset of [ISO 8601](http://en.wikipedia.org/wiki/ISO_8601). Dates are parseable by almost any ISO 8601 date parser or merely by parsing from position. All dates will be formatted as follows:
+
+`2012-12-31T13:22:55Z`
+
+where `2012` is the year, `12` represents December, `31` represents the 31st day of the month, `13` represents 1 PM, `22` minutes and `55` seconds past the hour. All times will be expressed in terms of UTC.
+
+This format was chosen to minimize ambiguity and edge cases in terms of parsing while maximizing readability of dates during
+development.
+
+### Object IDs
+
+Object ids will always be transferred as strings to avoid issues with with limitations of JavaScript integers. You can assume that object ids are integers.
View
59 content/docs/basics/migrations.md
@@ -0,0 +1,59 @@
+# Migrations
+
+We reserve the right to make incremental changes to the API as we deem necessary. In order to make it possible to change the API but still support legacy applications, we will make use of migrations. Migrations are a per-app feature that developers may toggle for their own apps from the time that the old behavior is deprecated until the time that it has reached the end of its life (EOL). Once the EOL date is reached, the migration will be enabled for all apps with no legacy mode available.
+
+## Accessing Migration Data
+
+We offer a single toggle for each migration and app that will globally turn the migration on (current mode) or off (legacy mode) for that app as well as a per-call header mechanism that overrides the global behavior.
+
+### Global Toggle
+
+Global migration data may be accessed in the Edit App Page - https://alpha.app.net/developer/app/edit/[app_id]. From here, developers can toggle the behavior of their apps' migrations.
+
+By default, new apps will come with all existing migrations toggled to "Current" mode. This reflects the fact that support for legacy mode will eventually be removed. However, any migrations that are released after the app is created will be initially toggled to "Legacy" mode, so app developers can expect that the API behavior will not unexpectedly change for existing apps.
+
+### Per-call Toggle
+In addition to using the edit app toggles, we offer the X-ADN-Migration-Overrides header as a way for developers to override migration behavior on a per-call basis. This header should contain a **query-string encoded** list of valid [migration keys](#current-migrations) and values (0 or 1). For example, providing
+`X-ADN-Migration-Overrides: response_envelope=0`
+would disable [response envelopes](#current-migrations) for that particular call. We expect that some apps may be distributed in such a way that some users may be running old versions while others are running newer versions, so this override header may make it easier to adopt new functionality without causing regressions. As with the toggle, though, migration override keys cannot be used past their EOL dates. Also, X-ADN-Migration-Overrides is whitelisted for CORS, so we expect that it should be usable in all contexts.
+
+### Migration Response Header
+All calls to our endpoints will return X-ADN-Migrations-Enabled, a query-string encoded list of migration keys that are enabled for that particular API call. This list will take into account globally toggled migrations as well as those enabled by X-ADN-Migration-Overrides.
+
+### Using Migrations with JSONP
+For JSONP requests we offer the ability to override the default migration behavior on a per-call basis. To do this, add a list of valid [migration keys](#current-migrations) and values (0 or 1) to the query string. For example, `https://alpha-api.app.net/stream/0/posts/stream/global?callback=json_callback&response_envelope=0`
+
+**Toggling migrations with the query string is ONLY for available JSONP requests.** Use the header mechanism for all other requests.
+
+## Current Migrations
+
+<table>
+ <thead>
+ <tr>
+ <th>Key</th>
+ <th>Migration (name)</th>
+ <th>Description</th>
+ <th>End-Of-Life Date</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><code>response_envelope</code></td>
+ <td>Response Envelope</td>
+ <td>Wraps all responses in a JSON <a href="/appdotnet/api-spec/blob/master/responses.md">Response envelope</a>.</td>
+ <td>2012-11-26</td>
+ </tr>
+ <tr>
+ <td><code>disable_min_max_id</code></td>
+ <td>Disable Min/Max ID</td>
+ <td>Disables the min_id and max_id <a href="resources/posts.md#general-parameters">general parameters</a> on endpoints that return Post objects. The new parameters are since_id and before_id.</td>
+ <td>2012-11-26</td>
+ </tr>
+ <tr>
+ <td><code>follow_pagination</code></td>
+ <td>Allow pagination of the /followers, /following endpoints</td>
+ <td>Turns on pagination for user /stream/0/users/[user_id]/{followers,following} endpoints using the <a href="/appdotnet/api-spec/blob/master/responses.md">response envelope</a> and <a href="resources/posts.md#general-parameters">since_id and before_id</a>.</td>
+ <td>2012-11-26</td>
+ </tr>
+ </tbody>
+</table>
View
77 content/docs/basics/rate-limits.md
@@ -0,0 +1,77 @@
+# Rate Limits
+
+Fundamental limits of server resources and network infrastructure make it necessary for us to limit the rate at which we handle requests. By enforcing request rate limits, we make it feasible to fairly and evenly distribute our capacity amongst our users and prevent apps from monopolizing these resources.
+
+## Enforcement
+
+Any request, authorized or unauthorized, may be subject to multiple rate limits. At present, authorized calls are limited per access token, while unauthorized calls are limited per IP address. When more than one limit applies to a request, the request will apply against each of those limits, but information will be returned on only the most restrictive of those limits.
+
+## Response Headers
+
+The following sample shows a set of three headers which might be returned with a response to a call to the API.
+
+```
+X-RateLimit-Remaining: 4959
+X-RateLimit-Limit: 5000
+X-RateLimit-Reset: 3600
+```
+
+The first header, ```X-RateLimit-Remaining```, indicates the total number of requests remaining for this cycle (4959). ```X-RateLimit-Limit``` indicates the total capacity (5000). ```X-RateLimit-Reset``` gives the number of seconds until the remaining number of requests will be reset to the capacity; in this case, ```X-RateLimit-Remaining``` will be reset to 5000 requests in 3600 seconds, irrespective of how many additional requests are made between now and then.
+
+## Exceeding Limits
+
+Should your request exceed any applicable rate limits, we will return a status code ```429``` (Too many requests). We ask that any app which is accessing our API respect this response code. The ```Retry-After``` header will contain the number of seconds before another request of this type can be made -- if your request receives a ```429``` code, your application should wait until the ```Retry-After``` period has elapsed before attempting the same kind of request.
+
+## Limits
+
+At present, these are the limit values we use.
+
+### Authenticated Requests (per token)
+
+
+<table>
+ <thead>
+ <tr>
+ <th>Type</th>
+ <th>Limit</th>
+ <th>Period</th>
+ <th>Notes</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>Global</td>
+ <td>5000</td>
+ <td>1 hour (3600 seconds)</td>
+ <td>Affects all authenticated endpoints, even if other limits apply as well.</td>
+ </tr>
+ <tr>
+ <td>Write</td>
+ <td>20</td>
+ <td>1 minute (60 seconds)</td>
+ <td>POST/DELETE requests.</td>
+ </tr>
+ </tbody>
+</table>
+
+### Unauthenticated Requests (per IP address)
+
+
+<table>
+ <thead>
+ <tr>
+ <th>Type</th>
+ <th>Limit</th>
+ <th>Period</th>
+ <th>Notes</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>Global</td>
+ <td>50</td>
+ <td>1 minute (60 seconds)</td>
+ <td>Affects all unauthenticated endpoints.</td>
+ </tr>
+ </tbody>
+</table>
View
123 content/docs/basics/responses.md
@@ -0,0 +1,123 @@
+# Responses
+
+>All information in this document assumes the ```response_envelope``` migration is active. Please refer to [Migrations](/appdotnet/api-spec/blob/master/migrations.md) for more information.
+
+All responses to requests to the App.net API endpoints described in [Resources](/appdotnet/api-spec/blob/master/resources/README.md#resources), whether successful or not, will be returned in the same type of envelope structure. This document will describe how that envelope works as well as how it can be used for convenient purposes, such as pagination.
+
+## Response Envelopes
+
+The top-level response is an object containing two keys. The first key, ```data```, corresponds to the actual response item requested. This may either be an object itself or a list of objects. The particular data returned is described in each endpoint's documentation. If the request is unsuccessful (results in an error), no ```data``` key will be present.
+
+The second key present, ```meta```, corresponds to an object containing additional information about the request. This object will always contain ```code```, a copy of the HTTP status code that has been returned. It will also contain [pagination data](#pagination-metadata) or [stream marker data](objects/stream_marker.md), when relevant.
+
+### Sample Response Envelope
+```js
+{
+ "data": ...,
+ "meta": {
+ "code": 200,
+ "marker": {
+ "id": "1",
+ "name": "global",
+ "percentage": 0,
+ "updated_at": "2012-11-09T23:35:38Z",
+ "version": "NWoZK3kTsExUV00Ywo1G5jlUKKs"
+ },
+ "max_id": 65039,
+ "min_id": 65039,
+ "more": true
+ }
+}
+```
+
+## JSONP
+
+We support JSONP for easy, unauthenticated cross-domain API requests with wide browser support. Normal JSON responses are wrapped in a Javascript function so they may be included in a webpage and fetched directly by the browser via a `script` tag. It is not possible to make requests to API endpoints which require authentication with JSONP.
+
+To use JSONP, add a `callback` parameter to the request's query string. For example:
+
+ https://alpha-api.app.net/stream/0/posts/stream/global?callback=awesome
+
+Will result in a response that looks something like this:
+
+ awesome({...})
+
+When using JSONP, our servers will return a 200 status code in the HTTP response, regardless of the effective status code.
+
+For more information on JSONP, see the Wikipedia page for [JSONP](http://en.wikipedia.org/wiki/JSONP).
+
+## CORS
+
+We support CORS for authenticated cross-domain API requests direct from browsers. Support for CORS may vary by browser. When using CORS, you are still responsible for obtaining, storing and supplying a valid access token with each request, if access to authenticated endpoints is required. For more information on CORS, see the Wikipedia page for [CORS](http://en.wikipedia.org/wiki/Cross-origin_resource_sharing).
+
+## Error Conditions
+
+If the request was unsuccessful for some reason, no ```data``` key will be returned -- the response object will only contain a ```meta``` object. Additional information pertaining to the type of error generated will be returned inside the ```meta``` object. In particular, the ```code``` and ```error_message``` keys will point out what sort of error occurred. There may also be a uniquely-identifying ```error_slug``` and ```error_id``` present that can be used to get more information about the error and which may be helpful in support requests with App.net staff.
+
+#### Error Slugs
+
+<table>
+ <thead>
+ <tr>
+ <th>Slug</th>
+ <th>Relevant on</th>
+ <th>Description</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><code>invalid-token</code></td>
+ <td>global</td>
+ <td>The passed OAuth token was not valid. It may have been corrupted or missing some of its data</td>
+ </tr>
+ <tr>
+ <td><code>not-authorized</code></td>
+ <td>global</td>
+ <td>The User for the given token has likely explicitly revoked access to your App. You may wish to reauthenticate that User.</td>
+ </tr>
+ <tr>
+ <td><code>token-expired</code></td>
+ <td>global</td>
+ <td>The passed token (or code) has reached the end of its lifetime. A new token will have to be generated.</td>
+ </tr>
+ <tr>
+ <td><code>code-used</code></td>
+ <td><a href="/appdotnet/api-spec/blob/master/auth.md#server-side-flow-ruby-python-php-java-etc">access_token</a></td>
+ <td>The passed OAuth <code>code</code> was already used to generate a token.</td>
+ </tr>
+ <tr>
+ <td><code>redirect-uri-required</code></td>
+ <td><a href="/appdotnet/api-spec/blob/master/auth.md#server-side-flow-ruby-python-php-java-etc">access_token</a></td>
+ <td>The call to access_token must include <code>redirect_uri</code>.</td>
+ </tr>
+ </tbody>
+</table>
+
+## Pagination Metadata
+
+<table>
+ <thead>
+ <tr>
+ <th>Name</th>
+ <th>Type</th>
+ <th>Description</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><code>max_id</code></td>
+ <td>string</td>
+ <td>The greatest ID returned in the data set. Inclusive. This should be considered an opaque identifier that may be passed as <code>since_id</code> in the next call in order to retrieve the next set of objects.</td>
+ </tr>
+ <tr>
+ <td><code>min_id</code></td>
+ <td>string</td>
+ <td>The least ID returned in the data set. Inclusive. This should be considered an opaque identifier that may be passed as <code>before_id</code.</td>
+ </tr>
+ <tr>
+ <td><code>more</code></td>
+ <td>boolean</td>
+ <td>If <code>more</code> is <code>true</code>, there are more matches available for the given query than would fit within <code>count</code> objects. If <code>more</code> is <code>false</code>, there are no more matches available.</td>
+ </tr>
+ </tbody>
+</table>
View
45 content/docs/index.md
@@ -0,0 +1,45 @@
+# App.net Stream API Spec
+
+This is a living, working document. We're in the early implementation stages of this, and we'd like your feedback, suggestions and ideas. There's nothing here that's going to blow your mind — yet. But that doesn't mean this is all there's going to be — please help us make this into something much bigger than it currently is.
+
+Please submit feedback to us — feel free to comment on commits, open issues, open pull requests, etc.
+
+## Very Important Warning
+
+**As we've started to open up the API to people as part of our early alpha program, it's important to note that this documentation is
+imperfect in many ways.** In particular, we're not done implementing all of the endpoints that you see here, and sometimes what we
+have written differs from this documentation. If you're running in to issues, drop us a line and we'll try to help.
+
+**If you're submitting your application to one of Apple's App Stores, be sure you follow the special instructions for modifying your login flow in the [Authentication](authentication/) section or your app will be rejected.**
+
+## Table of Contents
+
+* [Object definitions](objects/)
+* [Resource definitions](resources/)
+* [Authentication](authentication/)
+* [Web Intents](resources/intents/)
+
+## Wait, I wanted a syndication protocol that can do X, Y and Z!
+
+We're thinking about the best way to do this. It's something we're interested in providing, but since we've gotta start somewhere, we decided it would be best to start with an API defined in terms of things that the majority of developers are already familiar with.
+
+We want to think big with you. What would you like to see?
+
+## RFF — Requests for Feedback
+
+From time to time we'll ask for feedback on specific parts of the spec in particular. Right now, focus your mental energy on:
+
+* Object definitions, specifically annotation definitions.
+* Data export APIs. These are very, very important to us. If you were writing a backup tool, what would you want to see?
+* What do you think is missing?
+
+## How do I get involved?
+
+Open an issue! Submit a pull request! If you have ideas, let us know. Don't hold back — we want to hear your voice.
+
+## Your hosts
+
+* [Bryan Berg](http://ber.gd) ([github.com/berg](http://github.com/berg), [@berg](http://twitter.com/berg), bryan@ber.gd)
+* Mark Thurman ([github.com/mthurman](http://github.com/mthurman), mthurman@gmail.com)
+* [Alex Kessinger](http://alexkessinger.net) ([github.com/voidfiles](http://github.com/voidfiles), [@voidfiles](http://twitter.com/voidfiles), voidfiles@gmail.com)
+* Brian Armstrong ([github.com/mxml-barmstrong](http://github.com/mxml-barmstrong))
View
651 content/docs/meta/annotations.md
@@ -0,0 +1,651 @@
+# Annotations
+
+Annotations are metadata that are attached to Users or to Posts when they are created. This allows developers and users to add extra information to the post without interfering with the text content of the Post. They also allow developers to attach machine readable information about a user to the user object. Annotations will enable developers to build complex posts and new systems on top of the current App.net infrastructure.
+
+We're really excited to be launching this feature and appreciate any feedback on the following document. Please [open a github issue](https://github.com/appdotnet/api-spec/issues) to contribute to this document.
+
+## Concretely, what are annotations
+
+Let's say I'm at a restaurant eating a great dinner, but instead of just telling my followers about this restaurant I want them to be able to see a map of where it is. My Post could include geographic information about the address for the restaurant and then clients that support this geographic annotation could show the restaurant on a map (in addition to showing my post). If the restaurant is on [OpenTable](http://www.opentable.com), I could include an annotation indicating that and my followers could see the menu and make a reservation in their own App.net client. Annotations are what power complex posts with maps, pictures, videos, etc.
+
+## As a developer, why should I use annotations
+
+To build amazing things. This feature enables new ideas to be built without having to create a brand new API or ecosystem to support the idea. This is the plumbing that will enable new kinds of clients that aren't just about microblogging.
+
+Annotations are how App.net will do geographic information, attaching media to posts, and lots of other things that our 3rd party developers will create.
+
+## How do I use annotations
+
+### As a non-developer
+
+Right now, we're still working with developers to build out this system. As App.net clients and apps are developed that support annotations, we'll be updating everyone on App.net.
+
+### As a developer
+
+First here are some of the more technical details of annotations:
+
+- Each annotation can be thought of as a dictionary or JSON object.
+- Each User or Post is allowed at most 8192 bytes worth of annotations (in total, when serialized as JSON).
+- Post Annotations are immutable and can only be added to a Post at creation time.
+- User Annotations are mutable and can be updated at any time. Because they are mutable, each User can only have one annotation of each "type" (unlike Post annotations).
+
+#### Annotation format
+
+In general, annotations are a list of objects that have a ```type``` and a ```value```.
+
+```js
+[
+ {
+ "type": "com.example.awesome",
+ "value": {
+ "annotations work": "beautifully"
+ }
+ }
+]
+```
+
+<table>
+ <tr>
+ <th>Field</th>
+ <th>Type</th>
+ <th>Description</th>
+ </tr>
+ <tr>
+ <td><code>type</code></td>
+ <td>string</td>
+ <td>A string that looks like a reversed domain name to identify the data format for this annotation. <em>There is no authentication or authorization performed on this field. Just because you create annotations with the type <code>com.example.awesome</code> does not imply you are the only one that is using that namespace or that the <code>value</code> will match the format you expect.</em></td>
+ </tr>
+ <tr>
+ <td><code>value</code></td>
+ <td>object</td>
+ <td>A complex object containing the metadata for this annotation. <em>Be extremely careful with this data, except for well known annotations, no validation is performed on this field.</em></td>
+ </tr>
+</table>
+
+##### Post Annotation format
+
+```js
+{
+ "annotations": [
+ {
+ "type": "com.example.awesome",
+ "value": {
+ "annotations work": "beautifully"
+ }
+ }
+ ],
+ "created_at": "2012-08-30T23:30:14Z",
+ "entities": {
+ "hashtags": [],
+ "links": [],
+ "mentions": []
+ },
+ "html": "<span itemscope=\"https://app.net/schemas/Post\">first annotation post</span>",
+ "id": "1",
+ "num_replies": 0,
+ "num_reposts": 0,
+ "num_stars": 0,
+ "source": {
+ "link": "https://join.app.net/",
+ "name": "App.net"
+ },
+ "text": "first annotation post",
+ "thread_id": "1255",
+ "user": {...},
+ "you_reposted": false,
+ "you_starred": false
+}
+```
+
+The ```post.annotations``` field will be a list of individual annotation objects.
+
+##### User Annotation format
+
+User annotations are meant to provide more information about the user. **They are not meant to be an arbitrary data store for apps**. For example, if a user has a homepage, a blog, or a handle on a different social network, that information belongs in the User annotation.
+
+
+```js
+{
+ "id": "1", // note this is a string
+ "username": "mthurman",
+ "name": "Mark Thurman",
+ "description": { ... },
+ "timezone": "US/Pacific",
+ "locale": "en_US",
+ "avatar_image": { ... },
+ "cover_image": { ... },
+ "type": "human",
+ "created_at": "2012-07-16T17:23:34Z",
+ "counts": { ... },
+ "follows_you": false,
+ "you_follow": true,
+ "you_muted": false,
+ "annotations": [
+ {
+ "type": "net.app.core.directory.blog",
+ "value": {
+ "url": "http://myawesomeblog.com"
+ }
+ }
+ ]
+}
+```
+
+The ```user.annotations``` field will be a list of individual annotation objects.
+
+
+#### Creating annotations
+
+Annotations are currently live in the API.
+
+To create Post annotations you must give App.net a well-formed JSON encoded post that matches the [Post schema](objects/post.md). Please see the [Create Post](https://github.com/appdotnet/api-spec/blob/master/resources/posts.md#create-a-post) documentations for more information.
+
+To add or update User annotations, you [Update a user profile](https://github.com/appdotnet/api-spec/blob/master/resources/users.md#update-a-user) and pass in the annotations you want to add or update. To delete an annotation, omit the ```value``` key for the annotation type you want to delete. For example, to delete a user's blog url, specify ```{"type": "net.app.core.directory.blog"}```.
+
+#### Displaying annotations
+
+Every client can choose if/how it chooses to display annotations. As stated above be very careful when consuming this data and **do not assume that it follows a specific schema.** Treat data in annotations as untrusted data. Program defensively: your app should not crash or otherwise throw an error if it receives a string where there is usually a dictionary, etc. App.net will coordinate with the community to define schemas for common annotation formats. They will live under the ```net.app.core.*``` namespace. This is the only restricted annotation namespace. Any annotation in this namespace must be validated by the API against a [published schema](#core-annotations). Outside of this namespace, developers may create annotations in either the ```net.app.[username]``` namespace or a reversed-domain namespace of their choosing.
+
+Since annotations can be up to 8192 bytes, they are not included with posts by default. When you make a request for posts or users, you can include the parameter ```include_annotations=1``` to receive all annotations object (or just ```include_user_annotations=1``` or ```include_post_annotations=1```). See [general Post parameters](https://github.com/appdotnet/api-spec/blob/master/resources/posts.md#general-parameters) for more information.
+
+# Annotations formats
+
+Since annotations are just launching, we invite the community to propose schemas and collaborate on them. App.net is currently working with the community to define common schemas for things like photos, other media, and geographic data. To propose these formats, please [open an issue](https://github.com/appdotnet/api-spec/issues) and tag it with the ```annotations``` label.
+
+Some annotations are core to the platform and their schemas will be [published below](#core-annotations). Other schemas may be useful across multiple App.net apps, but not be "core" to the platform. The community has started a page on the [App.net API wiki](https://github.com/appdotnet/api-spec/wiki/Annotations) to catalog these common non-core annotations.
+
+We will be defining core annotations soon for the following types of data:
+
+* Media enclosures, e.g., photos, video, etc.
+* Long-form content
+* Attribution and source
+* Additional content license grants, where users can opt in to Creative Commons licensing, etc., if desired.
+
+Developers are invited to create ad-hoc annotations for data not well represented here; if possible, care should be taken not to overlap with existing annotations. If possible, Posts with ad-hoc annotations designed to address edge-cases in well-known annotations should include both the well-known annotation and only the augmented parts in the ad-hoc annotation.
+
+## Core Annotations
+
+### Post
+
+* [Crosspost](#crosspost): net.app.core.crosspost
+* [Embedded Media](#embedded-media): net.app.core.oembed
+* [Geolocation](#geolocation): net.app.core.geolocation
+* [Language](#language): net.app.core.language
+
+### User
+
+* [Blog URL](#blog): net.app.core.directory.blog
+* [Facebook Id](#facebook): net.app.core.directory.facebook
+* [Homepage](#homepage): net.app.core.directory.homepage
+* [Twitter Username](#twitter): net.app.core.directory.twitter
+* [Geolocation](#geolocation): net.app.core.geolocation
+
+
+### Blog
+
+> net.app.core.directory.blog
+
+A pointer to the user's blog.
+
+#### Example
+
+```js
+{
+ "type": "net.app.core.directory.blog",
+ "value": {
+ "url": "http://myawesomeblog.com",
+ }
+}
+```
+#### Fields
+
+<table>
+ <tr>
+ <th>Field</th>
+ <th>Required?</th>
+ <th>Type</th>
+ <th>Description</th>
+ </tr>
+ <tr>
+ <td><code>url</code></td>
+ <td>Required</td>
+ <td>string</td>
+ <td>A valid URL pointing to the User's blog.</td>
+ </tr>
+</table>
+
+### Crosspost
+
+> net.app.core.crosspost
+
+The crosspost annotation is meant to specify the original or canonical source of a Post on App.net from somewhere else on the web.
+
+#### Example
+
+```js
+{
+ "type": "net.app.core.crosspost",
+ "value": {
+ "canonical_url": "https://twitter.com/AppDotNet/status/234705338849443840",
+ }
+}
+```
+#### Fields
+
+<table>
+ <tr>
+ <th>Field</th>
+ <th>Required?</th>
+ <th>Type</th>
+ <th>Description</th>
+ </tr>
+ <tr>
+ <td><code>canonical_url</code></td>
+ <td>Required</td>
+ <td>string</td>
+ <td>A valid URL pointing to the source of the original content.</td>
+ </tr>
+</table>
+
+### Embedded Media
+
+> net.app.core.oembed
+
+The embedded media annotation specifies an image, video, or other rich content that should be displayed with this post. It uses the [JSON oEmbed specification](http://oembed.com). We only support the ```photo```, ```video```, and ```rich``` oEmbed types.
+
+We highly recommend providing the ```embeddable_url``` attribute so other clients can request different oEmbed details for this object from the original oEmbed provider (if there is one).
+
+#### Examples
+
+##### Photo
+
+```js
+{
+ "type": "net.app.core.oembed",
+ "value": {
+ "version": "1.0",
+ "type": "photo",
+ "width": 240,
+ "height": 160,
+ "title": "ZB8T0193",
+ "url": "http://farm4.static.flickr.com/3123/2341623661_7c99f48bbf_m.jpg",
+ "author_name": "Bees",
+ "author_url": "http://www.flickr.com/photos/bees/",
+ "provider_name": "Flickr",
+ "provider_url": "http://www.flickr.com/",
+ "embeddable_url": "http://www.flickr.com/photos/bees/2341623661/"
+ }
+}
+```
+
+##### Video
+
+```js
+{
+ "type": "net.app.core.oembed",
+ "value": {
+ "version": "1.0",
+ "type": "video",
+ "provider_name": "YouTube",
+ "provider_url": "http://youtube.com/",
+ "width": 425,
+ "height": 344,
+ "title": "Amazing Nintendo Facts",
+ "author_name": "ZackScott",
+ "author_url": "http://www.youtube.com/user/ZackScott",
+ "html":
+ "<object width=\"425\" height=\"344\">
+ <param name=\"movie\" value=\"http://www.youtube.com/v/M3r2XDceM6A&fs=1\"></param>
+ <param name=\"allowFullScreen\" value=\"true\"></param>
+ <param name=\"allowscriptaccess\" value=\"always\"></param>
+ <embed src=\"http://www.youtube.com/v/M3r2XDceM6A&fs=1\"
+ type=\"application/x-shockwave-flash\" width=\"425\" height=\"344\"
+ allowscriptaccess=\"always\" allowfullscreen=\"true\"></embed>
+ </object>",
+ "embeddable_url": "http://youtube.com/watch?v=M3r2XDceM6A"
+ }
+}
+
+```
+
+##### Rich
+
+```js
+{
+ "type": "net.app.core.oembed",
+ "value": {
+ "provider_url": "http://soundcloud.com",
+ "description": "Listen to Merenti - La Karambaa by M\u00e9renti | Create, record and share the sounds you create anywhere to friends, family and the world with SoundCloud, the world's largest community of sound creators.",
+ "title": "Merenti - La Karambaa by M\u00e9renti",
+ "html": "<iframe width=\"500\" height=\"166\" scrolling=\"no\" frameborder=\"no\" src=\"http://w.soundcloud.com/player/?url=http%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F6733249&show_artwork=true&maxwidth=900\"></iframe>",
+ "author_name": "M\u00e9renti",
+ "height": 166,
+ "width": 500,
+ "thumbnail_url": "http://i1.sndcdn.com/artworks-000003051440-mm2z46-t500x500.jpg?d95e793",
+ "thumbnail_width": 500,
+ "version": "1.0",
+ "provider_name": "SoundCloud",
+ "type": "rich",
+ "thumbnail_height": 500,
+ "author_url": "http://soundcloud.com/mrenti"
+ "embeddable_url": "http://soundcloud.com/mrenti/merenti-la-karambaa"
+ }
+}
+
+```
+#### Fields
+
+**To correspond with the oEmbed spec, this annotation accepts keys that are not specified below.**
+
+<table>
+ <tr>
+ <th>Field</th>
+ <th>Required?</th>
+ <th>Type</th>
+ <th>Description</th>
+ </tr>
+ <tr>
+ <td><code>type</code></td>
+ <td>Required</td>
+ <td>string</td>
+ <td><code>photo</code>, <code>video</code>, or <code>rich</code> corresponding to the oEmbed type.</td>
+ </tr>
+ <tr>
+ <td><code>version</code></td>
+ <td>Required</td>
+ <td>string</td>
+ <td>Must be <code>1.0</code>.</td>
+ </tr>
+ <tr>
+ <td><code>width</code></td>
+ <td>Required</td>
+ <td>integer</td>
+ <td>The width in pixels needed to display the embeddable content.</td>
+ </tr>
+ <tr>
+ <td><code>height</code></td>
+ <td>Required</td>
+ <td>integer</td>
+ <td>The height in pixels needed to display the embeddable content.</td>
+ </tr>
+ <tr>
+ <td><code>url</code></td>
+ <td>Required if <code>type="photo"</code></td>
+ <td>string</td>
+ <td>The source URL for the image.</td>
+ </tr>
+ <tr>
+ <td><code>html</code></td>
+ <td>Required if <code>type="video"</code> or <code>type="rich"</code></td>
+ <td>string</td>
+ <td>The HTML to display the rich or video content. It should have no margins or padding. App.net does <strong>no validation</strong> of of this field. Please program defensively. You may wish to load this in an off-domain iframe to avoid XSS vulnerabilities.</td>
+ </tr>
+ <tr>
+ <td><code>embeddable_url</code></td>
+ <td>Optional (but recommended)</td>
+ <td>string</td>
+ <td>A URL that can be given to an oEmbed provider to recreate the oEmbed data contained in this annotation. This is useful so other clients can get updated information or retrieve a different sized embedding through an oEmbed endpoint.</td>
+ </tr>
+ <tr>
+ <td><code>title</code></td>
+ <td>Optional</td>
+ <td>string</td>
+ <td>A title for this embedded content.</td>
+ </tr>
+ <tr>
+ <td><code>author_name</code></td>
+ <td>Optional</td>
+ <td>string</td>
+ <td>The author of this embedded content.</td>
+ </tr>
+ <tr>
+ <td><code>author_url</code></td>
+ <td>Optional</td>
+ <td>string</td>
+ <td>The URL for the author of this embedded content.</td>
+ </tr>
+ <tr>
+ <td><code>provider_name</code></td>
+ <td>Optional</td>
+ <td>string</td>
+ <td>The service that provides this embedded content.</td>
+ </tr>
+ <tr>
+ <td><code>provider_url</code></td>
+ <td>Optional</td>
+ <td>string</td>
+ <td>The URL for the service that provides this embedded content.</td>
+ </tr>
+ <tr>
+ <td><code>cache_age</code></td>
+ <td>Optional</td>
+ <td>integer</td>
+ <td>How long (in seconds) should clients cache the embedded content.</td>
+ </tr>
+ <tr>
+ <td><code>thumbnail_url</code></td>
+ <td>Optional</td>
+ <td>string</td>
+ <td>A URL to an image that represents this resource. If this parameter is specified, <code>thumbnail_height</code> and <code>thumbnail_width</code> must also be present.</td>
+ </tr>
+ <tr>
+ <td><code>thumbnail_height</code></td>
+ <td>Optional</td>
+ <td>string</td>
+ <td>The height of the thumbnail image. If this parameter is specified, <code>thumbnail_url</code> and <code>thumbnail_width</code> must also be present.</td>
+ </tr>
+ <tr>
+ <td><code>thumbnail_width</code></td>
+ <td>Optional</td>
+ <td>string</td>
+ <td>The height of the thumbnail image. If this parameter is specified, <code>thumbnail_height</code> and <code>thumbnail_url</code> must also be present.</td>
+ </tr>
+</table>
+
+### Facebook
+
+> net.app.core.directory.facebook
+
+A pointer to the user's Facebook account.
+
+#### Example
+
+```js
+{
+ "type": "net.app.core.directory.facebook",
+ "value": {
+ "id": "244611465578667",
+ }
+}
+```
+#### Fields
+
+<table>
+ <tr>
+ <th>Field</th>
+ <th>Required?</th>
+ <th>Type</th>
+ <th>Description</th>
+ </tr>
+ <tr>
+ <td><code>id</code></td>
+ <td>Required</td>
+ <td>string</td>
+ <td>A Facebook user id representing the App.net User.</td>
+ </tr>
+</table>
+
+### Geolocation
+
+> net.app.core.geolocation
+
+The geolocation annotation is meant to specify a geographic point on the Earth. It is not meant to specify:
+
+* a human place (city, building, park, "San Francisco", "The Mission", "The Moscone Center"). We're investigating how to efficiently provide this data in the core api.
+* paths, regions, or complex geographic shapes. We recommend using a common schema (like [GeoJSON](http://www.geojson.org/)) in your own annotation if you need this kind of solution.
+
+#### Examples
+
+Just the required parameters:
+```js
+{
+ "type": "net.app.core.geolocation",
+ "value": {
+ "latitude": 74.0064,
+ "longitude": 40.7142
+ }
+}
+```
+
+With all optional parameters:
+```js
+{
+ "type": "net.app.core.geolocation",
+ "value": {
+ "latitude": 74.0064,
+ "longitude": 40.7142,
+ "altitude": 4400,
+ "horizontal_accuracy": 100,
+ "vertical_accuracy": 100,
+ }
+}
+```
+#### Fields
+
+<table>
+ <tr>
+ <th>Field</th>
+ <th>Required?</th>
+ <th>Type</th>
+ <th>Description</th>
+ </tr>
+ <tr>
+ <td><code>latitude</code></td>
+ <td>Required</td>
+ <td>decimal</td>
+ <td>The latitude of the geographic location in decimal degrees. Must range from -90 (the South Pole) to 90 (the North Pole).</td>
+ </tr>
+ <tr>
+ <td><code>longitude</code></td>
+ <td>Required</td>
+ <td>decimal</td>
+ <td>The longitude of the geographic location in decimal degrees. Must range from -180 to 180.</td>
+ </tr>
+ <tr>
+ <td><code>altitude</code></td>
+ <td>Optional</td>
+ <td>decimal</td>
+ <td>The altitude (in meters) of the geographic location. Can be negative.</td>
+ </tr>
+ <tr>
+ <td><code>horizontal_accuracy</code></td>
+ <td>Optional</td>
+ <td>decimal</td>
+ <td>The horizontal accuracy (in meters) of the instrument providing this geolocation point. Must be >= 0.</td>
+ </tr>
+ <tr>
+ <td><code>vertical_accuracy</code></td>
+ <td>Optional</td>
+ <td>decimal</td>
+ <td>The vertical accuracy (in meters) of the instrument providing this geolocation point. Must be >= 0.</td>
+ </tr>
+</table>
+
+### Homepage
+
+> net.app.core.directory.homepage
+
+A pointer to the user's homepage.
+
+#### Example
+
+```js
+{
+ "type": "net.app.core.directory.homepage",
+ "value": {
+ "url": "http://thisisme.com",
+ }
+}
+```
+#### Fields
+
+<table>
+ <tr>
+ <th>Field</th>
+ <th>Required?</th>
+ <th>Type</th>
+ <th>Description</th>
+ </tr>
+ <tr>
+ <td><code>url</code></td>
+ <td>Required</td>
+ <td>string</td>
+ <td>A valid URL pointing to the User's homepage.</td>
+ </tr>
+</table>
+
+### Language
+
+> net.app.core.language
+
+The language annotation allows a User to indicate what language this post was written in.
+
+#### Example
+
+```js
+{
+ "type": "net.app.core.language",
+ "value": {
+ "language": "en",
+ }
+}
+```
+#### Fields
+
+<table>
+ <tr>
+ <th>Field</th>
+ <th>Required?</th>
+ <th>Type</th>
+ <th>Description</th>
+ </tr>
+ <tr>
+ <td><code>language</code></td>
+ <td>Required</td>
+ <td>string</td>
+ <td>A valid ISO 639-1 language code. Note that we only accept a subset of language codes right now. Please see <a href="https://github.com/appdotnet/api-spec/wiki/Language-codes">our current list</a> of accepted language codes. If we're missing your language, please <a href="https://github.com/appdotnet/api-spec/issues">open an issue</a>.</td>
+ </tr>
+</table>
+
+### Twitter
+
+> net.app.core.directory.twitter
+
+A pointer to the user's Twitter account.
+
+#### Example
+
+```js
+{
+ "type": "net.app.core.directory.twitter",
+ "value": {
+ "username": "appdotnet",
+ }
+}
+```
+#### Fields
+
+<table>
+ <tr>
+ <th>Field</th>
+ <th>Required?</th>
+ <th>Type</th>
+ <th>Description</th>
+ </tr>
+ <tr>
+ <td><code>username</code></td>
+ <td>Required</td>
+ <td>string</td>
+ <td>A Twitter username representing the App.net User.</td>
+ </tr>
+</table>
View
194 content/docs/meta/entities.md
@@ -0,0 +1,194 @@
+## Entities
+Entities allow users and applications to provide rich text formatting for posts. They provide common formatting for mentions and hashtags but they also allow links to be embedded with anchor text which gives more context. Each entity type is a list with 0 or more entities of the same type.
+
+Entities are designed to be very simple to render — they should relatively easily translate into [`NSAttributedString`](https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSAttributedString_Class/Reference/Reference.html) objects and the like.
+
+Usually entities are extracted from the Post text by App.net's servers. We allow users to specify some entities at Post creation time. Please refer to the [user specified entites](#user-specified-entities) documentation for more information.
+
+Ranges specified by entities may be adjacent, but may not overlap.
+
+All of the following examples are about the following post:
+
+> @berg FIRST post on this new site #newsocialnetwork
+
+### Mentions
+Bring another user's attention to your post. A mention starts with <code>@</code>.
+
+```js
+"mentions": [{
+ "name": "berg",
+ "id": "2",
+ "pos": 0,
+ "len": 5,
+}]
+```
+<table>
+ <tr>
+ <th>Field</th>
+ <th>Type</th>
+ <th>Description</th>
+ </tr>
+ <tr>
+ <td><code>name</code></td>
+ <td>string</td>
+ <td>The username being mentioned (doesn't include '@').</td>
+ </tr>
+ <tr>
+ <td><code>id</code></td>
+ <td>string</td>
+ <td>The user id of the mentioned user.</td>
+ </tr>
+ <tr>
+ <td><code>pos</code></td>
+ <td>integer</td>
+ <td>The 0 based index where this entity begins <code>text</code> (include @).</td>
+ </tr>
+ <tr>
+ <td><code>len</code></td>
+ <td>integer</td>
+ <td>The length of the substring in <code>text</code> that represents this mention. Since <code>@</code> is included, <code>len</code> will be the length of the <code>name</code> + 1.</td>
+ </tr>
+</table>
+
+### Hashtags
+Tag a post about a specific subject. A hashtag starts with <code>#</code>.
+
+```js
+"hashtags": [{
+ "name": "newsocialnetwork",
+ "pos": 34,
+ "len": 17
+}]
+```
+<table>
+ <tr>
+ <th>Field</th>
+ <th>Type</th>
+ <th>Description</th>
+ </tr>
+ <tr>
+ <td><code>name</code></td>
+ <td>string</td>
+ <td>The text of the hashtag (not including #).</td>
+ </tr>
+ <tr>
+ <td><code>pos</code></td>
+ <td>integer</td>
+ <td>The 0 based index where this entity begins <code>text</code> (include #).</td>
+ </tr>
+ <tr>
+ <td><code>len</code></td>
+ <td>integer</td>
+ <td>The length of the substring in <code>text</code> that represents this hashtag. Since <code>#</code> is included, <code>len</code> will be the length of the <code>name</code> + 1.</td>
+ </tr>
+</table>
+
+### Links
+Link to another website.
+
+```js
+"links": [{
+ "text": "this new site",
+ "url": "https://join.app.net"
+ "pos": 20,
+ "len": 13
+}]
+```
+<table>
+ <tr>
+ <th>Field</th>
+ <th>Type</th>
+ <th>Description</th>
+ </tr>
+ <tr>
+ <td><code>text</code></td>
+ <td>string</td>
+ <td>The anchor text to be linked (could be a url).</td>
+ </tr>
+ <tr>
+ <td><code>url</code></td>
+ <td>string</td>
+ <td>The destination url (only http or https accepted).</td>
+ </tr>
+ <tr>
+ <td><code>pos</code></td>
+ <td>integer</td>
+ <td>The 0 based index where this entity begins <code>text</code>.</td>
+ </tr>
+ <tr>
+ <td><code>len</code></td>
+ <td>integer</td>
+ <td>The length of the substring in <code>text</code> that represents this link.</td>
+ </tr>
+</table>
+
+### User Specified Entites
+
+Entities are automatically extracted from the post text but there are 2 cases where users and apps can set the entities on a post.
+
+#### Mentions in machine only posts
+
+[Machine only posts](post.md#machine-only-posts) don't have any text so entities cannot be extracted. We allow you to specify up to 10 users (by username or id) who can be mentioned in a machine only post. A machine only post with mentions is treated as a [directed post](../resources/posts.md#general-parameters) to those users. You should not pass the ```pos``` or ```len``` keys in these mentions. Please see the example:
+
+```js
+{
+ "annotations": ...,
+ "machine_only": true,
+ "entities": {
+ "mentions": [
+ {
+ "name": "mthurman"
+ },
+ {
+ "id": "1"
+ },
+ ...
+ ]
+ }
+}
+```
+
+#### Links with custom anchor text
+
+If you'd like to provide a link without including the entire URL in your post text or user description, you can specify a custom link at Post creation time or User update time. If you provide any links, **App.net will not extract any links on the server**. Mentions and hashtags will still be extracted and your provided links must not overlap with these extracted entities. So you **cannot** have a custom link around a hashtag or mention.
+
+To prevent phishing, any link where the anchor text differs from the destination domain will be followed by the domain of the link target. These extra characters will not count against the 256 character Post limit.
+
+The ```text``` attribute of a link should be omitted as it will always be filled in from the post text.
+
+##### Example
+
+If you created the following post:
+
+```js
+{
+ "text": "I love this website!",
+ "entities": {
+ "links": [
+ {
+ "pos": 7,
+ "len": 12,
+ "url": "https://alpha.app.net"
+ }
+ ]
+ }
+}
+```
+
+App.net will store and return:
+
+```js
+{
+ "text": "I love this website [alpha.app.net]!",
+ "entities": {
+ "links": [
+ {
+ "pos": 7,
+ "len": 12,
+ "url": "https://alpha.app.net"
+ }
+ ]
+ },
+ ...
+}
+```
View
119 content/docs/other/feeds.md
@@ -0,0 +1,119 @@
+# Feeds
+
+<table class="table table-striped">
+ <thead>
+ <tr>
+ <th>Description</th>
+ <th>Path</th>
+ <th>HTTP Method</th>
+ <th>Authentication Required?</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><a href="">Retrieve a feed for a hashtag</a></td>
+ <td></td>
+ <td></td>
+ <td></td>
+ </tr>
+ <tr>
+ <td><a href="">Retrieve a feed for a User</a></td>
+ <td></td>
+ <td></td>
+ <td></td>
+ </tr>
+ </tbody>
+</table>
+
+## General Information
+
+### Basic Use
+
+Feeds describe our system for simple syndication of public posts on App.net. We currently support RSS as a syndication format. This means you should be able to use them anywhere you currently use RSS feeds.
+
+There are 2 different kinds of feeds, but they all follow the same pattern:
+
+* Users Post feed: A feed for a single User's public posts on App.net. This is a feed version of the [Retrieve Posts created by a User](/appdotnet/api-spec/blob/master/resources/posts.md#retrieve-posts-created-by-a-user) endpoint.
+* Hashtag feed: A feed containing all public Posts that are tagged with a specific hashtag. This is a feed version of the [Retrieve tagged Posts](/appdotnet/api-spec/blob/master/resources/posts.md#retrieve-tagged-posts) endpoint.
+
+We intend to support more feed formats and richer support for filters in the near future.
+
+*Note:* While the URLs are similar to other API URLs feeds, they are under a different root.
+
+### Filters
+
+Feeds do not currently support filters or general parameters like the JSON API.
+
+### Response Format
+
+All responses are returned as RSS. We are following the spec for RSS 2.0 as described in the [RSS 2.0 specification](http://cyber.law.harvard.edu/rss/rss.html).
+
+## Retrieve a feed for a User
+
+Retrieve a [feed](#feeds) for the User [@voidfiles](http://alpha.app.net/voidfiles). This endpoint is similar to the '[Retrieve Posts created by a User](/appdotnet/api-spec/blob/master/resources/posts.md#retrieve-posts-created-by-a-user)' endpoint.
+
+### URL
+> https://alpha-api.app.net/feed/rss/users/@username/posts
+
+### Example
+
+> GET https://alpha-api.app.net/feed/rss/users/@voidfiles/posts
+
+```xml
+<?xml version='1.0' encoding='utf-8'?>
+<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
+ <channel>
+ <title>Posts from voidfiles on App.net</title>
+ <link>https://alpha.app.net/voidfiles</link>
+ <description>Hi, I work at App.net</description>
+ <atom:link href="https://alpha-api.app.net/feed/rss/users/@voidfiles/posts" type="application/rss+xml"/>
+ <image>
+ <title>Posts from voidfiles on App.net</title>
+ <link>https://alpha.app.net/voidfiles</link>
+ <url>https://dqdwyydysypcm.cloudfront.net/image/4/Go50UQd5N9mi_APkpQt9JAp4ZsDfMlOTnoB4P-0N5rmpFGtnro2b52yUcUr_bPbxKlxx_4EHHiujdE-RRpSB6oZd0bHGy4xKlwInNBClbebDS7DoyyPHtIK9LY5x-kQSdnPKyKhtogJxD04SGOQMLPkCasZM42nLVgZIIhcbmbBrzxNJaoRoCNOrzS1ib9fQcAwPEg</url>
+ </image>
+ <item>
+ <title>voidfiles: #hashtag test</title>
+ <description>
+ <span itemscope="https://join.app.net/schemas/Post"><a href="https://alpha.app.net/hashtags/hashtag" itemprop="hashtag" data-hashtag-name="hashtag">#hashtag</a> test</span>
+ </description>
+ <pubDate>Fri, 31 Aug 2012 17:15:31 +0000</pubDate>
+ <guid>https://alpha.app.net/voidfiles/post/1387</guid>
+ <link>https://alpha.app.net/voidfiles/post/1387</link>
+ <category>hashtag</category>
+ </item>
+ </channel>
+</rss>
+```
+
+## Retrieve a feed for a hashtag
+
+Retrieve a [feed](#feed) for the specified hashtag. This endpoint is similar to the '[Retrieve tagged Posts](/appdotnet/api-spec/blob/master/resources/posts.md#retrieve-tagged-posts)' endpoint.
+
+### URL
+> https://alpha-api.app.net/feed/rss/posts/tag/hashtag
+
+### Example
+> GET https://alpha-api.app.net/feed/rss/posts/tag/hashtag
+
+```xml
+<?xml version='1.0' encoding='utf-8'?>
+<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
+ <channel>
+ <title>#hashtag - App.net</title>
+ <link>https://alpha.app.net/hashtags/hashtag</link>
+ <description>Posts about #hashtag</description>
+ <atom:link href="https://alpha-api.app.net/feed/rss/posts/tag/hashtag" type="application/rss+xml"/>
+ <item>
+ <title>voidfiles: #hashtag test</title>
+ <description>
+ <span itemscope="https://join.app.net/schemas/Post"><a href="https://alpha.app.net/hashtags/hashtag" itemprop="hashtag" data-hashtag-name="hashtag">#hashtag</a> test</span>
+ </description>
+ <pubDate>Fri, 31 Aug 2012 17:15:31 +0000</pubDate>
+ <guid>https://alpha.app.net/voidfiles/post/1387</guid>
+ <link>https://alpha.app.net/voidfiles/post/1387</link>
+ <category>hashtag</category>
+ </item>
+ </channel>
+</rss>
+```
View
32 content/docs/other/web-intents.md
@@ -0,0 +1,32 @@
+# Web Intents
+
+Web intents are an easy way to integrate with App.net; you don't even need to use Javascript. Intents in their most basic form are just carefully constructed URLs. By clicking on an intent link, a user will be taken to a page on App.net with a prompt to carry out an action, such as creating a post. If the user is not logged in to App.net, she/he will first authenticate before being presented with the action dialog.
+
+## The Post Intent
+
+Currently, the only supported intent is the Post Intent. It allows you to create a link that will present the user with a post creation box and any pre-filled text that you may have supplied.
+
+The base URL for this intent is ```https://alpha.app.net/intent/post```.
+
+You may optionally prepopulate the post creation box by supplying a ```text``` query parameter to the URL.
+
+For example, this URL ```https://alpha.app.net/intent/post?text=@voidfiles+save+some+coffee+for+me``` will create a post that reads:
+
+ @voidfiles save some coffee for me
+
+At this point the end user will be able to edit and then submit the post.
+
+
+## Javascript & Intents
+
+While you don't need to write any Javascript to use intents, it does make for a nicer experience. If you want to, you can use Javascript to open the intents dialog in a popup window.
+
+For example, the following Javascript will open a Post Intent in a popup. The popup should be at least 700 x 350 pixels.
+
+```
+window.open(
+ 'https://alpha.app.net/intent/post?text=@voidfiles+save+some+coffee+for+me',
+ 'adn_post',
+ 'width=750,height=350,left=100,top=100'
+);
+```
View
567 content/docs/resources/filter/index.md
</
@@ -0,0 +1,567 @@
+## Filter
+
+A Filter restricts a stream of messages on the server side so your client only sees what it's interested in. [Streams](stream.md) are currently the only way to use filters right now.
+
+```js
+{
+ "clauses": [
+ {
+ "field": "/data/entities/hashtags/*/name",
+ "object_type": "post",
+ "operator": "contains",
+ "value": "rollout"
+ }
+ ],
+ "id": "1",
+ "match_policy": "include_any",
+ "name": "Posts about rollouts"
+}
+```
+
+### Filter fields
+
+<table>
+ <thead>
+ <tr>
+ <th>Field</th>
+ <th>Type</th>
+ <th>Description</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><code>id</code></td>
+ <td>string</td>
+ <td>Primary identifier for a filter. This will be an integer, but it is always expressed as a string to avoid limitations with the way JavaScript integers are expressed.</td>
+ </tr>
+ <tr>
+ <td><code>name</code></td>
+ <td>string</td>
+ <td>An optional User assigned name for this filter.</td>
+ </tr>
+ <tr>
+ <td><code>clauses</code></td>
+ <td>list</td>
+ <td>A list of <a href="#filter-clauses">filter clauses</a> to match against. Must be non-empty.</td>
+ </tr>
+ <tr>
+ <td><code>match_policy</code></td>
+ <td>string</td>
+ <td>How should the clauses be joined together? One of <code>include_any</code>, <code>include_all</code>, <code>exclude_any</code>, or <code>exclude_all</code>. For example, <code>include_any</code> will include a message if it matches any of the clauses and <code>exclude_all</code> will exclude a message if it matches all of the clauses. This allows either white- or blacklist filtering.</td>
+ </tr>
+ </tbody>
+</table>
+
+### Filter Clauses
+
+<table>
+ <thead>
+ <tr>
+ <th>Field</th>
+ <th>Type</th>
+ <th>Description</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><code>object_type</code></td>
+ <td>string</td>
+ <td>What type of object does this filter operate on? Must be one of <code>post</code>, <code>star</code>, <code>user_follow</code>. </td>
+ </tr>
+ <tr>
+ <td><code>operator</code></td>
+ <td>string</td>
+ <td>How should <code>field</code> be matched against <code>value</code>.
+ <br>
+ <table>
+ <tr>
+ <th>Operator</th>
+ <th>Description</th>
+ </tr>
+ <tr>
+ <td><code>equals</code></td>
+ <td>Does <code>field</code> equal <code>value</code>.</td>
+ </tr>
+ <tr>
+ <td><code>matches</code></td>
+ <td>Is the string <code>value</code> a substring of <code>field</code>.</td>
+ </tr>
+ <tr>
+ <td><code>lt</code></td>
+ <td>Is the integer in <code>field</code> &lt; <code>value</code>.</td>
+ </tr>
+ <tr>
+ <td><code>le</code></td>
+ <td>Is the integer in <code>field</code> &le; <code>value</code>.</td>
+ </tr>
+ <tr>
+ <td><code>gt</code></td>
+ <td>Is the integer in <code>field</code> &gt; <code>value</code>.</td>
+ </tr>
+ <tr>
+ <td><code>ge</code></td>
+ <td>Is the integer in <code>field</code> &ge; <code>value</code>.</td>
+ </tr>
+ <tr>
+ <td><code>one_of</code></td>
+ <td>Is the <code>field</code> an element in the list <code>value</code>.</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td><code>field</code></td>
+ <td>string</td>
+ <td>A <a href="#json-pointer">JSON Pointer</a> string that specifies what part of the message we should match against.</td>
+ </tr>
+ <tr>
+ <td><code>value</code></td>
+ <td>string, int, or list</td>
+ <td>A string, integer, or list that the message's data is compared against. Some <a href="#filter-variables">variables</a> are also accepted.</td>
+ </tr>
+ </tbody>
+</table>
+
+### Filter variables
+
+<table>
+ <thead>
+ <tr>
+ <th>Value</th>
+ <th>Type</th>
+ <th>Description</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><code>$authorized_userids</code></td>
+ <td>list</td>
+ <td>A list of the current user ids who have authorized the App that is using this filter in a stream. Since this is a list, make sure you use the <code>one_of</code> operator with this variable.</td>
+ </tr>
+ </tbody>
+</table>
+
+### JSON Pointer
+
+We use a slightly modified version of the [JSON Pointer](http://tools.ietf.org/html/draft-ietf-appsawg-json-pointer-04) standard to specify which part of a message we should filter against. According to the spec:
+
+> JSON Pointer defines a string syntax for identifying a specific value within a JSON document.
+
+For instance, in the message:
+
+```js
+{
+ "data": [
+ {
+ "id": "2", // note this is a string
+ "user": {
+ ...
+ },
+ "created_at": "2012-07-16T17:25:47Z",
+ "text": "@mthurman stop trolling",
+ "html": "<span itemprop=\"mention\" data-mention-name=\"mthurman\" data-mention-id=\"1\">@mthurman</span> stop trolling",
+ "source": {
+ "client_id": "udxGzAVBdXwGtkHmvswR5MbMEeVnq6n4",
+ "name": "Clientastic for iOS",
+ "link": "http://app.net"
+ },
+ "machine_only": false,
+ "reply_to": "1",
+ "thread_id": "1",
+ "num_replies": 0,
+ "num_reposts": 0,
+ "num_stars": 0,
+ "entities": {
+ "mentions": [{
+ "name": "mthurman",
+ "id": "2",
+ "pos": 0,
+ "len": 9
+ }],
+ "hashtags": [{],
+ "links": []
+ },
+ "you_reposted": false,
+ "you_starred": false
+ },
+ ...
+ ],
+ "meta": {
+ "code": 200,
+ "max_id": "2",
+ "min_id": "1",
+ "more": false
+ }
+}
+```
+
+* ```/data/source/client_id``` = "udxGzAVBdXwGtkHmvswR5MbMEeVnq6n4"
+* ```/data/entities/mentions/0/name``` = "mthurman"
+* ```/data/num_replies``` = 0
+
+We extend JSON pointer slightly to allow all the elements of a list to match. For example, to answer the question "Does this post contain the hashtag 'rollout'", you'd use a field selector like ```/data/entities/hashtags/*/name```. Following the JSON Pointer spec, if you'd like to encode a literal ```*``` you can use ```~2``` instead.
+
+# Filters
+
+## Interacting with individual Filters
+
+<table class="table table-striped">
+ <thead>
+ <tr>
+ <th>Description</th>
+ <th>Path</th>
+ <th>HTTP Method</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><a href="/appdotnet/api-spec/blob/master/resources/filters.md#create-a-filter">Create a Filter</a></td>
+ <td>/stream/0/filters</td>
+ <td>POST</td>
+ </tr>
+ <tr>
+ <td><a href="/appdotnet/api-spec/blob/master/resources/filters.md#retrieve-a-filter">Retrieve a Filter</a></td>
+ <td>/stream/0/filters/[filter_id]</td>
+ <td>GET</td>
+ </tr>
+ <tr>
+ <td><a href="/appdotnet/api-spec/blob/master/resources/filters.md#update-a-filter">Update a Filter</a></td>
+ <td>/stream/0/filters/[filter_id]</td>
+ <td>PUT</td>
+ </tr>
+ <tr>
+ <td><a href="/appdotnet/api-spec/blob/master/resources/filters.md#delete-a-filter">Delete a Filter</a></td>
+ <td>/stream/0/filters/[filter_id]</td>
+ <td>DELETE</td>
+ </tr>
+ </tbody>
+</table>
+
+## Interacting with multiple Filters
+
+<table class="table table-striped">
+ <thead>
+ <tr>
+ <th>Description</th>
+ <th>Path</th>
+ <th>HTTP Method</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><a href="/appdotnet/api-spec/blob/master/resources/filters.md#get-current-users-filters">Get the current User's Filters</a></td>
+ <td>/stream/0/filters</td>
+ <td>GET</td>
+ </tr>
+ <tr>
+ <td><a href="/appdotnet/api-spec/blob/master/resources/filters.md#delete-all-of-the-current-users-filters">Delete the current User's Filters</a></td>
+ <td>/stream/0/filters</td>
+ <td>DELETE</td>
+ </tr>
+ </tbody>
+</table>
+
+## Create a Filter
+
+Create a <a href="../objects/filter.md">Filter</a> for the current user.
+
+Send a JSON document that matches the <a href="../objects/filter.md">filter schema</a> with an HTTP header of ```Content-Type: application/json```. Currently, the only keys we use from your JSON will be ```name```, ```match_policy``` and ```clauses```.
+
+> This endpoint is currently migrated by the ```response_envelope``` migration. Please refer to the [Migrations documentation](/appdotnet/api-spec/blob/master/migrations.md#current-migrations) for more info.
+
+### URL
+> https://alpha-api.app.net/stream/0/filters
+
+### Data
+
+A JSON object representing the filter to create. See <a href="../objects/filter.md">the filter object</a> for more information. (Omit the <code>id</code> parameter).</td>
+
+### Example
+
+> POST https://alpha-api.app.net/stream/0/filters
+>
+> Content-Type: application/json
+>
+> DATA {"match_policy": "include_any", "clauses": [{"operator": "contains", "field": "/data/entities/hashtags/*/name", "object_type": "post", "value": "rollout"}], "name": "Posts about rollouts"}
+```js
+{
+ "data": {
+ "clauses": [
+ {
+ "field": "/data/entities/hashtags/*/name",
+ "object_type": "post",
+ "operator": "contains",
+ "value": "rollout"