NAV
shell java python

B2B API v1.0

Last updated: April 27, 2022

Introduction

Musaffa’s API is one of the most comprehensive Shariah-Compliant Stock Screener organized around REST. Our API has predictable resource-oriented URLs, accepts form-encoded request bodies, returns JSON-encoded responses, and uses standard HTTP response codes, authentication, and verbs.

All requests are made to endpoints beginning: https://platform.musaffa.com/api.

Developer Agreement

By using Musaffa’s API, you agree to our Terms of Use.

Rate Limits

There are limitations for the API calls.

Depending on the B2B subscription plan it can be up to 100 000 API calls per month and 1 API call per second.

If your limit is exceeded, you will receive a response with status code 429.

Authentication and API

Musaffa will provide a secret key and a client ID to every B2B client.

secretKey=< should be shared separately for each client >

clientId=< should be shared separately for each client >

UTC is used for time zone “UTC+5”

TimeZone = "UTC"

DateTimeFormatter = "yyyyMMddHHmmss"

Using current time, the secret key, the client ID and a body of the message a token is generated using the following code:

token = Base64.getEncoder().encodeToString(DigestUtils.sha512 (secretKey + time + json String body))

The token is placed in the header of the message for both sides of the communication and used for validating messages.

Example Token Generation

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.http.*;
import org.springframework.web.client.RestTemplate;

import java.time.Instant; import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.Base64; import java.util.HashMap; import java.util.Map;

class ProfileApplicationTests { private String secretKey = "gUkXp2s5v8yBE(dYjhTi5PeShVmYq3t6w9z$C&F)JMcQfTjWnZ"; private String clientId = "EjXfR2rt7xADG";
private String generatedToken(String time, String jsonInString) { return Base64.getEncoder().encodeToString(DigestUtils.sha512(secretKey + time + jsonInString)); } }

String secretKey = "gRUkXp2s5v8yBEyGbPeShVmYq3t6w9z$C&F)JMcQfTjWnZ"

String jsonInStringBody = "{"stock":"AAPL"}"

String time = ZonedDateTime.ofInstant(nowUtc, zoneId).format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));

String token = Base64.getEncoder().encodeToString(DigestUtils.sha512(secretKey + time + jsonInStringBody));

List of Stocks

curl --location --request POST
'https://platform.musaffa.com/b2b/api/v1/musaffa/stocks/list'
--header 'token: token'
--header 'clientId: clientId'
--header 'time: yyyyMMddHHmmss'
--header 'Content-Type: application/json'
--data-raw '{
    "country":"US",
    "sector":"Information Technology"
}'
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.http.*;
import org.springframework.web.client.RestTemplate;

import java.time.Instant; import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.Base64; import java.util.HashMap; import java.util.Map;

RestTemplate restTemplate = new RestTemplate(); Instant nowUtc = Instant.now(); ZoneId zoneId = ZoneId.of("UTC+5"); String time = ZonedDateTime.ofInstant(nowUtc, zoneId).format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")); Map<String, Object> requestBody = new HashMap<>(); requestBody.put("country", "ID"); requestBody.put("sector", "Information Technology"); ObjectMapper mapper = new ObjectMapper(); String jsonInString = "";

try { jsonInString = mapper.writeValueAsString(requestBody); } catch (JsonProcessingException e) { e.printStackTrace(); }

HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); headers.set("token", generatedToken(time, jsonInString)); headers.set("time", time); headers.set("clientId", clientId); HttpEntity<String> http = new HttpEntity<>(jsonInString, headers); ResponseEntity<Object> response = restTemplate.exchange("https://platform.musaffa.com/b2b/api/v1/musaffa/stocks/list", HttpMethod.POST, http, Object.class); System.out.println("List ticker RESULT : " + response.getBody());

import requests 
import hashlib 
import base64
from datetime import datetime
import pytz

client_id = "EjXfR2rt7xADG" secret_key= "gUkXp2s5v8yBE(dYjhTi5PeShVmYq3t6w9z$C&F)JMcQfTjWnZ" url = "https://platform.musaffa.com/b2b/api/v1/musaffa/stocks/list"

