When to Use
Use this skill when an internal system — a research notebook, a risk engine, an execution algo, a client-facing portal — asks for vendor market data, and the firm must decide whether that specific purpose is inside the scope it actually licensed (Bloomberg B-PIPE, LSEG Real-Time / DACS, ICE Data Services, S&P Capital IQ).
The gate exists because licensing breaches are discovered late and priced retroactively. Under the Nasdaq Global Data Agreement, any use of the Information not already provided for in the Nasdaq Requirements — expressly including derived information, retransmission, redistribution and index calculation — requires prior written approval and payment of the applicable fees (GDA s.4(c)). Nasdaq may audit a Distributor's records, reports and systems, normally no more than once in twelve months (s.7(a)). Where a Final Audit finds underreporting, the amounts plus interest are due within sixty days, and for a good-faith error the Distributor's liability reaches back three years (s.7(e)); underreporting of 10% or more of reported Reportable Units also makes the Distributor liable for Nasdaq's audit, legal and administrative costs (s.7(f)). Other venues and vendors impose their own audit clauses on comparable terms — read yours.
When NOT to Use
- Not a fee calculator. It counts contractual seats, not fee-liable units. Its seat counter cannot produce a vendor invoice or an exchange usage declaration — see the unit-of-count pitfall below.
- Not a replacement for the vendor's entitlement system. Bloomberg EMRS and LSEG DACS enforce permissioning at the feed itself. This gate sits upstream of them and does not remove the need to configure them correctly.
- Not for venue-level entitlement or subscriber classification. Professional
vs non-professional status, per-venue licences and real-time vs delayed tiers
belong to
market-data-entitlement-and-licensing-per-venueandreal-time-vs-delayed-data-entitlement-handling. - Not a legal opinion. It enforces the scope a compliance owner has encoded. Reading the contract and encoding it correctly is still a human job.
Prerequisites
VendorContractSpec:vendor_id,vendor_name,license_tier,allowed_use_cases,is_non_display_allowed,is_redistribution_allowed,max_concurrent_entitlements,current_active_entitlements(default 0),contract_expiration_date(ISO-8601YYYY-MM-DD, orNonefor "not tracked").DataAccessRequest:request_id,vendor_id,requested_by_system,use_case_type,is_external_redistribution,requested_seats(default 1).- A durable store for the returned
VendorUsageAuditReportobjects. The engine's in-memory buffer is bounded and is not the retained audit record.
Workflow
Checks run in this order and short-circuit on the first denial. The order is part
of the contract: it determines which status an auditor sees for a request that
breaches more than one restriction.
- Contract term gate — if
as_of_dateis pastcontract_expiration_date, deny withCONTRACT_EXPIRED. Checked first because a lapsed term withdraws every other permission. A contract registered withcontract_expiration_date=Noneis not gated on expiry; the engine logs a warning once per vendor so the omission is visible rather than silent. - External redistribution gate — deny with
REDISTRIBUTION_LICENSING_VIOLATIONwhen the request is external redistribution and the contract does not permit it. A request counts as redistribution if eitheris_external_redistributionis True oruse_case_type == "EXTERNAL_REDISTRIBUTION"; the two signals can disagree, and this is the breach with the longest back-fee tail, so it fails closed on either one alone. - Non-display gate — if
use_case_type == "NON_DISPLAY_TRADING"andis_non_display_allowedis False, deny withNON_DISPLAY_LICENSING_VIOLATION. Non-display means machine access without a natural person reading a display; it is fee-liable whether the engine runs on a desktop, in a datacenter or in the cloud. - Licensed scope gate — if the normalised
use_case_typeis not inallowed_use_cases, deny withUNAUTHORIZED_USE_CASE_VIOLATION. Unlisted means unlicensed: never widen the list to make a request pass. - Concurrency headroom gate — if
current_active_entitlements + requested_seatswould exceedmax_concurrent_entitlements, deny withCONCURRENCY_CAP_EXCEEDED. A request landing exactly on the cap is approved. - Reserve and record — on approval the seats are reserved against the contract
and a
VendorUsageAuditReportis returned. Denials never mutate contract state. When the consuming system disconnects, callrelease_entitlement(vendor_id, seats).
Full procedure: see
references/workflows.md. Standards reference: seereferences/standards.md. Printable pre-flight checklist: seeassets/checklist.md.
Common Pitfalls
- Approving without ever releasing. Every approval reserves seats permanently
until
release_entitlementreturns them. A gate wired into connection setup but not into teardown drifts into denying compliant requests within hours, and the usual "fix" is to raise the cap above what the contract actually licensed. - Reading the seat counter as a reportable unit count. Nasdaq's non-display unit of count is the greater of (a) the number of Subscribers that can modify the application in real time or (b) the number of Devices (usually servers) that receive and benefit from the Information. A per-request seat counter will understate it. Derive declarations from your infrastructure inventory.
- Assuming "derived" means "unrestricted". Derived Data is information that cannot be reverse-engineered back into Exchange Information or into a recognisable substitute for it. A client-facing chart of vendor quotes, a redistributed index recalculated from them, or a "summary" from which the underlying prices can be recovered is not derived data — it is redistribution, and GDA s.4(c) requires prior written approval and fees before it happens.
- Trusting one of two disagreeing signals. A caller that sets
use_case_type="EXTERNAL_REDISTRIBUTION"but leavesis_external_redistributionFalse is still redistributing. Gate on both. - Placeholder expiry dates. A hard-coded future
contract_expiration_dateauthorises everything until the day it passes and then denies everything at once. Populate it from the executed contract or leave itNoneand track expiry elsewhere. - Running desktop-terminal data through an algo. A research desktop subscription does not carry non-display rights; pointing an automated strategy at it is a licensing breach regardless of how the bytes reached the process.
Verification
- Instantiate
VendorUsageRestrictionEngine. Register a B-PIPE-style contract (is_non_display_allowed=True,is_redistribution_allowed=False,max_concurrent_entitlements=10,current_active_entitlements=2,contract_expiration_date="2027-12-31"). - Submit an internal HFT request (
use_case_type="NON_DISPLAY_TRADING",is_external_redistribution=False) $\implies$APPROVED,active_entitlements_remaining == 7. - Submit a client-portal request with
is_external_redistribution=True$\implies$REDISTRIBUTION_LICENSING_VIOLATION,is_approvedFalse, and the contract'scurrent_active_entitlementsunchanged. - Submit
use_case_type="EXTERNAL_REDISTRIBUTION"withis_external_redistribution=False$\implies$ stillREDISTRIBUTION_LICENSING_VIOLATION. - Evaluate with
as_of_datepast the expiry $\implies$CONTRACT_EXPIRED. - Run
python -m unittest discover -s skills/data-vendor-contractual-usage-restriction-tracking/scripts.