OneNote API and PHP

onenote apiRecently Microsoft released an API for my brain indexer favourite tool, OneNote.

To say I’m excited by the opportunities presented with this API, especially when it has some more features, would be an understatement. What’s really promising is how open the dev team are being about the API’s progress and out how quickly they are rolling new stuff out.

The API is particularly interesting to me as I had spent the previous 6 months on and off figuring out how I might get at the data in my Notebooks. Firstly I looked in some depth at how I might implement the syncing protocol MS-FSSHTTP, but that turned out to be a dead end. My fall-back was to teach myself C# and I got pretty far writing a .NET/WPF desktop application which consumed the OneNote COM API, the plan being to use it to stream data out to the cloud to be consumed by other devices.

But I don’t need to worry about that now! As soon as the API supports reading content, particularly tags – hint: you can vote for this feature here – then I’ll be all over writing the app I’ve wanted to build for the last 2 years.

Anyway, currently you can create new pages with the API, which is still pretty cool, so I thought that whilst I waited for reading/tag support (you voted, right?) I’d kick the tyres of the API using PHP.

So, firstly I’ve built a library to do the OAuth 2.0 stuff with the Live Connect API, you can find this on Github or packaged up ready to use with composer. Note that whilst the library will make authenticating against Live Connect Just Work it doesn’t yet implement a large number of OneDrive related content retrieval methods – though it should be pretty trivial for you to do this yourself if you need those features too.

The next thing on my list is to create a new library to wrap the OneNote API method by method, but for now here’s an example of how easy it is to consume the API once the authentication is taken care of.

The following should work on any web server, I’m using Linux/Apache.


Create composer.json, put this in it:

    "require": {
        "siftware/live-connect": "dev-master"
    "autoload": {
        "psr-4": {
            "Siftware\": "src/Siftware"

Install composer

curl -s | php
mv composer.phar composer

Pull down the library

./composer install

Create bootstrap.php

* Get these from
define("LC_CLIENT_ID", "<put yours here>");
define("LC_CLIENT_SECRET", "<put yours here>");

// this should match the URL you gave when getting your CLIENT_SECRET
define("LC_CALLBACK_URL", "");

require_once __DIR__ . '/../vendor/autoload.php';

use SiftwareLiveConnect;
use SiftwareLogger;

* PSR-3 compatible logger. Logs to file,  if you want to disable logging then just
* pass false as second parameter. See the class interface for more options.
* You can of course ditch this and pass in your own PS3-R logger instance
$logger = new Logger(PsrLogLogLevel::DEBUG);

$liveConnect = new LiveConnect(LC_CLIENT_ID, LC_CLIENT_SECRET, LC_CALLBACK_URL, $logger);

* See here for a full list of scopes and what they are used for:
$liveConnect->setScopes("wl.offline_access, wl.signin, wl.basic, office.onenote_create");

Create callback.php

require __DIR__ . "/bootstrap.php";

* If Live Connect doesn't recognise the source of the request, (because no
* credentials are presented) the OAuth process is kicked off.
* Stage 1 is to ask the user to accept the connection then redirect to the callback
* URL (which is specified when signing up with Live Connect for the app) with the
* auth code in the query string. This is that callback URL.
* The authenticate() method below is OAuth stage 2. It passes the auth code back
* to Live Connect and hopefully receives both an authentication token and also a
* refresh token (as well as a token expiry date), the initiating user shouldn't
* need to visit here again unless:
* 1) they manually de-authorise your app
* 2) the tokens are no longer available
* 3) new scopes are needed

$authCode = (isset($_GET["code"]) ? $_GET["code"] : "");

if (!$liveConnect->authenticate($authCode))
    print "Unable to authenticate against Live Connect";

    // clearly you'll want to handle this differently
    // all good
    header("Location: /");

Finally, a simple example POSTing a multipart document containing the HTML ‘Presentation’ field

 * Quick and dirty use of siftware/live-connect to post to the
 * new OneNote API. Over the coming weeks I'll wrap this up 

require __DIR__ . "/bootstrap.php";

use SiftwareLiveRequest;
use GuzzleHttpPostPostFile;

// ISO 8601 standard time stamp
$now = date('c');

$template = utf8_encode('<!DOCTYPE html>
            <title>onenote-api test page</title>
            <meta name="created" content="' . $now . '"/>
            <p>Hello OneNote World</p>

$liveRequest = new LiveRequest("",
                $logger, $liveConnect->getAccessToken());


// we don't need any standard POST fields for this example
$fields = array();

//pass in an array of GuzzleHttpPostPostFile(s)
$files[] = new PostFile("Presentation", $template, "fileName.html", array("Content-Type" => "application/xhtml+xml"));

$output = $liveRequest->post($fields, $files);

print "<pre>";
print_r(json_decode($output)) ;
print "</pre>";

You should get some output like this:

stdClass Object
    [links] => stdClass Object
            [oneNoteClientUrl] => stdClass Object
                    [href] => onenote:<your stuff>

            [oneNoteWebUrl] => stdClass Object
                    [href] =><your stuff>

There is some excellent documentation on what you can currently  do with the API so you should be able to quickly build upon this example to write some more complex pages.