country = "US" sector = "Energy" json_body = '{"country":"' + country + '","sector":"' + sector + '"}'

now = datetime.utcnow() date_time_format = now.strftime("%Y%m%d%H%M%S") token_pre_generate = secret_key + date_time_format + json_body token_sha512 = hashlib.sha512(token_pre_generate.encode("utf8")).digest() token_base64 = base64.b64encode(token_sha512)

headers = { "token" : token_base64, "clientId" : client_id, "time" : date_time_format, "Content-Type" : "application/json" }

x = requests.post(url=url, data=json_body, headers=headers) print(x.json())

Success Response

[
    {
        "stockName": "DCII.JK",
        "companyName": "DCI Indonesia Tbk PT",
        "status": "COMPLIANT",
        "ranking": 5
    },
    {
        "stockName": "DMMX.JK",
        "companyName": "Digital Mediatama Maxima PT",
        "status": "COMPLIANT",
        "ranking": 4
    },
    {
        "stockName": "MCAS.JK",
        "companyName": "M Cash Integrasi Tbk PT",
        "status": "COMPLIANT",
        "ranking": 2
    },
    ......
    {
        "stockName": "MKNT.JK",
        "companyName": "Mitra Komunikasi Nusantara Tbk PT",
        "status": "NON_COMPLIANT",
        "ranking": 0
    },
    {
        "stockName": "WGSH.JK",
        "companyName": "Wira Global Solusi Tbk PT",
        "status": "COMPLIANT",
        "ranking": 1
    }
]

Get Shariah-Compliant Screening Results for stocks. You can query by stock ticker.

List of Sectors:

  • Health Care
  • Financials
  • Information Technology Consumer Staples Real Estate
  • Energy
  • Industrials
  • Materials
  • Utilities
  • Consumer Discretionary
  • Communication Services

Sample country codes:

US, UK, SG etc

Stocks request information

Category Value
Http method POST
URL https://platform.musaffa.com/b2b/api/v1/musaffa/stocks/list

Stocks request headers

Field Value Description
token < token > Should be shared separately for each client
clientId < clientId > Should be shared separately for each client
time < yyyyMMddHHmmss > Server time with "zoneId" TimeZone and formated in yyyyMMddHHmmss string
Content-Type "application/json" Request content type

Stocks request body in JSON format

Field Value Description
country "US" Country code
sector "Information Technology" Sector

Stocks response data structure (JSON array)

Field Type Description
stockName String Stock symbol
companyName String Company name
status String Shariah-compliance Status
(Halal, Not Halal, Doubtful, Not Covered)
ranking Number Compliance Rank (0-5)

Stock Screening Report

curl --location --request POST
'https://platform.musaffa.com/b2b/api/v1/musaffa/stocks/get'
--header 'token: token'
--header 'clientId: clientId'
--header 'time: yyyyMMddHHmmss'
--header 'Content-Type: application/json'
--data-raw '{
    "stock":"AAPL"
}'
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.http.*;
import org.springframework.web.client.RestTemplate;

import java.time.Instant; import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.Base64; import java.util.HashMap; import java.util.Map;

RestTemplate restTemplate = new RestTemplate(); Instant nowUtc = Instant.now(); ZoneId zoneId = ZoneId.of("UTC+5"); String time = ZonedDateTime.ofInstant(nowUtc, zoneId).format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")); Map<String, Object> requestBody = new HashMap<>(); requestBody.put("stock", "AAPL"); ObjectMapper mapper = new ObjectMapper(); String jsonInString = "";

try { jsonInString = mapper.writeValueAsString(requestBody); } catch (JsonProcessingException e) { e.printStackTrace(); }

HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); headers.set("token", generatedToken(time, jsonInString)); headers.set("time", time); headers.set("clientId", clientId); HttpEntity<String> requestHttpEntity = new HttpEntity<>(jsonInString, headers); ResponseEntity<Object> response = restTemplate.exchange("https://platform.musaffa.com/b2b/api/v1/musaffa/stocks/get", HttpMethod.POST, requestHttpEntity, Object.class); System.out.println("One ticker RESULT : " + response.getBody());

