Skip to content

Latest commit

 

History

History
1857 lines (1484 loc) · 46.4 KB

DOCS.md

File metadata and controls

1857 lines (1484 loc) · 46.4 KB

Simple test

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))

Usage principles

To perform a request on the Stream Chat API, you need to:

Create a StreamRequest

You do so by calling static methods on Stream Model classes.

Set all information you want in the StreamRequest

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.

Perform the request

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)

Explicitly pass in API key and secret

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);

Simple Example

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
            });

All examples

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)