# EU Payment Institution & EMI Licence Monitor (`automa-flow/eba-psd2-payment-institution-monitor`) Actor

Check EU/EEA payment institutions, EMIs, AISPs and PISPs in the EBA PSD2 Register. Save a baseline, then see what changed in authorisation, payment services and passporting on later runs.

- **URL**: https://apify.com/automa-flow/eba-psd2-payment-institution-monitor.md
- **Developed by:** [Vadim Bezrukov](https://apify.com/automa-flow) (community)
- **Categories:** Business, Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 institution checkeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## EU Payment Institution & EMI Licence Monitor

Verify and monitor EU/EEA payment institutions, electronic money institutions,
AISPs and PISPs. The first run stores a last-successful baseline from the
official EBA PSD2 Register; later runs emit typed authorisation, payment-service
and passporting changes.

This Actor normalises the public EBA Payment Institutions Register. It is not
affiliated with the EBA, does not use EBA branding, and is not legal or
compliance advice. National competent authorities remain responsible for the
underlying information. The EBA register itself does not confer legal status.
Verify legally consequential decisions against EBA and the relevant NCA.

### Check one institution

```json
{
  "mode": "watchlist",
  "monitorKey": "eba-demo",
  "institutions": [
    {
      "registerId": "IE_CBI!C187865"
    }
  ],
  "includeServices": true,
  "includePassporting": true,
  "includeAgents": false,
  "includeBranches": true,
  "changesOnly": false,
  "baselineMode": "emitSnapshot"
}
```

Open the Actor, keep this example and click **Start**. Expect a `BASELINE` row
for Stripe Technology Europe, Limited with current PSD2/EMD2 services and
passporting host countries; every later run of this example writes the current
record again because `changesOnly` is off here (turn it on for a schedule that
should stay quiet). The configured price is **$0.015** for that first
verified institution (`apify-actor-start` + `institution-checked`). No EBA login or
proxy is needed.

Keep the same `monitorKey` on a daily or weekly schedule. Last-good state lives
in the named store `eba-psd2-payment-institution-monitor-state`, so a second
run compares against the first. Unchanged successful checks are still paid; a
quiet run can have an empty Dataset - inspect `CHECKS` and `RUN_SUMMARY`.

### Two modes

| Mode | Use it for | Result |
| --- | --- | --- |
| `watchlist` | Scheduled counterparty monitoring | First run `BASELINE`; later runs typed `CHANGE` rows |
| `lookup` | Agent/API current snapshot | One `SNAPSHOT` per institution; no monitor state |

Resolve each target in this order: `registerId` (EBA EntityCode), exact
`nationalId`, then exact name plus ISO `country`. If a name or national id
matches more than one institution, the Actor returns `AMBIGUOUS_TARGET` with
candidates instead of guessing.

Some EBA EntityCodes occur under multiple institution types with different
authorisation histories. These also return `AMBIGUOUS_TARGET`; the Actor
preserves the previous baseline and does not charge for the ambiguous check.

MCP / agent: ask “Check this EU payment institution’s EBA PSD2 authorisation
and passporting” via
<https://mcp.apify.com?tools=automa-flow/eba-psd2-payment-institution-monitor>.

### Sample output

First watchlist run (abridged). Live Stripe rows include the full service and
passporting arrays.

```json
{
  "record_type": "BASELINE",
  "status": "FOUND",
  "entity_id": "IE_CBI!C187865",
  "name": "Stripe Technology Europe, Limited",
  "institution_type": "PSD_EMI",
  "authorization_status": "Authorised",
  "change_types": ["BASELINE"],
  "source": "eba_psd2_register",
  "scraped_at": "2026-09-13T12:00:00Z"
}
```

With `changesOnly: true`, a later run with no changes emits no Dataset rows. Filter `record_type=CHANGE`
for webhooks.

### Change types

`BASELINE`, `REGISTER_STATUS_CHANGED`, `AUTHORIZATION_WITHDRAWN`,
`AUTHORIZATION_RESTORED`, `PAYMENT_SERVICE_ADDED`, `PAYMENT_SERVICE_REMOVED`,
`PASSPORT_COUNTRY_ADDED`, `PASSPORT_COUNTRY_REMOVED`, `PASSPORT_SERVICE_CHANGED`,
`BRANCH_ADDED`, `BRANCH_REMOVED`, `AGENT_ADDED`, `AGENT_REMOVED`,
`ENTITY_METADATA_CHANGED`, `ENTITY_NO_LONGER_FOUND`, `ENTITY_FOUND_AGAIN`.

`ENTITY_NO_LONGER_FOUND` and `ENTITY_FOUND_AGAIN` report disappearance and
reappearance in the register. They do not imply that an authorisation was
withdrawn or restored. Those authorisation events require register status or
date evidence. Event IDs distinguish observations by monitor key, timestamp
and fingerprint and remain unchanged when a saved delivery is recovered.

Each change row includes `previous`, `current`, source evidence and
`observed_at`. A failed or incomplete register download never overwrites
last-good state and never invents a permission, passport or agent withdrawal.

### Source

Official EBA PSD2 Register golden-copy JSON (zipped), advertised at:

- `https://www.eba.europa.eu/risk-and-data-analysis/data/registers/payment-institutions-register`
- `https://euclid.eba.europa.eu/register/pir/registerDownload`

The Actor downloads the current file once per run and checks all your
institutions against it. Default memory is 1024 MB and the run timeout is 5
minutes. Postal addresses are omitted.
Agent names and national identifiers are omitted. Output is transformed /
normalised from the register and must be labelled as such if republished.
Attribute the European Banking Authority as the source.

### Schedule example

```json
{
  "mode": "watchlist",
  "monitorKey": "payment-partners",
  "institutions": [
    { "registerId": "IE_CBI!C187865" },
    { "name": "UAB Aspora Europe", "country": "LT" }
  ],
  "changesOnly": true,
  "baselineMode": "emitSnapshot"
}
```

Point an Apify webhook at `record_type=CHANGE` Dataset items.

### API example

```javascript
import { ApifyClient } from "apify-client";

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client
  .actor("automa-flow/eba-psd2-payment-institution-monitor")
  .call({
    mode: "lookup",
    institutions: [{ registerId: "IE_CBI!C187865" }],
  });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("automa-flow/eba-psd2-payment-institution-monitor").call(
    run_input={
        "mode": "lookup",
        "institutions": [{"registerId": "IE_CBI!C187865"}],
    },
)
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["status"], item.get("entity_id"), item.get("authorization_status"))
```

### Pricing

Pay per checked institution, plus the run start fee below. Platform usage is
included for paid-plan users. Individual Dataset rows do not add a separate charge.
See the live Pricing tab for current rates.

| Event | When it is charged | Price |
| --- | --- | ---: |
| `apify-actor-start` | Automatic run start at the default 1024 MB (one event). Includes quiet later checks and source failures. | $0.01 |
| `institution-checked` | Once per unique institution successfully evaluated, including unchanged or authoritative NOT\_FOUND | $0.005 |

| Run | Events | Event fees |
| --- | --- | --- |
| 1 institution, first or quiet | start + 1 check | $0.015 |
| 20 unique institutions | start + 20 checks | $0.11 |
| 100 unique institutions | start + 100 checks | $0.51 |

The Store minimum `maxTotalChargeUsd` is **$0.03**. That is higher than the
$0.015 one-institution event bill so a ~20 MB register download can finish
instead of aborting at the event-fee floor.

Not charged as custom events: retries, ambiguous names, source failures, duplicate
targets, individual child services or individual change events. A source-failed
run still pays the platform start fee.

### Limitations

- The EBA central register reproduces NCA submissions and has no legal
  significance. An omitted or incorrectly included firm does not change its
  legal status.
- Authorisation status is the register's ENT\_AUT date-list (the same odd/even
  rule as the Euclid UI), not an independent legal conclusion. That is why
  status-only diffs are labelled `REGISTER_STATUS_CHANGED`.