import requests 
import hashlib 
import base64
from datetime import datetime
import pytz

client_id = "EjXfR2rt7xADG" secret_key= "gUkXp2s5v8yBE(dYjhTi5PeShVmYq3t6w9z$C&F)JMcQfTjWnZ" url = "https://platform.musaffa.com/b2b/api/v1/musaffa/stocks/get"

stock = "AAPL" json_body = '{"stock":"' + stock + '"}' now = datetime.utcnow()

date_time_format = now.strftime("%Y%m%d%H%M%S")

token_pre_generate = secret_key + date_time_format + json_body token_sha512 = hashlib.sha512(token_pre_generate.encode("utf8")).digest() token_base64 = base64.b64encode(token_sha512)

headers = { "token" : token_base64, "clientId" : client_id, "time" : date_time_format, "Content-Type" : "application/json" }

x = requests.post(url=url, data=json_body, headers=headers) print(x.json())

Success Response

{
    "companyName": "Apple Inc",
    "stockName": "AAPL",
    "shariahComplianceStatus": "COMPLIANT",
    "complianceRanking": 1,
    "revenueBreakdown": {
        "notHalal": 2.1,
        "doubtful": 2.0,
        "halal": 95.9,
        "status": "Pass"
    },
    "interestBearingSecuritiesAndAssets": {
        "interestRatio": 10.0,
        "status": "Pass"
    },
    "interestBearingDebt": {
        "debtRatio": 5.0,
        "status": "Pass"
    },
    "source": "30-MARCH-2021"
}

Get Shariah-Compliant Screening Results for stocks. You can query by stock ticker.

Stock request information

Category Value
Http method POST
URL https://platform.musaffa.com/b2b/api/v1/musaffa/stocks/get

Stock request headers

Field Value Description
token < token > Should be shared separately for each client
clientId < clientId > Should be shared separately for each client
time < yyyyMMddHHmmss > Server time with "zoneId" TimeZone and formated in yyyyMMddHHmmss string
Content-Type "application/json" Request content type

Stock request body in JSON format

Field Value Description
stock "AAPL" Stock symbol

Stock response data structure (JSON)

Field Type Description
companyName String Company name
stockName String Stock symbol
shariahComplianceStatus String Shariah-compliance Status (Halal, Not Halal, Doubtful, Not Covered)
complianceRanking number Compliance Rank (0-5)
revenueBreakdown
{ notHalal, doubtful, halal, status }
Object
notHalal=>Float,
doubtful=>Float,
halal=>Float,
status=>String
Revenue Breakdown
Combined revenue from ‘Doubtful’ and ‘Not-Halal’ sources must be less than 5% of total revenue to be Shariah compliant based on AAOIFI stock screening methodology.
Thus,
  • if Doubtful+Not Halal revenue is equal or more than 5%, it is ‘Fail’
  • if Doubtful+Not Halal revenue is less than 5%, it is ‘Pass’
  • if Halal, Doubtful and Not halal has no value, then the status will be ’NOT_COVERED’
interestBearingSecuritiesAndAssets
{ interestRatio, status }
Object
interestRatio=>Float,
status=>String
Interest-bearing Securities and Assets
Interest-Bearing Securities and Assets should be less than 30% of Trailing 36-month Average Market Capitalization to be Shariah compliant based on AAOIFI stock screening methodology.Thus,
  • if Interest Ratio is equal or more than 30%, then the status will be ‘Fail’
  • if Interest Ratio is less than 30%, then the status will be ‘Pass’
  • if Interest Ratio has no value, then the status will be ’NOT_COVERED’
