Java |
System.out.println(App.get().request()); |
Groovy |
println App.get().request() |
Scala |
println(App.get.request) |
Kotlin |
println(App.get().request()) |
Clojure |
println (.request (App/get)) |
To perform a request on the Stream Chat API, you need to:
You do so by calling static methods on Stream Model classes.
StreamRequest objects have builder style methods. Some methods require xxxRequestObject instances. All xxxRequestObject classes have builder included, and when there is a corresponding model they have a buildFrom
method.
This can be done either synchronously, calling the request()
method and handling the StreamException exceptions, or asynchronously, calling the requestAsync(Consumer<Response> onSuccess, Consumer<StreamException> onError)
By default the underlying HTTP client tries to get STREAM_KEY
& STREAM_SECRET
environmental variables or get io.getstream.chat.apiKey
& io.getstream.chat.apiSecret
system properties.
You can override this behavior by explicitly passing in the API key and secret and setting a new default client.
var properties = new Properties();
properties.put(DefaultClient.API_KEY_PROP_NAME, "<api-key>");
properties.put(DefaultClient.API_SECRET_PROP_NAME, "<api-secret>");
var client = new DefaultClient(properties);
DefaultClient.setInstance(client);
Synchronous:
try {
Message message = Message.send("team", "sample_channel")
.message(MessageRequestObject.builder().text("Sample message").userId("fakeUserId").build())
.request().getMessage();
} catch (StreamException e) {
// Handle the exception
}
Asynchronous:
Message.send("team", "sample_channel")
.message(MessageRequestObject.builder().text("Sample message").userId("fakeUserId").build())
.requestAsync(
(sendMessageResponse) -> {
Message message = sendMessageResponse.getMessage();
},
(exception) -> {
// Handle the exception
});
Upsert users
Single user
User.upsert()
.user(
UserRequestObject.builder()
.id(userId)
.role("admin")
.additionalField("book", "dune")
.build())
.request();
Batch of users
User.upsert()
.user(
UserRequestObject.builder()
.id(userId1)
.role("admin")
.additionalField("book", "dune")
.build())
.user(
UserRequestObject.builder()
.id(userId2)
.role("user")
.additionalField("book", "1984")
.build())
.user(
UserRequestObject.builder()
.id(userId3)
.role("admin")
.additionalField("book", "Fahrenheit 451")
.build())
.request();
Set user teams
// creates or updates a user from backend to be part of the "red" and "blue" teams
User.upsert()
.user(UserRequestObject.builder().id(id).teams(Arrays.asList("red", "blue")).build())
.request();
Partially update user
Standard
/*
* make partial update call for userID
* it set's user.role to "admin", sets user.field = {'text': 'value'}
* and user.field2.subfield = 'test'.
* NOTE:
* changing role is available only for server-side auth.
* field name should not contain dots or spaces, as dot is used as path separator.
*/
// response will contain user object with updated users info
User.partialUpdate()
.user(
UserPartialUpdateRequestObject.builder()
.id("userId")
.setValue("role", "admin")
.setValue("field", Collections.singletonMap("text", "value"))
.setValue("field2.subfield", "test")
.build())
.request();
// partial update for multiple users
User.partialUpdate()
.user(
UserPartialUpdateRequestObject.builder()
.id("userId")
.setValue("field", "value")
.build())
.user(
UserPartialUpdateRequestObject.builder()
.id("userId2")
.unsetValue("field.value")
.build())
.request();
Change a user role
User.partialUpdate()
.user(
UserPartialUpdateRequestObject.builder()
.id("tommaso")
.setValue("name", "Tommy Doe")
.setValue("role", "admin")
.build())
Update App Settings
Standard
// disable auth checks, allows dev token usage
App.update().disableAuthChecks(true).request();
// re-enable auth checks
App.update().disableAuthChecks(false).request();
// Disallow guests from using queryUsers
App.update().userSearchDisallowedRoles(Arrays.asList("guest")).request();
Disable permissions checks
// disable permission checks
App.update().disablePermissionsChecks(true).request();
// re-enable permission checks
App.update().disablePermissionsChecks(false).request();
Enforce unique usernames in app
App.update().enforceUniqueUsernames("app").request();
Enforce unique usernames in team
App.update().enforceUniqueUsernames("team").request();
Enable teams
App.update().multiTenantEnabled(true).request();
Enable image moderation
App.update().imageModerationEnabled(true).request();
Configure webhooks
// update webhook URLs
App.update()
.webhookURL("https://example.com/webhooks/stream/push") // sets Push webhook address
.beforeMessageSendHookUrl(
"https://example.com/webhooks/stream/before-message-send") // sets Before Message Send
// webhook address
.customActionHandlerUrl(
"https://example.com/webhooks/stream/custom-commands?type={type}") // sets Custom
// Commands webhook
// address
.request();
Configure APN
App.update()
.aPNConfig(
APNConfigRequestObject.builder()
.authKey(Files.readAllBytes(Paths.get("./auth-key.p8")))
.authType(AuthenticationType.TOKEN)
.keyId("key_id")
.bundleId("com.apple.test")
.teamId("team_id")
.notificationTemplate(
"{\"aps\" :{\"alert\":{\"title\":\"{{ sender.name }}\",\"subtitle\":\"New direct message from {{ sender.name }}\",\"body\":\"{{ message.text }}\"},\"badge\":\"{{ unread_count }}\",\"category\":\"NEW_MESSAGE\"}}")
.build())
.request();
Configure APN for development
App.update()
.aPNConfig(
APNConfigRequestObject.builder()
.authKey(Files.readAllBytes(Paths.get("./auth-key.p8")))
.authType(AuthenticationType.TOKEN)
.development(true)
.keyId("key_id")
.bundleId("com.apple.test")
.teamId("team_id")
.notificationTemplate(
"{\"aps\" :{\"alert\":{\"title\":\"{{ sender.name }}\",\"subtitle\":\"New direct message from {{ sender.name }}\",\"body\":\"{{ message.text }}\"},\"badge\":\"{{ unread_count }}\",\"category\":\"NEW_MESSAGE\"}}")
.build())
.request();
Configure Firebase
App.update()
.firebaseConfig(
FirebaseConfigRequestObject.builder()
.serverKey("server_key")
.notificationTemplate(
"{\"message\":{\"notification\":{\"title\":\"New messages\",\"body\":\"You have {{ unread_count }} new message(s) from {{ sender.name }}\"},\"android\":{\"ttl\":\"86400s\",\"notification\":{\"click_action\":\"OPEN_ACTIVITY_1\"}}}}")
.dataTemplate(
"{\"sender\":\"{{ sender.id }}\",\"channel\":{\"type\": \"{{ channel.type }}\",\"id\":\"{{ channel.id }}\"},\"message\":\"{{ message.id }}\"}")
.build())
.request();
Query users
User.list().filterCondition(FilterCondition.in("id", "john", "jack", "jessie")).request();
UserListResponse response =
User.list()
.filterCondition(FilterCondition.in("id", "jessica"))
.filterCondition("last_active", -1)
.filterCondition("presence", true)
.request();
Query banned users
List<User> bannedUsers = User.list()
.filterCondition("banned", true)
.request()
.getUsers();
Query users with teams
User.list()
.filterConditions(
FilterCondition.and(
FilterCondition.eq("name", "Jordan")),
FilterCondition.contains("teams", "red"))));
Get or create channel (type,id)
Standard
Channel.getOrCreate("messaging", "travel")
.data(
ChannelRequestObject.builder()
.additionalField("name", "Awesome channel about traveling")
.createdBy(UserRequestObject.builder().id("myuserid").build())
.build())
.request();
Channel pagination
Channel.getOrCreate(type, id)
.messages(MessagePaginationParameters.builder().limit(20).idLt(lastMessageId).build())
.members(PaginationParameters.builder().limit(20).offset(0).build())
.watchers(PaginationParameters.builder().limit(20).offset(0).build())
.request();
Create a channel with team
Channel.getOrCreate("messaging", "red-general")
.data(ChannelRequestObject.builder().team("red").build())
.request();
Get or create channel (type)
Channel.getOrCreate("messaging")
.data(
ChannelRequestObject.builder()
.member(ChannelMemberRequestObject.builder().userId("thierry").build())
.member(ChannelMemberRequestObject.builder().userId("tommaso").build())
.createdBy(UserRequestObject.builder().id("myuserid").build())
.build())
.request();
Query channels
Query channels
List<Channel> channels =
Channel.list().filterCondition("type", "messaging")
.sort(Sort.builder().field("last_message_at").direction(Direction.DESC).build())
.request().getChannels().stream()
.map(channelResponse -> channelResponse.getChannel())
.collect(Collectors.toList());
for (Channel channel : channels) {
System.out.println(channel.getAdditionalFields().get("name") + ":" + channel.getCId());
}
Pagination
Channel.list().filterCondition("type", "messaging")
.sort(Sort.builder().field("last_message_at").direction(Direction.DESC).build())
.limit(20).offset(10).request();
Query accepted invites
Channel.list().filterCondition("invite", "accepted").userId("u2").request();
Query rejected invites
Channel.list().filterCondition("invite", "rejected").userId("u2").request();
Query muted channels
// retrieve all channels excluding muted ones
Channel.list()
.filterCondition("muted", false)
.filterCondition(FilterCondition.in("members", userId))
.request();
// retrieve all muted channels
Channel.list()
.filterCondition("muted", true)
.filterCondition(FilterCondition.in("members", userId))
.request();
With teams
Channel.list().filterCondition("team", "red-team").request();
Partially update channel
Standard
Map<String, String> channelDetail = new HashMap<>();
channelDetail.put("topic", "Plants and Animals");
channelDetail.put("rating", "pg");
// Here's a channel with some custom field data that might be useful
Channel.getOrCreate(type, id)
.data(
ChannelRequestObject.builder()
.additionalField("source", "user")
.additionalField("source_detail", Collections.singletonMap("user_id", 123))
.additionalField("channel_detail", channelDetail)
.build())
.request();
// let's change the source of this channel
Channel.partialUpdate(type, id).setValue("source", "system").request();
// since it's system generated we no longer need source_detail
Channel.partialUpdate(type, id).unsetValue("source_detail").request();
// and finally update one of the nested fields in the channel_detail
Channel.partialUpdate(type, id).setValue("channel_detail.topic", "Nature").request();
// and maybe we decide we no longer need a rating
Channel.partialUpdate(type, id).unsetValue("channel_detail.rating").request();
Use a different blocklist
Map<String, Object> configOverrides = new HashMap<>();
configOverrides.put("blocklist", "medical_blocklist");
configOverrides.put("blocklist_behavior", "block");
Channel.partialUpdate(type, id).setValue("config_overrides", configOverrides).request();
Disable replies
Channel.partialUpdate(type, id)
.setValue("config_overrides", Collections.singletonMap("replies", false))
.request();
Remove overrides and go back to default settings
Channel.partialUpdate(type, id).setValue("config_overrides", Collections.EMPTY_MAP).request();
Update channel Full update (overwrite)
Channel.update(type, id)
.data(
ChannelRequestObject.builder()
.additionalField("name", "myspecialchannel")
.additionalField("color", "green")
.build())
.message(
MessageRequestObject.builder()
.text("Thierry changed the channel color to green")
.userId("Thierry")
.build())
.request();
Add/remove members
Channel.update(type, id).addMember("thierry").addMember("josh").request();
// Or hiding the history of the channel when adding a new member
Channel.update(type, id).addMember("john").hideHistory(true).request();
// Removing a member
Channel.update(type, id).removeMember("tommaso").request();
Channel.update(type, id)
.addMember("tommaso")
.message(
MessageRequestObject.builder()
.text("Tommaso joined the channel")
.userId("tommaso")
.build())
.request();
Leaving a channel
Channel.update(type, id).removeMember(myUserId).request();
Add/remove moderators
Channel.update(type, id).addModerator("thierry").addModerator("josh").request();
Channel.update(type, id).demoteModerator("tommaso").request();
Inviting users
Channel.update("messaging", "awesome-chat").invite("nick").request();
Accepting an invite
Channel.update("messaging", "awesome-chat")
.acceptInvite(true)
.userId("nick")
.message(MessageRequestObject.builder().text("Nick joined the channel").build())
.request();
Rejecting an invite
Channel.update("messaging", "awesome-chat")
.acceptInvite(false)
.userId("nick")
.request();
Freeze a channel
ChannelRequestObject channelRequestObject = ChannelRequestObject.buildFrom(channel);
channelRequestObject.setFrozen(true);
Channel.update(channel.getType(), channel.getId())
.data(channelRequestObject)
.message(
MessageRequestObject.builder()
.text("Thierry has frozen the channel")
.userId("Thierry")
.build())
.request();
Unfreeze a channel
ChannelRequestObject channelRequestObject = ChannelRequestObject.buildFrom(channel);
channelRequestObject.setFrozen(false);
Channel.update(channel.getType(), channel.getId())
.data(channelRequestObject)
.message(
MessageRequestObject.builder()
.text("Thierry has unfrozen the channel")
.userId("Thierry")
.build())
.request();
Add moderators to a channel
Channel.update("livestream", "fortnite").addModerator("thierry").addModerator("tommaso").request();
Remove moderators from a channel
Channel.update(type, id).demoteModerator("thierry").request();
Enable automatic translation
// enable auto-translation only for this channel
ChannelRequestObject channelRequestObject = ChannelRequestObject.buildFrom(channel);
channelRequestObject.setAutoTranslationEnabled(true);
Channel.update(channel.getType(), channel.getId()).data(channelRequestObject).request();
// ensure all messages are translated in english for this channel
ChannelRequestObject channelRequestObject2 = ChannelRequestObject.buildFrom(channel);
channelRequestObject2.setAutoTranslationEnabled(true);
channelRequestObject2.setAutoTranslationLanguage(Language.EN);
Channel.update(channel.getType(), channel.getId()).data(channelRequestObject2).request();
// auto translate messages for all channels
App.update().autoTranslationEnabled(true).request();
Enable/Disable slow mode
// Enable slow mode and set cooldown to 1s
Channel.update("messaging", "general").cooldown(1).request();
// Increase cooldown to 30s
Channel.update("messaging", "general").cooldown(30).request();
// Disable slow mode
Channel.update("messaging", "general").cooldown(0).request();
Delete channel
Channel.delete(type, id).request();
Delete many channels
var taskId = Channel.deleteMany(List.of("c:1", "c:2"), DeleteStrategy.HARD).request().getTaskId();
Hide channel
// hides the channel until a new message is added there
Channel.hide(type, id).userId(userId).request();
// hides the channel until a new message is added there. This also clears the history for the user
Channel.hide(type, id).clearHistory(true).userId(userId).request();
Show channel
Channel.show(type, id).userId(userId).request();
Truncate channel
Channel.truncate(type, id).request();
Mute channel
// mute channel for a user
Channel.mute().channelCid(cid).userId(userId).request();
// mute a channel for 2 weeks
Channel.mute()
.channelCid(cid)
.userId(userId)
.expiration(TimeUnit.MILLISECONDS.convert(14, TimeUnit.DAYS))
.request();
// mute a channel for 10 seconds
Channel.mute().channelCid(cid).userId(userId).expiration(10000L).request();
// check if a channel is muted for the user
user.getChannelMutes().stream()
.anyMatch(channelMute -> channelMute.getChannel().getCId().equals(channel.getCId()));
Unmute channel
Channel.unmute().channelCid(cid).userId(userId).request();
Query members
Pagination and ordering
// returns up to 100 members ordered by created_at ascending
Channel.queryMembers().type(type).id(id).request();
// returns up to 100 members ordered by created_at descending
Channel.queryMembers()
.type(type)
.id(id)
.sort(Sort.builder().field("created_at").direction(Direction.DESC).build())
.request();
// returns up to 100 members ordered by user_id descending
Channel.queryMembers()
.type(type)
.id(id)
.sort(Sort.builder().field("user_id").direction(Direction.DESC).build())
.request();
// paginate by user_id in descending order
Channel.queryMembers()
.type(type)
.id(id)
.sort(Sort.builder().field("user_id").direction(Direction.DESC).build())
.userIdLt(lastMember.getUserId())
.request();
// paginate by created at in ascending order
Channel.queryMembers()
.type(type)
.id(id)
.sort(Sort.builder().field("created_at").direction(Direction.ASC).build())
.createdAtAfter(lastMember.getCreatedAt())
.request();
// paginate using offset
Channel.queryMembers().type(type).id(id).offset(20);
Few examples
// query members by user.name
Channel.queryMembers().filterCondition("name", "tommaso").request();
// autocomplete members by user name
Channel.queryMembers()
.filterCondition(FilterCondition.autocomplete("name", "tomm"))
.request();
// query member by id
Channel.queryMembers().filterCondition("user_id", "tommaso").request();
// query multiple members by id
Channel.queryMembers()
.filterCondition(
FilterCondition.in("user_id", "tommaso", "thierry"))
.request();
// query channel moderators
Channel.queryMembers().filterCondition("is_moderator", true).request();
// query for banned members in channel
Channel.queryMembers().filterCondition("banned", true).request();
// query members with pending invites
Channel.queryMembers().filterCondition("invite", "pending").request();
// query members who joined the channel directly or accepted an invite
Channel.queryMembers().filterCondition("joined", true).request();
// query members who have rejected invite or have pending invite
Channel.queryMembers().filterCondition("joined", false).request();
// query all the members
Channel.queryMembers().request();
// order results by member created at descending
Channel.queryMembers()
.sort(Sort.builder().field("created_at").direction(Direction.DESC).build())
.request();
// query for user.email (currently the only supported custom field)
Channel.queryMembers().filterCondition("user.email", "[email protected]").request();
Export channels
String taskId =
Channel.export()
.channel(
ChannelExportRequestObject.builder()
.type("livestream")
.id("white_room")
.messagesSince(
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX")
.parse("2020-11-10T09:30:00.000Z"))
.messagesSince(
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX")
.parse("2020-11-10T11:30:00.000Z"))
.build())
.request()
.getTaskId();
Export channels status
ChannelExportStatusResponse response = Channel.exportStatus(taskId).request();
System.out.println(response.getStatus()); // the status for this task
System.out.println(response.getResult()); // the result object, only present if the task is completed
System.out.println(response.getResult().getUrl()); // the link to the JSON export
System.out.println(response.getError()); // if not null the description of the task error
Create channel type
Standard
ChannelType.create()
.name("public")
.permission(
PermissionRequestObject.builder()
.name("Allow reads for all")
.priority(999)
.resources(List.of(ResourceAction.READ_CHANNEL, ResourceAction.CREATE_MESSAGE))
.action(Action.ALLOW)
.build())
.permission(
PermissionRequestObject.builder()
.name("Deny all")
.priority(1)
.resources(List.of(ResourceAction.ALL))
.action(Action.DENY)
.build())
.mutes(false)
.reactions(false)
.request();
With command
ChannelType.create().name("support-channel-type").commands(Arrays.asList("ticket")).request();
List channel types
ChannelType.list().request();
Get channel type
ChannelType.get("public").request();
Update channel type
Update a few elements in channel type
ChannelType.update("public")
.permission(
PermissionRequestObject.builder()
.name("Allow reads for all")
.priority(999)
.resources(Arrays.asList(Resource.READ_CHANNEL, Resource.CREATE_MESSAGE))
.roles(Arrays.asList("*"))
.action(Action.ALLOW)
.build())
.permission(
PermissionRequestObject.builder()
.name("Deny all")
.priority(1)
.resources(Arrays.asList(Resource.ALL))
.roles(Arrays.asList("*"))
.action(Action.DENY)
.build())
.replies(false)
.commands(Arrays.asList("all"))
.request();
Update channel type features
ChannelType.update("public")
.typingEvents(false)
.readEvents(true)
.connectEvents(true)
.search(false)
.reactions(true)
.replies(false)
.mutes(true)
.request();
Update channel type settings
ChannelType.update("public")
.automod(AutoMod.DISABLED)
.messageRetention("7")
.maxMessageLength(140)
.commands(Arrays.asList("ban", "unban"))
.request();
Grant the UseFrozenChannel permission
List<PermissionRequestObject> permissions =
ChannelType.get("messaging").request().getPermissions().stream()
.map(policy -> PermissionRequestObject.buildFrom(policy))
.collect(Collectors.toList());
permissions.add(
PermissionRequestObject.builder()
.name("Admin users can use frozen channels")
.priority(600)
.resources(Arrays.asList(Resource.USE_FROZEN_CHANNEL))
.roles(Arrays.asList("admin"))
.owner(false)
.action(Action.ALLOW)
.build());
ChannelType.update("messaging").permissions(permissions).request();
Set permissions
ChannelType.update("messaging")
.permission(
PermissionRequestObject.builder()
.name("Admin users can perform any action")
.priority(600)
.resources(Arrays.asList(Resource.ALL))
.roles(Arrays.asList("admin"))
.owner(false)
.action(Action.ALLOW)
.build())
.permission(
PermissionRequestObject.builder()
.name("Anonymous users are not allowed")
.priority(500)
.resources(Arrays.asList(Resource.ALL))
.roles(Arrays.asList("anonymous"))
.owner(false)
.action(Action.DENY)
.build())
.permission(
PermissionRequestObject.builder()
.name("Users can modify their own messages")
.priority(400)
.resources(Arrays.asList(Resource.UPDATE_MESSAGE))
.roles(Arrays.asList("user"))
.owner(true)
.action(Action.ALLOW)
.build())
.permission(
PermissionRequestObject.builder()
.name("Users can create channels")
.priority(300)
.resources(Arrays.asList(Resource.CREATE_CHANNEL))
.roles(Arrays.asList("user"))
.owner(false)
.action(Action.ALLOW)
.build())
.permission(
PermissionRequestObject.builder()
.name("Members of a channel can read and send messages")
.priority(200)
.resources(Arrays.asList(Resource.READ_CHANNEL, Resource.CREATE_MESSAGE))
.roles(Arrays.asList("channel_member"))
.owner(false)
.action(Action.ALLOW)
.build())
.permission(
PermissionRequestObject.builder()
.name("Anything not matching the previous list should not be allowed")
.priority(100)
.resources(Arrays.asList(Resource.ALL))
.roles(Arrays.asList("*"))
.owner(false)
.action(Action.DENY)
.build())
.request();
Delete channel type
ChannelType.delete("public").request();
Send new message
Simple example
Message.send(type, id)
.message(
MessageRequestObject.builder()
.text(
"@Josh I told them I was pesca-pescatarian. Which is one who eats solely fish who eat other fish.")
.userId(userId)
.build())
.request();
Complex example
Message.send(type, id)
.message(
MessageRequestObject.builder()
.text(
"@Josh I told them I was pesca-pescatarian. Which is one who eats solely fish who eat other fish.")
.attachment(
AttachmentRequestObject.builder()
.type("image")
.assetURL("https://bit.ly/2K74TaG")
.thumbURL("https://bit.ly/2Uumxti")
.additionalField("myCustomField", 123)
.build())
.mentionedUsers(Arrays.asList(josh.getId()))
.additionalField("anotherCustomField", 234)
.userId(userId)
.build())
.skipPush(true)
.request();
With url enrichment
Message.send(type, id)
.message(
MessageRequestObject.builder()
.text(
"Check this bear out https://imgur.com/r/bears/4zmGbMN")
.userId(userId)
.build())
.request();
Create a thread
Message.send(type, id)
.message(
MessageRequestObject.builder()
.text("Hey, I am replying to a message!")
.parentId(parentId)
.showInChannel(false)
.userId(userId)
.build())
.request();
Quote a message
// Create the initial message
Message.send(type, id)
.message(
MessageRequestObject.builder()
.id("first_message_id")
.text("The initial message")
.userId(userId)
.build())
.request();
// Quote the initial message
Message.send(type, id)
.message(
MessageRequestObject.builder()
.text("This is the first message that quotes another message")
.quotedMessageId("first_message_id")
.userId(userId)
.build())
.request();
Silent message
Message.send(type, id)
.message(
MessageRequestObject.builder()
.text("You completed your trip")
.userId(systemUserId)
.silent(true)
.attachment(
AttachmentRequestObject.builder()
.type("trip")
.additionalField("tripData", tripData)
.build())
.build())
.request();
Get message
Message.get(messageId).request();
Update message
Standard
Message message = Message.get("123").request().getMessage();
MessageRequestObject messageRequestObject = MessageRequestObject.buildFrom(message);
messageRequestObject.setText("the edited version of my text");
Message.update(message.getId()).message(messageRequestObject).request();
Pin and unpin message
// create pinned message
Message message =
Message.send(channelType, channelId)
.message(
MessageRequestObject.builder()
.text("my message")
.pinned(true)
.pinExpires(
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX")
.parse("2077-01-01T00:00:00Z"))
.userId(userId)
.build())
.request()
.getMessage();
// unpin message
MessageRequestObject messageRequestObject = MessageRequestObject.buildFrom(message);
messageRequestObject.setPinned(false);
Message message2 =
Message.update(message.getId()).message(messageRequestObject).request().getMessage();
// pin message for 120 seconds
MessageRequestObject messageRequestObject2 = MessageRequestObject.buildFrom(message2);
messageRequestObject2.setPinned(true);
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.SECOND, 120);
messageRequestObject2.setPinExpires(calendar.getTime());
Message message3 =
Message.update(message2.getId()).message(messageRequestObject2).request().getMessage();
// change message expiration to 2077
MessageRequestObject messageRequestObject3 = MessageRequestObject.buildFrom(message3);
messageRequestObject3.setPinExpires(
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX").parse("2077-01-01T00:00:00Z"));
Message message4 =
Message.update(message3.getId()).message(messageRequestObject3).request().getMessage();
// remove expiration date from pinned message
MessageRequestObject messageRequestObject4 = MessageRequestObject.buildFrom(message4);
messageRequestObject4.setPinExpires(null);
Message.update(message4.getId()).message(messageRequestObject4).request();
Partial update message
Message originalMessage =
Message.send(channelType, channelId)
.message(
MessageRequestObject.builder()
.text("this message is about to be partially updated")
.additionalField("color", "red")
.additionalField("details", Collections.singletonMap("status", "pending"))
.userId(userId)
.build())
.request()
.getMessage();
// partial update message text
Message updated =
Message.partialUpdate(originalMessage.getId())
.setValue("text", "the text was partial updated")
.userId(userId)
.request()
.getMessage();
// unset color property
updated =
Message.partialUpdate(originalMessage.getId())
.unsetValue("color")
.userId(userId)
.request()
.getMessage();
// set nested property
updated =
Message.partialUpdate(originalMessage.getId())
.setValue("details.status", "complete")
.userId(userId)
.request()
.getMessage();
Delete message
Message.delete(messageId).request();
// hard delete the message (works only server-side)
Message.delete(messageId).hard(true).request();
Upload file or image
String pdfFileUrl =
Message.uploadFile("messaging", "general", userId, "application/pdf")
.file(new File("./helloworld.pdf"))
.request()
.getFile();
String pngFileUrl =
Message.uploadImage("messaging", "general", userId, "image/png")
.file(new File("./helloworld.png"))
.request()
.getFile();
Message.send("messaging", "general")
.message(
MessageRequestObject.builder()
.text("Check out what I have uploaded in parallel")
.attachment(
AttachmentRequestObject.builder()
.type("image")
.assetURL(pngFileUrl)
.thumbURL(pngFileUrl)
.build())
.attachment(
AttachmentRequestObject.builder().type("url").assetURL(pdfFileUrl).build())
.userId(userId)
.build())
.request();
Send reaction
Standard
// Add reaction 'love' with custom field
Reaction.send(messageId)
.enforceUnique(false)
.reaction(
ReactionRequestObject.builder()
.type("love")
.additionalField("myCustomField", 123)
.userId(userId)
.build())
.request();
// Add reaction 'like' and replace all other reactions of this user by it
Reaction.send(messageId)
.enforceUnique(true)
.reaction(ReactionRequestObject.builder().type("like").userId(userId).build())
.request();
Clap reaction
// user claps 5 times on a message
Reaction.send(messageId)
.enforceUnique(false)
.reaction(ReactionRequestObject.builder().type("clap").score(5).userId(userId).build())
.request();
// same user claps 20 times more
Reaction.send(messageId)
.enforceUnique(false)
.reaction(ReactionRequestObject.builder().type("clap").score(25).userId(userId).build())
.request();
Delete reaction
Reaction.delete(messageId, "love").request();
Get reactions
// get the first 10 reactions
Reaction.list(messageId).limit(10).request();
// get 3 reactions past the first 10
Reaction.list(messageId).limit(3).offset(10).request();
Get replies
// retrieve the first 20 messages inside the thread
Message.getReplies(parentMessageId).limit(20).request();
// retrieve the 20 more messages before the message with id "42"
Message.getReplies(parentMessageId).limit(20).idLte("42").request();
Search messages
Search by user and text
Message.search()
.filterCondition(FilterCondition.in("members", "john"))
.messageFilterCondition(
FilterCondition.autocomplete("text", "supercalifragilisticexpialidocious"))
.limit(2)
.offset(0)
.request();
Search messages with attachment
// Search by Attachment
Message.search().messageFilterCondition(FilterCondition.exists("attachments")).request();
Flag message
Message.flag(messageId).userId(userId).request();
Mute user
// mute
User.mute().targetId(targetUserId).userId(userId).request();
// mute for 60 minutes
User.mute().targetId(targetUserId).timeout(60).userId(userId).request();
Ban/unban user
Standard
// ban a user for 60 minutes from all channel
User.ban()
.targetUserId("eviluser")
.timeout(60)
.reason("Banned for one hour")
.bannedById(userId)
.request();
// ban a user and their IP address for 24 hours
User.ban()
.targetUserId("eviluser")
.timeout(24 * 60)
.ipBan(true)
.reason("Please come back tomorrow")
.bannedById(userId)
.request();
// ban a user from the livestream:fortnite channel
User.ban()
.targetUserId("eviluser")
.id("livestream:fortnite")
.reason("Profanity is not allowed here")
.bannedById(userId)
.request();
// remove ban from channel
User.unban("eviluser").type("livestream").id("fortnite").request();
// remove global ban
User.unban("eviluser").request();
Shadow ban
// shadow ban a user from all channels
User.ban().targetUserId("eviluser").shadow(true).bannedById(userId).request();
// shadow ban a user from a channel
User.ban().targetUserId("eviluser").type(type).id(id).shadow(true).bannedById(userId).request();
// remove shadow ban from channel
User.unban("eviluser").type(type).id(id).request();
// remove global shadow ban
User.unban("eviluser").request();
Query Banned Users
Standard
// retrieve the list of banned users
User.list().filterCondition("banned", true).limit(10).offset(0).request();
// query for banned members from one channel
User.queryBanned().filterCondition("channel_cid", "livestream:123").request();
With pagination
// get the bans for channel livestream:123 in descending order
List<Ban> bans =
User.queryBanned()
.filterCondition("channel_cid", "livestream:123")
.sort(Sort.builder().field("created_at").direction(Direction.DESC).build())
.request()
.getBans();
// get the next page of bans for the same channel
List<Ban> nextPageBans =
User.queryBanned()
.filterCondition("channel_cid", "livestream:123")
.createdAtBefore(bans.get(bans.size() - 1).getCreatedAt())
.sort(Sort.builder().field("created_at").direction(Direction.DESC).build())
.request()
.getBans();
Create block list
// add a new block list for this app
Blocklist.create().name("no-cakes").words(Arrays.asList("fudge", "cream", "sugar")).request();
// use the block list for all channels of type messaging
ChannelType.update("messaging")
.blocklist("no-cakes")
.blocklistBehavior(BlocklistBehavior.BLOCK)
.request();
List block lists
Blocklist.list().request();
Get block list
Blocklist.get("no-cakes").request();
Update block list
Blocklist.update("no-cakes").words(Arrays.asList("fudge", "cream", "sugar", "vanilla")).request();
Delete block list
Blocklist.delete("no-cakes").request();
Send event
// sends an event to all connected clients on the channel
Event.send(channelType, channelId)
.event(
EventRequestObject.builder()
.type("friendship_request")
.additionalField("text", "Hey there, long time no see!")
.userId(userId)
.build())
.request();
Send user event
Event.sendUserCustom(targetUserId)
.event(
EventUserCustomRequestObject.builder()
.type("friendship_request")
.additionalField("text", "Hey there, long time no see!")
.build())
.request();
Create command
Command.create()
.name("ticket")
.description("Create a support ticket")
.args("[description]")
.setValue("support_commands_set")
.request();
List commands
Command.list().request();
Get command
Command.get("ticket").request();
Update command
Command.update("ticket").description("Create customer support tickets").request();
Delete command
Command.delete("ticket").request();
Check SQS
// set your SQS queue details
App.update()
.sqsKey("yourkey")
.sqsKey("yoursecret")
.sqsUrl("https://sqs.us-east-1.amazonaws.com/123456789012/MyQueue")
.request();
// send a test message
App.checkSqs().request();
Check SNS
// set your SNS topic details
App.update()
.snsKey("yourkey")
.snsKey("yoursecret")
.snsTopicArn("arn:aws:sns:us-east-1:123456789012:my-topic")
.request();
// send a test message
App.checkSns().request();
Create device
Device.create().id("firebase-token").userId(userId).request();
Delete device
Device.delete("firebase-token", userId).request();
List devices
Device.list(targetUserId).request();
Check push
App.checkPush().messageId(messageId).userId(userId).request();
Get rate limits
// 1. Get Rate limits
App.getRateLimits().request();
// 2. Get Rate limits, iOS and Android
App.getRateLimits().ios(true).android(true).request();
// 3. Get Rate limits for specific endpoints
App.getRateLimits().endpoint("QueryChannels").endpoint("SendMessage").request();
Export user
User.export(userId).request();
Deactivate user
User.deactivate(targetUserId).request();
User.deactivate(targetUserId).createdById(userId).markMessagesDeleted(true).request();
Reactivate user
User.reactivate(targetUserId).request();
User.reactivate(targetUserId).restoreMessages(true).name("I am back").createdById(userId).request();
Delete user
Standard
User.delete(targetUserId).markMessagesDeleted(false).request();
Hard delete
User.delete(targetUserId)
.deleteConversationChannels(true)
.markMessagesDeleted(true)
.hardDelete(true)
.request();
Delete many users
var taskId = User.deleteMany(List.of("u1", "u2"))
.deleteUserStrategy(DeleteStrategy.SOFT)
.deleteMessagesStrategy(DeleteStrategy.HARD)
.request().getTaskId();
var taskStatusResponse = TaskStatus.get(taskId).request();
// "completed".equals(taskStatusResponse.status);
Translate message
Message.send(channelType, channelId)
.message(
MessageRequestObject.builder()
.id(messageId)
.text("Hello, I would like to have more information about your product.")
.userId(userId)
.build())
.request();
// returns the message.text translated into French
MessageTranslateResponse response =
Message.translate(messageId).language(Language.FR).request();
System.out.println(response.getMessage().getI18n().get("fr_text"));
// "Bonjour, J'aimerais avoir plus d'informations sur votre produit."
Mark all read
Channel.markAllRead().userId(userId).request();
Mark read
Channel.markRead(channelType, channelId).request();
Delete file
Message.deleteFile(channelType, channelId, url).request();
Delete image
Message.deleteImage(channelType, channelId, url).request();
Flag user
User.flag(targetUserId).userId(userId).request();
Get many messages
Message.getMany(channelType, channelId, Arrays.asList(messageId1, messageId2)).request();
Run message command action
Message.runCommandAction(messageId)
.formData(Collections.singletonMap("image_action", "send"))
.userId(userId)
.request();
Unflag message
Message.unflag(messageId).userId(userId).request();
Unflag user
User.unflag(targetUserId).userId(userId).request();
Create custom permission
Permission.create().id("MyCustomId").name("My custom permission").action("DeleteChannel").request());
Create custom role
Role.create().name("My custom role").request();
Delete custom permission
Permission.delete("MyCustomId").request()
Delete custom role
Role.delete("My custom role").request();
Get custom permission
Permission.get("MyCustomId").request()
List custom permission
Permission.list().request();
List custom roles
Role.list().request();
Update custom permission
Permission.update("MyCustomId", "My custom permission")
.action("DeleteChannel")
.owner(true)
.request());
Get App Settings
App.get().request();
Create guest
User.createGuest()
.user(UserRequestObject.builder().id(guestId).name("Guest user").build())
.request();
Unmute user
User.unmute().singleTargetId(targetUserId).userId(userId).request();
Query message flags
Message.queryFlags().request();
Get task status
var taskId = "123";
var taskStatusResponse = TaskStatus.get(taskId).request();
// {LinkedHashMap@4341} size = 2
// id = "b9843be8-bcf0-484b-af01-726e1d3b82a3"
// status = "completed"
// createdAt = {Date@4339} "Tue Nov 02 17:54:28 CET 2021"
// updatedAt = {Date@4340} "Tue Nov 02 17:54:32 CET 2021"
// rateLimit = {RateLimit@4342} "RateLimit(limit=300, remaining=299, reset=Tue Nov 02 17:55:00 CET 2021)"
// duration = "10.07ms"
Create a file import
// Generate S3 upload URL
var createUrlResponse = Import.createImportUrl("streamchatjava.json").request();
// Now, upload the import file to S3.
//
// Note: if you use OkHttp library this is super tricky because of the library's internals:
// The headers sent to this endpoint must be Content-Type: application/json, instead OkHttp sends
// Content-Type: application/json; charset=utf-8 which wouldn't be wrong in general but
// in this particular case AWS will return a 403 error.
// The only way to overwrite this header is to attach a network interceptor.
var client =
new OkHttpClient.Builder()
.addNetworkInterceptor(
chain -> {
var request =
chain
.request()
.newBuilder()
.removeHeader("Accept-Encoding")
.removeHeader("User-Agent")
.removeHeader("Connection")
.removeHeader("Content-Type")
.addHeader("Content-Type", "application/json")
.build();
return chain.proceed(request);
})
.build();
var request =
new Request.Builder()
.url(createUrlResponse.getUploadUrl())
.put(RequestBody.create(MediaType.parse("application/json"), Files.readString("streamchatjava.json")))
.build();
client.newCall(request).execute();
Import.createImport(createUrlResponse.getPath(), Import.ImportMode.Upsert);
Verify webhook
// signature comes from the HTTP header x-signature
boolean valid = App.verifyWebhook(body, signature)