Abstract

Micropub is an open API standard that is used to create posts on one's own domain using third-party clients. Web apps and native apps (e.g. iPhone, Android) can use Micropub to post short notes, photos, events or other posts to your own site.

Author's Note

This section is non-normative.

This specification was contributed to the W3C from the IndieWebCamp community. More history and evolution of Micropub can be found on the IndieWebCamp wiki.

Status of This Document

This section describes the status of this document at the time of its publication. Other documents may supersede this document. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at http://www.w3.org/TR/.

This document was published by the Social Web Working Group as a First Public Working Draft. This document is intended to become a W3C Recommendation. If you wish to make comments regarding this document, please send them to public-socialweb@w3.org (subscribe, archives). All comments are welcome.

Publication as a First Public Working Draft does not imply endorsement by the W3C Membership. This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.

This document was produced by a group operating under the 5 February 2004 W3C Patent Policy. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.

This document is governed by the 1 September 2015 W3C Process Document.

Table of Contents

1. Introduction

Micropub is a spec to create content on a server using web or native app clients.

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC2119].

1.1 Background

This section is non-normative.

The Micropub vocabulary is derived directly from the [Microformats] vocabulary. Micropub is meant to be a serialization of Microformats that can be submitted as an HTTP POST. The method for developing new Micropub vocabularies is to look at the Microformats representation and work backwards.

2. Syntax

Similar to how [Microformats] has a relatively small ruleset for parsing HTML documents into a data structure, Micropub defines a small set of rules to interpret HTTP POST and GET requests as Micropub commands. Where Microformats does not require changing the parsing rules to introduce new properties of an object such as an [h-entry], Micropub similarly does not require changing parsing rules to interpret requests that may correspond to different post types, such as posting videos vs "likes".

The Micropub syntax describes how to interpret HTTP POST and GET requests into a useful action the server can take.

2.1 Overview

All Micropub requests to create posts are sent as x-www-form-urlencoded, multipart form-data [HTML5], or [JSON]-encoded HTTP requests. Responses typically do not include a response body, indicating the needed information (such as the URL of the created post) in HTTP headers. When a response body is required, it is returned as either form-encoded or JSON, depending on the HTTP Accept [RFC7231] header.

2.2 Reserved Properties

A few POST body property names are reserved when requests are sent as x-www-form-urlencoded or multipart form data.

When creating posts, all other properties in the request are considered properties of the object being created.

2.3 Create

To create a post, send an HTTP POST request to the Micropub endpoint indicating the type of post you are creating, as well as specifying the properties of the post.

h={microformats object type}

e.g. h=entry

All parameters not beginning with "mp-" are properties of the object being created.

e.g. content=hello+world

To specify multiple values for a property, such as multiple categories of an h-entry, use array bracket notation for the property name.

e.g. category[]=foo&category[]=bar

Properties that accept multiple values MUST also accept a single value as a string. A complete example of a form-encoded request follows.

Example 1
h=entry&content=hello+world&category[]=foo&category[]=bar

2.3.1 Uploading Files

To upload files, format the whole request as multipart/form-data and send the file(s) as a standard property.

For example, to upload a photo with a caption, send a request that contains three parts, named h, content and photo.

Example 2
multipart/form-data; boundary=553d9cee2030456a81931fb708ece92c

--553d9cee2030456a81931fb708ece92c
Content-Disposition: form-data; name="h"

entry
--553d9cee2030456a81931fb708ece92c
Content-Disposition: form-data; name="content"

Hello World!
--553d9cee2030456a81931fb708ece92c
Content-Disposition: form-data; name="photo"; filename="aaronpk.png"
Content-Type: image/png
Content-Transfer-Encoding: binary

... (binary data) ...
--553d9cee2030456a81931fb708ece92c--

2.3.2 JSON Syntax

Alternately, you can create a post with JSON syntax by sending the entry in the parsed Microformats2 JSON format. However, in this case, you cannot also send a file.