interestBearingDebt
{ debtRatio, status }
Object
debtRatio=>Float,
status=>String
Interest-bearing Debt
Interest-Bearing Debt should be less than 30% of Trailing 36-Month Average Market Capitalization to be Shariah compliant based on AAOIFI stock screening methodology.
Thus,
  • if Debt Ratio is equal or more than 30%, then the status will be ‘Fail’
  • if Debt Ratio is less than 30%, then the status will be ‘Pass’
  • if Debt Ratio has no value, then the status will be ’NOT_COVERED’
source String Reporting dates of the company

List of Stock Screening Reports

curl --location --request POST
'https://platform.musaffa.com/b2b/api/v2/musaffa/stocks/screening-list'
--header 'token: token'
--header 'clientId: clientId'
--header 'time: yyyyMMddHHmmss'
--header 'Content-Type: application/json'
--data-raw '{
    "stocks":["AAPL","NFLX","TSLA"]
}'
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.http.*;
import org.springframework.web.client.RestTemplate;

import java.time.Instant; import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.Base64; import java.util.HashMap; import java.util.Map;

RestTemplate restTemplate = new RestTemplate(); Instant nowUtc = Instant.now(); ZoneId zoneId = ZoneId.of("UTC+5"); String time = ZonedDateTime.ofInstant(nowUtc, zoneId).format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));

ObjectMapper mapper = new ObjectMapper(); String jsonInString = "";

try { jsonInString = mapper.writeValueAsString({"stocks":["AAPL","NFLX","TSLA"]}); } catch (JsonProcessingException e) { e.printStackTrace(); }

HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); headers.set("token", generatedToken(time, jsonInString)); headers.set("time", time); headers.set("clientId", clientId); HttpEntity<String> requestHttpEntity = new HttpEntity<>(jsonInString, headers); ResponseEntity<Object> response = restTemplate.exchange("https://platform.musaffa.com/b2b/api/v2/musaffa/stocks/screening-list", HttpMethod.POST, requestHttpEntity, Object.class); System.out.println("One ticker RESULT : " + response.getBody());

import requests 
import hashlib 
import base64
from datetime import datetime
import pytz

client_id = "EjXfR2rt7xADG" secret_key= "gUkXp2s5v8yBE(dYjhTi5PeShVmYq3t6w9z$C&F)JMcQfTjWnZ" url = "https://platform.musaffa.com/b2b/api/v2/musaffa/stocks/screening-list"

json_body = '{"stocks":["AAPL","NFLX","TSLA"]}' now = datetime.utcnow()

date_time_format = now.strftime("%Y%m%d%H%M%S")

token_pre_generate = secret_key + date_time_format + json_body token_sha512 = hashlib.sha512(token_pre_generate.encode("utf8")).digest() token_base64 = base64.b64encode(token_sha512)

headers = { "token" : token_base64, "clientId" : client_id, "time" : date_time_format, "Content-Type" : "application/json" }

x = requests.post(url=url, data=json_body, headers=headers) print(x.json())

Success Response

[
    {
        "companyName": "Apple Inc",
        "stockName": "AAPL",
        "shariahComplianceStatus": "COMPLIANT",
        "complianceRanking": 1,
        "revenueBreakdown": {
            "notHalal": 0.27,
            "halal": 95.91,
            "doubtful": 3.82,
            "status": "Pass"
        },
        "interestBearingSecuritiesAndAssets": {
            "interestRatio": 2.69,
            "status": "Pass"
        },
        "interestBearingDebt": {
            "debtRatio": 5.9,
            "status": "Pass"
        },
        "source": "March 26, 2022"
    },
    {
        "companyName": "Netflix Inc",
        "stockName": "NFLX",
        "shariahComplianceStatus": "QUESTIONABLE",
        "complianceRanking": 0,
        "revenueBreakdown": {
            "notHalal": 2.49,
            "halal": 0.0,
            "doubtful": 97.51,
            "status": "Fail"
        },
        "interestBearingSecuritiesAndAssets": {
            "interestRatio": 3.1,
            "status": "Pass"
        },
        "interestBearingDebt": {
            "debtRatio": 7.49,
            "status": "Pass"
        },
        "source": "March 31, 2022"
    },
    {
        "companyName": "Tesla Inc",
        "stockName": "TSLA",
        "shariahComplianceStatus": "COMPLIANT",
        "complianceRanking": 5,
        "revenueBreakdown": {
            "notHalal": 0.15,
            "halal": 99.85,
            "doubtful": 0.0,
            "status": "Pass"
        },
        "interestBearingSecuritiesAndAssets": {
            "interestRatio": 3.54,
            "status": "Pass"
        },
        "interestBearingDebt": {
            "debtRatio": 0.95,
            "status": "Pass"
        },
        "source": "March 31, 2022"
    }
]