- Freedom-to-provide-services comes from host countries in `Services`. Branch
  establishment comes from `PSD_BR` child records. The dump does not always
  attach services to a branch row.
- The Console example runs with `changesOnly: false`, so successful checks appear in the Dataset: the first run emits `BASELINE`, later runs a `SNAPSHOT` per
  institution. A `changesOnly` run with no diffs can be empty; `RUN_SUMMARY`
  still reports verified counts.
- Keep `includeServices` / `includePassporting` / `includeBranches` /
  `includeAgents` stable for a monitor key.
- Monitor state is one named KVS record, capped at 8 MiB. Last-good snapshots
  stay even after an id is dropped from the watchlist, so re-adding it diffs
  instead of emitting a fresh `BASELINE`. Passport-heavy EMIs can fill the cap
  well before 500 institutions. If a save would exceed the cap, the run status
  is `STATE_LIMIT`: `CHECKS` and `RUN_SUMMARY` are published, Dataset rows are
  not written, state is not saved, and `institution-checked` is not charged.
  The platform start fee still applies. Split the watchlist
  across `monitorKey`s. `RUN_SUMMARY.state_bytes` warns from 70% of the cap.

### FAQ

**Why is the Dataset empty on the second run?**
`changesOnly` is the default for your own inputs (the Console example turns it
off). Unchanged institutions are recorded in `CHECKS`, not the Dataset. That is
a successful quiet check, not a source failure.