Example 3
{
  "type": ["h-entry"],
  "properties": {
    "content": ["hello world"],
    "category": ["foo","bar"]
  }
}

2.3.3 Nested Microformats Objects

Whenever possible, nested Microformats objects should be avoided. A better alternative is to reference objects by their URLs. The most common example is including an h-card for a venue, such as checking in to a location or tagging a photo with a person or location. In these cases, it is better to reference the object by URL, creating it first if necessary.

This technique has the advantage of ensuring that each object that is created has its own URL (each piece of data has its own link). This also gives the server an opportunity to handle each entity separately. E.g., rather than creating a duplicate of an existing venue, it may give back a link to one that was already created, possibly even merging in newly received data first.

In some cases, it does not make sense for the nested object to have a URL. For example, when posting an h-measure value, there is no reason for the h-measure itself to have a URL, so this is an acceptable case to use the nested microformats object syntax.

The example below creates a new "weight" measurement post as an h-entry with a h-measure objects to describe the weight and bodyfat values.

Example 4
h=entry
&weight[type]=h-measure
&weight[properties][num]=155.73
&weight[properties][unit]=lb
&bodyfat[type]=h-measure
&bodyfat[properties][num]=19.83
&bodyfat[properties][unit]=%

Example 5
{
  "type": ["h-entry"],
  "properties": {
    "weight": [
      {
        "type": "h-measure",
        "properties": {
          "num": ["155.73"],
          "unit": ["lb"]
        }
      }
    ],
    "bodyfat": [
      {
        "type": "h-measure",
        "properties": {
          "num": ["19.83"],
          "unit": ["%"]
        }
      }
    ]
  }
}

2.3.4 Response

When the post is created, the Micropub endpoint MUST return either an HTTP 201 Created status code or HTTP 202 Accepted code, and MUST return a Location header indicating the URL of the created post. [RFC2616]

If the target also provides a shortlink, or if it syndicated the post to another location, the Micropub endpoint MAY return additional URLs using the HTTP Link header, along with an appropriate "rel" value. For example, it can return the short URL of a post by responding with:

Link: <http://aaron.pk/xxxxx>; rel="shortlink"
or can include the location of the syndicated post with:
Link: <https://https://myfavoritesocialnetwork.example/aaronpk/xxxxxx>; rel="syndication"

If the endpoint chooses to process the request asynchronously rather than creating and storing the post immediately, it MUST return an HTTP 202 Accepted status code, and MUST also return the Location header in this case. If the server is going to return 202, it MUST ensure the object will be created successfully prior to returning 202, as clients will expect the object at the indicated URL to exist at some point in the (near) future. In other words, the server must do any error checking and validation before returning 202.

2.4 Update

Warning

This section does not currently have interoperable implementations on both the server and client side, and therefore may change significantly once more implementation experience is gathered.

Updating entries can be done with either a JSON post or form-encoded post. The syntax of the update request is the same in both cases, using the array bracket notation when encoding in form-encoded format.

To update an entry, send mp-action=update and specify the URL of the entry that is being updated using the "url" property. The request MUST also include either a replace, add or delete property containing the updates to make.

2.4.1 Replace

Replace all values of the property. If the property does not exist already, it is created.

Example 6
mp-action=update
&url=http://example.com/post/1
&replace[properties][content]=hello+moon

Example 7
{
  "mp-action": "update",
  "url": "http://example.com/post/1",
  "replace": {
    "properties": {
      "content": ["hello moon"]
    }
  }
}

This will replace the entire entry content with the new text.

2.4.2 Add

If there are any existing values for this property, they are not changed, the new values are added. If the property does not exist already, it is created.

Adding a syndication URL

Use case: adding a syndication link to a post after it has been published. For example, when a client supports posting first then syndicating to MyFavoriteSocialNetwork or Wikimedia after the fact, the site needs a way to update the original post with the new syndication URL.