Get Shariah-Compliant Screening Results for stocks. You can query by stock tickers. Maximum permissible limit of tickers per request is 100.

Stock bulk request information

Category Value
Http method POST
URL https://platform.musaffa.com/b2b/api/v2/musaffa/stocks/screening-list

Stock bulk request headers

Field Value Description
token < token > Should be shared separately for each client
clientId < clientId > Should be shared separately for each client
time < yyyyMMddHHmmss > Server time with "zoneId" TimeZone and formated in yyyyMMddHHmmss string
Content-Type "application/json" Request content type

Stock bulk request body in JSON format

Field Value Description
stocks ["AAPL","NFLX","TSLA, . . . . "] Stock symbol list (Maximum 100 symbols per request)

Stock bulk response data structure (JSON array)

Field Type Description
companyName String Company name
stockName String Stock symbol
shariahComplianceStatus String Shariah-compliance Status (Halal, Not Halal, Doubtful, Not Covered)
complianceRanking number Compliance Rank (0-5)
revenueBreakdown
{ notHalal, doubtful, halal, status }
Object
notHalal=>Float,
doubtful=>Float,
halal=>Float,
status=>String
Revenue Breakdown
Combined revenue from ‘Doubtful’ and ‘Not-Halal’ sources must be less than 5% of total revenue to be Shariah compliant based on AAOIFI stock screening methodology.
Thus,
  • if Doubtful+Not Halal revenue is equal or more than 5%, it is ‘Fail’
  • if Doubtful+Not Halal revenue is less than 5%, it is ‘Pass’
  • if Halal, Doubtful and Not halal has no value, then the status will be ’NOT_COVERED’
interestBearingSecuritiesAndAssets
{ interestRatio, status }
Object
interestRatio=>Float,
status=>String
Interest-bearing Securities and Assets
Interest-Bearing Securities and Assets should be less than 30% of Trailing 36-month Average Market Capitalization to be Shariah compliant based on AAOIFI stock screening methodology.Thus,
  • if Interest Ratio is equal or more than 30%, then the status will be ‘Fail’
  • if Interest Ratio is less than 30%, then the status will be ‘Pass’
  • if Interest Ratio has no value, then the status will be ’NOT_COVERED’
interestBearingDebt
{ debtRatio, status }
Object
debtRatio=>Float,
status=>String
Interest-bearing Debt
Interest-Bearing Debt should be less than 30% of Trailing 36-Month Average Market Capitalization to be Shariah compliant based on AAOIFI stock screening methodology.
Thus,
  • if Debt Ratio is equal or more than 30%, then the status will be ‘Fail’
  • if Debt Ratio is less than 30%, then the status will be ‘Pass’
  • if Debt Ratio has no value, then the status will be ’NOT_COVERED’
source String Reporting dates of the company

Dividend Purification

curl --location --request POST
'https://platform.musaffa.com/b2b/api/v2/musaffa/stocks/dividends/pure'
--header 'token: token'
--header 'clientId: clientId'
--header 'time: yyyyMMddHHmmss'
--header 'Content-Type: application/json'
--data-raw '{
    "stock":"AAPL"
}'
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.http.*;
import org.springframework.web.client.RestTemplate;

import java.time.Instant; import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.Base64; import java.util.HashMap; import java.util.Map;

