Integration requirements

Authorized User JWT

The User Authorization service needs to generate a JWT token. It must be signed with a shared secret using HMAC SHA256 alogorithm. The secret must match JWT secret token available at Settings > General for the corresponding accesstype account. The payload of the JWT must consist of email and id as shown below:

  email: "", // Email of the user, required
  id: 42, // unique id of the user in the external system, required
  provider: "quintype", // name of the external system, can be `quintype` or `wordpress`, optional, defaults to quintype
  name: "John" // name of the user, optional

For a user thats logged in to your website, this JWT token must be set as user context if you are using Accesstype-JS or passed as a query param if you are using APIs directly.

Story Attributes Endpoint

The Publisher must create a Story Attributes API that responds with attributes of a story.

  • It must be a public endpoint.
  • It must accept story-id query param.
  • It must respond in the below format
    visibility: 'subscription', // Can be one of 'subscription', 'login', 'public' //Required
    published-at: 1571716286097, // Integer  //Optional - if not provided defaults to epoch of 1990
    access-level: 999, //whole numbers  //Optional - if not provided defaults to 0
    attributes: [{ // Optional, required if Content Taxonomy Endpoint as described below is used
      name: 'section',
      values: ['sports', 'cricket']
      name: 'author',
      values: ['menaka']

This endpoint URL needs to be updated as Story attributes Endpoint in Accesstype at Settings > General. Accesstype will be calling this endpoint with a story-id query string param. The response will be used for next 3 mins before calling publisher’s server again.

Content Taxonomy Endpoint - Optional

When publisher wants to have fine grain access control based on custom attributes specific to her publishing platform, she must create a Content Taxonomy Endpoint.

  • It must be a public endpoint.
  • It must respond with custom attributes and their possible values in the below format
    type: story, //Optional, defaults to `story`
    attributes: [{ // Any thing in below format, except the reserved ones i.e ['visibility', 'published-at', 'access-level'] // Max 10 distinct attributes allowed
      name: 'section', //string
      values: [{label: 'Sports', value: 'sports'}, {label: 'Science and Tech', value: 'science'}] //array of objects
      search-url: '', //url //optional
      name: 'author',
      values: [{label: 'Menaka', value: 'menaka'}, {label: 'John', value: 'john'}]
  • Each attribute must have name and values.
  • values is an array of objects with label and value fields. label must be user friendly/readable. value must be unique, generally its the slug.
  • search-url can also be passed optionally if the count of values is too large. Every search-url endpoint must accept q and limit query params and respond in the below format:
    name: 'section', //string
    values: [{
        label: 'Sports',  //string
        value: 'sports'  //string
        label: 'Science and Tech',
        value: 'science'


This endpoint URL needs to be updated in Accesstype Settings. Accesstype would let you configure subscription plans with your custom attributes.

Reader ID - Optional

When publisher wants to avail Metered Paywall feature for Anonymous/Logged-In users, a Reader Id for every unique user/device needs to be provided to Accesstype.

On mobile apps, device Id can serve as a unique Reader Id.

Setting a cookie on users browser is the method generally used to identify unique user/device. With more and more tracking prevention policies being adopted by browsers, its the best to set this cookie from 1st party domain. ATJS looks for the availablility of at-meter cookie for using as Reader Id. If this is unavailable, it make a POST call to the configured readerIdUrl publisher endpoint.

Below is sample Javascript code that can be used on publisher server for defining the endpoint:

function setReaderId({ request }) {
  const cookies = cookie.parse(request.headers.get("Cookie") || "");
  let headers = {};
  let origin = new URL(request.headers.get("Origin"));

  if (!cookies["at-meter"]) {
    headers["Set-Cookie"] = `at-meter=${crypto.randomBytes(16).toString("hex")}; Path=/; Domain=${
    }; Expires=Wed, 21 Oct 2075 07:28:00 GMT; SameSite=None; Secure;`;

  return new Response("{}", { status: 201, headers: headers });