To add syndication URLs, include one or more URLs in the update request.

Example 8
mp-action=update
&url=http://aaronpk.example/notes/2014/06/01/2/indieweb
&add[properties][syndication][]=https://archive.org/example

Example 9
{
  "mp-action": "update",
  "url": "http://aaronparecki.com/notes/2014/06/01/2/indieweb",
  "add": {
    "properties": {
      "syndication": ["https://archive.org/"]
    }
  }
}

Adding Tags

Use case: adding tags to a post after it's been created.

To add multiple values to a property (such as category), use array notation to specify the multiple values.

Example 10
mp-action=update
&url=http://aaronpk.example/notes/2014/06/01/2/indieweb
&add[properties][category][]=webmention
&add[properties][category][]=indieweb

Example 11
{
  "mp-action": "update",
  "url": "http://aaronpk.example/notes/2014/06/01/2/indieweb",
  "add": {
    "properties": {
      "category": ["webmention","indieweb"]
    }
  }
}

2.4.3 Remove

If the property exists, remove it. This completely removes the specified property.

Example 12
mp-action=update
&url=http://example.com/post/1
&delete[properties]=category

Example 13
{
  "mp-action": "update",
  "url": "http://example.com/post/1",
  "delete": {
    "properties": ["category"]
  }
}

For properties with multiple values, such as categories, you can remove individual entries by value. If no values remain, the property is removed.

Example 14
mp-action=update
&url=http://example.com/post/1
&delete[properties][category]=indieweb

Example 15
{
  "mp-action": "update",
  "url": "http://example.com/post/1",
  "delete": {
    "properties": {
      "category": ["indieweb"]
    }
  }
}

2.4.4 Response

The server MUST respond to successful update requests with HTTP 200 or 204, depending on whether the response body has content. No body is required in the response.

2.5 Delete

To delete an entire entry at a URL, send a POST request containing mp-action=delete and the URL of the item in the url property.

Example 16
mp-action=delete
&url=http://example.com/post/1

Example 17
{
  "mp-action": "delete",
  "url": "http://example.com/post/1"
}

Some Micropub endpoints may support undeleting posts. To undelete a post, use "undelete" as the action.

Example 18
mp-action=undelete
&url=http://example.com/post/1

Example 19
{
  "mp-action": "undelete",
  "url": "http://example.com/post/1"
}

2.6 Querying

Warning

This section does not currently have interoperable implementations on both the server and client side, and therefore may change significantly once more implementation experience is gathered.

Micropub clients may need to query the Micropub endpoint to discover its capabilities, such as finding a list of syndication targets that it displays to the user, or retrieving the source of a post to display in the updating interface.

To query, make a GET request to the micropub endpoint and use the q parameter to specify what you are querying.

Note: The Micropub endpoint may include a query string such as ?micropub=endpoint, so in this case, Micropub clients MUST append the q parameter instead of replacing the query string.

2.6.1 Syndication Targets

To return a list of supported syndication targets, use q=syndicate-to.

GET /micropub?q=syndicate-to

The syndication targets MUST be returned as form-encoded array syntax by default.

Example 20
GET /micropub?q=syndicate-to
Authorization: Bearer xxxxxxxxx

syndicate-to[]=https://archive.org/
&syndicate-to[]=https://wikimedia.org/
&syndicate-to[]=https://myfavoritesocialnetwork.example/aaronpk

If the request includes an Accept header that includes application/json then the endpoint MUST return the response in JSON format.

Example 21
GET /micropub?q=syndicate-to
Authorization: Bearer xxxxxxxxx
Accept: application/json

{
  "syndicate-to": [
    "https://archive.org/",
    "https://wikimedia.org/",
    "https://myfavoritesocialnetwork.example/aaronpk"
  ]
}

3. How to Implement

