Skip to main content
Aggregator connections let Matcher pull transaction data from Open-Finance data aggregators (Pluggy, Belvo). You create a connection with a sealed credential, mint a webhook token bound to it, and the aggregator’s webhooks then drive inbound pulls. This guide covers the full lifecycle.
Credentials (clientId/secret) are inbound-only: they are sealed before persistence and are never returned in a response, a log, or an error. Every response on this surface is secret-free by construction. The tenant is always resolved from the JWT, never from the request body.

Create a connection


curl -X POST "https://api.matcher.example.com/v1/discovery/aggregator-connections" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "vendor": "pluggy",
    "configName": "pluggy-main",
    "baseUrl": "https://api.pluggy.ai",
    "accountRef": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
    "clientId": "...",
    "secret": "..."
  }'
Field values:
  • vendorpluggy or belvo.
  • configName — unique (tenant-scoped) connection identity; a duplicate is a 409. The webhook token-mint endpoint binds a token to this name.
  • baseUrl — vendor API base URL, stored as the connection host.
  • accountRef — opaque vendor account reference (Pluggy itemId, Belvo link id) threaded onto the webhook pull.
  • clientId / secret — aggregator API credential; sealed and never emitted.
A successful create returns 201 with the secret-free connection descriptor:
{
  "vendor": "pluggy",
  "configName": "pluggy-main",
  "baseUrl": "https://api.pluggy.ai",
  "accountRef": "a1b2c3d4-5678-90ab-cdef-1234567890ab"
}

List, get, update, delete


# List (cursor-paginated, secret-free)
curl -X GET "https://api.matcher.example.com/v1/discovery/aggregator-connections?limit=20" \
  -H "Authorization: Bearer $TOKEN"

# Get by opaque id
curl -X GET "https://api.matcher.example.com/v1/discovery/aggregator-connections/{id}" \
  -H "Authorization: Bearer $TOKEN"

Update

Edit an existing connection by id so a mistyped baseUrl is not permanent. The vendor is immutable. The credential is optional: supply both clientId and secret to rotate the sealed credential, or omit both to leave the stored secret intact. Supplying exactly one is a 400.
curl -X PUT "https://api.matcher.example.com/v1/discovery/aggregator-connections/{id}" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "configName": "pluggy-main",
    "baseUrl": "https://api.pluggy.ai",
    "accountRef": "a1b2c3d4-5678-90ab-cdef-1234567890ab"
  }'

Delete

curl -X DELETE "https://api.matcher.example.com/v1/discovery/aggregator-connections/{id}" \
  -H "Authorization: Bearer $TOKEN"
Delete soft-deletes the connection (204), freeing its config name for reuse. A non-aggregator connection id returns 404 on any by-id operation — this surface never confirms the existence of a non-aggregator row.

Test a connection


Run a live connectivity check for an existing connection using its already-sealed credential, addressed by (vendor, configName). No credential is supplied or returned.
curl -X POST "https://api.matcher.example.com/v1/discovery/aggregator-connections/test" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "vendor": "pluggy", "configName": "pluggy-main" }'
{ "vendor": "pluggy", "configName": "pluggy-main", "healthy": true }
A credentials-don’t-work outcome is an expected test result surfaced as "healthy": false with a 200 — not an error. A missing connection is a 404.

Connector types


List the connector types the engine registry has actually registered for this deployment, each tagged with a backend-derived category (database or rest). The list reflects the live registry — only connectors registered at boot appear. It drives the connection form’s type-select.
curl -X GET "https://api.matcher.example.com/v1/discovery/connector-types" \
  -H "Authorization: Bearer $TOKEN"
{
  "types": [
    { "type": "postgres", "category": "database" },
    { "type": "rest-generic", "category": "rest" }
  ]
}
Aggregator-vendor types (Pluggy/Belvo) are excluded here — they are provisioned through the aggregator-connections surface above.

Mint a webhook token


Mint a webhook token bound to an existing aggregator connection. The raw token and its provider-facing webhook URL are returned once — only the token’s SHA-256 hash is stored.
curl -X POST "https://api.matcher.example.com/v1/discovery/webhooks/tokens" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "vendor": "pluggy",
    "connection_config_name": "pluggy-main"
  }'
{
  "token": "<raw-token-shown-once>",
  "webhookUrl": "https://api.matcher.example.com/v1/discovery/webhooks/pluggy/<raw-token>",
  "vendor": "pluggy"
}
Configure the returned webhookUrl in the aggregator’s dashboard. A missing target connection returns 404.

Response codes


StatusMeaning
200Get, list, test, or connector-types returned
201Connection created / token minted
204Connection soft-deleted
400Invalid vendor, partial credential pair, or invalid pagination
401Tenant could not be resolved
404Connection not found (or not an aggregator)
409Connection with that config name already exists