RestTemplate restTemplate = new RestTemplate(); Instant nowUtc = Instant.now(); ZoneId zoneId = ZoneId.of("UTC+5"); String time = ZonedDateTime.ofInstant(nowUtc, zoneId).format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")); Map<String, Object> requestBody = new HashMap<>(); requestBody.put("stock", "AAPL"); ObjectMapper mapper = new ObjectMapper(); String jsonInString = "";

try { jsonInString = mapper.writeValueAsString(requestBody); } catch (JsonProcessingException e) { e.printStackTrace(); }

HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); headers.set("token", generatedToken(time, jsonInString)); headers.set("time", time); headers.set("clientId", clientId); HttpEntity<String> requestHttpEntity = new HttpEntity<>(jsonInString, headers); ResponseEntity<Object> response = restTemplate.exchange("https://platform.musaffa.com/b2b/api/v2/musaffa/stocks/dividends/pure", HttpMethod.POST, requestHttpEntity, Object.class); System.out.println("One ticker RESULT : " + response.getBody());

import requests 
import hashlib 
import base64
from datetime import datetime
import pytz

client_id = "EjXfR2rt7xADG" secret_key= "gUkXp2s5v8yBE(dYjhTi5PeShVmYq3t6w9z$C&F)JMcQfTjWnZ" url = "https://platform.musaffa.com/b2b/api/v2/musaffa/stocks/dividends/pure"

stock = "AAPL" json_body = '{"stock":"' + stock + '"}' now = datetime.utcnow()

date_time_format = now.strftime("%Y%m%d%H%M%S")

token_pre_generate = secret_key + date_time_format + json_body token_sha512 = hashlib.sha512(token_pre_generate.encode("utf8")).digest() token_base64 = base64.b64encode(token_sha512)

headers = { "token" : token_base64, "clientId" : client_id, "time" : date_time_format, "Content-Type" : "application/json" }

x = requests.post(url=url, data=json_body, headers=headers) print(x.json())

Success Response

{
  "non-compliant_revenue_ratio": 4.09,
  "dividend_per_share_for_quarter": 0.23,
  "dividend_purification_amount_per_share": 4.25227049219663e-12
}

Get Dividend Purification Results for stocks. You can query by stock ticker.

Purification request information

Category Value
Http method POST
URL https://platform.musaffa.com/b2b/api/v2/musaffa/stocks/dividends/pure

Purification request headers

Field Value Description
token < token > Should be shared separately for each client
clientId < clientId > Should be shared separately for each client
time < yyyyMMddHHmmss > Server time with "zoneId" TimeZone and formated in yyyyMMddHHmmss string
Content-Type "application/json" Request content type

Purification request body in JSON format

Field Value Description
stock "AAPL" Stock symbol

Purification response data structure (JSON)

Field Type Description
non-compliant_revenue_ratio Number Percentage of non-compliant revenue out of total revenue
dividend_per_share_for_quarter Number Dividend per share for the latest quarter
dividend_purification_amount_per_share Number Dividend purification amount per share (DPAPS)

Formula for dividend purification: Dividend purification amount per share = Last Dividend per Share * (IR+QR)/100

IR - Impermissible Revenue Ratio QR - Questionable Revenue Ratio

Related Stocks

curl --location --request GET
'https://platform.musaffa.com/b2b/api/v1/musaffa/stocks/related/AAPL'
--header 'token: token'
--header 'clientId: clientId'
--header 'time: yyyyMMddHHmmss'
--header 'Content-Type: application/json'
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.http.*;
import org.springframework.web.client.RestTemplate;

import java.time.Instant; import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.Base64;

private String secretKey = "gUkXp2s5v8yBE(dYjhTi5PeShVmYq3t6w9z$C&F)JMcQfTjWnZ"; private String clientId = "EjXfR2rt7xADG";

RestTemplate restTemplate = new RestTemplate(); Instant nowUtc = Instant.now(); ZoneId zoneId = ZoneId.of("UTC+5"); String time = ZonedDateTime.ofInstant(nowUtc, zoneId).format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));