This section covers how to implement the Micropub API, both in a client that can discover an endpoint and publish to it, and on a server to support an endpoint to create/update/delete posts in response.

3.1 Endpoint Discovery

It should be possible to configure an API client by authenticating as your domain name using [IndieAuth]. After signing in, your domain needs a way to specify the API endpoint the client will use to create new posts.

Add a <link> tag in the HTML head of your home page, or send an HTTP Link header.

Link: <https://example.com/micropub>; rel="micropub"

<link rel="micropub" href="https://example.com/micropub">

3.2 Authentication and Authorization

An app that wants to post to a user's Micropub endpoint will need to obtain authorization from the user in order to get an access token. Authorization SHOULD be handled via the OAuth 2.0 [RFC6749] protocol, including the [IndieAuth] extension which supports endpoint discovery. See Obtaining an Access Token for more details.

Micropub requests are authenticated by including a Bearer Token in either the HTTP header or a form-encoded body parameter as described in the OAuth Bearer Token RFC. [RFC6750]

HTTP Header

Authorization: Bearer XXXXXXXXX

Form-Encoded Body Parameter

access_token=XXXXXXXXX

3.3 Scope

The client may request one or more scopes during the authorization request. It does this according to standard OAuth 2.0 techniques, by passing a space-separated list of scope names in the authorization request. [RFC6749]

The authorization server must indicate to the user any scopes that are part of the request, whether or not the authorization server recognizes the scopes. The authorization server may also allow the user to add or remove scopes that the client requests.

For example, most Micropub servers require clients to obtain the "post" scope in order to create posts. However, some servers may require more granular scope requests, such as "delete" or "post:video". See Scope for more details and a list of all currently used values for scope.

3.4 Examples of Creating Objects

This section is non-normative.

To indicate the object being created, use a property called h, (which would never be the name of a property of a microformats object), followed by the name of the microformats object. Examples:

The following properties may be included in a request to create a new [h-entry]:

3.4.1 New Note

Posting a new note with tags, syndicating to myfavoritesocialnetwork:

  • content
  • category
  • published (optional, defaults to "now" if not present. Useful for writing offline and syncing later.)
  • mp-syndicate-to

Example 22
POST /micropub HTTP/1.1
Host: aaronpk.example
Authorization: Bearer XXXXXXXXXXX
Content-type: application/x-www-form-urlencoded

h=entry
&content=My+favorite+of+the+%23quantifiedself+trackers%2C+finally+released+their+official+API
&category[]=quantifiedself&category[]=api
&mp-syndicate-to=https://myfavoritesocialnetwork.example/aaronpk

Minimal Example

Example 23
POST /micropub HTTP/1.1
Host: example.com
Content-type: application/x-www-form-urlencoded
Authorization: Bearer XXXXXXX

h=entry
&content=Hello+World

Example 24
curl https://example.com/micropub -d h=entry -d "content=Hello World" -H "Authorization: Bearer XXXXXXX"

3.4.2 New Reply

Posting a new note with tags, syndicating to myfavoritesocialnetwork:

  • content
  • in-reply-to
  • published
  • mp-syndicate-to

Example 25
POST /micropub HTTP/1.1
Host: aaronpk.example
Authorization: Bearer XXXXXXXXXXX
Content-type: application/x-www-form-urlencoded

h=entry
&content=%40BarnabyWalters+My+favorite+for+that+use+case+is+Redis.
&in-reply-to=http://waterpigs.example/notes/4S0LMw/
&mp-syndicate-to=https://myfavoritesocialnetwork.example/aaronpk

3.4.3 New Repost

Posting a new repost, and adding additional tags.

  • repost-of
  • category

Example 26
POST /micropub HTTP/1.1
Host: aaronpk.example
Authorization: Bearer XXXXXXXXXXX
Content-type: application/x-www-form-urlencoded

h=entry
&repost-of=http://waterpigs.example/notes/4S0LMw/
&category=realtime

