Skip to content

Commit 0be0a5d

Browse files
authored
Add Fundraising API endpoints SDK with examples (#10)
* Add fundraising yaml * Update client for fund raising * Add initial fund raising examples * Add m&a endpoint * Extend example * Gen types * Lint
1 parent 37b13a8 commit 0be0a5d

File tree

9 files changed

+1069
-2
lines changed

9 files changed

+1069
-2
lines changed

packages/api/src/client/base.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import type {
3030
getProjectRecapResponse,
3131
getAssetListResponse,
3232
getAssetListParameters,
33+
APIResponseWithMetadata,
3334
getPreviewsResponse,
3435
getReportByAssetIDParameters,
3536
getReportByAssetIDResponse,
@@ -38,6 +39,12 @@ import type {
3839
getResearchReportByIdParameters,
3940
getResearchReportByIdResponse,
4041
getResearchReportTagsResponse,
42+
getFundingRoundsParameters,
43+
FundingRound,
44+
getFundingRoundsInvestorsParameters,
45+
Investors,
46+
getAcquisitionDealsParameters,
47+
AcquisitionDeal,
4148
} from "@messari-kit/types";
4249
import { LogLevel, type Logger, makeConsoleLogger, createFilteredLogger, noOpLogger } from "../logging";
4350
import type { PaginatedResult, RequestOptions, ClientEventMap, ClientEventType, ClientEventHandler } from "./types";
@@ -249,6 +256,29 @@ export interface DiligenceAPIInterface {
249256
getDiligenceReport(params: getReportByAssetIDParameters): Promise<getReportByAssetIDResponse>;
250257
}
251258

259+
/**
260+
* Interface for the Fundraising API methods
261+
*/
262+
export interface FundraisingAPIInterface {
263+
/**
264+
* Gets a list of all fundraising rounds based on provided filters
265+
* @param params Query parameters for filtering funding rounds
266+
*/
267+
getFundingRounds(params?: getFundingRoundsParameters): Promise<APIResponseWithMetadata<FundingRound[]>>;
268+
269+
/**
270+
* Gets a list of all investors for a given fundraising round
271+
* @param params Query parameters for filtering investors
272+
*/
273+
getFundingRoundsInvestors(params?: getFundingRoundsInvestorsParameters): Promise<APIResponseWithMetadata<Investors[]>>;
274+
275+
/**
276+
* Gets a list of all acquisition deals based on provided filters
277+
* @param params Query parameters for filtering acquisition deals
278+
*/
279+
getAcquisitionDeals(params?: getAcquisitionDealsParameters): Promise<APIResponseWithMetadata<AcquisitionDeal[]>>;
280+
}
281+
252282
/**
253283
* Abstract base class for the Messari client
254284
* Defines the structure and common functionality that all client implementations must provide

packages/api/src/client/client.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ import {
2121
getResearchReports,
2222
getResearchReportById,
2323
getResearchReportTags,
24+
getFundingRounds,
25+
getFundingRoundsInvestors,
26+
getAcquisitionDeals,
2427
} from "@messari-kit/types";
2528
import type {
2629
createChatCompletionParameters,
@@ -63,6 +66,12 @@ import type {
6366
getResearchReportByIdParameters,
6467
getResearchReportByIdResponse,
6568
getResearchReportTagsResponse,
69+
getFundingRoundsParameters,
70+
getFundingRoundsResponse,
71+
getFundingRoundsInvestorsParameters,
72+
getFundingRoundsInvestorsResponse,
73+
getAcquisitionDealsParameters,
74+
getAcquisitionDealsResponse,
6675
} from "@messari-kit/types";
6776
import type { Agent } from "node:http";
6877
import { pick } from "../utils";
@@ -82,6 +91,7 @@ import type {
8291
import type {
8392
AIInterface,
8493
AssetInterface,
94+
FundraisingAPIInterface,
8595
DiligenceAPIInterface,
8696
IntelInterface,
8797
MarketsInterface,
@@ -774,4 +784,30 @@ export class MessariClient extends MessariClientBase {
774784
});
775785
},
776786
};
787+
788+
public readonly fundraising: FundraisingAPIInterface = {
789+
getFundingRounds: async (params: getFundingRoundsParameters) => {
790+
return this.requestWithMetadata<getFundingRoundsResponse, PaginationMetadata>({
791+
method: getFundingRounds.method,
792+
path: getFundingRounds.path(),
793+
queryParams: pick(params, getFundingRounds.queryParams),
794+
});
795+
},
796+
797+
getFundingRoundsInvestors: async (params: getFundingRoundsInvestorsParameters) => {
798+
return this.requestWithMetadata<getFundingRoundsInvestorsResponse, PaginationMetadata>({
799+
method: getFundingRoundsInvestors.method,
800+
path: getFundingRoundsInvestors.path(),
801+
queryParams: pick(params, getFundingRoundsInvestors.queryParams),
802+
});
803+
},
804+
805+
getAcquisitionDeals: async (params: getAcquisitionDealsParameters) => {
806+
return this.requestWithMetadata<getAcquisitionDealsResponse, PaginationMetadata>({
807+
method: getAcquisitionDeals.method,
808+
path: getAcquisitionDeals.path(),
809+
queryParams: pick(params, getAcquisitionDeals.queryParams),
810+
});
811+
},
812+
};
777813
}

packages/examples/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
"start:marketdata": "tsx src/marketData.ts",
1515
"start:recaps": "tsx src/recaps.ts",
1616
"start:diligence": "tsx src/diligence.ts",
17-
"start:research": "tsx src/research.ts"
17+
"start:research": "tsx src/research.ts",
18+
"start:fundraising": "tsx src/fundraising.ts"
1819
},
1920
"dependencies": {
2021
"@messari-kit/api": "workspace:*",
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
import { MessariClient } from "@messari-kit/api";
2+
import { printTable } from "console-table-printer";
3+
import type { getAcquisitionDealsParameters, getFundingRoundsInvestorsParameters, getFundingRoundsParameters } from "@messari-kit/types";
4+
import dotenv from "dotenv";
5+
6+
// Load environment variables from .env file
7+
dotenv.config();
8+
9+
// Get API key from environment variable
10+
const API_KEY = process.env.MESSARI_API_KEY;
11+
12+
// Check if API key is available
13+
if (!API_KEY) {
14+
console.error("Error: MESSARI_API_KEY environment variable is not set.");
15+
console.error("Please create a .env file with your API key or set it in your environment.");
16+
process.exit(1);
17+
}
18+
19+
// Initialize the Messari client
20+
const client = new MessariClient({
21+
apiKey: API_KEY,
22+
// Optional: Override the base URL if needed
23+
// baseUrl: "https://api.messari.io",
24+
});
25+
26+
async function main() {
27+
const roundMap: Record<string, { entityName: string; type: string }> = {};
28+
// Get the latest funding rounds filter by type and announcedAfter date
29+
try {
30+
const roundsParams: getFundingRoundsParameters = { page: 1, limit: 10, type: "Seed,Series A", announcedAfter: "2025-01-01T00:00:00Z" };
31+
const resp = await client.fundraising.getFundingRounds(roundsParams);
32+
33+
console.log("\n--------------------------------");
34+
console.log("Funding Rounds");
35+
console.log("--------------------------------");
36+
const rounds = resp.data;
37+
if (rounds.length > 0) {
38+
for (const round of rounds) {
39+
if (round.id && round.fundedEntity?.name) {
40+
roundMap[round.id] = { entityName: round.fundedEntity?.name, type: round.type ?? "" };
41+
}
42+
}
43+
const rows = rounds.map((r) => ({
44+
"Id": r.id,
45+
"Date": r.announcementDate,
46+
"Entity": r.fundedEntity?.name,
47+
"Type": r.type,
48+
"Amount Raised": r.amountRaisedUSD,
49+
}));
50+
printTable(rows);
51+
}
52+
} catch (error) {
53+
console.error("Error calling getProjectRecap:", error);
54+
}
55+
56+
// Get the funding round investors
57+
try {
58+
const investorsParams: getFundingRoundsInvestorsParameters = { page: 1, limit: 10, type: "Seed,Series A", announcedAfter: "2025-01-01T00:00:00Z" };
59+
const resp = await client.fundraising.getFundingRoundsInvestors(investorsParams);
60+
61+
console.log("\n--------------------------------");
62+
console.log("Funding Round - Investors");
63+
console.log("--------------------------------");
64+
65+
const rounds = resp.data;
66+
if (rounds.length > 0) {
67+
for (const round of rounds) {
68+
const roundName = roundMap[round.fundingRoundId ?? ""];
69+
if (!roundName) {
70+
continue;
71+
}
72+
73+
console.log("Round Id:", round.fundingRoundId);
74+
console.log(roundName.entityName, "-", roundName.type);
75+
if (round.organizations) {
76+
const rows = round.organizations.map((o) => ({
77+
"Id": o.id,
78+
"Name": o.name,
79+
"Location": o.location,
80+
}));
81+
printTable(rows);
82+
}
83+
}
84+
}
85+
} catch (error) {
86+
console.error("Error calling getProjectRecap:", error);
87+
}
88+
89+
// Get the acquisition deals
90+
try {
91+
const dealsParams: getAcquisitionDealsParameters = { page: 1, limit: 10 };
92+
const resp = await client.fundraising.getAcquisitionDeals(dealsParams);
93+
94+
console.log("\n--------------------------------");
95+
console.log("M&A Deals");
96+
console.log("--------------------------------");
97+
98+
const deals = resp.data;
99+
if (deals.length > 0) {
100+
const rows = deals.map((d) => ({
101+
"Date": d.announcementDate,
102+
"Entity": d.acquiredEntity?.name,
103+
"Acquirer": d.acquiringEntity?.name,
104+
"Type": d.status,
105+
"Amount Raised": d.transactionAmountUSD,
106+
}));
107+
printTable(rows);
108+
}
109+
} catch (error) {
110+
console.error("Error calling getAcquisitionDeals:", error);
111+
}
112+
}
113+
114+
main().catch(console.error);

packages/types/src/index.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,5 +346,50 @@ export const getReportByAssetID = {
346346
path: (p: PathParams) => `/diligence/v1/report/asset/${p.assetId}`
347347
} as const;
348348

349+
350+
export type getFundingRoundsResponse = components['schemas']['FundingRound'][];
351+
export type getFundingRoundsError = components['schemas']['APIError'];
352+
353+
export type getFundingRoundsParameters = { fundedEntityId?: string; investorId?: string; type?: string; stage?: string; raisedAmountMax?: number; raisedAmountMin?: number; isTokenFunded?: boolean; announcedBefore?: string; announcedAfter?: string; page?: number; limit?: number };
354+
355+
356+
export const getFundingRounds = {
357+
method: 'GET' as const,
358+
pathParams: [] as const,
359+
queryParams: ['fundedEntityId', 'investorId', 'type', 'stage', 'raisedAmountMax', 'raisedAmountMin', 'isTokenFunded', 'announcedBefore', 'announcedAfter', 'page', 'limit'] as const,
360+
bodyParams: [] as const,
361+
path: () => '/funding/v1/rounds'
362+
} as const;
363+
364+
365+
export type getFundingRoundsInvestorsResponse = components['schemas']['Investors'][];
366+
export type getFundingRoundsInvestorsError = components['schemas']['APIError'];
367+
368+
export type getFundingRoundsInvestorsParameters = { fundedEntityId?: string; investorId?: string; type?: string; stage?: string; raisedAmountMax?: number; raisedAmountMin?: number; isTokenFunded?: boolean; announcedBefore?: string; announcedAfter?: string; page?: number; limit?: number };
369+
370+
371+
export const getFundingRoundsInvestors = {
372+
method: 'GET' as const,
373+
pathParams: [] as const,
374+
queryParams: ['fundedEntityId', 'investorId', 'type', 'stage', 'raisedAmountMax', 'raisedAmountMin', 'isTokenFunded', 'announcedBefore', 'announcedAfter', 'page', 'limit'] as const,
375+
bodyParams: [] as const,
376+
path: () => '/funding/v1/rounds/investors'
377+
} as const;
378+
379+
380+
export type getAcquisitionDealsResponse = components['schemas']['AcquisitionDeal'][];
381+
export type getAcquisitionDealsError = components['schemas']['APIError'];
382+
383+
export type getAcquisitionDealsParameters = { acquiringEntityId?: string; acquiredEntityId?: string; transactionAmountMin?: number; transactionAmountMax?: number; announcedBefore?: string; announcedAfter?: string; page?: number; limit?: number };
384+
385+
386+
export const getAcquisitionDeals = {
387+
method: 'GET' as const,
388+
pathParams: [] as const,
389+
queryParams: ['acquiringEntityId', 'acquiredEntityId', 'transactionAmountMin', 'transactionAmountMax', 'announcedBefore', 'announcedAfter', 'page', 'limit'] as const,
390+
bodyParams: [] as const,
391+
path: () => '/funding/v1/mergers-and-acquisitions'
392+
} as const;
393+
349394
// Re-export schema types
350395
export * from './schema';

packages/types/src/schema.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ export type APIResponse = components['schemas']['APIResponse'];
1313

1414
export type APIResponseWithMetadata = components['schemas']['APIResponseWithMetadata'];
1515

16+
export type AcquisitionDeal = components['schemas']['AcquisitionDeal'];
17+
18+
export type AcquisitionDealStatus = components['schemas']['AcquisitionDealStatus'];
19+
20+
export type Announcement = components['schemas']['Announcement'];
21+
1622
export type Asset = components['schemas']['Asset'];
1723

1824
export type AssetList = components['schemas']['AssetList'];
@@ -73,6 +79,14 @@ export type ExtractResponse = components['schemas']['ExtractResponse'];
7379

7480
export type ExtractResponseMetadata = components['schemas']['ExtractResponseMetadata'];
7581

82+
export type FundingEntity = components['schemas']['FundingEntity'];
83+
84+
export type FundingRound = components['schemas']['FundingRound'];
85+
86+
export type FundingRoundStage = components['schemas']['FundingRoundStage'];
87+
88+
export type FundingRoundType = components['schemas']['FundingRoundType'];
89+
7690
export type GetAllEventsRequest = components['schemas']['GetAllEventsRequest'];
7791

7892
export type GetEventResponse = components['schemas']['GetEventResponse'];
@@ -85,6 +99,8 @@ export type GroupedEntity = components['schemas']['GroupedEntity'];
8599

86100
export type IntelResponse = components['schemas']['IntelResponse'];
87101

102+
export type Investors = components['schemas']['Investors'];
103+
88104
export type NetworkMetrics = components['schemas']['NetworkMetrics'];
89105

90106
export type NewsAsset = components['schemas']['NewsAsset'];
@@ -93,10 +109,16 @@ export type NewsResponse = components['schemas']['NewsResponse'];
93109

94110
export type OHLCV = components['schemas']['OHLCV'];
95111

112+
export type Organization = components['schemas']['Organization'];
113+
96114
export type PaginationResult = components['schemas']['PaginationResult'];
97115

116+
export type Person = components['schemas']['Person'];
117+
98118
export type PlatformContract = components['schemas']['PlatformContract'];
99119

120+
export type Project = components['schemas']['Project'];
121+
100122
export type ProjectRecapResponse = components['schemas']['ProjectRecapResponse'];
101123

102124
export type PropositionResponse = components['schemas']['PropositionResponse'];

0 commit comments

Comments
 (0)