Working with Plans and Access Codes

0 Let's build a simple integration that:

  1. Uses a Client ID and Client Secret to obtain an oauth token
  2. Access a list of available plans and their price options
  3. Create a Purchase Order for a list of access codes
  4. Check the Purchase Order status
  5. Fetch the access codes when the purchase order is complete

Authentication

Let's assume that you got your bearer token from the Authentication tutorial

let token = await getBearerToken();

We will then use the access_token obtained in any subsequent requests to the list the available plans, create the purchase order and list the access codes.

Get List of Plans

So, for example if we want to list the plans available we could:

let base_url = 'https://api.edufocal.net'; //sandbox url or api url
async function getPlans() {
  let plansResponse = await fetch(base_url + '/v1/plans', {
    headers: {
      'Authorization': 'Bearer ' + token.access_token
    }
  });
  let plansJson = await plansResponse.json();
}
console.log(await getPlans());

You will get a response similar to:

{
    "plans": [
        {
            "id": 101,
            "name": "EduFocal Basic",
            "category": "basic",
            "exam_category": null,
            "exam_level": null,
            "description": "You will get access to our test prep content"
        },
        {
            "id": 545,
            "name": "EduFocal Plus - Grade 4",
            "category": "plus",
            "exam_category": "pep",
            "exam_level": "GR4",
            "description": "Access to EduFocal Plus for Grade 4 and all of basic package"
        },
        {
            "id": 612,
            "name": "EduFocal Plus - Grade 5",
            "category": "plus",
            "exam_category": "pep",
            "exam_level": "GR5",
            "description": "Access to EduFocal Plus for Grade 5 all of basic package"
        },
        {
            "id": 711,
            "name": "EduFocal Plus - Grade 6",
            "category": "plus",
            "exam_category": "pep",
            "exam_level": "GSAT",
            "description": "Access to EduFocal Plus for Grade 6 and all of basic package"
        },
    ]
}

Get Prices for Specific Plan

Now to view the prices for a specific plan we can call prices endpoint:

let plans = await getPlans();
async function getPrices(planId) {
  let response = await fetch(base_url + '/v1/plans/' + planId + '/prices'{
    headers: {
      'Authorization': 'Bearer ' + token.access_token
    }
  });
}

let prices = await getPrices(plans[0].id);

console.log(prices);

The result looks like:

{
    "prices": [
        {
            "id": 1,
            "plan_id": 1,
            "name": "Monthly",
            "description": "Your plan will last for 30 days",
            "currency": "JMD",
            "charge": 2500,
            "valid_for_period": "30 days"
        }
    ]
}

Create Purchase Order

We now have enough information to create a Purchase Order for the Basic Plan on the Monthly price:

async function createPurchaseOrder(planId, priceId, quantity) {
  let params = {
    'plan_id': planId,
    'plan_price_id': priceId,
    'quantity': quantity
  };

  let response = await fetch('/v1/purchase_orders', {
    method: 'POST',
    mode: 'cors',
    cache: 'no-cache',
    headers: {
      'Content-Type': 'application/json',
      'Accept': 'application/json'
    },
    body: JSON.stringify(params)
  });

  let result = await response.json();
  return result;
}
console.log(
  await createPurchaseOrder(plans[0].id, prices[0].id, 100)
);

You should get an HTTP 201 result with a response body like:

{
    "id": 15,
    "status": "created",
    "quantity": 100,
    "plan_id": 1,
    "plan_price_id": 1,
    "last_updated_at": "2021-04-17T06:58:15.000000Z"
}

You are not allowed to request more than 100 items in a single order.

Check Purchase Order Status

When you create a purchase order, the codes for the purchase order may not be created right away. As such, you will have to check the purchase order endpoint to see if the status is changed to "completed".

async function getPurchaseOrder(id) {
  let response = await fetch(base_url + '/v1/purchase_orders/' + id, {
    headers: {
      'Authorization': 'Bearer ' + token.access_token
    }
  });
}

let purchaseOrder = await getPurchaseOrder(15);

console.log(purchaseOrder);

And looks something like this:

{
    "id": 15,
    "status": "completed",
    "quantity": 100,
    "plan_id": 1,
    "plan_price_id": 1,
    "last_updated_at": "2021-04-17T06:59:11.000000Z"
}

Once your purchase order is listed as completed you can fetch the codes by:

async function getPurchaseOrderCodes(id) {
  let response = await fetch(base_url + '/v1/purchase_orders/' + id +'/codes?limit=5', {
    headers: {
      'Authorization': 'Bearer ' + token.access_token
    }
  });
}

let codes = await getPurchaseOrderCodes(15);

console.log(codes);

And we get a list of access codes like:

{
    "id": 2,
    "codes": [
        {
            "id": 5346263,
            "code": "1185318918673",
            "value": "400.00",
            "currency": "JMD",
            "type": "Monthly",
            "valid_for": "30 days"
        },
        {
            "id": 5346264,
            "code": "4565194629918",
            "value": "400.00",
            "currency": "JMD",
            "type": "Monthly",
            "valid_for": "30 days"
        },
        {
            "id": 5346265,
            "code": "9945435361815",
            "value": "400.00",
            "currency": "JMD",
            "type": "Monthly",
            "valid_for": "30 days"
        },
        {
            "id": 5346266,
            "code": "6439148645375",
            "value": "400.00",
            "currency": "JMD",
            "type": "Monthly",
            "valid_for": "30 days"
        },
        {
            "id": 5346267,
            "code": "9984386196176",
            "value": "400.00",
            "currency": "JMD",
            "type": "Monthly",
            "valid_for": "30 days"
        }
    ],
    "cursor": {
        "starting_at": "aWQ9NTM0NjI2OCxsaW1pdD01"
    }
}

Make special note of the pagination cursor listed, which indicates there are more results to page through if you choose to.

Paging through codes

You may want to page through the codes by checking if there is a cursor attached to your results. The starting_at parameter can be passed to the codes endpoint to get the next page like so: /v1/purchase_orders/15/codes?starting_at=aWQ9NTM0NjI2OCxsaW1pdD01