**Does a schedule really compare with yesterday?**
Yes, when `mode` is `watchlist` and `monitorKey` is unchanged. State is stored
under `eba-psd2-payment-institution-monitor-state`, not in the run's temporary
default store.

**Can I watch 500 large EMIs on one key?**
The input allows 500 ids. One 8 MiB record cannot always hold 500
passport-heavy snapshots. Split large EMI lists. A refused save is
`STATE_LIMIT`, not a quiet empty Dataset.

**What does STATE\_LIMIT mean?**
The named monitor record would exceed 8 MiB. Read `CHECKS` and
`RUN_SUMMARY.state_bytes`, then split the watchlist. Last-good state from
earlier runs is left untouched.

**Is this legal advice or an EBA product?**
No. Attribute EBA as the source and verify consequential decisions with the
relevant NCA.

# Actor input Schema

## `mode` (type: `string`):

watchlist compares each institution with last successful state. lookup returns the current snapshot only and does not write monitor state.

## `monitorKey` (type: `string`):

One key per watchlist. The same key reuses last verified state across scheduled runs. lookup ignores stored state. This is a namespace, not a secret.

## `institutions` (type: `array`):

Up to 500 institutions. Resolve in this order: official EBA registerId (EntityCode), exact nationalId, then exact name plus ISO country. Duplicate identifiers are evaluated once. Ambiguous names are returned, not guessed. Passport-heavy EMIs can fill the 8 MiB state cap well before 500 ids — split those watchlists.

## `includeServices` (type: `boolean`):

Official PSD2/EMD2 service codes from the EBA dump.

## `includePassporting` (type: `boolean`):

Host-country freedom-to-provide-services rows from the register dump. Branch establishment is included when includeBranches is true.

## `includeAgents` (type: `boolean`):

Attach agent EntityCodes, host countries and status. Names, addresses and national identifiers of agents are omitted. Leave off unless you need agent churn — large agent lists inflate monitor state.

## `includeBranches` (type: `boolean`):

Attach EEA branch EntityCodes, host countries and status.

## `changesOnly` (type: `boolean`):

When true, later watchlist runs emit CHANGE rows and diagnostics only. Unchanged institutions stay in CHECKS with an empty Dataset. The first run still emits BASELINE. lookup always emits snapshots. The example keeps it off so every run shows the current record.

## `baselineMode` (type: `string`):

emitSnapshot returns each institution's first verified observation, including the Console prefill. storeOnly saves that baseline without Dataset rows — do not use it for the Store default run.

## Actor input object example

```json
{
  "mode": "watchlist",
  "monitorKey": "eba-demo",
  "institutions": [
    {
      "registerId": "IE_CBI!C187865"
    },
    {
      "name": "Stripe Technology Europe, Limited",
      "country": "IE"
    }
  ],
  "includeServices": true,
  "includePassporting": true,
  "includeAgents": false,
  "includeBranches": true,
  "changesOnly": true,
  "baselineMode": "emitSnapshot"
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `changes` (type: `string`):

One row per change type. Filter record\_type=CHANGE for alerts.

## `checks` (type: `string`):

Includes duplicates, invalid entries, unchanged institutions and inputs skipped before source access.

## `runSummary` (type: `string`):

Verification counts, accepted event charges, budget refusals, STATE\_LIMIT, named-store size and recovery status.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "mode": "watchlist",
    "monitorKey": "eba-demo",
    "institutions": [
        {
            "registerId": "IE_CBI!C187865"
        }
    ],
    "includeServices": true,
    "includePassporting": true,
    "includeAgents": false,
    "includeBranches": true,
    "changesOnly": false,
    "baselineMode": "emitSnapshot"
};

// Run the Actor and wait for it to finish
const run = await client.actor("automa-flow/eba-psd2-payment-institution-monitor").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "mode": "watchlist",
    "monitorKey": "eba-demo",
    "institutions": [{ "registerId": "IE_CBI!C187865" }],
    "includeServices": True,
    "includePassporting": True,
    "includeAgents": False,
    "includeBranches": True,
    "changesOnly": False,
    "baselineMode": "emitSnapshot",
}

# Run the Actor and wait for it to finish
run = client.actor("automa-flow/eba-psd2-payment-institution-monitor").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "mode": "watchlist",
  "monitorKey": "eba-demo",
  "institutions": [
    {
      "registerId": "IE_CBI!C187865"
    }
  ],
  "includeServices": true,
  "includePassporting": true,
  "includeAgents": false,
  "includeBranches": true,
  "changesOnly": false,
  "baselineMode": "emitSnapshot"
}' |
apify call automa-flow/eba-psd2-payment-institution-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automa-flow/eba-psd2-payment-institution-monitor"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/yVM8Olmr2nE1zSe0a/builds/f2uuQJego9DRYYVem/openapi.json
