Shariah-first research, by API
MARBIN's Shariah-first research engine, read-only: the Shariah screen with its ratios and method, purification, zakat, the market reading, entry signals and the long-term model portfolio. Data and methodology, not investment advice; the screen is mechanical, not a fatwa. The API never trades and never holds anyone's broker key. A white-label bank's own systems also run its customers here (the customer and account API, below): machine sign-in, one bank only.
Keys
| Full key | mk_live_… | For your server. Send it as Authorization: Bearer. Every endpoint. |
| Widget key | mk_pub_live_… | Safe in a web page. Screen, purification and zakat only, and only from the websites listed on the key. |
| Sandbox key | mk_sandbox_… | Sample figures for building and testing. Every endpoint; every answer is marked as sample data. |
Each key has its own requests-a-minute limit. Calls are logged by key, endpoint and status, never with the key or the answer. To get a key, write to [email protected].
Endpoints
GET /v1/healthno key
Is the engine running?. Heartbeat, last scan and stocks covered. No key needed.
curl -H "Authorization: Bearer $MARBIN_KEY" \ "https://api.marbin.co.uk/v1/health"
GET /v1/universe
Stocks covered. Every stock the engine follows, with its Shariah status and when it was last checked.
curl -H "Authorization: Bearer $MARBIN_KEY" \ "https://api.marbin.co.uk/v1/universe"
GET /v1/screen/{symbol}widget
Shariah screen for one stock. The verdict with its evidence: business activity, debt and cash against the 24-month average market value, interest income against revenue, the limits used and the method. A key carrying the client's own Shariah limits gets the verdict decided by those limits.
Parameters: symbol
curl -H "Authorization: Bearer $MARBIN_KEY" \ "https://api.marbin.co.uk/v1/screen/AAPL"
GET /v1/screenwidget
Shariah screen for many stocks. Up to 50 symbols a call, in one answer.
Parameters: symbols
curl -H "Authorization: Bearer $MARBIN_KEY" \ "https://api.marbin.co.uk/v1/screen?symbols=AAPL,MSFT,NVDA"
GET /v1/purification/{symbol}widget
Purification. The share of each dividend to give away (the company's interest income as a share of its revenue). Add dividend= to get the amount.
Parameters: symbol, dividend
curl -H "Authorization: Bearer $MARBIN_KEY" \ "https://api.marbin.co.uk/v1/purification/AAPL?dividend=120"
GET /v1/zakatwidget
Zakat on a portfolio. Zakat at 2.5% two common ways: every share at market value (market_value), and each share at its company's own zakatable assets -- cash, short-term investments, receivables and inventory per share from its latest balance sheet, against its price (company_assets; AAOIFI Shariah Standard 35), a quarter of the value where a company's figures are missing (named in proxied). The live nisab (85 g gold, 595 g silver) in the currency asked for. Each holding's Shariah status and zakatable share come back too. quarter_rule (the older flat 25%) is kept for version 1.3's clients.
Parameters: holdings, cash, currency, standard
curl -H "Authorization: Bearer $MARBIN_KEY" \ "https://api.marbin.co.uk/v1/zakat?holdings=AAPL:5000,MSFT:2500&cash=1000"
GET /v1/market
Market reading. Index trends against their 200-day averages, and the VIX fear gauge.
curl -H "Authorization: Bearer $MARBIN_KEY" \ "https://api.marbin.co.uk/v1/market"
GET /v1/signals
Entry signals. Stocks that passed every gate at the last scan, best score first.
curl -H "Authorization: Bearer $MARBIN_KEY" \ "https://api.marbin.co.uk/v1/signals"
GET /v1/model/core
Long-term model portfolio. The holdings MARBIN's rules pick today, with the rules.
curl -H "Authorization: Bearer $MARBIN_KEY" \ "https://api.marbin.co.uk/v1/model/core"
GET /v1/filings/{symbol}
Company filings red flags. US companies: SEC 8-K red flags (bankruptcy, triggering events, delisting, restated results) and insider buying and selling over 90 days, sales after exercising options counted apart. The engine checks its watchlist twice a day; covered=false for a company with no SEC filings. Shown, not acted on.
Parameters: symbol
curl -H "Authorization: Bearer $MARBIN_KEY" \ "https://api.marbin.co.uk/v1/filings/AAPL"
GET /v1/track-record
How MARBIN's forecasts have done. From the forecast ledger: each kind of forecast (the return model, the MARBIN score, analysts' price targets, the risk score) at each horizon, checked against what happened -- rank correlation with the outcome (mean_ic), top-minus-bottom fifth (spread_pct), analysts' hit rates. Past results are no guide to the future.
curl -H "Authorization: Bearer $MARBIN_KEY" \ "https://api.marbin.co.uk/v1/track-record"
GET /v1/history
What the history holds. The dates covered, the stocks, the exchange-rate pairs and every field a stock's daily reading has.
curl -H "Authorization: Bearer $MARBIN_KEY" \ "https://api.marbin.co.uk/v1/history"
GET /v1/history/fields
What every history field means. Each field a stock's daily reading can carry, with its unit, and the fields sent when fields= isn't given.
curl -H "Authorization: Bearer $MARBIN_KEY" \ "https://api.marbin.co.uk/v1/history/fields"
GET /v1/history/{symbol}
One stock's daily readings. The engine's closing reading of a stock on each day: price and technicals, MARBIN score and risk score (with their parts), stop and target, forecast, analysts, the Shariah verdict and ratios, fundamentals, filings red flags and insider selling. fields= picks columns (or all); 30 days by default, up to 400.
Parameters: symbol, from, to, fields
curl -H "Authorization: Bearer $MARBIN_KEY" \ "https://api.marbin.co.uk/v1/history/AAPL?from=2026-10-01&fields=score,risk_score,shariah_passed"
GET /v1/history/day/{date}
Every stock on one day. The whole universe's reading on one day.
Parameters: date
curl -H "Authorization: Bearer $MARBIN_KEY" \ "https://api.marbin.co.uk/v1/history/day/2026-10-02?fields=score,risk_score"
GET /v1/history/market
The market by day. The VIX and each index against its 200-day average.
curl -H "Authorization: Bearer $MARBIN_KEY" \ "https://api.marbin.co.uk/v1/history/market?from=2026-10-01"
GET /v1/fx/{pair}
Exchange rates by day. Daily closing rates, e.g. GBPUSD.
Parameters: pair
curl -H "Authorization: Bearer $MARBIN_KEY" \ "https://api.marbin.co.uk/v1/fx/GBPUSD?from=2026-09-01"
Widget for your website
A zakat and purification calculator in your own page, with a widget key that lists your website:
<div data-marbin-zakat data-key="mk_pub_live_…"></div> <div data-marbin-purify data-key="mk_pub_live_…"></div> <script src="https://api.marbin.co.uk/widget.js" async></script>
Plans
| Trial | 1,000 checks a month (25 assets, once a day) | free |
| Starter | 7,500 checks a month (100 assets, 3 times a day) | £250 a month, in advance; beyond that, £30 per 1,000 checks from prepaid credit |
| Growth | 35,000 checks a month (500 assets, 3 times a day) | £900 a month, in advance; beyond that, £22 per 1,000 checks from prepaid credit |
| Professional | 180,000 checks a month (2,000 assets, 4 times a day) | £2,500 a month, in advance; beyond that, £12 per 1,000 checks from prepaid credit |
| Enterprise | unlimited checks (the whole universe, any rate) | £5,000 a month, in advance |
| Widget | 20,000 checks a month (a website's zakat and purification calculators) | £50 a month, in advance; beyond that, £2.5 per 1,000 checks from prepaid credit |
Plans are paid in advance, month by month, and count checks: one per asset answered -- a
screen of 50 stocks is 50 checks, a zakat sum one per holding, a day's history one per stock; other answers one
each. Every answer says how many it counted (checks). Refused requests never count. Beyond a plan's
monthly checks, each is paid from your prepaid credit at the plan's rate; with no credit left the request is
refused (429) until you top up. Trial and sandbox stop at theirs.
Versions and changes
Everything under /v1 stays compatible: fields and endpoints may be added, never removed or changed
in meaning. A breaking change comes as /v2, announced at least six months before /v1
retires. Every answer carries api_version.
Keys can be rotated: the new key works at once, the old one for the overlap chosen (up to 14 days). The API guide covers keys, every endpoint, errors, rate limits, webhooks (signed notifications to your systems) and the sandbox.
For banks: customers and accounts
A white-label bank's own systems onboard, list, follow and pause its customers, at their own address,
https://bank-api.marbin.co.uk (not this one). Machine sign-in is OAuth 2.0
client credentials: MARBIN gives the bank a client id and secret (only a fingerprint of the secret is kept; it can be
rotated with a 7-day overlap); POST /v1/oauth/token swaps them for a token that lives 15 minutes and
carries only the scopes asked for. A client sees its own bank's customers only -- another bank's are "not found".
Every call needs its scope and the client's bank role, and every call, refused ones too, is in the bank's audit log.
Every POST needs an Idempotency-Key header. Errors are always
{"error": {"code", "message"}, "request_id"}; a method a path doesn't take is
405 method_not_allowed with an Allow header (no CORS: it's for the bank's servers). Wrong
secrets back off the address sending them (429 slow_down with Retry-After); the right
secret from the bank's own address still works. Money figures are after costs, as on the customer's own
page; each account says whether it is live or practice, and the two are never added together. On request, mutual
TLS at the edge in front of the same flow.
curl -u "$CLIENT_ID:$CLIENT_SECRET" -d grant_type=client_credentials -d "scope=customers:read accounts:read" \ "https://bank-api.marbin.co.uk/v1/oauth/token" curl -H "Authorization: Bearer $TOKEN" "https://bank-api.marbin.co.uk/v1/customers?status=approved&limit=50"
Many customers at once: POST /v1/customers/batch, up to 500 a call, one result per customer
(invited, or rejected and why); the invitation emails go out in the background. The bank's staff can do the same
from a CSV file in the partner portal (Customers, Invite in bulk).
Brokers: MARBIN sets which brokers each bank's customers may connect. POST /v1/customers answers them
(brokers: allowed and the bank's default -- only brokers a customer can
connect on the bank's portal today); when none can be connected on the
bank's portal, onboarding is refused with 409 no_broker_allowed. A customer already connected keeps
their broker.
POST /v1/oauth/token
Machine sign-in: an access token. OAuth 2.0 client credentials (RFC 6749 section 4.4). Send the client id and secret MARBIN gave the bank -- HTTP Basic (preferred) or client_id and client_secret in the form -- with grant_type=client_credentials and, optionally, scope (space-separated, at most the client's). The token lives 15 minutes; ask for a new one when it runs out. Errors here are RFC 6749's: {error, error_description}.
GET /v1/customerscustomers:read
The bank's customers. Paged, oldest id first: limit (1-200, default 50) and the next_cursor of the page before. Filters: status, kind (live or practice: the main account's), email, external_id. Removed customers only with status=removed. Scope: customers:read.
POST /v1/customerscustomers:write
Onboard a customer. An invitation in the bank's name, pending until approved: emailed to the customer in the bank's name (powered by MARBIN) unless send_invitation is false, and their email queued for the bank portal's sign-in list (sign_in_access). The customer signs in on the bank's portal with this email, connects their own broker account and makes their choices, then the bank approves them. Record the bank's own customer check (bank_check) and customer number (external_id) here if they're ready. One person, one provider: an email already with MARBIN or another provider is refused (409 already_with_another_provider, never which), and so is a new customer over the bank's customer limit (409 over_customer_limit). Scope: customers:write.
POST /v1/customers/batchcustomers:write
Onboard customers in bulk. Up to 500 customers in one call, each checked as POST /v1/customers checks one and as the partner portal's Invite in bulk checks a line: a bad email or name, the same email or external_id twice in the request, already the bank's customer, already with MARBIN or another provider (never which), over the bank's customer limit. The ready ones are invited at once (pending until approved, their sign-in access queued); their invitation emails go out in the background at about 2 a second (send_invitations: false to leave them to the bank). One result per customer, in the request's order: a rejected one changes nothing; the call answers 200 whatever the mix. A retry with the same Idempotency-Key gets the same answer and invites no one twice. Scope: customers:write.
GET /v1/customers/{customer_id}customers:read
One customer. With their accounts, each live or practice. Scope: customers:read.
POST /v1/customers/{customer_id}/bank-checkcustomers:write
Record the bank's own customer check. Before approval (invited or registered): the reference of the bank's own customer check, who did it and when. Shown to the bank's staff; MARBIN's approval flow is unchanged. Scope: customers:write.
GET /v1/accounts/{account_id}/holdingsaccounts:read
What MARBIN holds in an account. Each holding and the totals after costs, in the account's currency: total_cost = paid + buying costs; gain = value - total_cost; if_sold_today also takes off a sale's estimated costs. The same figures as the customer's own page and app. Scope: accounts:read.
GET /v1/accounts/{account_id}/performanceaccounts:read
How an account has done. Time-weighted returns against funds the customer could hold instead (day, week, month, year to date, since start), and the money made: holdings after buying costs, sales net of selling costs. Past results are no guide to the future. Scope: accounts:read.
POST /v1/accounts/{account_id}/pauseaccounts:pause
Pause an account. No new trades; the stops on its holdings stay. One person is enough: a safety action never waits. Scope: accounts:pause.
POST /v1/accounts/{account_id}/resumeaccounts:pause
Resume a paused account. Only a paused account (never an approval). Dual control -- one approver at MARBIN and one at the bank -- will apply here once it's switched on; today the client's bank role is the guard. Scope: accounts:pause.
Machine-readable
/v1/openapi.json describes every endpoint (OpenAPI 3).