public String stock = "AAPL"; HttpHeaders headers = new HttpHeaders(); headers.set("token", generatedToken(time, stock)); headers.set("time", time); headers.set("clientId", clientId); HttpEntity<String> requestHttpEntity = new HttpEntity<>(headers); ResponseEntity<Object> response = restTemplate.exchange("https://platform.musaffa.com/b2b/api/v1/musaffa/stocks/related/" + stock, HttpMethod.GET, requestHttpEntity, Object.class); System.out.println("Related stock RESULT : " + response.getBody());

private String generatedToken(String time, String stock) { return Base64.getEncoder().encodeToString(DigestUtils.sha512(secretKey + time + stock)); }

import requests 
import hashlib 
import base64
from datetime import datetime
import pytz

client_id = "EjXfR2rt7xADG" secret_key= "gUkXp2s5v8yBE(dYjhTi5PeShVmYq3t6w9z$C&F)JMcQfTjWnZ"

stock = "AAPL" url = "https://platform.musaffa.com/b2b/api/v1/musaffa/stocks/related/{stock}"

now = datetime.utcnow() date_time_format = now.strftime("%Y%m%d%H%M%S") token_pre_generate = secret_key + date_time_format + stock token_sha512 = hashlib.sha512(token_pre_generate.encode("utf8")).digest() token_base64 = base64.b64encode(token_sha512)

headers = { "token" : token_base64, "clientId" : client_id, "time" : date_time_format, "Content-Type" : "application/json" }

x = requests.get(url=url , headers=headers) print(x.json())

Success Response

[
    {
        "companyName": "Samsung Electronics Co Ltd",
        "stockName": "SSNNF",
        "shariahComplianceStatus": "NON_COMPLIANT",
        "complianceRanking": 0
    },
    {
        "companyName": "Canon Inc",
        "stockName": "CAJ",
        "shariahComplianceStatus": "COMPLIANT",
        "complianceRanking": 3
    },
    {
        "companyName": "Wipro Ltd",
        "stockName": "WIT",
        "shariahComplianceStatus": "QUESTIONABLE",
        "complianceRanking": 0
    },
    {
        "companyName": "Microsoft Corp",
        "stockName": "MSFT",
        "shariahComplianceStatus": "QUESTIONABLE",
        "complianceRanking": 0
    }
]

Related stocks is a list of stocks which match with current stock by market, industry and sector.

Category Value
Http method GET
URL https://platform.musaffa.com/b2b/api/v1/musaffa/stocks/related/{AAPL}
URL Param Stock symbol
Field Value Description
token < token > Should be shared separately for each client
clientId < clientId > Should be shared separately for each client
time < yyyyMMddHHmmss > Server time with "zoneId" TimeZone and formated in yyyyMMddHHmmss string
Field Type Description
companyName String Company name
stockName String Stock symbol
shariahComplianceStatus String Shariah-compliance Status (Halal, Not Halal, Doubtful, Not Covered)
complianceRanking number Compliance Rank (0-5)

Webhook

curl --location --request POST
'https://webhook_url'
--header 'token: token'
--header 'clientId: clientId'
--header 'time: yyyyMMddHHmmss'
--header 'Content-Type: application/json'
--data-raw '{
    "companyName" : "Meta Platforms Inc",
    "stockName" : "FB",
    "lastUpdate" : "2022-04-05T08:49:28.089Z",
    "shariahComplianceStatus" : "DOUBTFUL",
    "complianceRanking" : 0,
    "revenueBreakdown" : {
        "notHalal" : 0.39,
        "doubtful" : 97.46,
        "halal" : 2.1500015,
        "status" : "Fail"
    },
    "interestBearingSecuritiesAndAssets" : {
        "interestRatio" : 6.99,
        "status" : "Pass"
    },
    "interestBearingDebt" : {
        "debtRatio" : 0.0,
        "status" : "Pass"
    },
    "source" : "31-12-2021"
}'

Setting up webhook:

You provide us your webhook URL. All stock data updates will be sent through webhook instantly.

You can check your webhook header in the following format:

Webhook request information

