Skip to content

Commit

Permalink
Support new Membership API and Webhook (#1163)
Browse files Browse the repository at this point in the history
line/line-openapi#86

# Support new Membership API and Webhook

We have implemented and supported new API and Webhook about Membership.

## API to get a list of users who joined the membership

You can obtain a list of user IDs for users who have joined the
membership of your LINE Official Account by calling
`client.getJoinedMembershipUsers(...)`.

Documents:
https://developers.line.biz/en/reference/messaging-api/#get-membership-user-ids

## Membership Webhook 

We have introduced new Webhook events `MembershipEvent` that indicates
that a user has joined, left or renewed a membership of your LINE
Official Account.

Documents:
https://developers.line.biz/en/reference/messaging-api/#membership-event

## For more details
 
For more details, check out the announcement:
https://developers.line.biz/en/news/2025/02/13/membership-api/

Co-authored-by: github-actions <github-actions@github.com>
  • Loading branch information
github-actions[bot] and github-actions authored Feb 13, 2025
1 parent c1718c6 commit 0678d7e
Show file tree
Hide file tree
Showing 14 changed files with 375 additions and 1 deletion.
1 change: 1 addition & 0 deletions lib/messaging-api/.openapi-generator/FILES
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ model/genderDemographicFilter.ts
model/getAggregationUnitNameListResponse.ts
model/getAggregationUnitUsageResponse.ts
model/getFollowersResponse.ts
model/getJoinedMembershipUsersResponse.ts
model/getMembershipSubscriptionResponse.ts
model/getMessageContentTranscodingResponse.ts
model/getWebhookEndpointResponse.ts
Expand Down
58 changes: 58 additions & 0 deletions lib/messaging-api/api/messagingApiClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { ErrorResponse } from "../model/errorResponse.js";
import { GetAggregationUnitNameListResponse } from "../model/getAggregationUnitNameListResponse.js";
import { GetAggregationUnitUsageResponse } from "../model/getAggregationUnitUsageResponse.js";
import { GetFollowersResponse } from "../model/getFollowersResponse.js";
import { GetJoinedMembershipUsersResponse } from "../model/getJoinedMembershipUsersResponse.js";
import { GetMembershipSubscriptionResponse } from "../model/getMembershipSubscriptionResponse.js";
import { GetWebhookEndpointResponse } from "../model/getWebhookEndpointResponse.js";
import { GroupMemberCountResponse } from "../model/groupMemberCountResponse.js";
Expand Down Expand Up @@ -589,6 +590,63 @@ export class MessagingApiClient {
const parsedBody = text ? JSON.parse(text) : null;
return { httpResponse: res, body: parsedBody };
}
/**
* Get a list of user IDs who joined the membership.
* @param membershipId Membership plan ID.
* @param start A continuation token to get next remaining membership user IDs. Returned only when there are remaining user IDs that weren\'t returned in the userIds property in the previous request. The continuation token expires in 24 hours (86,400 seconds).
* @param limit The max number of items to return for this API call. The value is set to 300 by default, but the max acceptable value is 1000.
*
* @see <a href="https://developers.line.biz/en/reference/messaging-api/#get-membership-user-ids"> Documentation</a>
*/
public async getJoinedMembershipUsers(
membershipId: number,
start?: string,
limit?: number,
): Promise<GetJoinedMembershipUsersResponse> {
return (
await this.getJoinedMembershipUsersWithHttpInfo(
membershipId,
start,
limit,
)
).body;
}

/**
* Get a list of user IDs who joined the membership..
* This method includes HttpInfo object to return additional information.
* @param membershipId Membership plan ID.
* @param start A continuation token to get next remaining membership user IDs. Returned only when there are remaining user IDs that weren\'t returned in the userIds property in the previous request. The continuation token expires in 24 hours (86,400 seconds).
* @param limit The max number of items to return for this API call. The value is set to 300 by default, but the max acceptable value is 1000.
*
* @see <a href="https://developers.line.biz/en/reference/messaging-api/#get-membership-user-ids"> Documentation</a>
*/
public async getJoinedMembershipUsersWithHttpInfo(
membershipId: number,
start?: string,
limit?: number,
): Promise<Types.ApiResponseType<GetJoinedMembershipUsersResponse>> {
const queryParams = {
start: start,
limit: limit,
};
Object.keys(queryParams).forEach((key: keyof typeof queryParams) => {
if (queryParams[key] === undefined) {
delete queryParams[key];
}
});

const res = await this.httpClient.get(
"/v2/bot/membership/{membershipId}/users/ids".replace(
"{membershipId}",
String(membershipId),
),
queryParams,
);
const text = await res.text();
const parsedBody = text ? JSON.parse(text) : null;
return { httpResponse: res, body: parsedBody };
}
/**
* Get a list of memberships.
*
Expand Down
29 changes: 29 additions & 0 deletions lib/messaging-api/model/getJoinedMembershipUsersResponse.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* LINE Messaging API
* This document describes LINE Messaging API.
*
* The version of the OpenAPI document: 0.0.1
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/

/**
* List of users who have joined the membership
*/
export type GetJoinedMembershipUsersResponse = {
/**
* A list of user IDs who joined the membership. Users who have not agreed to the bot user agreement, are not following the bot, or are not active will be excluded. If there are no users in the membership, an empty list will be returned.
*
* @see <a href="https://developers.line.biz/en/reference/messaging-api/#get-membership-user-ids">userIds Documentation</a>
*/
userIds: Array<string> /**/;
/**
* A continuation token to get next remaining membership user IDs. Returned only when there are remaining user IDs that weren\'t returned in the userIds property in the previous request. The continuation token expires in 24 hours (86,400 seconds).
*
* @see <a href="https://developers.line.biz/en/reference/messaging-api/#get-membership-user-ids">next Documentation</a>
*/
next?: string /**/;
};
1 change: 1 addition & 0 deletions lib/messaging-api/model/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ export * from "./genderDemographicFilter.js";
export * from "./getAggregationUnitNameListResponse.js";
export * from "./getAggregationUnitUsageResponse.js";
export * from "./getFollowersResponse.js";
export * from "./getJoinedMembershipUsersResponse.js";
export * from "./getMembershipSubscriptionResponse.js";
export * from "./getMessageContentTranscodingResponse.js";
export * from "./getWebhookEndpointResponse.js";
Expand Down
139 changes: 139 additions & 0 deletions lib/messaging-api/tests/api/MessagingApiClientTest.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { ErrorResponse } from "../../model/errorResponse.js";
import { GetAggregationUnitNameListResponse } from "../../model/getAggregationUnitNameListResponse.js";
import { GetAggregationUnitUsageResponse } from "../../model/getAggregationUnitUsageResponse.js";
import { GetFollowersResponse } from "../../model/getFollowersResponse.js";
import { GetJoinedMembershipUsersResponse } from "../../model/getJoinedMembershipUsersResponse.js";
import { GetMembershipSubscriptionResponse } from "../../model/getMembershipSubscriptionResponse.js";
import { GetWebhookEndpointResponse } from "../../model/getWebhookEndpointResponse.js";
import { GroupMemberCountResponse } from "../../model/groupMemberCountResponse.js";
Expand Down Expand Up @@ -1472,6 +1473,144 @@ describe("MessagingApiClient", () => {
server.close();
});

it("getJoinedMembershipUsersWithHttpInfo", async () => {
let requestCount = 0;

const server = createServer((req, res) => {
requestCount++;

equal(req.method, "GET");
const reqUrl = new URL(req.url, "http://localhost/");
equal(
reqUrl.pathname,
"/v2/bot/membership/{membershipId}/users/ids"
.replace("{membershipId}", "0") // number
.replace("{start}", "DUMMY") // string
.replace("{limit}", "0"), // number
);

// Query parameters
const queryParams = new URLSearchParams(reqUrl.search);
equal(
queryParams.get("start"),
String(
// start: string
"DUMMY" as unknown as string, // paramName=start(enum)
),
);
equal(
queryParams.get("limit"),
String(
// limit: number
"DUMMY" as unknown as number, // paramName=limit(enum)
),
);

equal(req.headers["authorization"], `Bearer ${channel_access_token}`);
equal(req.headers["user-agent"], "@line/bot-sdk/1.0.0-test");

res.writeHead(200, { "Content-Type": "application/json" });
res.end(JSON.stringify({}));
});
await new Promise(resolve => {
server.listen(0);
server.on("listening", resolve);
});

const serverAddress = server.address();
if (typeof serverAddress === "string" || serverAddress === null) {
throw new Error("Unexpected server address: " + serverAddress);
}

const client = new MessagingApiClient({
channelAccessToken: channel_access_token,
baseURL: `http://localhost:${String(serverAddress.port)}/`,
});

const res = await client.getJoinedMembershipUsersWithHttpInfo(
// membershipId: number
0, // paramName=membershipId(number or int or long)

// start: string
"DUMMY" as unknown as string, // paramName=start(enum)

// limit: number
"DUMMY" as unknown as number, // paramName=limit(enum)
);

equal(requestCount, 1);
server.close();
});

it("getJoinedMembershipUsers", async () => {
let requestCount = 0;

const server = createServer((req, res) => {
requestCount++;

equal(req.method, "GET");
const reqUrl = new URL(req.url, "http://localhost/");
equal(
reqUrl.pathname,
"/v2/bot/membership/{membershipId}/users/ids"
.replace("{membershipId}", "0") // number
.replace("{start}", "DUMMY") // string
.replace("{limit}", "0"), // number
);

// Query parameters
const queryParams = new URLSearchParams(reqUrl.search);
equal(
queryParams.get("start"),
String(
// start: string
"DUMMY" as unknown as string, // paramName=start(enum)
),
);
equal(
queryParams.get("limit"),
String(
// limit: number
"DUMMY" as unknown as number, // paramName=limit(enum)
),
);

equal(req.headers["authorization"], `Bearer ${channel_access_token}`);
equal(req.headers["user-agent"], "@line/bot-sdk/1.0.0-test");

res.writeHead(200, { "Content-Type": "application/json" });
res.end(JSON.stringify({}));
});
await new Promise(resolve => {
server.listen(0);
server.on("listening", resolve);
});

const serverAddress = server.address();
if (typeof serverAddress === "string" || serverAddress === null) {
throw new Error("Unexpected server address: " + serverAddress);
}

const client = new MessagingApiClient({
channelAccessToken: channel_access_token,
baseURL: `http://localhost:${String(serverAddress.port)}/`,
});

const res = await client.getJoinedMembershipUsers(
// membershipId: number
0, // paramName=membershipId(number or int or long)

// start: string
"DUMMY" as unknown as string, // paramName=start(enum)

// limit: number
"DUMMY" as unknown as number, // paramName=limit(enum)
);

equal(requestCount, 1);
server.close();
});

it("getMembershipListWithHttpInfo", async () => {
let requestCount = 0;

Expand Down
5 changes: 5 additions & 0 deletions lib/webhook/.openapi-generator/FILES
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,17 @@ model/imageMessageContent.ts
model/imageSet.ts
model/joinEvent.ts
model/joinedMembers.ts
model/joinedMembershipContent.ts
model/leaveEvent.ts
model/leftMembers.ts
model/leftMembershipContent.ts
model/linkContent.ts
model/linkThingsContent.ts
model/locationMessageContent.ts
model/memberJoinedEvent.ts
model/memberLeftEvent.ts
model/membershipContent.ts
model/membershipEvent.ts
model/mention.ts
model/mentionee.ts
model/messageContent.ts
Expand All @@ -47,6 +51,7 @@ model/pnpDelivery.ts
model/pnpDeliveryCompletionEvent.ts
model/postbackContent.ts
model/postbackEvent.ts
model/renewedMembershipContent.ts
model/roomSource.ts
model/scenarioResult.ts
model/scenarioResultThingsContent.ts
Expand Down
2 changes: 2 additions & 0 deletions lib/webhook/model/event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { JoinEvent } from "./models.js";
import { LeaveEvent } from "./models.js";
import { MemberJoinedEvent } from "./models.js";
import { MemberLeftEvent } from "./models.js";
import { MembershipEvent } from "./models.js";
import { MessageEvent } from "./models.js";
import { ModuleEvent } from "./models.js";
import { PostbackEvent } from "./models.js";
Expand All @@ -47,6 +48,7 @@ export type Event =
| LeaveEvent // leave
| MemberJoinedEvent // memberJoined
| MemberLeftEvent // memberLeft
| MembershipEvent // membership
| MessageEvent // message
| ModuleEvent // module
| PostbackEvent // postback
Expand Down
23 changes: 23 additions & 0 deletions lib/webhook/model/joinedMembershipContent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* Webhook Type Definition
* Webhook event definition of the LINE Messaging API
*
* The version of the OpenAPI document: 1.0.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/

import { MembershipContent } from "./membershipContent.js";

import { MembershipContentBase } from "./models.js";

export type JoinedMembershipContent = MembershipContentBase & {
type: "joined";
/**
* The ID of the membership that the user joined. This is defined for each membership.
*/
membershipId: number /**/;
};
23 changes: 23 additions & 0 deletions lib/webhook/model/leftMembershipContent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* Webhook Type Definition
* Webhook event definition of the LINE Messaging API
*
* The version of the OpenAPI document: 1.0.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/

import { MembershipContent } from "./membershipContent.js";

import { MembershipContentBase } from "./models.js";

export type LeftMembershipContent = MembershipContentBase & {
type: "left";
/**
* The ID of the membership that the user left. This is defined for each membership.
*/
membershipId: number /**/;
};
30 changes: 30 additions & 0 deletions lib/webhook/model/membershipContent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* Webhook Type Definition
* Webhook event definition of the LINE Messaging API
*
* The version of the OpenAPI document: 1.0.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/

import { JoinedMembershipContent } from "./models.js";
import { LeftMembershipContent } from "./models.js";
import { RenewedMembershipContent } from "./models.js";

export type MembershipContent =
| JoinedMembershipContent // joined
| LeftMembershipContent // left
| RenewedMembershipContent; // renewed

/**
* Content of the membership event.
*/
export type MembershipContentBase = {
/**
* Type of membership event.
*/
type: string /**/;
};
Loading

0 comments on commit 0678d7e

Please sign in to comment.