3.4.4 New Article

Posting a new article with HTML content.

  • name
  • content[html]
  • category
  • published

Example 27
POST /micropub HTTP/1.1
Host: aaronparecki.com
Content-type: application/x-www-form-urlencoded

h=entry
&name=Itching%3A+h-event+to+iCal+converter
&content[html]=Now+that+I%27ve+been+%3Ca+href%3D%22http%3A%2F%2Faaronparecki.com%22%3Ecreating+a+list+of+events%3C%2Fa%3E
+on+my+site+it+would+be+great+if+I+could+get+a+more+calendar-like+view+of+that+list...
&category[]=indieweb&category[]=hevent&category[]=events
&category[]=calendar&category[]=p3k

3.4.5 Adding Files

When a Micropub request includes a file, the entire request is sent in multipart form-data encoding, and the file is named by content type, either audio, video or photo. A request MAY include one or more of these files.

When OwnYourGram makes a Micropub request to post a video, it also sends a photo which is a thumbnail preview of the video.

In PHP, these files are accessible using the $_FILES array:

$_FILES['video']
$_FILES['photo']
$_FILES['audio']

Note that there is no practical way to upload a file when the request body is JSON encoded.

The Micropub endpoint may store the file directly, or make an external request to upload it to a different backend storage, such as Amazon S3.

A. Resources

This section is non-normative.

B. Implementations

This section is non-normative.

B.1 Libraries

B.2 Servers

B.3 Clients

B.4 Services

Note: Many of the services below are also open source Micropub clients.

C. Acknowledgements

The editor wishes to thank the IndieWebCamp community and other implementers for their support, encouragement and enthusiasm.

D. References

D.1 Normative references

[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://tools.ietf.org/html/rfc2119

D.2 Informative references

[HTML5]
Ian Hickson; Robin Berjon; Steve Faulkner; Travis Leithead; Erika Doyle Navara; Edward O'Connor; Silvia Pfeiffer. HTML5. 28 October 2014. W3C Recommendation. URL: http://www.w3.org/TR/html5/
[IndieAuth]
Aaron Parecki. IndieAuth. Living Specification. URL: http://indiewebcamp.com/IndieAuth-spec
[JSON]
D. Crockford. The application/json Media Type for JavaScript Object Notation (JSON). July 2006. Informational. URL: https://tools.ietf.org/html/rfc4627
[Microformats]
Microformats. URL: http://microformats.org
[RFC2616]
R. Fielding; J. Gettys; J. Mogul; H. Frystyk; L. Masinter; P. Leach; T. Berners-Lee. Hypertext Transfer Protocol -- HTTP/1.1. June 1999. Draft Standard. URL: https://tools.ietf.org/html/rfc2616
[RFC5870]
A. Mayrhofer; C. Spanring. A Uniform Resource Identifier for Geographic Locations ('geo' URI). June 2010. Proposed Standard. URL: https://tools.ietf.org/html/rfc5870
[RFC6749]
D. Hardt, Ed.. The OAuth 2.0 Authorization Framework. October 2012. Proposed Standard. URL: https://tools.ietf.org/html/rfc6749
[RFC6750]
M. Jones; D. Hardt. The OAuth 2.0 Authorization Framework: Bearer Token Usage. October 2012. Proposed Standard. URL: https://tools.ietf.org/html/rfc6750
[RFC7231]
R. Fielding, Ed.; J. Reschke, Ed.. Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content. June 2014. Proposed Standard. URL: https://tools.ietf.org/html/rfc7231
[h-adr]
Tantek Çelik. h-adr. Living Specification. URL: http://microformats.org/wiki/h-adr
[h-card]
Tantek Çelik. h-card. Living Specification. URL: http://microformats.org/wiki/h-card
[h-entry]
Tantek Çelik. h-entry. Living Specification. URL: http://microformats.org/wiki/h-entry