From 2551a7569989151178e49bf9a7952e002d7c0b0b Mon Sep 17 00:00:00 2001 From: YHorodyskyi <120653542+YHorodyskyi@users.noreply.github.com> Date: Mon, 21 Sep 2026 16:11:52 +0300 Subject: [PATCH 1/2] feat(ai): add AI Usage Members API support (#730) --- src/ai/index.ts | 73 ++++++++++++++++++++++++++++++++++++++++++++ tests/ai/api.test.ts | 59 +++++++++++++++++++++++++++++++++++ 2 files changed, 132 insertions(+) diff --git a/src/ai/index.ts b/src/ai/index.ts index dbdfdc92d..2fce1fba2 100644 --- a/src/ai/index.ts +++ b/src/ai/index.ts @@ -545,6 +545,29 @@ export class Ai extends CrowdinApi { return this.getList(url, options?.limit, options?.offset); } + /** + * @param options optional parameters for the request + * @see https://support.crowdin.com/developer/enterprise/api/v2/#tag/AI/operation/api.ai.usage.members.getMany + */ + listAiOrganizationUsageMembers( + options?: AiModel.ListAiUsageMembersOptions, + ): Promise> { + let url = `${this.url}/ai/usage/members`; + url = this.addQueryParam(url, 'userIds', options?.userIds?.join(',')); + url = this.addQueryParam(url, 'orderBy', options?.orderBy); + return this.getList(url, options?.limit, options?.offset); + } + + /** + * @param memberId user identifier + * @see https://support.crowdin.com/developer/enterprise/api/v2/#tag/AI/operation/api.ai.usage.members.get + */ + getAiOrganizationUsageMember(memberId: number): Promise> { + const url = `${this.url}/ai/usage/members/${memberId}`; + + return this.get(url, this.defaultConfig()); + } + /** * @param aiProviderId ai Provider identifier * @param path raw provider API path after `/gateway/` @@ -1235,6 +1258,32 @@ export class Ai extends CrowdinApi { return this.getList(url, options?.limit, options?.offset); } + /** + * @param userId user identifier + * @param options optional parameters for the request + * @see https://support.crowdin.com/developer/api/v2/#tag/AI/operation/api.ai.usage.members.getMany + */ + listAiUserUsageMembers( + userId: number, + options?: AiModel.ListAiUsageMembersOptions, + ): Promise> { + let url = `${this.url}/users/${userId}/ai/usage/members`; + url = this.addQueryParam(url, 'userIds', options?.userIds?.join(',')); + url = this.addQueryParam(url, 'orderBy', options?.orderBy); + return this.getList(url, options?.limit, options?.offset); + } + + /** + * @param userId user identifier + * @param memberId user identifier + * @see https://support.crowdin.com/developer/api/v2/#tag/AI/operation/api.ai.usage.members.get + */ + getAiUserUsageMember(userId: number, memberId: number): Promise> { + const url = `${this.url}/users/${userId}/ai/usage/members/${memberId}`; + + return this.get(url, this.defaultConfig()); + } + /** * @param userId user identifier * @param aiProviderId ai Provider identifier @@ -1847,6 +1896,30 @@ export namespace AiModel { } /* ai Request Logs Section END */ + /* ai Usage Members Section START */ + export interface AiUsageMember { + user: { + id: number; + username: string; + fullName: string; + avatarUrl: string; + }; + /** in USD; `null` means no limit, `0` means AI usage is blocked for the user */ + dailyCostLimit: number | null; + dailyCostSpent: number; + dailyResetAt: string; + /** in USD; `null` means no limit, `0` means AI usage is blocked for the user */ + monthlyCostLimit: number | null; + monthlyCostSpent: number; + monthlyResetAt: string; + } + + export interface ListAiUsageMembersOptions extends PaginationOptions { + userIds?: number[]; + orderBy?: string; + } + /* ai Usage Members Section END */ + export type Action = 'pre_translate' | 'alignment' | 'qa_check'; export type ProviderType = | 'open_ai' diff --git a/tests/ai/api.test.ts b/tests/ai/api.test.ts index 8c5c6f226..756d3c015 100644 --- a/tests/ai/api.test.ts +++ b/tests/ai/api.test.ts @@ -24,6 +24,7 @@ describe('AI API', () => { const projectId = 123; const jobId = 'test-job'; const eventId = '12312event'; + const memberId = 5; const name = 'name'; const action = 'pre_translate'; @@ -1282,6 +1283,40 @@ describe('AI API', () => { .reply(200, { data: [{ data: { id: 1 } }], pagination: { offset: 0, limit }, + }) + .get('/ai/usage/members', undefined, { + reqheaders: { + Authorization: `Bearer ${api.token}`, + }, + }) + .reply(200, { + data: [{ data: { user: { id: memberId } } }], + pagination: { offset: 0, limit }, + }) + .get(`/ai/usage/members/${memberId}`, undefined, { + reqheaders: { + Authorization: `Bearer ${api.token}`, + }, + }) + .reply(200, { + data: { user: { id: memberId } }, + }) + .get(`/users/${userId}/ai/usage/members`, undefined, { + reqheaders: { + Authorization: `Bearer ${api.token}`, + }, + }) + .reply(200, { + data: [{ data: { user: { id: memberId } } }], + pagination: { offset: 0, limit }, + }) + .get(`/users/${userId}/ai/usage/members/${memberId}`, undefined, { + reqheaders: { + Authorization: `Bearer ${api.token}`, + }, + }) + .reply(200, { + data: { user: { id: memberId } }, }); }); @@ -1888,4 +1923,28 @@ describe('AI API', () => { expect(res.data.length).toBe(1); expect(res.pagination.limit).toBe(limit); }); + + it('List AI Organization Usage Members', async () => { + const res = await api.listAiOrganizationUsageMembers(); + expect(res.data.length).toBe(1); + expect(res.data[0].data.user.id).toBe(memberId); + expect(res.pagination.limit).toBe(limit); + }); + + it('Get AI Organization Usage Member', async () => { + const res = await api.getAiOrganizationUsageMember(memberId); + expect(res.data.user.id).toBe(memberId); + }); + + it('List AI User Usage Members', async () => { + const res = await api.listAiUserUsageMembers(userId); + expect(res.data.length).toBe(1); + expect(res.data[0].data.user.id).toBe(memberId); + expect(res.pagination.limit).toBe(limit); + }); + + it('Get AI User Usage Member', async () => { + const res = await api.getAiUserUsageMember(userId, memberId); + expect(res.data.user.id).toBe(memberId); + }); }); From 0c5dcf0db73335b72a56e0ad26bcb43efd3a3da2 Mon Sep 17 00:00:00 2001 From: andrii-bodnar Date: Mon, 21 Sep 2026 13:14:32 +0000 Subject: [PATCH 2/2] chore: version 1.58.0 [skip ci] --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f5c8b0df6..b3dc56333 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@crowdin/crowdin-api-client", - "version": "1.57.0", + "version": "1.58.0", "description": "JavaScript library for Crowdin API", "main": "out/index.js", "types": "out/index.d.ts",