As a commerce aggregator, social profile directory, or engagement network, your public business metadata provides authenticity proof. This playbook helps you format APIs and build FinHero-compliant mappers for thin-file merchant underwriting.
Package verified registration status, review counts, posting intervals, and sentiment scores for SME underwriting.
Create the Javascript mapping script formatting public profiles into standard social variables.
Test the adapter parsing correctness using lint tools and deterministic local test fixtures.
This B2C-oriented schema validates that a business operates consistently. Follower counts are analyzed alongside engagement rates to detect invalid audiences and protect against fraudulent profiles.
How social presence details convert to verification credentials. The process runs locally within the secure FinSys sandboxed execution environment.
Your API doesn't need to match this structure directly. The adapter maps profile outputs into these 8 canonical fields.
| Field Key | Data Type | Constraint / Range | Credit Scoring Interpretation |
|---|---|---|---|
| accountTenureMonths | number | months [0 - 600] | Age of oldest verified public profile. Proxy for merchant business continuity. |
| followerCount | number | count [0 - 100000000] | Aggregate audience size. Checked alongside engagement to verify audience authenticity. |
| engagementRate90d | number | ratio [0.0 - 1.0] | Average interactions per impression. Near-zero values flag bot-boosted accounts. |
| postingConsistency12m | number | ratio [0.0 - 1.0] | Fraction of months with active posting. Distinguishes active companies from dormant profiles. |
| verifiedBusinessAccount | boolean | true / false | Platform verification status. Confirms independent platform business verification. |
| customerRatingAvg | number | rating [0.0 - 5.0] | Average customer review rating. Strong indicator for consumer-facing businesses. |
| negativeSentimentRatio90d | number | ratio [0.0 - 1.0] | Fraction of negative public mentions. Elevated rates signal customer delivery issues. |
| accountFlags24m | number | count [0 - 100] | Count of platform strikes/suspensions. Values ≥2 flag high risk. |
Select a profile preset or customize values in the control panel to see live mapping calculations for public directory outputs.
Complete template files for the Social Media mapping adapter. Implement `fetch` and `extract` methods conformant to the `social-media` category schema.
// manifest.json: Declares entrypoint & outputs metadata
{
"manifestVersion": 1,
"id": "social-media-adapter-v1",
"displayName": "Social Verification Ingestion",
"category": "social-media",
"version": 1,
"produces": [
"accountTenureMonths",
"followerCount",
"engagementRate90d",
"postingConsistency12m",
"verifiedBusinessAccount",
"customerRatingAvg",
"negativeSentimentRatio90d",
"accountFlags24m"
],
"requiredIdentityFields": [],
"implementation": {
"type": "typescript",
"entryPoint": "extract.mjs"
}
}
// extract.mjs: Queries API, transforms metrics to canonical fields
const API_URL = process.env.FAKE_SOCIAL_API_URL ?? "http://fake-social-api:4400";
const API_KEY = process.env.FAKE_SOCIAL_API_KEY ?? "demo-key";
const round4 = (n) => Number(n.toFixed(4));
const ratio = (num, den) => (den > 0 ? round4(num / den) : 0);
const clamp01 = (n) => Math.max(0, Math.min(1, n));
const adapter = {
id: "social-media-adapter-v1",
category: "social-media",
version: 1,
produces: [
"accountTenureMonths",
"followerCount",
"engagementRate90d",
"postingConsistency12m",
"verifiedBusinessAccount",
"customerRatingAvg",
"negativeSentimentRatio90d",
"accountFlags24m"
],
async fetch(identity) {
if (!identity?.ic || !identity?.fullName) {
throw new Error("fake-social-v1: identity.ic and identity.fullName are required");
}
const res = await fetch(`${API_URL}/v1/profiles/lookup`, {
method: "POST",
headers: { "content-type": "application/json", "x-api-key": API_KEY },
body: JSON.stringify({ ic: identity.ic, fullName: identity.fullName })
});
if (!res.ok) {
throw new Error(`fake-social-v1 fetch failed: HTTP ${res.status}`);
}
return res.json();
},
async extract(raw) {
const profile = raw.profile ?? {};
const posting = raw.posting12m ?? {};
const sentiment = raw.sentiment90d ?? {};
return [{
instanceKey: "default",
observedAt: new Date().toISOString(),
values: {
accountTenureMonths: Number(profile.accountAgeMonths ?? 0),
followerCount: Number(profile.followers ?? 0),
engagementRate90d: round4(Number(raw.engagement90d?.engagementRate ?? 0)),
postingConsistency12m: clamp01(ratio(Number(posting.activeMonths ?? 0), 12)),
verifiedBusinessAccount: Boolean(profile.verified),
customerRatingAvg: round4(Number(raw.reviews?.avgRating ?? 0)),
negativeSentimentRatio90d: ratio(
Number(sentiment.negativeMentions ?? 0),
Number(sentiment.totalMentions ?? 0)
),
accountFlags24m: Number(raw.flags24m?.count ?? 0)
}
}];
}
};
export default adapter;
// test.mjs: Offline verification tests
import { runFixtures } from "@finsys/adapter-toolkit";
import adapter from "./extract.mjs";
const fixtures = [
{
name: "aiman-hassan-social",
identity: { ihsId: 1, ic: "850101015432", fullName: "Aiman bin Hassan" },
expected: [
{
instanceKey: "default",
values: {
followerCount: 18500,
verifiedBusinessAccount: true
}
}
]
}
];
const results = await runFixtures(adapter, fixtures);
console.log(results);
if (results.some(r => !r.ok)) {
console.error("โ Social Media verification failed");
process.exit(1);
} else {
console.log("โ
Social Media validation passed!");
}
Validate manifest schemas and test mapping logic locally using the CLI or docker configurations.