Skip to main content

Implementation

Publish an entity at your domain

Stand up an OLPN identity on a static host, a CMS, or a dynamic server.

This guide walks through publishing an entity document at a domain you control. The exact steps depend on your stack. All paths end up at the same place: https://{your-domain}/olpn.json returns a valid OLPN entity document with HTTP 200 and content-type application/json.

Prerequisites

  • A domain you own.
  • Ability to serve a static file at an arbitrary path or edit the HTML of a page at the domain root.
  • An HTTPS certificate. Any modern host handles this automatically.

Option A. Static host

Netlify, Cloudflare Pages, GitHub Pages, S3 + CloudFront, Vercel, Deno Deploy, and similar hosts can serve a static JSON file at any path. This is the easiest setup.

  1. Create olpn.json at the root of your site source. Use the minimum viable shape from the entity document reference.
  2. Commit and deploy. Confirm https://{your-domain}/olpn.json returns the document in a plain fetch.
  3. Verify: search for §:entity:{your-domain} at olpn.org/search. You should see your profile with no credentials or properties yet.

Option B. WordPress

WordPress does not serve arbitrary JSON paths by default. Two reasonable paths:

B.1 File in the web root

Upload olpn.json directly to the WordPress install's web root (next to index.php). Most hosts expose this via FTP or a file manager. Apache and nginx will serve it directly without involving WordPress.

You will need to:

  • Check your server's MIME type table sends application/json for .json files. Most do by default.
  • Bypass any caching plugin that strips or rewrites non-HTML paths.

B.2 REST endpoint in a mu-plugin

For finer control, write a small must-use plugin that registers a REST route:

<?php
// wp-content/mu-plugins/olpn.php

add_action('rest_api_init', function () {
  register_rest_route('olpn/v1', '/entity', [
    'methods' => 'GET',
    'permission_callback' => '__return_true',
    'callback' => function () {
      return [
        'version' => '0.9',
        'network_id' => '§:entity:example.com',
        'entity_type' => 'person',
        'details' => [
          'name' => get_bloginfo('name'),
          'domain' => 'example.com',
        ],
        'properties' => [],
        'credentials' => [],
      ];
    },
  ]);
});

add_action('init', function () {
  add_rewrite_rule('^olpn\.json$', 'index.php?rest_route=/olpn/v1/entity', 'top');
});

The rewrite maps /olpn.json at the domain root to the REST route. Flush permalinks after activating. You still need to handle the § character if your setup mangles multibyte URLs.

Option C. Ghost (HTML embed only)

Ghost does not serve arbitrary JSON paths. The only path is the HTML embed in your homepage:

  1. Open Settings → Code injection → Site Header in Ghost Admin.
  2. Paste a <script id="olpn-hub" type="application/json">...</script> block. See HTML fallback.
  3. Save. Confirm the embed appears in your homepage source by doing a view-source on the homepage.
  4. Verify at olpn.org/search.

Option D. Dynamic app (Express, Fastify, Astro, Next, etc.)

Add a single route that returns the entity JSON.

// Express
app.get('/olpn.json', (req, res) => {
  res.type('application/json').send({
    version: '0.9',
    network_id: '§:entity:example.com',
    entity_type: 'person',
    details: { name: 'Example', domain: 'example.com' },
    properties: [],
    credentials: [],
  });
});

Same pattern in other frameworks. The document body can be static, computed, or pulled from a database. If computed, cache the response aggressively; recomputing an entity document per request is overkill.

After publishing

  1. Confirm the document is reachable in a plain curl (curl -v https://{your-domain}/olpn.json). HTTP 200, content-type application/json, parseable JSON.
  2. Search at olpn.org/search and confirm the resolver can find it. Check the "Show Details" trace.
  3. Move on to Publish an ownership record to anchor your domain as a verified property.