Category Value Description
Http method POST Webhook method
URL https://webhook_url Your webhook URL

Webhook request headers

Field Value Description
token < token > Should be shared separately for each client
clientId < clientId > Should be shared separately for each client
time < yyyyMMddHHmmss > Server time with "zoneId" TimeZone and formated in yyyyMMddHHmmss string
Content-Type "application/json" Request content type

Webhook request body in JSON format

Field Type Description
companyName String Company name
stockName String Stock symbol
shariahComplianceStatus String Shariah-compliance Status (Halal, Not Halal, Doubtful, Not Covered)
complianceRanking number Compliance Rank (0-5)
revenueBreakdown
{ notHalal, doubtful, halal, status }
Object
notHalal=>Float,
doubtful=>Float,
halal=>Float,
status=>String
Revenue Breakdown
Combined revenue from ‘Doubtful’ and ‘Not-Halal’ sources must be less than 5% of total revenue to be Shariah compliant based on AAOIFI stock screening methodology.
Thus,
  • if Doubtful+Not Halal revenue is equal or more than 5%, it is ‘Fail’
  • if Doubtful+Not Halal revenue is less than 5%, it is ‘Pass’
  • if Halal, Doubtful and Not halal has no value, then the status will be ’NOT_COVERED’
interestBearingSecuritiesAndAssets
{ interestRatio, status }
Object
interestRatio=>Float,
status=>String
Interest-bearing Securities and Assets
Interest-Bearing Securities and Assets should be less than 30% of Trailing 36-month Average Market Capitalization to be Shariah compliant based on AAOIFI stock screening methodology.Thus,
  • if Interest Ratio is equal or more than 30%, then the status will be ‘Fail’
  • if Interest Ratio is less than 30%, then the status will be ‘Pass’
  • if Interest Ratio has no value, then the status will be ’NOT_COVERED’
interestBearingDebt
{ debtRatio, status }
Object
debtRatio=>Float,
status=>String
Interest-bearing Debt
Interest-Bearing Debt should be less than 30% of Trailing 36-Month Average Market Capitalization to be Shariah compliant based on AAOIFI stock screening methodology.
Thus,
  • if Debt Ratio is equal or more than 30%, then the status will be ‘Fail’
  • if Debt Ratio is less than 30%, then the status will be ‘Pass’
  • if Debt Ratio has no value, then the status will be ’NOT_COVERED’
source String Reporting dates of the company

Errors

The Musaffa API uses the following error codes:

Error Response
400 Bad Request:

{
    "message": "Data validation error!",
    "errors": [
        {
            "field": "token",
            "value": "",
            "message": "Token invalid or token generation error!"
        } 
    ]
}

Gives a "Time expired" error if the token time exceeds 5 seconds
400 Bad Request:

{
    "message": "Data validation error!",
    "errors": [
        {
            "field": "time",
            "value": "20220328162043",
            "message": "Time expired!"
        }
    ]
}

Error Response
429 Too Many Requests:

{
    "path": "/api/v1/musaffa/stocks/get",
    "error": "Too Many Requests",
    "message": "Request more than once per second",
    "timestamp": "2022-05-12T15:18:17.943",
    "status": 429
}

Error Response
429 Too Many Requests:

{
    "path": "/api/v1/musaffa/stocks/get",
    "error": "Too Many Requests",
    "message": "Your monthly limit is over",
    "timestamp": "2022-05-12T15:18:17.943",
    "status": 429
}
Error Code Meaning
400 Bad Request -- Your request is invalid.
401 Unauthorized -- The access token is invalid or has been revoked.
403 Forbidden -- The stock requested is hidden for administrators only.
404 Not Found -- The specified stock could not be found.
405 Method Not Allowed -- You tried to access a stock with an invalid method.
406 Not Acceptable -- You requested a format that isn't json.
429 Too Many Requests -- You're requesting too many stocks! Slow down!
500 Internal Server Error -- We had a problem with our server. Try again later.
503 Service Unavailable -- We're temporarily offline for maintenance. Please try again later.