Matches API¶
The Matches API provides AI-powered company-grant matching with a hybrid scoring algorithm. It supports both real-time match calculation and persisted match management with user interaction tracking.
All match endpoints require authentication and are scoped to the current user's tenant.
Scoring Algorithm¶
Matches are scored using a weighted hybrid algorithm:
| Component | Weight | Description |
|---|---|---|
| Semantic similarity | 25% | Embedding cosine similarity (all-mpnet-base-v2) |
| Rule-based criteria | 30% | Country, NACE codes, company size |
| Carbon alignment | 25% | Carbon categories, certifications, taxonomy objectives |
| Collaborative | 10% | Peer interaction signals from similar companies |
| Recency | 10% | Deadline urgency scoring |
Disqualifying rules:
- Country mismatch returns a score of 0
- Company size mismatch (when grant explicitly restricts sizes) returns a score of 0
- Carbon-focused grants receive a 1.2x bonus (capped at 1.0)
Endpoints¶
GET /matches¶
List persisted matches with optional filtering. This is the primary frontend-aligned endpoint for match listing.
Authentication: Required
{
"items": [
{
"id": "d4e5f6a7-b8c9-0123-def0-456789012345",
"company_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"grant_id": "b1c2d3e4-f5a6-7890-bcde-f12345678901",
"score": 0.87,
"rule_score": 0.92,
"semantic_score": 0.81,
"recency_score": 0.95,
"collaborative_score": 0.65,
"carbon_score": 0.88,
"match_reasons": [
"Country match: DE",
"NACE code overlap: M71",
"Carbon category match: renewable_energy",
"ISO_14001 certification recognized"
],
"is_viewed": true,
"is_saved": false,
"is_dismissed": false,
"created_at": "2025-01-15T10:30:00Z",
"grant": {
"id": "b1c2d3e4-f5a6-7890-bcde-f12345678901",
"title": "Green Innovation Fund",
"deadline": "2025-06-30T23:59:59Z",
"is_carbon_focused": true
}
}
],
"total": 42,
"page": 1,
"page_size": 20
}
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
company_id | UUID | -- | Filter by company ID |
status | string | -- | Filter: saved, dismissed, active |
min_score | float | -- | Minimum weighted score (0.0-1.0) |
page | integer | 1 | Page number |
page_size | integer | 20 | Items per page (1-100) |
POST /matches/calculate¶
Trigger match calculation for a company. Calculates matches and persists them to the database.
Authentication: Required
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
company_id | UUID | Yes | Company to calculate matches for |
Synchronous Execution
Currently, match calculation runs synchronously and returns a pseudo task_id. Future versions will support asynchronous Celery-based calculation.
Status Codes:
| Code | Description |
|---|---|
| 200 | Calculation complete |
| 401 | Not authenticated |
| 404 | Company not found or wrong tenant |
GET /matches/stats¶
Get match statistics for a company or entire tenant.
Authentication: Required
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
company_id | UUID | -- | Filter by company ID |
GET /matches/match/{match_id}¶
Get a single match by its ID with full details including the associated grant.
Authentication: Required
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
match_id | UUID | Match ID |
Status Codes:
| Code | Description |
|---|---|
| 200 | Match returned |
| 401 | Not authenticated |
| 404 | Match not found or wrong tenant |
PATCH /matches/match/{match_id}/action¶
Update the status of a match (save, dismiss, or restore).
Authentication: Required
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
action | string | Yes | Action: save, dismiss, or restore |
Action Behavior:
| Action | Effect |
|---|---|
save | Sets is_saved=true, is_dismissed=false |
dismiss | Sets is_dismissed=true, is_saved=false |
restore | Sets both is_saved=false, is_dismissed=false |
Status Codes:
| Code | Description |
|---|---|
| 200 | Action applied, updated match returned |
| 400 | Invalid action value |
| 401 | Not authenticated |
| 404 | Match not found or wrong tenant |
GET /matches/{company_id}¶
Calculate and return real-time matches for a company using the hybrid matching algorithm. Results are not persisted by default.
Authentication: Required
{
"items": [
{
"grant": {
"id": "b1c2d3e4-f5a6-7890-bcde-f12345678901",
"title": "Green Innovation Fund",
"is_carbon_focused": true
},
"score": 0.87,
"rule_score": 0.92,
"semantic_score": 0.81,
"recency_score": 0.95,
"collaborative_score": 0.65,
"carbon_score": 0.88,
"match_reasons": [
"Country match: DE",
"NACE code overlap: M71"
]
}
],
"total": 15,
"company_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
company_id | UUID | Company ID |
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
page | integer | 1 | Page number |
page_size | integer | 20 | Items per page (1-100) |
min_score | float | 0.0 | Minimum score threshold (0-1) |
GET /matches/{company_id}/saved¶
Get persisted matches for a company, including user interaction state.
Authentication: Required
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
company_id | UUID | Company ID |
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
page | integer | 1 | Page number |
page_size | integer | 20 | Items per page (1-100) |
POST /matches/{company_id}/refresh¶
Recalculate matches for a company and optionally persist the results.
Authentication: Required
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
company_id | UUID | Company ID |
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
save_results | boolean | true | Persist results to database |
limit | integer | 20 | Maximum matches to calculate (1-100) |
PATCH /matches/{company_id}/{grant_id}/view¶
Mark a match as viewed.
Authentication: Required
Status Codes:
| Code | Description |
|---|---|
| 204 | Match marked as viewed |
| 404 | Match or company not found |
PATCH /matches/{company_id}/{grant_id}/save¶
Toggle a match's saved state.
Authentication: Required
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
saved | boolean | true | Saved state value |
PATCH /matches/{company_id}/{grant_id}/dismiss¶
Toggle a match's dismissed state.
Authentication: Required
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
dismissed | boolean | true | Dismissed state value |
Match Response Schema¶
MatchResponse (persisted)¶
| Field | Type | Description |
|---|---|---|
id | UUID | Match record ID |
company_id | UUID | Company ID |
grant_id | UUID | Grant ID |
score | float | Weighted total score (0-1) |
rule_score | float | Rule-based component (0-1) |
semantic_score | float | Semantic similarity component (0-1) |
recency_score | float | Recency/urgency component (0-1) |
collaborative_score | float | Collaborative filtering (0-1) |
carbon_score | float | Carbon alignment component (0-1) |
match_reasons | string[] | Human-readable match explanations |
score_breakdown | object | Full score breakdown details |
is_viewed | boolean | Whether user has viewed this match |
is_saved | boolean | Whether user has saved this match |
is_dismissed | boolean | Whether user has dismissed this match |
grant | object | Full grant details (when included) |
created_at | string | ISO 8601 creation timestamp |
updated_at | string | ISO 8601 last update timestamp |
MatchResultResponse (real-time)¶
| Field | Type | Description |
|---|---|---|
grant | object | Full grant details |
score | float | Weighted total score (0-1) |
rule_score | float | Rule-based component (0-1) |
semantic_score | float | Semantic similarity (0-1) |
recency_score | float | Recency/urgency (0-1) |
collaborative_score | float | Collaborative filtering (0-1) |
carbon_score | float | Carbon alignment (0-1) |
match_reasons | string[] | Human-readable match explanations |