Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Releasing - POC3 #1509

Merged
merged 252 commits into from
Dec 20, 2023
Merged
Changes from 1 commit
Commits
Show all changes
252 commits
Select commit Hold shift + click to select a range
9024111
Last change.
billy-the-fish Jul 28, 2023
891872a
Latest changes.
billy-the-fish Jul 28, 2023
2c1eec1
Update on review.
billy-the-fish Jul 31, 2023
2fbadad
Merge branch 'staging' of github.com:AgoraIO/Doc-Source-Private into …
billy-the-fish Aug 1, 2023
6b83aee
call quality guide.
billy-the-fish Aug 1, 2023
67a19c8
Update prerequisites
billy-the-fish Aug 1, 2023
499aa7a
Filter out the docs without an example.
billy-the-fish Aug 1, 2023
30a291d
Updates on review.
billy-the-fish Aug 1, 2023
e1f9f65
Update API ref.
billy-the-fish Aug 2, 2023
490b763
Update API ref.
billy-the-fish Aug 2, 2023
179a89f
Update docs to match the examples supplied so far.
billy-the-fish Aug 4, 2023
9da1f5e
Add the custom audio, but not published as PR is not accepted yet.
billy-the-fish Aug 5, 2023
9bab009
Last update.
billy-the-fish Aug 5, 2023
7204360
POC3 iOS get-stared changes.
nirm2009 Aug 16, 2023
1826028
POC3 iOS call-quality changes.
nirm2009 Aug 17, 2023
eeef267
Updated doc structure
saudsami Aug 18, 2023
a77a9f3
Update
saudsami Aug 18, 2023
60762a8
Updates
saudsami Aug 19, 2023
eb2cd5b
call quality updates
saudsami Aug 21, 2023
06a8c83
Updates
saudsami Aug 21, 2023
54f5abe
POC3 iOS authentication changes.
nirm2009 Aug 22, 2023
5546c90
POC3 macOS get-started, call-quality, authentication changes.
nirm2009 Aug 23, 2023
e98fc8a
Merge branch 'milestone-19-video-sdk-for-react-web' of github.com:Ago…
billy-the-fish Aug 24, 2023
3c99eea
Merge branch 'milestone-19-video-sdk-for-react-web' of github.com:Ago…
billy-the-fish Aug 24, 2023
04a916a
Start merging all the PRs for POC3
billy-the-fish Aug 24, 2023
3d201ea
Start merging all the PRs for POC3
billy-the-fish Aug 24, 2023
772cc32
Merge branch 'milestone-21-new-get-started-architecture' of github.co…
billy-the-fish Aug 24, 2023
c988e6d
Merge branch 'android-poc3-docs' of github.com:AgoraIO/Doc-Source-Pri…
billy-the-fish Aug 25, 2023
9e0d390
Merge the other projects.
billy-the-fish Aug 25, 2023
397843d
Updates
saudsami Aug 26, 2023
4b27e15
Merge the other projects.
billy-the-fish Aug 28, 2023
fe0ac88
Merge pull request #333 from AgoraIO/android-poc3-docs
billy-the-fish Aug 28, 2023
0b73371
iOS macOS updates to match the latest code.
nirm2009 Aug 28, 2023
8db02ba
Merge branch 'poc3-ios-doc-updates' of https://github.com/AgoraIO/Doc…
nirm2009 Aug 28, 2023
284c207
Updates
saudsami Aug 29, 2023
bca1856
Merge branch 'milestone-21-new-get-started-architecture' of github.co…
billy-the-fish Aug 29, 2023
dc27ddb
Update to GetStarted.
billy-the-fish Aug 29, 2023
b67bb8c
Authentification workflow.
billy-the-fish Aug 29, 2023
c40a3ea
Call quality updates.
billy-the-fish Aug 29, 2023
f92d454
Merge pull request #330 from AgoraIO/poc3-ios-doc-updates
billy-the-fish Aug 29, 2023
0df25b4
call quality doc updates
saudsami Aug 30, 2023
9181d62
Review updates
saudsami Aug 30, 2023
e8def35
Update
saudsami Aug 30, 2023
954e607
Pulled from the milestone branch
saudsami Aug 30, 2023
ae18063
doc structure
saudsami Aug 30, 2023
526016d
Updates
saudsami Aug 31, 2023
143fae3
Merge pull request #344 from AgoraIO/poc3-flutter-docs
billy-the-fish Aug 31, 2023
fb5bd52
reversed changes committed to the wrong branch
saudsami Sep 1, 2023
63e47c3
unity poc3
hussain-khalid Sep 4, 2023
70a25c3
update get started for vsdk poc3 web
Kishan-Dhakan Sep 5, 2023
381fc70
update vsdk secure auth docs
Kishan-Dhakan Sep 5, 2023
8b085d6
get started
billy-the-fish Sep 5, 2023
a624796
Merge branch 'milestone-21-new-get-started-architecture' of github.co…
billy-the-fish Sep 5, 2023
83b587a
Authentication guide.
billy-the-fish Sep 5, 2023
6f6b6b5
update call quality doc
Kishan-Dhakan Sep 5, 2023
afa2016
Call quality
billy-the-fish Sep 5, 2023
7243761
Merge pull request #355 from AgoraIO/Unity-poc3-docs
billy-the-fish Sep 5, 2023
732b4a2
Merge branch 'milestone-21-new-get-started-architecture' of github.co…
billy-the-fish Sep 5, 2023
2d636f9
Windows POC3 Code Doc
Pankajg123 Sep 5, 2023
2803ba5
Updated for call quality
Pankajg123 Sep 6, 2023
757f164
Get started.
billy-the-fish Sep 6, 2023
4ae8719
Call quality.
billy-the-fish Sep 7, 2023
63a7f84
Call quality.
billy-the-fish Sep 7, 2023
d734371
Merge pull request #357 from AgoraIO/vsdk-web-poc3
billy-the-fish Sep 7, 2023
4cf3d27
implement Secure Authentication Server POC3 To DOC
Pankajg123 Sep 12, 2023
4fd1160
Merge pull request #366 from AgoraIO/POC3_Windows_get_started
billy-the-fish Sep 15, 2023
02ca5cc
cloud proxy + additional updates
hussain-khalid Sep 17, 2023
7534f72
media encryption unity
hussain-khalid Sep 17, 2023
8499cc0
android media player updates (#411)
saudsami Sep 19, 2023
87c67da
Update shared/video-sdk/get-started/get-started-sdk/project-implement…
hussain-khalid Sep 19, 2023
118f54c
Update shared/video-sdk/get-started/get-started-sdk/project-implement…
hussain-khalid Sep 19, 2023
5058e63
cloud-proxy updates
hussain-khalid Sep 19, 2023
a727a1f
Merge branch '391-rewrite-the-cloud-proxy-doc-in-poc3-style-hussain' …
hussain-khalid Sep 19, 2023
0633379
Review updates
hussain-khalid Sep 19, 2023
124ce2c
review updates
saudsami Sep 20, 2023
7310f5f
Updates
saudsami Sep 20, 2023
3fa3414
review update
saudsami Sep 20, 2023
e0759f3
update cloud proxy doc
Kishan-Dhakan Sep 20, 2023
76cf88f
Merge pull request #413 from AgoraIO/386-rewrite-the-stream-media-to-…
hussain-khalid Sep 22, 2023
4a195f9
media-player
hussain-khalid Sep 22, 2023
19f2a77
resolve conflicts
Kishan-Dhakan Sep 22, 2023
180a493
Merge branch 'milestone39-rewrite-video-sdk-docs' of https://github.c…
Pankajg123 Sep 23, 2023
354d8b9
audioAndVoiceEffects
hussain-khalid Sep 24, 2023
2c0b90d
Update project-implement/unity.mdx
hussain-khalid Sep 25, 2023
31da08b
Merge pull request #409 from AgoraIO/391-rewrite-the-cloud-proxy-doc-…
billy-the-fish Sep 27, 2023
64aed18
product-workflow
hussain-khalid Oct 2, 2023
16d6497
updated logic in swift join channel to show each of the three methods…
maxxfrazer Oct 2, 2023
92d9e84
removed all spaces after triple ticks, which shouldn't be there
maxxfrazer Oct 2, 2023
a59b760
Merge pull request #499 from AgoraIO/markdown-space-after-dashes
maxxfrazer Oct 2, 2023
78b3e4b
added small description comment to callback handlers, added one for v…
maxxfrazer Oct 2, 2023
70b3b13
Merge pull request #500 from AgoraIO/update-ios-callbacks/milestone39
maxxfrazer Oct 3, 2023
d5dacd0
removed android and flutter separated implementations. added shared f…
maxxfrazer Oct 6, 2023
23f8ff3
removed separate ios and macos implementation, bundled them with andr…
maxxfrazer Oct 6, 2023
25b978b
removed older swift implementations
maxxfrazer Oct 6, 2023
f5aecad
android and flutter using poc3 mdx file for ensure-channel-quality
maxxfrazer Oct 6, 2023
3622624
Geofencing unity
hussain-khalid Oct 7, 2023
b8eb3e1
audio and voice effects updates
hussain-khalid Oct 8, 2023
ad99771
updates
hussain-khalid Oct 8, 2023
fc379a9
Product workflow updates
hussain-khalid Oct 9, 2023
61be253
updated ensure channel quality to include ios and macos.
maxxfrazer Oct 9, 2023
40f64dc
cal quality updates
hussain-khalid Oct 10, 2023
ee10603
added cloud proxy and encrypt media streams poc3 templates
maxxfrazer Oct 10, 2023
6f23902
added geofencing poc3 example for ios and macos
maxxfrazer Oct 10, 2023
a12fe3c
added reactjs to the geofencing example, but it will currently not re…
maxxfrazer Oct 10, 2023
ef9ad1c
Api ref updates + additional updates
hussain-khalid Oct 11, 2023
c9c0e95
virtual background
hussain-khalid Oct 11, 2023
2a82dbf
updates
hussain-khalid Oct 11, 2023
150cbdf
resolved build issues
saudsami Oct 12, 2023
27164f0
POC3 docs in new doc structure
nirm2009 Oct 16, 2023
982a1b2
updated ios to have testing hardware options
maxxfrazer Oct 17, 2023
cc1371e
Merge pull request #668 from AgoraIO/poc3-joint-file-ios
maxxfrazer Oct 17, 2023
cde83b5
update platform added incorrectly fixed
maxxfrazer Oct 17, 2023
fd464b0
updated cloud proxy for ios and macos
maxxfrazer Oct 17, 2023
f97d617
removed duplicated lines
maxxfrazer Oct 17, 2023
14abd01
update ios screensharing code to use the replaykit extension
maxxfrazer Oct 17, 2023
b8ea2f7
update encrypt media, play media and custom audio video to use poc3.m…
maxxfrazer Oct 18, 2023
afa044a
updated virtual background coumentation, including test your implemen…
maxxfrazer Oct 18, 2023
3d541a6
moved platform specific code to enable-audio-publishing code asset file
maxxfrazer Oct 18, 2023
4ad8211
Merge pull request #641 from AgoraIO/poc3-joint-file
maxxfrazer Oct 18, 2023
cd077f7
added device compatibility check for virtual background
maxxfrazer Oct 19, 2023
4eedda2
Merge pull request #677 from AgoraIO/virtual-background-checkdevice/m…
maxxfrazer Oct 19, 2023
2ec3b78
Raw Video Audio Processing iOS POC3 new structure
nirm2009 Oct 18, 2023
d67c5f1
Fix auto-numbering, remove empty blocks from other platforms, remove …
maxxfrazer Oct 19, 2023
792e4fb
added examples of modifying the pixelbuffer and audio buffer
maxxfrazer Oct 19, 2023
ff7060b
added api references for each ios and macos code blocks in cloud-prox…
maxxfrazer Oct 19, 2023
ac93a0a
Merge pull request #678 from AgoraIO/add-references
maxxfrazer Oct 19, 2023
ece945e
multi-channel live streaming
hussain-khalid Oct 19, 2023
b73a807
updates
hussain-khalid Oct 20, 2023
0bf4faf
Merge pull request #676 from AgoraIO/poc3-joint-file-ios
maxxfrazer Oct 20, 2023
7e7f15d
added spatial audio for ios and macos poc3 style-y
maxxfrazer Oct 23, 2023
8bbd486
added api reference links for custom-video-and-audio, geofencing and …
maxxfrazer Oct 23, 2023
0c0d1b8
Merge pull request #684 from AgoraIO/spatial-audio-ios
maxxfrazer Oct 24, 2023
29d2462
Merge pull request #685 from AgoraIO/ios-api-refs-customvideoaudio-ge…
maxxfrazer Oct 24, 2023
bbcffa9
622 changes.
nirm2009 Oct 25, 2023
8ea10b3
Merge pull request #646 from AgoraIO/607-rewrite-the-geofencing-doc-i…
hussain-khalid Oct 25, 2023
5886ec2
Merge pull request #679 from AgoraIO/627-rewrite-the-live-streaming-o…
hussain-khalid Oct 25, 2023
2c994bd
Merge pull request #441 from AgoraIO/396-rewrite-the-audio-and-voice-…
hussain-khalid Oct 25, 2023
ad91191
Merge pull request #655 from AgoraIO/398-rewrite-the-virtual-backgrou…
hussain-khalid Oct 25, 2023
dc87dcf
Merge branch 'milestone39-rewrite-video-sdk-docs' into 386-rewrite-th…
hussain-khalid Oct 25, 2023
5691706
added code blocks for joining and leaving secondary channel, added co…
maxxfrazer Oct 26, 2023
1d7c2cf
updated all ios links to use engine api ref constant if required. add…
maxxfrazer Oct 27, 2023
7cbb4ec
Merge pull request #689 from AgoraIO/622-rewrite-the-live-streaming-o…
maxxfrazer Oct 27, 2023
18e5080
Merge pull request #439 from AgoraIO/386-rewrite-the-stream-media-to-…
hussain-khalid Oct 28, 2023
fb9aab6
Merge branch 'milestone39-rewrite-video-sdk-docs' into 393-rewrite-th…
hussain-khalid Oct 28, 2023
e5becb0
Merge pull request #654 from AgoraIO/393-rewrite-the-screen-share-vol…
hussain-khalid Oct 28, 2023
e9d97a1
merge conflicts
Kishan-Dhakan Nov 1, 2023
d3e7b76
refactor web get started
Kishan-Dhakan Nov 1, 2023
89ff6a7
added screensharing example code in poc3 for macos
maxxfrazer Nov 2, 2023
90576eb
update macos screenshare api reference links to open in new tab
maxxfrazer Nov 2, 2023
c459c86
update web cloud proxy doc (#434)
Kishan-Dhakan Nov 3, 2023
67fcb6a
New poc3 structure for unity (#705)
hussain-khalid Nov 8, 2023
948e91c
added display media section to play-media story
maxxfrazer Nov 7, 2023
b7e4acd
Update shared/video-sdk/develop/play-media/project-implementation/poc…
maxxfrazer Nov 8, 2023
5a6b14a
Update shared/video-sdk/develop/play-media/project-implementation/poc…
maxxfrazer Nov 8, 2023
352679d
fix geofencing and spatial audio layouts
maxxfrazer Nov 8, 2023
dcbcc70
Merge pull request #717 from AgoraIO/play-media-display-media/milesto…
maxxfrazer Nov 8, 2023
0cd9279
Merge branch 'milestone39-rewrite-video-sdk-docs' into macos-screensh…
maxxfrazer Nov 8, 2023
0a6d9b2
Merge pull request #709 from AgoraIO/macos-screenshare/milestone39-re…
maxxfrazer Nov 8, 2023
1b52001
updates
hussain-khalid Nov 8, 2023
4d3f922
Merge branch 'milestone39-rewrite-video-sdk-docs' into New-poc3-struc…
hussain-khalid Nov 8, 2023
56b31e2
align ios, macos, and unity in product-workflow doc
maxxfrazer Nov 9, 2023
7a2f71b
Merge pull request #720 from AgoraIO/ios-unity-align/New-poc3-structu…
hussain-khalid Nov 9, 2023
70a3593
Merge pull request #719 from AgoraIO/New-poc3-structure-unity-2
hussain-khalid Nov 14, 2023
6a0b154
Pulled from staging
saudsami Nov 14, 2023
e58ae64
get started
hussain-khalid Nov 15, 2023
3ae5840
updates
hussain-khalid Nov 15, 2023
480fdd7
updates
hussain-khalid Nov 16, 2023
e55ac0d
updates
hussain-khalid Nov 16, 2023
9f2d54a
updates
hussain-khalid Nov 16, 2023
8200996
updated terminal to sh on code block
maxxfrazer Nov 16, 2023
69ca7fa
added POST request example for all, and removed GET for iOS/macOS (#732)
maxxfrazer Nov 16, 2023
299b2d3
added api ref links to get started guide for ios macos. added permiss…
maxxfrazer Nov 16, 2023
0cc5b74
pulled from the milestone
saudsami Nov 16, 2023
0b7aa7f
Merge pull request #729 from AgoraIO/get-started-reactjs
hussain-khalid Nov 17, 2023
0309848
pulled from staging
saudsami Nov 18, 2023
de5388c
update
saudsami Nov 18, 2023
4f6ff28
Merge branch 'milestone39-rewrite-video-sdk-docs' of https://github.c…
Kishan-Dhakan Nov 20, 2023
f8fbd28
fix merge conflicts, fix unrendering sections in multiple platforms
Kishan-Dhakan Nov 20, 2023
8861824
add auth workflow poc3
Kishan-Dhakan Nov 20, 2023
673cadb
add cloud proxy
Kishan-Dhakan Nov 20, 2023
66d1832
add more apps
Kishan-Dhakan Nov 21, 2023
fa0a86e
android updates for quickstart, authentication and call quality (#736)
saudsami Nov 21, 2023
8b1be70
Poc3 android code insertion (#745)
saudsami Nov 21, 2023
3648dbd
Pulled from the milestone
saudsami Nov 21, 2023
b27d921
Update
saudsami Nov 21, 2023
3f7be84
get-started numbering fix
saudsami Nov 22, 2023
be999e0
geofencing + cloud proxy (#735)
hussain-khalid Nov 22, 2023
c84993d
resolved merge conflicts
saudsami Nov 22, 2023
5a27a17
update play-media to include macos (#749)
maxxfrazer Nov 23, 2023
503d668
Audio and voice effects + product workflow for reactjs (#746)
hussain-khalid Nov 23, 2023
841b629
updates (#741)
hussain-khalid Nov 23, 2023
427f501
Update
saudsami Nov 23, 2023
a788c08
audio-voice-effects iOS + macOS (#753)
maxxfrazer Nov 23, 2023
4a284a4
added ains code for ios and macos (#754)
maxxfrazer Nov 24, 2023
a0f89ad
multichannel streaming and custom media (#755)
hussain-khalid Nov 24, 2023
b657f2b
Call quality reactjs poc3 (#756)
hussain-khalid Nov 24, 2023
6633d76
add call quality doc
Kishan-Dhakan Nov 24, 2023
c8b311a
Authentication workflow + ai denoiser for reactjs (#761)
hussain-khalid Nov 25, 2023
d9ad8ef
milestone39 review updates and improvements (#762)
saudsami Nov 25, 2023
4df1221
spatial audio + media encryption (#763)
hussain-khalid Nov 26, 2023
b8dc3d4
add product workflow doc
Kishan-Dhakan Nov 27, 2023
bade24f
add spatial audio docs
Kishan-Dhakan Nov 27, 2023
82c2f68
add denoiser docs
Kishan-Dhakan Nov 27, 2023
57690dc
add custom av docs
Kishan-Dhakan Nov 27, 2023
fb651d7
resolve conflicts
Kishan-Dhakan Nov 27, 2023
e16a093
resolve conflicts
Kishan-Dhakan Nov 27, 2023
433faa1
updates
saudsami Nov 27, 2023
258b7ed
updated macos for raw video and custom audio-video (#767)
maxxfrazer Nov 27, 2023
b600c6f
Merge branch 'milestone39-rewrite-video-sdk-docs' of https://github.c…
saudsami Nov 27, 2023
a9b420a
custom-audio-video macos updates
saudsami Nov 27, 2023
ba8564f
pulled from milestone
saudsami Nov 27, 2023
89f5940
Voice calling updates/milestone39 rewrite video sdk docs (#764)
saudsami Nov 27, 2023
0ce8032
Call quality max suggestions (#760)
hussain-khalid Nov 27, 2023
9567501
Multiple Channels Updates macOS (#768)
maxxfrazer Nov 27, 2023
728ebe8
Project Test Sections (#759)
maxxfrazer Nov 28, 2023
bdd06f5
Update
saudsami Nov 28, 2023
4961f63
poc3.mdx header updates (#772)
saudsami Nov 28, 2023
ff3fd26
Update
saudsami Nov 28, 2023
d1cd513
update
saudsami Nov 28, 2023
0214b08
Update
saudsami Nov 28, 2023
654bf27
Updates after final checking (#769)
hussain-khalid Nov 29, 2023
b8011fd
Docs organization changes (#771)
atovpeko Nov 29, 2023
053c43b
Review updates/milestone39-poc3 (#779)
saudsami Nov 30, 2023
f3634db
Move api ref web (#775)
Kishan-Dhakan Nov 30, 2023
88b3704
Release notes for ReactJS (#778)
atovpeko Nov 30, 2023
a1a9570
Multi-channel updates + Custom media source + Raw audio and video (#774)
hussain-khalid Nov 30, 2023
fb8d927
pulled from staging
saudsami Nov 30, 2023
29718e9
update
saudsami Dec 1, 2023
b4ae873
Update
saudsami Dec 1, 2023
cd9aa61
Live stream over multiple channela doc (#780)
Kishan-Dhakan Dec 1, 2023
ee3c1fd
Encryption Handler iOS (#783)
maxxfrazer Dec 2, 2023
5edabfc
updates for voice calling (#787)
hussain-khalid Dec 3, 2023
afdd394
Add error codes doc/milestone39 (#788)
saudsami Dec 3, 2023
96f2173
updates
saudsami Dec 3, 2023
87b6e09
fix ios declared variables and probe test in call quality doc (#794)
maxxfrazer Dec 4, 2023
5976ef4
Merge branch '789-update-puml-diagrams-to-work-with-light-and-dark-th…
saudsami Dec 5, 2023
5dc7b3d
get-started update
saudsami Dec 5, 2023
7ac964d
non-poc3 platforms update
saudsami Dec 5, 2023
df53302
pulled from milestone
saudsami Dec 5, 2023
06f1014
updates
saudsami Dec 6, 2023
9d7ef34
review updates
saudsami Dec 6, 2023
72aabef
Merge branch 'milestone39-rewrite-video-sdk-docs' of github.com:Agora…
saudsami Dec 6, 2023
7de8296
Added web demo links (#801)
saudsami Dec 6, 2023
6d06823
pulled from staging
saudsami Dec 6, 2023
d093768
updates
saudsami Dec 6, 2023
06f8941
Merge branch 'milestone39-rewrite-video-sdk-docs' of github.com:Agora…
saudsami Dec 6, 2023
26fb301
Voice changes for poc3 web (#804)
Kishan-Dhakan Dec 7, 2023
a3ad5df
Merge branches 'reskin-milestone39-poc3' and 'milestone39-rewrite-vid…
saudsami Dec 7, 2023
baa11c5
update token example code link to latest release
maxxfrazer Dec 12, 2023
b7ba4da
pulled from staging
saudsami Dec 20, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
pulled from staging
saudsami committed Dec 20, 2023
commit b7ba4dabc2da577df94929dff6a97a10d98162cd
38 changes: 0 additions & 38 deletions .github/ISSUE_TEMPLATE/.docs-update-issue.md

This file was deleted.

19 changes: 0 additions & 19 deletions .github/ISSUE_TEMPLATE/milestone-management.md

This file was deleted.

36 changes: 36 additions & 0 deletions .github/ISSUE_TEMPLATE/milestone-management.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: "[Internal] Milestone management"
description: Checklist for milestone tasks
title: "[Internal] Milestone management"
labels: 'Enhancement'
assignees: atovpeko

body:
- type: markdown
attributes:
value: "❗️ This Issue template is for Agora use only ❗️"

- type: textarea
attributes:
label: Details
validations:
required: true

- type: checkboxes
id: tasks
attributes:
label: "Take the following project management steps to fulfill this milestone:"
options:
- label: "Run the full scope of the proposed EN doc updates by the PO"
required: false
- label: "Merge all PRs and close relevant tickets when the work is done"
required: false
- label: "Create and share a Vercel instance for review and stakeholder signoff"
required: false
- label: "Implement comments from stakeholders until fully resolved"
required: false
- label: "Publish updates to https://docs.agora.io/en/"
required: false
- label: "Inform the stakeholders"
required: false
- label: "Close the milestone"
required: false
12 changes: 9 additions & 3 deletions .github/ISSUE_TEMPLATE/new-issue.yml
Original file line number Diff line number Diff line change
@@ -11,6 +11,7 @@ body:
label: Platform
description: Select the platform for the documentation update.
options:
- All or multiple (please specify)
- Android
- iOS
- Web
@@ -24,12 +25,19 @@ body:
validations:
required: true

- type: textarea
attributes:
label: Platform details
validations:
required: false

- type: dropdown
id: product
attributes:
label: Product
description: Select the product for the documentation update.
options:
- All or multiple (please specify)
- Video Calling
- Interactive Live Streaming
- Voice Calling
@@ -43,10 +51,8 @@ body:
required: true

- type: textarea
id: other_product
attributes:
label: Other Product
description: Enter the name of the product if you selected "Other" in the previous dropdown.
label: Product details
validations:
required: false

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
name: "[Internal] Rewrite a document according to the new architecture"
description: Describe this issue template's purpose here.
title: "Rewrite the '<Doc Title>' doc in POC3 style"
labels: 'Enhancement'
assignees: saudsami

body:
- type: markdown
attributes:
value: "❗️ This Issue template is for Agora use only ❗️"

- type: textarea
id: business_case
attributes:
label: Business case
value: |
The POC3 reference app simplifies the integration process of Video SDK. Clients can simply clone the code repository to experience and test product features. Add code for the implementation of **Document title** to the `video-sdk-samples-<platform>` code repository. Update the document to POC3 style and include the updated code. Use conditional blocks, where required, to create variants for Interactive live streaming, Broadcast Streaming, and Voice calling
validations:
required: true

- type: textarea
id: subject_matter_expert
attributes:
label: Subject Matter Expert
value: |
- Technical: Saud
- Language: Anastasia
- PM: Max (only if essential)
validations:
required: true

- type: textarea
id: scope
attributes:
label: Scope
placeholder: |
The products and documents to be updated:
* The code repository for your platform.
* The README file in the sample code folder.
* The Video calling document for the feature: <document-link>
validations:
required: true

- type: textarea
id: platforms
attributes:
label: Platforms
placeholder: |
- [Android](https://github.com/AgoraIO/video-sdk-samples-android) - Saud
- [iOS](https://github.com/AgoraIO/video-sdk-samples-ios) - Dasun
- [Web](https://github.com/AgoraIO/video-sdk-samples-js) - Kishan
> ... (and similarly for all other platforms)
validations:
required: false

- type: textarea
id: acceptance_criteria
attributes:
label: Acceptance criteria
placeholder: |
* The code uses best practices, runs without errors, and demonstrates the product feature.
* The documentation is technically correct, easy to use, follows the template structure, and follows the Google Developer Style Guide.
validations:
required: true

- type: textarea
id: additional_valuable_information
attributes:
label: Additional valuable information
placeholder: |
* Branch from and merge to the milestone branch.
* Use the same branch name in the code and docs repositories
validations:
required: false
13 changes: 13 additions & 0 deletions agora-chat/develop/ip_allowlist.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
title: 'TCP/TLS IP allowlist'
sidebar_position: 7
type: docs
description: >
Describes the TCP/TLS IP allowlist function
---

import IpAllowlist from '@docs/shared/chat-sdk/reference/_ip_allowlist.mdx';

export const toc = [{}];

<IpAllowlist PRODUCT="Chat" COMPANY="Agora" SDK="Chat SDK" CLIENT="app" />
6 changes: 3 additions & 3 deletions agora-chat/develop/ip_whitelist.mdx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
---
title: 'IP whitelist'
title: 'RESTful API IP whitelist'
sidebar_position: 6
type: docs
description: >
Describes the IP whitelist function
Describes the RESTful API IP whitelist function
---

import IpWhitelist from '@docs/shared/chat-sdk/reference/_ip_whitelist.mdx';

export const toc = [{}];

<IpWhitelist PRODUCT="Chat" COMPANY="Agora" SDK="Chat SDK" CLIENT="app" />
<IpWhitelist PRODUCT="Chat" COMPANY="Agora" SDK="Chat SDK" CLIENT="app" />
13 changes: 13 additions & 0 deletions agora-chat/develop/proxy.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
title: 'Cross-border dedicated proxy'
sidebar_position: 7
type: docs
description: >
Describes the cross-border dedicated proxy function
---

import CrossBorderProxy from '@docs/shared/chat-sdk/develop/_cross_border_proxy.mdx';

export const toc = [{}];

<CrossBorderProxy PRODUCT="Chat" COMPANY="Agora" SDK="Chat SDK" CLIENT="app" />
Binary file added assets/images/chat/callback_addr_list.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/chat/callback_secret.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 23 additions & 0 deletions cloud-recording/develop/manage-files.md
Original file line number Diff line number Diff line change
@@ -124,6 +124,29 @@ For example, in the filename `bak0_sid713476478245_cnameagora.m3u8`, `bak0` indi

After the cloud recording service enables the high availability mechanism, the names of the recorded TS/WebM files and the MP4 files are also prepended with `bak<n>`.

If you want to merge the original M3U8 file and the new M3U8 file generated after enabling the high availability mechanism into an MP4 file, you can use the <Link target="_blank" to="{{Global.CREC_TRANS_SCRIPT}}">transcoding script</Link> for file merging as follows (only applicable to merged recording files):

1. Please ensure that the server executing the transcoding script uses one of the following systems:
- Ubuntu 14.04+ x64
- CentOS 7.0+ x64
- Debian 8.0+

1. Enter the `transcoder` and `ffmpeg` paths in the terminal.

1. Execute the following command:

```sh
./ha_transcoder.exe -inputPath "<YourinputPath>" -ignoreNotExist -concatM3u8 -concatStrategy 0
```

| Parameter | Description | Is it required? |
|:---------------|:------------|:----------------|
| `-concatM3u8` | Merge the original M3U8 file and the new M3U8 file generated after enabling the high availability mechanism into one MP4 file. If this parameter is not set, the original M3U8 file and the new M3U8 file will be converted into MP4 files respectively. | no |
| `-concatStrategy` | Merge strategy, this parameter must be consistent with `-concatM3u8`. Can be set to: <ul><li> 0: (Default) If there is an overlap between two M3U8 files, the overlapping part of the original M3U8 file will be cut off; if there is a time interval between the two M3U8 files, the black frame of the corresponding time interval will be added.</li><li> 1: Merge two M3U8 files regardless of the overlap or time interval.</li></ul> | no |
| `-ignoreNotExist` | Missing TS files are ignored and black frames are used instead. If this parameter is not set, the absence of any TS file will cause the conversion to fail. | no |
| `-inputPath` | Input path, used to specify the absolute storage path of the files to be merged. | yes |
| `-outputPath` | Output path, used to specify the absolute storage path of the merged files. Defaults to the same as the input path. | no |

## File size
In an individual recording, the size of a recorded file depends on the audio and video bitrates of the media source and the duration of the recording. For example, if the audio bitrate is 48 Kbps, the video bitrate is 500 Kbps, and the recording lasts for 30 minutes (1800 seconds), the size of the recorded file is approximately (48 Kbps + 500 Kbps) * 1800 s = 986.4 Mbit, or 123.3 MB.

12 changes: 12 additions & 0 deletions extensions-marketplace/develop/integrate/dubbing-voice-changer.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
title: "Dubbing AI Voice Changer"
sidebar_position: 3
type: docs
description: >
Dubbing AI Voice Changer extension is an encapsulation of the core API of real-time AI voice conversion.
---
export const toc = [{}];

import DubbingVoiceChanger from '@docs/shared/extensions-marketplace/dubbing-voice-changer/index.mdx';

<DubbingVoiceChanger />
102 changes: 102 additions & 0 deletions flexible-classroom/reference/pricing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
---
title: Pricing
sidebar_position: 1
description: >
Provides you with information on Flexible Classroom pricing
---

export const toc = [{}]

This page explains how <Vg k="COMPANY" /> calculates your monthly bill for <Vg k="FC" />.

If you have already signed a contract with <Vg k="COMPANY" />, the billing terms and conditions within that contract take precedence.

The pricing on this page applies to one-to-one, small, large, and cloud classrooms only. For online proctoring pricing, contact sales@agora.io.

## <Vg k="FC" /> pricing

The unit prices for audio and video usage are as follows. The prices are in USD per 1,000 minutes.

| Usage type | Aggregate resolution of user subscribed videos | Interactive live streaming (Host and audience) | Broadcast streaming (Audience) |
|----------------------------|----------------------------------------------------------------------|--------------------------------------------------|----------------------------------|
| Audio | / | 2.99 | 2.19 |
| High-definition (HD) | Less than or equal to 921,600 (1280 × 720) | 5.99 | 3.99 |
| Full high-definition (FHD) | From greater than 921,600 (1280 × 720) to 2,073,600 (1920 × 1080) | 11.99 | 6.99 |
| Video 2K | From greater than 2,073,600 (1920 × 1080) to 3,686,400 (2560 × 1440) | 19.99 | 11.99 |
| Video 2K+ | From greater than 3,686,400 (2560 × 1440) to 8,847,360 (4096 × 2160) | 41.99 | 21.99 |

<Admonition type="info" title="Information">The difference between interactive live streaming and broadcast streaming is visible in the live broadcast scene. </Admonition>

## Cost calculation

Billing occurs monthly. At the end of each month, <Vg k="COMPANY" /> calculates the total duration of the audio and video usage in minutes for that month in all projects under your developer account. After deducting the monthly [10,000 free-of-charge minutes](#free-minutes) that <Vg k="COMPANY" /> grants to every account, <Vg k="COMPANY" /> multiplies any remaining usage by its corresponding unit price and adds up the costs to get the total cost for that month.

The basic formula is shown here:

**Monthly cost** = **<Vg k="FC" /> services** + **recording services** + **each service exceeding the free quota**

### Service usage

<Vg k="COMPANY" /> calculates the usage based on the number of users in the room. This means that usage for each room is the sum of the usages generated by all users in that room.

For each user, Agora starts timing when they join the room and ends when they leave the room, down to a minute.

Depending on whether the user subscribes to the video stream in the room, the usage is divided into the following categories:

- Audio usage: If the user does not subscribe to the video stream, audio usage is generated regardless of whether the user subscribes to the audio stream.
- Video usage: If the user successfully subscribes to the video stream, video usage is generated.

If a user subscribes to both audio and video streams, only the video usage is generated. Video usage is divided into four different types based on aggregate resolution and priced individually.

### Free minutes

The number of free minutes for each service and the billing strategy for the portion exceeding the free quota are detailed in the table below:

| Service item | Usage measurement | Services | Free monthly quota | Overage fee |
|--------------------|-------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| <Vg k="FC" /> | Duration, minutes | Services include classroom functions and server-side functions: <ul><li>Real-time audio and video interaction</li> <li>Interactive whiteboard</li> <li>Signaling</li> <li>Agora Chat</li> <li>Interactive teaching tools</li> <li>Classroom server RESTful API</li></ul> | <ul><li> The first 10,000 minutes of <Vg k="FC" /> services</li> <li>The first 1,000 images of interactive whiteboard document conversion</li> <li>Agora Chat: <ul><li>10,000 of monthly active users</li><li>10,000 automatically generated thumbnails </li> <li>10 GB of file download traffic</li> <li>1 GB of file storage </li> <li>5,000 peak concurrent users </li></ul></li></ul> | <ul><li>[<Vg k="FC" /> pricing](#-pricing)</li> <li>[Interactive whiteboard pricing](/interactive-whiteboard/reference/pricing)</li> <li>[Chat pricing](/agora-chat/reference/pricing)</li></ul> |
| Web page recording | Duration, minutes | Page recording used during class | The first 10,000 minutes | [Web page recording pricing](/cloud-recording/reference/pricing-webpage-recording) |

<Admonition type="info" title="Information">The free quotas for <Vg k="FC" /> services and recording services are calculated separately. </Admonition>

### Usage-based volume discounts

Agora automatically offers the following tiered discounts for total monthly usage that exceeds 100,000 minutes:

| Minutes used | Discount level |
|---------------------|----------------|
| 100,000 to 499,999 | 5% |
| 500,000 to 999,999 | 7% |
| 1,000,000 and above | 10% |

Note that the discounts for each tier are only applicable to the usage within the corresponding tier. For example, if the usage is 600,000 minutes, there will be no discount for 1 to 99,999 minutes, but there will be a 5% discount for 100,000 to 499,999 minutes and a 7% discount for 500,000 to 999,999 minutes.

## Examples

This section illustrates how Agora calculates aggregate video resolution, total usage per service type, and the associated costs.

Suppose that 1 teacher, 5 students, and 3 parents join a room at the same time and conduct a 60-minute interactive live video course. In this course:

- The teacher and 5 students interact via video. The resolution is 360 × 240.
- 3 parents subscribe to the video streams of the teacher and all students.
- The teacher shares their screen with all students and parents in the room. The resolution of both sent and received screen sharing streams is 1280 × 720.

### Calculate aggregate video resolution

The following table shows the calculations for the aggregate resolution for each user’s video stream subscriptions. These determine the unit prices for their video usage:

| User | Subscribed video streams | Aggregate video resolution | Total | Video type |
|----------|-------------------------------------------------------|------------------------------------------|-------------------------------------|-------------------------------------------------------|
| Teacher | 5 students | 360 × 240 × 5 | 432,000 | High-definition video (HD) |
| Student | Teacher + shared screen by teacher + 4 other students | 360 × 240 + 1280 x 720 + 360 × 240 × 4 | 1,353,600 | Full HD video |
| Parent | Teacher + shared screen by teacher + 5 students | 360 × 240 + 1280 x 720 + 360 × 240 × 5 | 1,440,000 | Full HD video |

### Cost calculation

The following table shows the calculation of the total cost of the live video course:

| Billed service (video type) | Total usage (minutes) = Sum of all individual usage | Unit price (US$/1,000 minutes) | Cost of each service (US$) | Total cost (US$) (rounded to two decimal places) |
|-----------------------------|-----------------------------------------------------|--------------------------------|----------------------------|--------------------------------------------------|
| HD | 60 | 5.99 | (60/1000) × 5.99 = 0.36 | The total cost is 6.12 |
| Full HD | 60 × 8 = 480 | 11.99 | (480/1000) × 11.99 = 5.76 | |

Original file line number Diff line number Diff line change
@@ -51,27 +51,35 @@ ChatClient.getInstance().groupManager().leaveGroup(groupId);

### Retrieve the member list of a chat group

To retrieve the member list of a chat group, choose the method based on the group size:
- When a group has less than 200 members, you can call the `getGroupFromServer` method to retrieve the group member list that contains the group owner, admins, and regular members.

- If the members of a chat group are greater than or equal to 200, list members of the chat group by page.
- If the members of a chat group are less than 200, call `getGroupFromServer` to retrieve the member list of the chat group.

Refer to the following sample code to retrieve the member list of a chat group:
```java
// If `true` is passed to the second parameter, the SDK returns the group member list that contains up to 200 group members.
// It is a synchronous method and may block the current thread.
Group group = ChatClient.getInstance().groupManager().getGroupFromServer(groupId, true);
List<String> memberList = group.getMembers();// gets regular members.
memberList.addAll(group.getAdminList());// gets group admins.
memberList.add(group.getOwner());// gets the group owner.
```
- When a group has more than 200 members, you can first call the `getGroupFromServer` method to get the group member list that contains the group owner and admins and then call the `fetchGroupMembers` method to obtain the list of regular group members.

```java
// List members of a chat group by page.
List<String> memberList = new ArrayList<>;
// If `true` is passed to the second parameter, the SDK returns the group member list that contains up to 200 group members.
// It is a synchronous method and may block the current thread.
Group group = ChatClient.getInstance().groupManager().getGroupFromServer(groupId, true);

List<String> memberList = new ArrayList<>();
CursorResult<String> result = null;
final int pageSize = 20;
do {
// It is a synchronous method and may block the current thread. The asynchronous method is asyncFetchGroupMembers(String, String, int, ValueCallBack).
result = ChatClient.getInstance().groupManager().fetchGroupMembers(groupId,
result != null? result.getCursor(): "", pageSize);
memberList.addAll(result.getData());
} while (!TextUtils.isnull(result.getCursor()) && result.getData().size() == pageSize);
} while (!TextUtils.isEmpty(result.getCursor()) && result.getData().size() == pageSize);

// Call getGroupFromServer to retrieve the member list of a chat group.
Group group = ChatClient.getInstance().groupManager().getGroupFromServer(groupId, true);
List<String> memberList = group.getMembers();
memberList.addAll(group.getAdminList());// gets group admins.
memberList.add(group.getOwner());// gets the group owner.
```

### Block and unblock a chat group
Original file line number Diff line number Diff line change
@@ -67,35 +67,39 @@ do {

### Retrieve the member list of a chat group

To retrieve the member list of a chat group, choose the method based on the size of the chat group:
- When a group has less than 200 members, you can call the `getGroupSpecificationFromServerWithId` method to retrieve the group member list that contains the group owner, admins, and regular members.

- If the number of chat group members is greater than or equal to 200, list members of the chat group by page.
- If the number of chat group members is less than 200, call `getGroupSpecificationFromServerWithId` to retrieve the member list of the chat group.
```objc
// If `true` is passed to the second parameter, the SDK returns the group member list that contains up to 200 group members.
// It is a synchronous method. The asynchronous method is [AgoraChatGroupManager getGroupSpecificationFromServerWithId:fetchMembers:completion:].
AgoraChatGroup *group = [[AgoraChatClient sharedClient].groupManager
getGroupSpecificationFromServerWithId:@"groupID"
fetchMembers:YES
error:nil];
NSArray *memberList = group.memberList;
```
Refer to the following sample code to retrieve the member list of a chat group:
- When a group has more than 200 members, you can first call the `getGroupSpecificationFromServerWithId` method to get the group member list that contains the group owner and admins and then call the `getGroupMemberListFromServerWithId` method to obtain the list of regular group members.
```objc
// List members of a chat group by page.
AgoraChatGroup *group = [[AgoraChatClient sharedClient].groupManager
getGroupSpecificationFromServerWithId:@"groupID"
fetchMembers:NO
error:nil];
NSMutableArray *memberList = [[NSMutableArray alloc]init];
NSInteger pageSize = 50;
NSString *cursor = nil;
AgoraChatCursorResult *result = [[AgoraChatCursorResult alloc]init];
do {
result = [[AgoraChatClient sharedClient].groupManager
getGroupMemberListFromServerWithId:@"groupID"
cursor:cursor
pageSize:pageSize
error:nil];
[memberList addObjectsFromArray:result.list];
cursor = result.cursor;
// It is a synchronous method. The asynchronous method is [AgoraChatGroupManager getGroupMemberListFromServerWithId:cursor:pageSize:completion:].
result = [[AgoraChatClient sharedClient].groupManager
getGroupMemberListFromServerWithId:@"groupID"
cursor:cursor
pageSize:pageSize
error:nil];
[memberList addObjectsFromArray:result.list];
cursor = result.cursor;
} while (result && result.list < pageSize);

// Call getGroupSpecificationFromServerWithId to retrieve the member list of a chat group.
AgoraChatGroup *group = [[AgoraChatClient sharedClient].groupManager
getGroupSpecificationFromServerWithId:@"groupID"
fetchMembers:YES
error:nil];
NSArray *memeberList = [group.memberList];
```

### Block and unblock a chat group
Original file line number Diff line number Diff line change
@@ -83,6 +83,7 @@ Refer to the following sample code to manage the chat group mute list:

```java
// The chat group owner and admins can call muteGroupMember to add the specified member to the chat group mute list. The muted member and all the other chat group admins or owner receive the onMuteListAdded callback.
// If you pass `-1` to `duration`, members are muted permanently.
ChatClient.getInstance().groupManager().muteGroupMembers(groupId, muteMembers, duration);

// The chat group owner and admins can call unmuteGroupMember to remove the specified user from the chat group mute list. The unmuted member and all the other chat group admins or owner receive the onMuteListRemoved callback.
2 changes: 1 addition & 1 deletion shared/chat-sdk/client-api/chat-room/_manage-chatrooms.mdx
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@ import ProjectImplement from '@docs/shared/chat-sdk/client-api/chat-room/manage-

Chat rooms enable real-time messaging among multiple users.

Chat rooms do not have a strict membership, and members do not retain any permanent relationship with each other. Once a chat room member goes offline, this member does not receive any push messages from the chat room and automatically leaves the chat room after 5 minutes. Chat rooms are widely applied in live broadcast use cases such as stream chat in Twitch.
Chat rooms do not have a strict membership, and members do not retain any permanent relationship with each other. Once going offline, chat room members cannot receive any messages from the chat room and automatically leave the chat room after 2 minutes. Chat rooms are widely applied in live broadcast use cases such as stream chat in Twitch.

This page shows how to use the Chat SDK to create and manage a chat room in your app.

Original file line number Diff line number Diff line change
@@ -9,8 +9,7 @@ Only the chat room owner can disband a chat room. Once a chat room is disbanded,
```objc
// The super admin can call createChatroomWithSubject to create a chat room.
AgoraChatError *error = nil;
AgoraChatroom *retChatroom = [[AgoraChatClient sharedClient].roomManager createChatroomWithSubject:@"aSubject" description:@"aDescription" invitees:@[@"user1",@[user2]]message:@"aMessage" maxMembersCount:aMaxMembersCount error:&error];

AgoraChatroom *retChatroom = [[AgoraChatClient sharedClient].roomManager createChatroomWithSubject:@"aSubject" description:@"aDescription" invitees:@[@"user1",@"user2"]message:@"aMessage" maxMembersCount:aMaxMembersCount error:&error];
// The chat room owner can call destroyChatroom to disband a chat room.
AgoraChatError *error = nil;
[[AgoraChatClient sharedClient].roomManager destroyChatroom:self.chatroom.chatroomId error:&error];
@@ -30,7 +29,7 @@ AgoraChatError *error = nil;
// All chat room members can call leaveChatroom to leave the specified chat room.
AgoraChatError *error = nil;
[AgoraChatClient sharedClient].roomManager leaveChatroom:@"aChatroomId" error:&error];
[[AgoraChatClient sharedClient].roomManager leaveChatroom:@"aChatroomId" error:&error];
```


Original file line number Diff line number Diff line change
@@ -70,7 +70,7 @@ To monitor the chat room events, you can call `addEventHandler` to listen for th

```javascript
conn.addEventHandler("eventName", {
onGroupEvent: function(msg){
onChatroomEvent: function(msg){
switch(msg.operation){
// Occurs when all the chat room members are unmuted.
case 'unmuteAllMembers':
Original file line number Diff line number Diff line change
@@ -84,6 +84,8 @@ You can add a specified user to your block list. Once you do that, you can still

Call `addUserToBlackList` to add the specified user to the block list.

You can add any other users to the block list, regardless of whether they are on the contact list or not. Contacts are still displayed on the contact list even if they are added to the block list. After adding users to the block list, you can still send messages to them, but will not receive messages from them as they cannot send messages or friend requests to you.

```java
// The effect of true and false is the same. I can send messages to users on the blacklist, but I cannot receive them when they send me messages.
ChatClient.getInstance().contactManager().addUserToBlackList(username,true);
Original file line number Diff line number Diff line change
@@ -124,9 +124,9 @@ try {

### Add a user to the block list

Call `addUserToBlockList` to add the specified user to the block list. Once you add a user to the block list, you can no longer receive messages from this user.
Call `addUserToBlockList` to add the specified user to the block list.

<div class="note alert">Users can add any other chat user to their block list, regardless of whether this other user is a contact or not. A contact added to the block list remains in the contact list.</div>
You can add any other users to the block list, regardless of whether they are on the contact list or not. Contacts are still displayed on the contact list even if they are added to the block list. After adding users to the block list, you can still send messages to them, but will not receive messages from them as they cannot send messages or friend requests to you.

```dart
// The user ID
32 changes: 13 additions & 19 deletions shared/chat-sdk/client-api/contacts/project-implementation/ios.mdx
Original file line number Diff line number Diff line change
@@ -30,32 +30,28 @@ Call `addContact` to add the specified user as a contact:
Use `ContactListener` to add the following callback events. When a user receives a contact invitation, you can accept or decline the invitation.
```objc
/*
* Adds a contact manager delegate
*/
// Adds a contact manager delegate
[[AgoraChatClient sharedClient].contactManager addDelegate:self delegateQueue:nil];
/*
* Removes the contact manager delegate
*/
//Removes the contact manager delegate
[[AgoraChatClient sharedClient].contactManager removeDelegate:self];
```

```objc
/*
* Occurs when a contact invitation is received.
*
* @param aUsername The username that sends the contact invitation.
* @param aMessage The invitation message.
*/
- (void)friendRequestDidReceiveFromUser:(NSString *)aUsername
message:(NSString *)aMessage
{ }

// The peer user accepts the contact invitation.
- (void)friendRequestDidApproveByUser:(NSString *)aUsername
{ }
// The peer user declines the contact invitation.
- (void)friendRequestDidDeclineByUser:(NSString *)aUsername
{ }
// The contact is deleted.
- (void)friendshipDidRemoveByUser:(NSString *)aUsername
{ }
```
#### Accept or decline the contact invitation
After receiving `friendRequestDidReceiveFromUser`, call `approveFriendRequestFromUser` or `declineFriendRequestFromUser` to accept or decline the invitation.
After receiving `friendRequestDidReceiveFromUser`, call `approveFriendRequestFromUser` or `declineFriendRequestFromUser` to accept or decline the invitation. The peer user receives the `friendRequestDidApprove` or `friendRequestDidDecline` callback.
```objc
/*
@@ -160,9 +156,7 @@ NSArray *userlist = [[AgoraChatClient sharedClient].contactManager getContacts];
### Manage the block list
You can add a specified user to your block list. Once you do that, you can still send chat messages to that user, but you cannot receive messages from them.
<div class="note alert">Users can add any other chat user to their block list, regardless of whether this other user is a contact or not. A contact added to the block list remains in the contact list.</div>
You can add any other users to the block list, regardless of whether they are on the contact list or not. Contacts are still displayed on the contact list even if they are added to the block list. After adding users to the block list, you can still send messages to them, but will not receive messages from them as they cannot send messages or friend requests to you.
#### Add a user to the block list
Original file line number Diff line number Diff line change
@@ -108,9 +108,9 @@ ChatClient.getInstance()

### Add a user to the block list

Call `addUserToBlockList` to add the specified user to the block list. Once you add a user to the block list, you can no longer receive messages from this user.
Call `addUserToBlockList` to add the specified user to the block list.

<div class="note alert">Users can add any other chat user to their block list, regardless of whether this other user is a contact or not. A contact added to the block list remains in the contact list.</div>
You can add any other users to the block list, regardless of whether they are on the contact list or not. Contacts are still displayed on the contact list even if they are added to the block list. After adding users to the block list, you can still send messages to them, but will not receive messages from them as they cannot send messages or friend requests to you.

```typescript
// Specify the user ID to be added to the block list.
Original file line number Diff line number Diff line change
@@ -114,9 +114,7 @@ List<string>list = SDKClient.Instance.ContactManager.GetAllContactsFromDB();

### Manage the block list

You can add a specified user to your block list. Once you do that, you can still send chat messages to that user, but you cannot receive messages from them.

<div class="note alert">Users can add any other chat user to their block list, regardless of whether this other user is a contact or not. A contact added to the block list remains in the contact list.</div>
ou can add any other users to the block list, regardless of whether they are on the contact list or not. Contacts are still displayed on the contact list even if they are added to the block list. After adding users to the block list, you can still send messages to them, but will not receive messages from them as they cannot send messages or friend requests to you.

#### Add a user to the block list

Original file line number Diff line number Diff line change
@@ -71,9 +71,7 @@ WebIM.conn.getContacts().then( (res) => {
### Manage the block list
You can add a specified user to your block list. Once you do that, you can still send chat messages to that user, but you cannot receive messages from them.
<div class="note alert">Users can add any other chat user to their block list, regardless of whether this other user is a contact or not. A contact added to the block list remains in the contact list.</div>
You can add any other users to the block list, regardless of whether they are on the contact list or not. Contacts are still displayed on the contact list even if they are added to the block list. After adding users to the block list, you can still send messages to them, but will not receive messages from them as they cannot send messages or friend requests to you.
#### Add a user to the block list
Original file line number Diff line number Diff line change
@@ -114,9 +114,7 @@ List<string>list = SDKClient.Instance.ContactManager.GetAllContactsFromDB();

### Manage the block list

You can add a specified user to your block list. Once you do that, you can still send chat messages to that user, but you cannot receive messages from them.

<div class="note alert">Users can add any other chat user to their block list, regardless of whether this other user is a contact or not. A contact added to the block list remains in the contact list.</div>
You can add any other users to the block list, regardless of whether they are on the contact list or not. Contacts are still displayed on the contact list even if they are added to the block list. After adding users to the block list, you can still send messages to them, but will not receive messages from them as they cannot send messages or friend requests to you.

#### Add a user to the block list

Original file line number Diff line number Diff line change
@@ -15,7 +15,7 @@ Before proceeding, ensure that your development environment meets the following

- Your project integrates a version of the Chat SDK later than v1.0.3 and has implemented the basic <Link to="/agora-chat/get-started/get-started-sdk">real-time chat functionalities</Link>.
- You understand the API call frequency limit as described in [Limitations](/agora-chat/reference/limitations).
- Because this feature is enabled by the Microsoft Azure Translation API, ensure that you understand the supported target languages as described in [Language support](https://docs.microsoft.com/en-us/azure).
- Because this feature is enabled by the Microsoft Azure Translation API, ensure that you understand the supported target languages as described in [Language support](https://learn.microsoft.com/en-us/azure/ai-services/translator/language-support).
- Translation is not enabled by default. To use this feature, you need to subscribe to the **Pro** or **Enterprise** [pricing plan](/agora-chat/reference/pricing-plan-details) and enable it in [Agora Console](https://console.agora.io/).

<div class="alert note">Add-on fees are incurred if you use this feature. See [Pricing](/agora-chat/overview/pricing#optional-add-on-fee) for details.</div>
Original file line number Diff line number Diff line change
@@ -13,7 +13,8 @@ List<Conversation> conversations = ChatClient.getInstance().chatManager().getAll
Call `getAllMessages` to retrieve all the messages of this conversation in the message. Alternatively, you can call `loadMoreMsgFromDB` to load messages from the local database. The loaded message will be placed in the memory based on the timestamp of the messages.

```java
Conversation conversation = ChatClient.getInstance().chatManager().getConversation(username);
Conversation conversation = ChatClient.getInstance().chatManager().getConversation(conversationId);

List<ChatMessage> messages = conversation.getAllMessages();
// startMsgId: Starting message ID for query. The SDK loads messages, starting from the specified one, in the descending order of the timestamp included in the messages.
// pageSize: Number of message to load on each page. The value range is [1,400].
@@ -25,7 +26,7 @@ List<ChatMessage> messages = conversation.loadMoreMsgFromDB(startMsgId, pagesize
Refer to the following code example to retrieve the count of unread messages:

```java
Conversation conversation = ChatClient.getInstance().chatManager().getConversation(username);
Conversation conversation = ChatClient.getInstance().chatManager().getConversation(conversationId);
conversation.getUnreadMsgCount();
```

@@ -42,7 +43,7 @@ ChatClient.getInstance().chatManager().getUnreadMessageCount();
Refer to the following code example to mark the specified messages as read:

```java
Conversation conversation = ChatClient.getInstance().chatManager().getConversation(username);
Conversation conversation = ChatClient.getInstance().chatManager().getConversation(conversationId);
// Mark all the messages in the current conversation as read.
conversation.markAllMessagesAsRead();
// Mark the specified message as read.
@@ -59,9 +60,9 @@ To delete them on the local device, call `deleteConversation` and `removeMessage

```java
// true indicates to keep the historical messages while deleting the conversation. To remove the historical messages as well, set it as true.
ChatClient.getInstance().chatManager().deleteConversation(username, true);
ChatClient.getInstance().chatManager().deleteConversation(conversationId, deleteMessages);
// Delete the specified message in the current conversation.
Conversation conversation = ChatClient.getInstance().chatManager().getConversation(username);
Conversation conversation = ChatClient.getInstance().chatManager().getConversation(conversationId);
conversation.removeMessage(deleteMsg.msgId);
```

@@ -101,10 +102,10 @@ If you want to insert a message to the current conversation without actually sen

```java
// Insert a message to the specified conversation.
Conversation conversation = ChatClient.getInstance().chatManager().getConversation(username);
Conversation conversation = ChatClient.getInstance().chatManager().getConversation(conversationId);
conversation.insertMessage(message);
// Insert a message.
ChatClient.getInstance().chatManager().saveMessage(message);
// ChatClient.getInstance().chatManager().saveMessage(message);
```

</PlatformWrapper>
Original file line number Diff line number Diff line change
@@ -21,18 +21,14 @@ try {
You can retrieve the messages in the specified conversation from the local database by specifying the conversation ID and chat type:

```dart
// The conversation ID.
String convId = "convId";
// Whether to create a conversation if the specified one does not exist. If you set it as true, the SDK returns a conversation object.
bool createIfNeed = true;
// The conversation type.
ChatConversationType conversationType = ChatConversationType.Chat;
// Call getConversation to get the specified conversation.
ChatConversation? conversation =
await ChatClient.getInstance.chatManager.getConversation(
convId,
conversationType,
true,
// Retrieves the conversation ID
ChatConversation? conversation = await ChatClient.getInstance.chatManager
.getConversation(conversationId, type: ChatConversationType.Chat);
// Only one message is loaded during SDK initialization. Call loadMessages to retrieve more messages.
List<ChatMessage> messages = await conversation!.loadMessages(
startMsgId: startMsgId,
loadCount: count,
direction: ChatSearchDirection.Up,
);
```

Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@ Refer to the following code sample to retrieve the messages in the specified con

```objc
// Retrieves the conversation ID
AgoraConversation *conversation = [[AgoraChatClient sharedClient].chatManager getConversation:conversationId type:type createIfNotExist:YES];
AgoraChatConversation *conversation = [[AgoraChatClient sharedClient].chatManager getConversation:conversationId type:type createIfNotExist:YES];
// Only one message is loaded during SDK initialization. Call loadMessagesStartFromId to retrieve more messages.
NSArray<AgoraChatMessage *> *messages = [conversation loadMessagesStartFromId:startMsgId count:count searchDirection:MessageSearchDirectionUp];
```
@@ -25,7 +25,7 @@ Refer to the following code example to retrieve the count of unread messages:

```objc
// Retrieves the ID of the specified conversation.
AgoraConversation *conversation = [[AgoraChatClient sharedClient].chatManager getConversation:conversationId type:type createIfNotExist:YES];
AgoraChatConversation *conversation = [[AgoraChatClient sharedClient].chatManager getConversation:conversationId type:type createIfNotExist:YES];
// Retrieves the count of unread messages.
NSInteger unreadCount = conversation.unreadMessagesCount;
```
@@ -38,7 +38,7 @@ Refer to the following code example to retrieve the count of all unread messages
```objc
NSArray *conversations = [[AgoraChatClient sharedClient].chatManager getAllConversations];
NSInteger unreadCount = 0;
for (AgoraConversation *conversation in conversations) {
for (AgoraChatConversation *conversation in conversations) {
unreadCount += conversation.unreadMessagesCount;
}
```
@@ -49,11 +49,11 @@ for (AgoraConversation *conversation in conversations) {
Refer to the following code example to mark the specified messages as read:

```objc
AgoraConversation *conversation = [[AgoraChatClient sharedClient].chatManager getConversation:conversationId type:type createIfNotExist:YES];
AgoraChatConversation *conversation = [[AgoraChatClient sharedClient].chatManager getConversation:conversationId type:type createIfNotExist:YES];
// Marks all messages of the specified conversation as read.
[conversation markAllMessagesAsRead:nil];
// Marks the specified message as read.
[onversation markMessageAsReadWithId:messageId error:nil];
[conversation markMessageAsReadWithId:messageId error:nil];
```

### Delete conversations and historical messages
@@ -69,7 +69,7 @@ To delete them on the local device, call `deleteConversation` and `removeMessage
NSArray *conversations = @{@"conversationID1",@"conversationID2"};
[[AgoraChatClient sharedClient].chatManager deleteConversations:conversations isDeleteMessages:YES completion:nil];
// Deletes the specified message of the current conversation.
AgoraConversation *conversation = [[AgoraChatClient sharedClient].chatManager getConversation:conversationId type:type createIfNotExist:YES];
AgoraChatConversation *conversation = [[AgoraChatClient sharedClient].chatManager getConversation:conversationId type:type createIfNotExist:YES];
[conversation deleteMessageWithId:.messageId error:nil];
```

@@ -102,7 +102,7 @@ If you want to insert a message to the current conversation without actually sen

```objc
// Inserts a message to the specified conversation.
AgoraConversation *conversation = [[AgoraChatClient sharedClient].chatManager getConversation:conversationId type:type createIfNotExist:YES];
AgoraChatConversation *conversation = [[AgoraChatClient sharedClient].chatManager getConversation:conversationId type:type createIfNotExist:YES];
[conversation insertMessage:message error:nil];
```

Original file line number Diff line number Diff line change
@@ -20,7 +20,7 @@ ChatClient.getInstance()
You can retrieve the messages in the specified conversation from the local database by specifying the conversation ID and chat type:

```typescript
// Sepcify the conversation ID.
// Specify the conversation ID.
const convId = "convId";
// Whether to create a conversation if the specified one does not exist. If you set it as true, this method always returns a conversation object.
const createIfNeed = true;
@@ -29,8 +29,8 @@ const convType = ChatConversationType.PeerChat;
// Call getConversation to retrieve the specified conversation.
ChatClient.getInstance()
.chatManager.getConversation(convId, convType, createIfNeed)
.then((message) => {
console.log("Getting conversations succeeds", message);
.then((conversation) => {
console.log("Getting conversations succeeds", conversation);
})
.catch((reason) => {
console.log("Getting conversations fails.", reason);
Original file line number Diff line number Diff line change
@@ -7,7 +7,10 @@ To send a message delivery receipt, take the following steps:
1. The message sender sets `setRequireDeliveryAck` in `ChatOptions` as `true` before sending the message:

```java
options.setRequireDeliveryAck(true);
ChatOptions chatOptions = new ChatOptions();
chatOptions.setRequireDeliveryAck(true);
...
ChatClient.getInstance().init(mContext, chatOptions);
```

2. Once the recipient receives the message, the SDK triggers `onMessageDelivered` on the message sender's client, notifying the message sender that the message has been delivered to the recipient.
@@ -19,11 +22,15 @@ To send a message delivery receipt, take the following steps:
@Override
public void onMessageReceived(List<ChatMessage> messages) {
}
// Occurs when the message deliery receipt is received
// Occurs when the message delivery receipt is received
@Override
public void onMessageDelivered(List<ChatMessage> message) {
}
};
// Register a message listener.
ChatClient.getInstance().chatManager().addMessageListener(msgListener);
// Remove the message listener when it is not used.
ChatClient.getInstance().chatManager().removeMessageListener(msgListener);
```

### Conversation and message read receipts
@@ -74,9 +81,9 @@ In one-to-one chats, the SDK supports sending both the conversation read receipt
1. Send a conversation read receipt when the recipient enters the conversation.

```java
// The message receiver calls ackMessageRead to send the conversation read receipt.
// The message receiver calls ackConversationRead to send the conversation read receipt.
try {
ChatClient.getInstance().chatManager().ackMessageRead(conversationId);
ChatClient.getInstance().chatManager().ackConversationRead(conversationId);
}catch (ChatException e) {
e.printStackTrace();
}
@@ -143,11 +150,11 @@ Follow the steps to implement chat message read receipts.

```java
// Set setIsNeedGroupAck as true when sending the group message
ChatMessage message = ChatMessage.createTxtSendMessage(content, to);
ChatMessage message = ChatMessage.createTextSendMessage(content, to);
message.setIsNeedGroupAck(true);
```

2. After the group member reads the chat group message, call `sendAckMessage` from the group member's client to send a message read receipt:
2. After the group member reads the chat group message, call `ackGroupMessageRead` from the group member's client to send a message read receipt:

```java
// Send the group message read receipt.
@@ -198,7 +205,15 @@ Follow the steps to implement chat message read receipts.
* @param startAckId The receipt ID from which you want to fetch. If you set it as null, the SDK fetches from the latest receipt.
* @return The message receipt list and a cursor.
*/
public void asyncFetchGroupReadAcks(final String msgId, final int pageSize,final String startAckId, final ValueCallBack<CursorResult<GroupReadAck>> callBack) {}
ChatClient.getInstance().chatManager().asyncFetchGroupReadAcks(msgId, pageSize, startAckId, new ValueCallBack<CursorResult<GroupReadAck>>() {
@Override
public void onSuccess(CursorResult<GroupReadAck> value) {// Succeeded in getting the details of the read receipt.
}
@Override
public void onError(int error, String errorMsg) {
// Failed to get the details of the read receipt.
}
});
```

</PlatformWrapper>
Original file line number Diff line number Diff line change
@@ -158,7 +158,7 @@ private void doAsyncFetchPinnedConversationsFromServer(final int limit, final St

### Delete historical messages from the server unidirectionally

Call `removeMessagesFromServer` to delete historical messages one way from the server. You can remove a maximum of 50 messages from the server each time. Once the messages are deleted, you can no longer retrieve them from the server. Other chat users can still get the messages from the server.
Call `removeMessagesFromServer` to delete historical messages one way from the server. You can remove a maximum of 50 messages from the server each time. Once the messages are deleted, you can no longer retrieve them from the server. The deleted messages are automatically removed from your local device. Other chat users can still get the messages from the server.

```java
Conversation conversation = ChatClient.getInstance().chatManager().getConversation(username);
@@ -183,9 +183,9 @@ conversation.removeMessagesFromServer(msgIdList, new CallBack() {
});
```

### Delete conversations and related messages from the server
### Delete conversations and related messages from the server unidirectionally

Call `deleteConversationFromServer` to delete conversations and their historical messages from the server. After the conversations are deleted from the server, you and other users can no longer get them from the server. If the historical messages are deleted with the conversations, all users can no longer get the messages from the server.
Call `deleteConversationFromServer` to delete conversations and their historical messages unidirectionally from the server. After the conversations and messages are deleted from the server, you can no longer get them from the server. The deleted conversations still exist on your local device, but the messages are automatically removed from the device. Other chat users can still get the conversations and their historical messages from the server.

```java
ChatClient.getInstance().chatManager().deleteConversationFromServer(conversationId, conversationType, isDeleteServerMessage, new CallBack() {
Original file line number Diff line number Diff line change
@@ -93,7 +93,7 @@ ChatCursorResult<ChatConversation> result =

### Delete historical messages from the server unidirectionally

Call `deleteRemoteMessagesBefore` or `deleteRemoteMessagesWithIds` to delete historical messages one way from the server. You can remove a maximum of 50 messages from the server each time. Once the messages are deleted, you can no longer retrieve them from the server. Other chat users can still get the messages from the server.
Call `deleteRemoteMessagesBefore` or `deleteRemoteMessagesWithIds` to delete historical messages one way from the server. You can remove a maximum of 50 messages from the server each time. Once the messages are deleted, you can no longer retrieve them from the server. The deleted messages are automatically removed from your local device. Other chat users can still get the messages from the server.

```dart
try {
@@ -114,9 +114,9 @@ try {
} on ChatError catch (e) {}
```

### Delete conversations and related messages from the server
### Delete conversations and related messages from the server unidirectionally

Call `deleteRemoteConversation` to delete conversations and their historical messages from the server. After the conversations are deleted from the server, you and other users can no longer get them from the server. If the historical messages are deleted with the conversations, all users can no longer get the messages from the server.
Call `deleteRemoteConversation` to delete conversations and their historical messages unidirectionally from the server. After the conversations and messages are deleted from the server, you can no longer get them from the server. The deleted conversations still exist on the local device, but the messages are automatically removed from your local device. Other chat users can still get the conversations and their historical messages from the server.

```dart
try {
Original file line number Diff line number Diff line change
@@ -72,7 +72,7 @@ Refer to the following code example to get a list of pinned conversations from t

### Delete historical messages from the server unidirectionally

Call `removeMessagesFromServerWithTimeStamp` or `removeMessagesFromServerMessageIds` to delete historical messages one way from the server. You can remove a maximum of 50 messages from the server each time. Once the messages are deleted, you can no longer retrieve them from the server. Other chat users can still get the messages from the server.
Call `removeMessagesFromServerWithTimeStamp` or `removeMessagesFromServerMessageIds` to delete historical messages one way from the server. You can remove a maximum of 50 messages from the server each time. Once the messages are deleted, you can no longer retrieve them from the server. The deleted messages are automatically removed from your local device. Other chat users can still get the messages from the server.

```objective-c
// Delete messages by timestamp
@@ -86,9 +86,9 @@ AgoraChatConversation* conversation = [AgoraChatClient.sharedClient.chatManager
}];
```

### Delete conversations and related messages from the server
### Delete conversations and related messages from the server unidirectionally

Call `deleteServerConversation` to delete conversations and their historical messages from the server. After the conversations are deleted from the server, you and other users can no longer get them from the server. If the historical messages are deleted with the conversations, all users can no longer get the messages from the server.
Call `deleteServerConversation` to delete conversations and their historical messages unidirectionally from the server. After the conversations and messages are deleted from the server, you can no longer get them from the server. The deleted conversations still exist on the local device, but the messages are automatically removed from the device. Other chat users can still get the conversations and their historical messages from the server.

```objective-c
[AgoraChatClient.sharedClient.chatManager deleteServerConversation:@"conversationId1" conversationType:AgoraChatConversationTypeChat isDeleteServerMessages:YES completion:^(NSString *aConversationId, AgoraChatError *aError) {
Original file line number Diff line number Diff line change
@@ -97,7 +97,7 @@ ChatClient.getInstance()

### Delete historical messages from the server unidirectionally

Call `removeMessagesFromServerWithTimestamp` or `removeMessagesFromServerWithMsgIds` to delete historical messages one way from the server. You can remove a maximum of 50 messages from the server each time. Once the messages are deleted, you can no longer retrieve them from the server. Other chat users can still get the messages from the server.
Call `removeMessagesFromServerWithTimestamp` or `removeMessagesFromServerWithMsgIds` to delete historical messages one way from the server. You can remove a maximum of 50 messages from the server each time. Once the messages are deleted, you can no longer retrieve them from the server. The deleted messages are automatically removed from your local device. Other chat users can still get the messages from the server.

```typescript
// Delete messages by message ID
@@ -124,9 +124,9 @@ ChatClient.getInstance()
});
```

### Delete conversations and related messages from the server
### Delete conversations and related messages from the server unidirectionally

Call `removeConversationFromServer` to delete historical messages one way from the server. You can remove a maximum of 50 messages from the server each time. Once the messages are deleted, you can no longer retrieve them from the server. Other chat users can still get the messages from the server.
Call `removeConversationFromServer` to delete conversations and their historical messages unidirectionally from the server. After the conversations and messages are deleted from the server, you can no longer get them from the server. The deleted conversations still exist on the local device, but the messages are automatically removed from the device. Other chat users can still get the conversations and their historical messages from the server.

```typescript
// convId: conversation ID
Original file line number Diff line number Diff line change
@@ -130,7 +130,7 @@ SDKClient.Instance.ChatManager.GetConversationsFromServerWithCursor(pinOnly, cur

### Delete historical messages from the server unidirectionally

Call `RemoveMessagesFromServer` to delete historical messages one way from the server. You can remove a maximum of 50 messages from the server each time. Once the messages are deleted, you can no longer retrieve them from the server. Other chat users can still get the messages from the server.
Call `RemoveMessagesFromServer` to delete historical messages one way from the server. You can remove a maximum of 50 messages from the server each time. Once the messages are deleted, you can no longer retrieve them from the server. The deleted messages are automatically removed from your local device. Other chat users can still get the messages from the server.

```csharp
SDKClient.Instance.ChatManager.RemoveMessagesFromServer(convId, ctype, time, new CallBack(
@@ -151,9 +151,9 @@ SDKClient.Instance.ChatManager.RemoveMessagesFromServer(convId, ctype, msgList,
));
```

### Delete conversations and related messages from the server
### Delete conversations and related messages from the server unidirectionally

Call `DeleteConversationFromServer` to delete conversations and their historical messages from the server. After the conversations are deleted from the server, you and other users can no longer get them from the server. If the historical messages are deleted with the conversations, all users can no longer get the messages from the server.
Call `DeleteConversationFromServer` to delete conversations and their historical messages unidirectionally from the server. After the conversations and messages are deleted from the server, you can no longer get them from the server. The deleted conversations still exist on your local device, but the messages are automatically removed from the device. Other chat users can still get the conversations and their historical messages from the server.

```csharp
SDKClient.Instance.ChatManager.DeleteConversationFromServer(conversationId, conversationType, isDeleteServerMessages, new CallBack(
Original file line number Diff line number Diff line change
@@ -76,7 +76,7 @@ connection.getServerPinnedConversations({pageSize:50, cursor: ''})

### Delete historical messages from the server unidirectionally

Call `removeHistoryMessages` to delete historical messages one way from the server. You can remove a maximum of 50 messages from the server each time. Once the messages are deleted, you can no longer retrieve them from the server. Other chat users can still get the messages from the server.
Call `removeHistoryMessages` to delete historical messages one way from the server. You can remove a maximum of 20 messages from the server each time. Once the messages are deleted, you can no longer retrieve them from the server. Other chat users can still get the messages from the server.

```javascript
// Delete messages by timestamp
@@ -85,9 +85,9 @@ connection.removeHistoryMessages({targetId: 'userId', chatType: 'singleChat', be
connection.removeHistoryMessages({targetId: 'userId', chatType: 'singleChat', messageIds: ['messageId']})
```

### Delete conversations and related messages from the server
### Delete conversations and related messages from the server unidirectionally

Call `deleteConversation` to delete conversations and related messages from the server.
Call `deleteConversation` to delete conversations and related messages unidirectionally from the server. Other chat users can still get the conversations and their historical messages from the server.

```javascript
let options = {
Original file line number Diff line number Diff line change
@@ -129,7 +129,7 @@ SDKClient.Instance.ChatManager.GetConversationsFromServerWithCursor(pinOnly, cur

### Delete historical messages from the server unidirectionally

Call `RemoveMessagesFromServer` to delete historical messages one way from the server. You can remove a maximum of 50 messages from the server each time. Once the messages are deleted, you can no longer retrieve them from the server. Other chat users can still get the messages from the server.
Call `RemoveMessagesFromServer` to delete historical messages one way from the server. You can remove a maximum of 50 messages from the server each time. Once the messages are deleted, you can no longer retrieve them from the server. The deleted messages are automatically removed from your local device. Other chat users can still get the messages from the server.

```csharp
SDKClient.Instance.ChatManager.RemoveMessagesFromServer(convId, ctype, time, new CallBack(
@@ -150,9 +150,9 @@ SDKClient.Instance.ChatManager.RemoveMessagesFromServer(convId, ctype, msgList,
));
```

### Delete conversations and related messages from the server
### Delete conversations and related messages from the server unidirectionally

Call `DeleteConversationFromServer` to delete conversations and their historical messages from the server. After the conversations are deleted from the server, you and other users can no longer get them from the server. If the historical messages are deleted with the conversations, all users can no longer get the messages from the server.
Call `DeleteConversationFromServer` to delete conversations and their historical messages unidirectionally from the server. After the conversations and messages are deleted from the server, you can no longer get them from the server. The deleted conversations still exist on your local device, but the messages are automatically removed from the device. Other chat users can still get the conversations and their historical messages from the server.

```csharp
SDKClient.Instance.ChatManager.DeleteConversationFromServer(conversationId, conversationType, isDeleteServerMessages, new CallBack(
Original file line number Diff line number Diff line change
@@ -5,17 +5,19 @@
Use the `ChatMessage` class to create a text message, and send the message.

```java
// Call createTextSendMessage to create a text message. Set content as the content of the text message, and toChatUsernames the user ID of the message recipient.
ChatMessage message = ChatMessage.createTxtSendMessage(content, toChatUsername);
// Set the message type using the MessageType attribute in Message.
// You can set `MessageType` as `Chat`, `Group`, or `Room`, which indicates whether to send the message to a peer user, a chat group, or a chat room.
message.setChatType(ChatType.GroupChat);
// Send the message
// Call createTextSendMessage to create a text message.
// Set `content` as the content of the text message.
// Set `conversationId` to the user ID of the peer user in one-to-one chat, group ID in group chat, and chat room ID in room chat.
ChatMessage message = ChatMessage.createTextSendMessage(content, conversationId);
// Set `ChatType` as `Chat`, `GroupChat`, or `ChatRoom` for one-to-one chat, group chat, or room chat.
message.setChatType(ChatMessage.GroupChat);
// Send the message.
ChatClient.getInstance().chatManager().sendMessage(message);
```

```java
// Calls setMessageStatusCallback to set the callback instance to get the status of messaging sending. You can update the status of messages in this callback, for example, adding a tip when the message sending fails.
// Call setMessageStatusCallback to set the callback instance to get the status of messaging sending.
// You can update the status of messages in this callback, for example, adding a tip when the message sending fails.
message.setMessageStatusCallback(new CallBack() {
@Override
public void onSuccess() {
@@ -41,7 +43,7 @@ Even high-priorities messages can be dropped when the server load goes too high.
You can set the priority for all types of messages in the chat room.

```java
ChatMessage message = ChatMessage.createTextSendMessage(content, toChatUsername);
ChatMessage message = ChatMessage.createTextSendMessage(content, conversationId);
message.setChatType(ChatMessage.ChatType.ChatRoom);
// Set the message priority. The default value is `Normal`, indicating the normal priority.
message.setPriority(ChatMessage.ChatRoomMessagePriority.PriorityHigh);
@@ -52,16 +54,19 @@ sendMessage(message);

You can use `MessageListener` to listen for message events. You can add multiple `MessageListener`s to listen for multiple events. When you no longer listen for an event, ensure that you remove the listener.

When a message arrives, the recipient receives an `onMessgesReceived` callback. Each callback contains one or more messages. You can traverse the message list, and parse and render these messages in this callback.
When a message arrives, the recipient receives an `onMessagesReceived` callback. Each callback contains one or more messages. You can traverse the message list, and parse and render these messages in this callback.

```java
ChatClient.getInstance().chatManager().addMessageListener(msgListener);
MessageListener msgListener = new MessageListener() {
// Traverse the message list, and parse and render the messages.
@Override
public void onMessageReceived(List<ChatMessage> messages) {
}
// Traverse the message list, and parse and render the messages.
@Override
public void onMessageReceived(List<ChatMessage> messages) {
}
};
// Add a message listener
ChatClient.getInstance().chatManager().addMessageListener(msgListener);
// Remove a message listener
ChatClient.getInstance().chatManager().removeMessageListener(msgListener);
ChatClient.getInstance().chatManager().removeMessageListener(msgListener);
```

@@ -104,7 +109,7 @@ Refer to the following code example to create and send a voice message:

```java
// Set voiceUri as the local URI of the audio file, and duration as the length of the file in seconds.
ChatMessage message = ChatMessage.createVoiceSendMessage(voiceUri, duration, toChatUsername);
ChatMessage message = ChatMessage.createVoiceSendMessage(voiceUri, duration, conversationId);
// Sets the chat type as one-to-one chat, group chat, or chatroom.
if (chatType == CHATTYPE_GROUP)
message.setChatType(ChatType.GroupChat);
@@ -130,7 +135,7 @@ Refer to the following code example to create and send an image message:

```java
// Set imageUri as the URI of the image file on the local device. false means not to send the original image. The SDK compresses image files that exceeds 100K before sending them.
ChatMessage.createImageSendMessage(imageUri, false, toChatUsername);
ChatMessage.createImageSendMessage(imageUri, false, conversationId);
// Sets the chat type as one-to-one chat, group chat, or chatroom.
if (chatType == CHATTYPE_GROUP)
message.setChatType(ChatType.GroupChat);
@@ -162,7 +167,7 @@ Refer to the following code example to create and send a video message:

```java
String thumbPath = getThumbPath(videoUri);
ChatMessage message = ChatMessage.createVideoSendMessage(videoUri, thumbPath, videoLength, toChatUsername);
ChatMessage message = ChatMessage.createVideoSendMessage(videoUri, thumbPath, videoLength, conversationId);
sendMessage(message);
```

@@ -225,7 +230,7 @@ Refer to the following code example to create, send, and receive a file message:

```java
// Set fileLocalUri as the URI of the file message on the local device.
ChatMessage message = ChatMessage.createFileSendMessage(fileLocalUri, toChatUsername);
ChatMessage message = ChatMessage.createFileSendMessage(fileLocalUri, conversationId);
// Sets the chat type as one-to-one chat, group chat, or chatroom.
if (chatType == CHATTYPE_GROUP) message.setChatType(ChatType.GroupChat);ChatClient.getInstance().chatManager().sendMessage(message);
```
@@ -270,9 +275,11 @@ To send and receive a location message, you need to integrate a third-party map

```java
// Sets the latitude and longitude information of the address.
ChatMessage message = ChatMessage.createLocationSendMessage(latitude, longitude, locationAddress, toChatUsername);
ChatMessage message = ChatMessage.createLocationSendMessage(latitude, longitude, locationAddress, conversationId);
// Sets the chat type as one-to-one chat, group chat, or chatroom.
if (chatType == CHATTYPE_GROUP) message.setChatType(ChatType.GroupChat);ChatClient.getInstance().chatManager().sendMessage(message);
if (chatType == CHATTYPE_GROUP)
message.setChatType(ChatType.GroupChat);
ChatClient.getInstance().chatManager().sendMessage(message);
```

### Send and receive a CMD message
@@ -283,15 +290,18 @@ CMD messages are command messages that instruct a specified user to take a certa

```java
ChatMessage cmdMsg = ChatMessage.createSendMessage(ChatMessage.Type.CMD);
// Sets the chat type as one-to-one chat, group chat, or chat room
cmdMsg.setChatType(ChatType.GroupChat)String action="action1";
// You can customize the action
CmdMessageBody cmdBody = new CmdMessageBody(action);String toUsername = "test1";
// Specify a username to send the cmd message.
cmdMsg.setTo(toUsername);cmdMsg.addBody(cmdBody); ChatClient.getInstance().chatManager().sendMessage(cmdMsg);
// Sets the chat type as one-to-one chat, group chat, or chat room.
cmdMsg.setChatType(ChatType.GroupChat);
String action="action1";
// You can customize the action.
CmdMessageBody cmdBody = new CmdMessageBody(action);
// Sets the message recipient: user ID of the recipient for one-to-one chat, group ID for group chat, or chat room ID for a chat room.
cmdMsg.setTo(conversationId);
cmdMsg.addBody(cmdBody);
ChatClient.getInstance().chatManager().sendMessage(cmdMsg);
```

To notify the recipient that a CMD message is received, use a seperate delegate so that users can deal with the message differently.
To notify the recipient that a CMD message is received, use a separate delegate so that users can deal with the message differently.

```java
MessageListener msgListener = new MessageListener()
@@ -300,7 +310,7 @@ MessageListener msgListener = new MessageListener()
@Override
public void onMessageReceived(List<ChatMessage> messages) {
}
// Occues when a CMD message is received
// Occurs when a CMD message is received
@Override
public void onCmdMessageReceived(List<ChatMessage> messages) {
}
@@ -319,7 +329,7 @@ ChatMessage customMessage = ChatMessage.createSendMessage(ChatMessage.Type.CUSTO
event = "gift"CustomMessageBody customBody = new CustomMessageBody(event);
// The data type of params is Map<String, String>.
customBody.setParams(params);customMessage.addBody(customBody);
// Specifies the user ID to receive the message, as Chat ID, chat group ID, or chat room ID.
// Sets the message recipient: user ID of the recipient for one-to-one chat, group ID for group chat, or chat room ID for a chat room.
customMessage.setTo(to);
// Sets the chat type as one-to-one chat, group chat, or chat room
customMessage.setChatType(chatType);ChatClient.getInstance().chatManager().sendMessage(customMessage);
@@ -331,7 +341,7 @@ customMessage.setChatType(chatType);ChatClient.getInstance().chatManager().sendM
If the message types listed above do not meet your requirements, you can use message extensions to add attributes to the message. This can be applied in more complicated messaging scenarios.

```java
ChatMessage message = ChatMessage.createTxtSendMessage(content, toChatUsername);
ChatMessage message = ChatMessage.createTextSendMessage(content, conversationId);
// Adds message attributes.
message.setAttribute("attribute1", "value");message.setAttribute("attribute2", true);
// Sends the message
Original file line number Diff line number Diff line change
@@ -9,11 +9,11 @@ Follow the steps to create and send a message, and listen for the result of send
```dart
// Sets the message type. Agora Chat supports 8 message types.
MessageType messageType = MessageType.TXT;
// Sets the user ID of the recipient.
// Sets `targetId` to the user ID of the peer user in one-to-one chat, group ID in group chat, and chat room ID in room chat.
String targetId = "tom";
// Sets the chat type. You can set it as a peer user, chat group, or chat room.
// Sets `chatType` as `Chat`, `GroupChat`, or `ChatRoom` for one-to-one chat, group chat, or room chat.
ChatType chatType = ChatType.Chat;
// Creates a message. For different message types, you need to set different parameters.
// Creates a message. Parameters vary with message types.
// Creates a text message.
ChatMessage msg = ChatMessage.createTxtSendMessage(
targetId: targetId,
Original file line number Diff line number Diff line change
@@ -5,19 +5,20 @@
Use the `AgoraChatTextMessageBody` class to create a text message, and then send the message.

```objective-c
// Call initWithText to create a text message. Set content as the text content and toChatUsername to the username to whom you want to send this text message.
AgoraChatTextMessageBody *textMessageBody = [[AgoraChatTextMessageBody alloc] initWithText:content];
AgoraChatMessage *message = [[AgoraChatMessage alloc] initWithConversationID:toChatUsername
from:fromChatUsername
to:toChatUsername
body:textMessageBody
ext:messageExt];
// Set the chat type as Group chat. You can also set is as chat (one-to-one chat) or chat room.
message.chatType = AgoraChatTypeGroupChat;
// Sends the message
[[AgoraChatClient sharedClient].chatManager sendMessage:message
progress:nil
completion:nil];
// Call initWithText to create a text message. Set `content` to the text content.
AgoraChatTextMessageBody *textMessageBody = [[AgoraChatTextMessageBody alloc] initWithText:content];
// Set `conversationId` to the user ID of the peer user in one-to-one chat, group ID in group chat, and chat room ID in room chat.
NSString* conversationId = @"remoteUserId";
AgoraChatMessage *message = [[AgoraChatMessage alloc] initWithConversationID:conversationId
body:textMessageBody
ext:messageExt];
// Set `message.chatType` to `AgoraChatTypeChat` for one-to-one chat, `AgoraChatTypeGroupChat` for group chat, and `AgoraChatTypeChatRoom` for room chat.
// The default value is `AgoraChatTypeChat`.
message.chatType = AgoraChatTypeChat;
// Send the message.
[[AgoraChatClient sharedClient].chatManager sendMessage:message
progress:nil
completion:nil];
```
You can set the priority of chat room messages.
@@ -90,7 +91,7 @@ You can also use `messagesDidRecall` to listen for the message recall state:
/**
* Occurs when a received message is recalled.
*/
- (void)messagesDidRecall:(NSArray *)aMessages;
- (void)messagesInfoDidRecall:(NSArray<EMRecallMessageInfo *> * _Nonnull)aRecallMessagesInfo;
```
### Send and receive an attachment message
@@ -114,7 +115,7 @@ AgoraChatMessage *message = [[AgoraChatMessage alloc] initWithConversationID:toC
ext:nil];
message.chatType = AgoraChatTypeChat;
// Set the chat type as Group chat. You can also set is as chat (one-to-one chat) or chat room.
message.chatType = AgoraChatTypeGroupChat;
// message.chatType = AgoraChatTypeGroupChat;
// Sends the message
[[AgoraChatClient sharedClient].chatManager sendMessage:message
progress:nil
@@ -148,7 +149,7 @@ AgoraChatMessage *message = [[AgoraChatMessage alloc] initWithConversationID:toC
ext:messageExt];
message.chatType = AgoraChatTypeChat;
// Set the chat type as Group chat. You can also set is as chat (one-to-one chat) or chat room.
message.chatType = AgoraChatTypeGroupChat;
// message.chatType = AgoraChatTypeGroupChat;
// Sends the message
[[AgoraChatClient sharedClient].chatManager sendMessage:message
progress:nil
@@ -189,7 +190,7 @@ AgoraChatMessage *message = [[AgoraChatMessage alloc] initWithConversationID:toC
ext:messageExt];
message.chatType = AgoraChatTypeChat;
// Set the chat type as Group chat. You can also set is as chat (one-to-one chat) or chat room.
message.chatType = AgoraChatTypeGroupChat;
// message.chatType = AgoraChatTypeGroupChat;
// Sends the message
[[AgoraChatClient sharedClient].chatManager sendMessage:message
progress:nil
@@ -229,7 +230,7 @@ AgoraChatMessage *message = [[AgoraChatMessage alloc] initWithConversationID:toC
ext:messageExt];
message.chatType = AgoraChatTypeChat;
// Set the chat type as Group chat. You can also set is as chat (one-to-one chat) or chat room.
message.chatType = AgoraChatTypeGroupChat;
// message.chatType = AgoraChatTypeGroupChat;
// Sends the message
[[AgoraChatClient sharedClient].chatManager sendMessage:message
progress:nil
@@ -269,7 +270,7 @@ AgoraChatMessage *message = [[AgoraChatMessage alloc] initWithConversationID:toC
ext:messageExt];
message.chatType = AgoraChatTypeChat;
// Set the chat type as Group chat. You can also set is as chat (one-to-one chat) or chat room.
message.chatType = AgoraChatTypeGroupChat;
// message.chatType = AgoraChatTypeGroupChat;
// Sends the message
[[AgoraChatClient sharedClient].chatManager sendMessage:message
progress:nil
@@ -290,7 +291,7 @@ AgoraChatMessage *message = [[AgoraChatMessage alloc] initWithConversationID:toC
ext:messageExt];
message.chatType = AgoraChatTypeChat;
// Set the chat type as Group chat. You can also set is as chat (one-to-one chat) or chat room.
message.chatType = AgoraChatTypeGroupChat;
// message.chatType = AgoraChatTypeGroupChat;
// Sends the message
[[AgoraChatClient sharedClient].chatManager sendMessage:message
progress:nil
@@ -315,7 +316,7 @@ The following code example shows how to create and send a customized message:
```objective-c
// Set event as the custom message event, for example "userCard".
// Set ext as the extension field of the event, for example as uid, nichname, and avator.
// Set ext as the extension field of the event, for example as uid, nickname, and avatar.
AgoraChatCustomMessageBody* body = [[AgoraChatCustomMessageBody alloc] initWithEvent:@"userCard" ext:@{@"uid":aUid ,@"nickname":aNickName,@"avatar":aUrl}];
AgoraChatMessage *message = [[AgoraChatMessage alloc] initWithConversationID:toChatUsername
from:fromChatUsername
@@ -324,7 +325,7 @@ AgoraChatMessage *message = [[AgoraChatMessage alloc] initWithConversationID:toC
ext:messageExt];
message.chatType = AgoraChatTypeChat;
// Set the chat type as Group chat. You can also set is as chat (one-to-one chat) or chat room.
message.chatType = AgoraChatTypeGroupChat;
// message.chatType = AgoraChatTypeGroupChat;
// Sends the message.
[[AgoraChatClient sharedClient].chatManager sendMessage:message
progress:nil
Original file line number Diff line number Diff line change
@@ -33,25 +33,26 @@ class ChatMessageCallback implements ChatMessageStatusCallback {
.catch((reason) => {
// The sending operation fails and the log is printed here.
console.log("send message operation fail.", reason);
});
})
};
```
Use the `ChatMessage` class to create a message, and `ChannelManager` to send the message.

```typescript
// Set the message type. The SDK supports 8 message types. For details, see descriptions in ChatMessageType.
// You can send different types of messages by setting this parameter.
// Set the message type. The SDK supports 8 message types.
const messageType = ChatMessageType.TXT;
// Set the user ID of the message recipient.
// Set `targetId` to the user ID of the peer user in one-to-one chat, group ID in group chat, and chat room ID in room chat.
const targetId = "tom";
// Set the chat type as a peer-to-peer chat, group chat, or chat room. For details, see descriptions in ChatMessageChatType.
// Set `chatType` as `PeerChat`, `GroupChat`, or `ChatRoom` for one-to-one chat, group chat, or room chat.
const chatType = ChatMessageChatType.PeerChat;
// Construct the message. For different message types, you need to set the different parameters.
// Construct the message. Parameters vary with message types.
let msg: ChatMessage;
if (messageType === ChatMessageType.TXT) {
// For a text message, set the message content.
const content = "This is text message";
msg = ChatMessage.createTextMessage(targetId, content, chatType);
} else if (messageType === ChatMessageType.IMAGE) {
// For am image message, set the file path, width, height, and display name of the image file.
// For an image message, set the file path, width, height, and display name of the image file.
const filePath = "/data/.../image.jpg";
const width = 100;
const height = 100;
Original file line number Diff line number Diff line change
@@ -5,16 +5,18 @@
Use the `Message` class to create a text message, and `IChannelManager` to send the message.

```csharp
// Call CreateTextSendMessage to create a text message. Set `content` as the content of the text message, and `toChatUsernames` the user ID of the message recipient.
Message msg = Message.CreateTextSendMessage(toChatUsername, content);
// Set the message type using the `MessageType` attribute in `Message`.
// You can set `MessageType` as `Chat`, `Group`, or `Room`, which indicates whether to send the message to a peer user, a chat group, or a chat room.
// Call CreateTextSendMessage to create a text message.
// Set `content` as the content of the text message.
// Set `conversationId` to the user ID of the peer user in one-to-one chat, group ID in group chat, and chat room ID in room chat.
Message msg = Message.CreateTextSendMessage(conversationId, content);
// Set `MessageType` in `Message` as `Chat`, `Group`, or `Room` for one-to-one chat, group chat, or room chat.
msg.MessageType = MessageType.Group;
// Set the priority of chat room messages. The default priority is `Normal`, indicating the normal priority.
msg.MessageType = MessageType.Room;
msg.SetRoomMessagePriority(RoomMessagePriority.High);
// msg.MessageType = MessageType.Room;
// msg.SetRoomMessagePriority(RoomMessagePriority.High);
// Call SendMessage to send the message.
// When sending the message, you can instantiate a `Callback` object to listen for the result of the message sending. You can also update the message state in this callback, for example, by adding a pop-up box that reminds the message sending fails.
// When sending the message, you can instantiate a `Callback` object to listen for the result of the message sending.
// You can also update the message state in this callback, for example, by adding a pop-up box that reminds the message sending fails.
SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack(
onSuccess: () => {
Debug.Log($"{msg.MsgId} Message sending succeeds.");
@@ -39,7 +41,7 @@ You can set the priority for all types of messages in the chat room. See code ex

You can use `IChatManagerDelegate` to listen for message events. You can add multiple `IChatManagerDelegates` to listen for multiple events. When you no longer listen for an event, ensure that you remove the delegate.

When a message arrives, the recipient receives an `OnMessgesReceived` callback. Each callback contains one or more messages. You can traverse the message list, and parse and render these messages in this callback and render these messages.
When a message arrives, the recipient receives an `OnMessagesReceived` callback. Each callback contains one or more messages. You can traverse the message list, and parse and render these messages in this callback and render these messages.

```csharp
// Inherit and instantiate IChatManagerDelegate.
Original file line number Diff line number Diff line change
@@ -10,18 +10,18 @@ function sendPrivateText() {
let option = {
// Set the message content.
msg: "message content",
// Set the username of the receiver.
to: "username",
// Set the chat type
// Set the user ID of the recipient for one-to-one chat, group ID for group chat, or chat room ID for room chat.
to: "userId",
// Set `chatType` as `singleChat` for one-to-one chat, `groupChat` for group chat, or `chatRoom` for room chat.
chatType: "singleChat",
};
// Create a text message.
let msg = WebIM.message.create(opt);
// Call send to send the message
conn.send(msg).then(()=>{
console.log("send private text Success");
let msg = AC.message.create(option);
// Call `send` to send the message
conn.send(msg).then((res)=>{
console.log("Send message success",res);
}).catch((e)=>{
console.log("Send private text error");
console.log("Send message fail",e);
});
}
```
@@ -47,7 +47,7 @@ function sendTextMessage() {
to: "chat room ID",
chatType: "chatRoom",
};
let msg = WebIM.message.create(opt);
let msg = AC.message.create(opt);
conn.send(msg).then(()=>{
console.log("Send message success");
}).catch((e)=>{
@@ -64,7 +64,7 @@ When a message arrives, the recipient receives an `onXXXMessage` callback. Each

```javascript
// Use `addEventHandler` to listen for callback events.
WebIM.conn.addEventHandler("eventName",{
connection.addEventHandler("eventName",{
// Occurs when the app is connected.
onOpened: function (message) {},
// Occurs when the connection is lost.
@@ -150,7 +150,7 @@ connection
```
You can also use `onRecallMessage` to listen for the message recall state:
```javascript
WebIM.conn.addEventHandler('MESSAGES',{
connection.addEventHandler('MESSAGES',{
onRecallMessage: => (msg) {
// You can insert a message here, for example, XXX has recalled a message.
console.log('Recalling the message succeeds',msg)
@@ -177,11 +177,11 @@ Refer to the following code example to create and send a voice message:
```javascript
var sendPrivateAudio = function () {
// Create a voice message.
var msg = new WebIM.message('audio');
var msg = new AC.message('audio');
// Select the local audio file.
var input = document.getElementById('audio');
// Turn the audio file to a binary file.
var file = WebIM.utils.getFileUrl(input);
var file = AC.utils.getFileUrl(input);
var allowType = {
'mp3': true,
'amr': true,
@@ -213,7 +213,7 @@ Refer to the following code example to create and send a voice message:
ext: {file_length: file.data.size}
};
// Create a voice message.
var msg = WebIM.message.create(option);
var msg = AC.message.create(option);
// Call send to send the voice message.
conn.send(msg).then((res)=>{
// Occurs when the audio file is successfully sent.
@@ -234,7 +234,7 @@ Refer to the following code example to create and send an image message:
// Select the local image file.
var input = document.getElementById("image");
// Turn the image to a binary file.
var file = WebIM.utils.getFileUrl(input);
var file = AC.utils.getFileUrl(input);
var allowType = {
jpg: true,
gif: true,
@@ -268,7 +268,7 @@ Refer to the following code example to create and send an image message:
},
};
// Create a voice message.
var msg = WebIM.message.create(option);
var msg = AC.message.create(option);
// Call send to send the voice message.
conn.send(msg).then((res)=>{
// Occurs when the audio file is successfully sent.
@@ -296,7 +296,7 @@ To send a URL image message, make sure you set `useOwnUploadFun` as `true`.
to: "username",
};
// Create an image message.
var msg = WebIM.message.create(option);
var msg = AC.message.create(option);
// Call send to send to image file.
conn.send(msg);
};
@@ -311,7 +311,7 @@ Refer to the following code example to create and send a video message:
// Select the local video file.
var input = document.getElementById("video");
// Turn the video to a binary file.
var file = WebIM.utils.getFileUrl(input);
var file = AC.utils.getFileUrl(input);
var allowType = {
mp4: true,
wmv: true,
@@ -343,7 +343,7 @@ Refer to the following code example to create and send a video message:
ext: {file_length: file.data.size},
};
// Create a video message.
var msg = WebIM.message.create(option);
var msg = AC.message.create(option);
// Call send to send the video message.
conn.send(msg).then((res)=>{
// Occurs when the message is sent.
@@ -364,7 +364,7 @@ Refer to the following code example to create, send, and receive a file message:
// Select the local file.
var input = document.getElementById("file");
// Turn the file message to a binary file.
var file = WebIM.utils.getFileUrl(input);
var file = AC.utils.getFileUrl(input);
var allowType = {
jpg: true,
gif: true,
@@ -399,7 +399,7 @@ Refer to the following code example to create, send, and receive a file message:
ext: {file_length: file.data.size},
};
// Create a file message.
var msg = WebIM.message.create(option);
var msg = AC.message.create(option);
// Call send to send the file message.
conn.send(msg).then((res) => {
// Occurs when the file message is sent.
@@ -411,6 +411,35 @@ Refer to the following code example to create, send, and receive a file message:
}
};
```
### Send a location message
To send and receive a location message, you need to integrate a third-party map service provider. When sending a location message, you get the longitude and latitude information of the location from the map service provider; when receiving a location message, you extract the received longitude and latitude information and displays the location on the third-party map.
```javascript
const sendLocMsg = () => {
let coords;
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function (position) {
coords = position.coords;
let option = {
chatType: "singleChat",
type: "loc",
to: "username",
addr: "London",
buildingName: "Digital Building",
lat: Math.round(coords.latitude),
lng: Math.round(coords.longitude),
};
let msg = AC.message.create(option);
conn.send(msg).then((res)=>{
console.log("Send message success", res);
}).catch((e)=>{
console.log("Send message fail", e);
});
})
}
}
```
### Send a CMD message
CMD messages are command messages that instruct a specified user to take a certain action. The recipient deals with the command messages themselves.
@@ -430,7 +459,7 @@ var options = {
ext :{'extmsg':'extends messages'}
}
// Create a CMD message.
var msg = WebIM.message.create(options);
var msg = AC.message.create(options);
// Call send to send the CMD message.
conn.send(msg).then((res)=>{
// Occurs when the message is sent.
@@ -464,7 +493,7 @@ var sendCustomMsg = function () {
ext: {},
}
// Create a custom message.
var msg = WebIM.message.create(options);
var msg = AC.message.create(options);
// Call send to send the custom message.
conn.send(msg).then((res)=>{
// Occurs when the message is sent.
@@ -494,7 +523,7 @@ function sendPrivateText() {
},
}
}
let msg = WebIM.message.create(options);
let msg = AC.message.create(options);
// Call send to send the extended message.
conn.send(msg).then((res)=>{
console.log("send private text Success");
Original file line number Diff line number Diff line change
@@ -5,16 +5,18 @@
Use the `Message` class to create a text message, and `IChannelManager` to send the message.

```csharp
// Call CreateTextSendMessage to create a text message. Set `content` as the content of the text message, and `toChatUsernames` the user ID of the message recipient.
Message msg = Message.CreateTextSendMessage(toChatUsername, content);
// Set the message type using the `MessageType` attribute in `Message`.
// You can set `MessageType` as `Chat`, `Group`, or `Room`, which indicates whether to send the message to a peer user, a chat group, or a chat room.
// Call CreateTextSendMessage to create a text message.
// Set `content` as the content of the text message.
// Set `conversationId` to the user ID of the peer user in one-to-one chat, group ID in group chat, and chat room ID in room chat.
Message msg = Message.CreateTextSendMessage(conversationId, content);
// Set `MessageType` in `Message` as `Chat`, `Group`, or `Room` for one-to-one chat, group chat, or room chat.
msg.MessageType = MessageType.Group;
//Set the priority of chat room messages. The default priority is `Normal`, indicating the normal priority.
msg.MessageType = MessageType.Room;
msg.SetRoomMessagePriority(RoomMessagePriority.High);
// Set the priority of chat room messages. The default priority is `Normal`, indicating the normal priority.
// msg.MessageType = MessageType.Room;
// msg.SetRoomMessagePriority(RoomMessagePriority.High);
// Call SendMessage to send the message.
// When sending the message, you can instantiate a `Callback` object to listen for the result of the message sending. You can also update the message state in this callback, for example, by adding a pop-up box that reminds the message sending fails.
// When sending the message, you can instantiate a `Callback` object to listen for the result of the message sending.
// You can also update the message state in this callback, for example, by adding a pop-up box that reminds the message sending fails.
SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack(
onSuccess: () => {
Debug.Log($"{msg.MsgId} Message sending succeeds.");
@@ -39,7 +41,7 @@ You can set the priority for all types of messages in the chat room. See code ex

You can use `IChatManagerDelegate` to listen for message events. You can add multiple `IChatManagerDelegates` to listen for multiple events. When you no longer listen for an event, ensure that you remove the delegate.

When a message arrives, the recipient receives an `OnMessgesReceived` callback. Each callback contains one or more messages. You can traverse the message list, and parse and render these messages in this callback and render these messages.
When a message arrives, the recipient receives an `OnMessagesReceived` callback. Each callback contains one or more messages. You can traverse the message list, and parse and render these messages in this callback and render these messages.

```csharp
// Inherit and instantiate IChatManagerDelegate.
Original file line number Diff line number Diff line change
@@ -59,7 +59,7 @@ You can call `unsubscribe` to unsubscribe from the presence statuses of the spec
You can call `fetchSubscribedMembersWithPageNum` to retrieve the list of your subscriptions in a paginated list, as shown in the following code sample:
```objc
[[AgoraChatClient sharedClient] presenceManager] fetchSubscribedMembersWithPageNum:0 pageSize:50 Completion:^(NSArray<NSString*>* members,AgoraChatError*error){
[[[AgoraChatClient sharedClient] presenceManager] fetchSubscribedMembersWithPageNum:0 pageSize:50 Completion:^(NSArray<NSString*>* members,AgoraChatError*error){
}];
```

@@ -68,7 +68,7 @@ You can call `fetchSubscribedMembersWithPageNum` to retrieve the list of your su
You can call `fetchPresenceStatus` to retrieve the current presence statuses of the specified users without the need to subscribe to them, as shown in the following code sample:

```objc
[[AgoraChatClient sharedClient] presenceManager] fetchPresenceStatus:@[@"Alice",@"Tom"] completion:^(NSArray<AgoraChatPresence*>* presences,AgoraChatError*error){
[[[AgoraChatClient sharedClient] presenceManager] fetchPresenceStatus:@[@"Alice",@"Tom"] completion:^(NSArray<AgoraChatPresence*>* presences,AgoraChatError*error){
}];
```

Original file line number Diff line number Diff line change
@@ -59,7 +59,7 @@ conn.unsubscribePresence(payload).then(res => {console.log(res)})

### Retrieve the list of subscriptions

You can call `getSubscribedPresenceList` to retrieve the list of your subscriptions in a paginated list, as shown in the following code sample:
You can call `getSubscribedPresencelist` to retrieve the list of your subscriptions in a paginated list, as shown in the following code sample:

```javascript
let option = {
Original file line number Diff line number Diff line change
@@ -59,12 +59,12 @@ conn
});
```

### Retrieve the reaction in the roaming message
### Retrieve the reaction in the historical message from the server

When calling `fetchHistoryMessages` to retrieve historical messages from the server, if the message has a reaction attached to it, the retrieved message body also contains the information of the reaction.
When calling `getHistoryMessages` to retrieve historical messages from the server, if the message has a reaction attached to it, the retrieved message body also contains the information of the reaction.

```javascript
conn.fetchHistoryMessages({ queue: "user", count: 20 }).then((messages) => {
conn.getHistoryMessages({ targetId:'targetId',chatType:'groupChat', pageSize: 20 }).then((messages) => {
console.log(messages);
});
```
1 change: 1 addition & 0 deletions shared/chat-sdk/client-api/reaction/understand/web.mdx
Original file line number Diff line number Diff line change
@@ -4,5 +4,6 @@
- `deleteReaction`: Removes the reaction from the specified message.
- `getReactionList`: Retrieves a list of reactions from the server.
- `getReactionDetail`: Retrieves the details of the reaction from the server.
- `getHistoryMessages`:Retrieves the reactions in historical messages from the server.

</PlatformWrapper>
Original file line number Diff line number Diff line change
@@ -7,12 +7,12 @@ Sending a thread message is similar to sending a message in a chat group. The di
```java
// Calls `createTxtSendMessage` to create a text message.
// Sets `content` to the content of the text message.
// Sets `chatThreadId` to the ID of a thread that receives the text message.
// Sets `chatThreadId` to the thread ID.
ChatMessage message = ChatMessage.createTxtSendMessage(content, chatThreadId);
// Sets `ChatType` to `GroupChat` as a thread that belongs to a chat group.
// Sets `ChatType` to `GroupChat` as a thread belongs to a chat group.
message.setChatType(ChatType.GroupChat);
// Sets `isChatThreadMessage` to `true` to mark this message as a thread message.
message.setisChatThreadMessage(true);
message.setIsChatThreadMessage(true);
// Calls `setMessageStatusCallback` to listen for the message sending status. You can implement subsequent settings in this callback, for example, displaying a pop-up if the message sending fails.
message.setMessageStatusCallback(new CallBack() {
@Override
@@ -86,25 +86,44 @@ MessageListener msgListener = new MessageListener() {

### Retrieve thread messages

Whether to retrieve thread messages from the server or local database depends on your production context.
You can retrieve thread messages locally or from the server, depending on your production environment.

When you join a thread, messages are displayed in chronological order by default. In this case, Agora recommends that you retrieve the historical messages of the thread from the server. When you recall a thread message, Agora recommend that you insert the recall notification in the local database.
You can check `ChatConversation#isChatThread()` to determine whether the current conversation is a thread conversation.

#### Retrieve thread messages from the server
#### Retrieve messages of a thread from the server

For details about how to retrieve messages from the server, see <Link to="/agora-chat/client-api/messages/retrieve-messages#retrieve-historical-messages-of-the-specified-conversation">Retrieve Historical Messages</Link>.
You can call `asyncFetchHistoryMessage` to retrieve messages of a thread from the server. The only difference between retrieving messages of a thread from the server and retrieving group messages is that a thread ID needs to be passed in for the former and a group ID is required for the latter.

#### Retrieve the conversation of a thread from the memory and local database
```java
String chatThreadId = "{your chatThreadId}";
Conversation.ConversationType type = Conversation.ConversationType.GroupChat;
int pageSize = 10;
String startMsgId = "";// Starting message ID for retrieving. If you pass in an empty string, the SDK will retrieve messages according to the search direction while ignoring this parameter.
Conversation.SearchDirection direction = Conversation.SearchDirection.DOWN;

ChatClient.getInstance().chatManager().asyncFetchHistoryMessage(chatThreadId, type,
pageSize, startMsgId, direction, new ValueCallBack<CursorResult<ChatMessage>>() {
@Override
public void onSuccess(CursorResult<ChatMessage> value) {

}

@Override
public void onError(int error, String errorMsg) {

}
});
```

#### Retrieve messages of a thread locally

By calling [`getAllConversations`](/agora-chat/client-api/messages/manage-messages#retrieve-conversations), you can only retrieve the conversations of one-to-one chats or group chats. To retrieve the conversation of a thread, refer to the following code sample:
By calling [`loadAllConversations`](/agora-chat/client-api/messages/manage-messages#retrieve-conversations), you can only retrieve local one-to-one chat conversations and group conversations. To retrieve messages of a thread locally, refer to the following code sample:

```java
// Sets the conversation type to group chat as a thread belongs to a chat group.
// Sets `isChatThread` to `true` to mark the conversation as a thread.
ChatConversation conversation = ChatClient.getInstance().chatManager().getConversation(chatThreadId, ChatConversationType.GroupChat, createIfNotExists, isChatThread);
// Retrieves all messages in the specified thread from the memory.
List<ChatMessage> messages = conversation.getAllMessages();
// Retrieves more messages in the specified thread from the local database. The SDK automatically loads and stores the retrieved messages to the memory.
// Retrieves messages in the specified thread from the local database. The SDK automatically loads and stores the retrieved messages to the memory.
List<ChatMessage> messages = conversation.loadMoreMsgFromDB(startMsgId, pagesize, searchDirection);
```

Original file line number Diff line number Diff line change
@@ -5,13 +5,13 @@
Sending a thread message is similar to sending a message in a chat group. The difference lies in the `isChatThreadMessage` field, as shown in the following code sample:

```dart
// Sets `targetGroup` to the ID of the chat group that receives the message.
// Sets `chatThreadId` to thread ID.
// Sets `content` to the message content.
ChatMessage msg = ChatMessage.createTxtSendMessage(
targetId: targetGroup,
chatThreadId: threadId,
content: content,
);
// Sets `ChatType` to GroupChat as a thread that belongs to a chat group.
// Sets `ChatType` to GroupChat as a thread belongs to a chat group.
msg.chatType = ChatType.GroupChat;
// Sets `isChatThreadMessage` to `true` to mark this message as a thread message.
msg.isChatThreadMessage = true;
@@ -77,8 +77,56 @@ Once a message is recalled in a thread, all chat group members receive the `Chat
ChatClient.getInstance.chatThreadManager.removeEventHandler("UNIQUE_HANDLER_ID");
```

### Retrieve thread messages from the server
### Retrieve thread messages

For details about how to retrieve messages from the server, see <Link to="/agora-chat/client-api/messages/retrieve-messages#retrieve-historical-messages-of-the-specified-conversation">Retrieve Conversations and Messages from Server</Link>.
You can retrieve thread messages locally or from the server, depending on your production environment.

You can check `ChatConversation#isChatThread()` to determine whether the current conversation is a thread conversation.

#### Retrieve messages of a thread from the server

You can call `fetchHistoryMessages` to retrieve messages of a thread from the server. The only difference between retrieving messages of a thread from the server and retrieving group messages is that a thread ID needs to be passed in for the former and a group ID is required for the latter.

```dart
try {
// The thread ID.
String threadId = "threadId";
// The conversation type is set to `GroupChat` as a thread belongs to a group conversation.
ChatConversationType convType = ChatConversationType.GroupChat;
// The number of thread messages that you expect to get on each page.
int pageSize = 10;
// The starting message ID for retrieving.
String startMsgId = "";
ChatCursorResult<ChatMessage?> cursor =
await ChatClient.getInstance.chatManager.fetchHistoryMessages(
conversationId: convId,
type: convType,
pageSize: pageSize,
startMsgId: startMsgId,
);
} on ChatError catch (e) {
}
```

#### Retrieve messages of a thread locally

By calling [`loadAllConversations`](/agora-chat/client-api/messages/manage-messages#retrieve-conversations), you can only retrieve local one-to-one chat conversations and group conversations. To retrieve messages of a thread locally, refer to the following code sample:

```dart
try {
// The thread ID.
String threadId = "threadId";
// The conversation type is set to `GroupChat` as a thread belongs a group conversation.
ChatConversationType convType = ChatConversationType.GroupChat;
ChatConversation? conversation = await ChatClient.getInstance.chatManager
.getConversation(threadId, type: convType);
// The starting message for retrieving.
String startMsgId = "startMsgId";
// The number of messages that you expect to retrieve on each page.
int pageSize = 10;
List<ChatMessage>? list = await conversation?.loadMessages(
startMsgId: startMsgId, loadCount: pageSize);
} on ChatError catch (e) {}
```

</PlatformWrapper>
Original file line number Diff line number Diff line change
@@ -7,15 +7,15 @@ Sending a thread message is similar to sending a message in a chat group. The di
```objc
// Calls `initWithConversationID` to create a text message.
// Sets `*message` to the content of the text message.
// Sets `*to` to the ID of a thread that receives the text message.
// Sets `chatThreadId` to the thread ID.
NSString *from = [[AgoraChatClient sharedClient] currentUsername];
NSString *to = self.currentConversation.conversationId;
AgoraChatMessage *message = [[AgoraChatMessage alloc] initWithConversationID:to from:from to:to body:aBody ext:aExt];
NSString *chatThreadId = self.currentConversation.conversationId;
AgoraChatMessage *message = [[AgoraChatMessage alloc] initWithConversationID:chatThreadId from:from to:chatThreadId body:aBody ext:aExt];
// Specifies whether a read receipt is required for this text message.
if([aExt objectForKey:MSG_EXT_READ_RECEIPT]) {
message.isNeedGroupAck = YES;
}
// Sets `chatType` to `AgoraChatTypeGroupChat` as a thread that belongs to a chat group.
// Sets `chatType` to `AgoraChatTypeGroupChat` as a thread belongs to a chat group.
message.chatType = (AgoraChatType)self.conversationType;
// Sets `isChatThread` to `YES` to mark this message as a thread message.
message.isChatThreadMessage = self.isChatThread;
@@ -61,8 +61,28 @@ Once a message is recalled in a thread, all chat group members receive the `Agor
{}
```

### Retrieve thread messages from the server
### Retrieve thread messages

For details about how to retrieve messages from the server, see <Link to="/agora-chat/client-api/messages/retrieve-messages#retrieve-historical-messages-of-the-specified-conversation">Retrieve Historical Messages</Link>.
You can retrieve thread messages locally or from the server, depending on your production environment.

You can check `AgoraChatConversation#isChatThread()` to determine whether the current conversation is a thread conversation.

#### Retrieve messages of a thread from the server

You can call `asyncFetchHistoryMessagesFromServer` to retrieve messages of a thread from the server. The only difference between retrieving messages of a thread from the server and retrieving group messages is that a thread ID needs to be passed in for the former and a group ID is required for the latter.

```objc
[AgoraChatClient.sharedClient.chatManager asyncFetchHistoryMessagesFromServer:@"threadId" conversationType:AgoraChatConversationTypeGroupChat startMessageId:@"" fetchDirection:AgoraChatMessageFetchHistoryDirectionUp pageSize:20 completion:^(AgoraChatCursorResult<AgoraChatMessage *> * _Nullable aResult, AgoraChatError * _Nullable aError) {

}];
```
#### Retrieve messages of a thread locally

By calling [`getAllConversations`](/agora-chat/client-api/messages/manage-messages#retrieve-conversations), you can only retrieve local one-to-one chat conversations and group conversations. To retrieve messages of a thread locally, refer to the following code sample:
```objc
AgoraChatConversation *conversation = [AgoraChatClient.sharedClient.chatManager getConversation:@"threadId" type:AgoraChatConversationTypeGroupChat createIfNotExist:NO isThread:YES];
[conversation loadMessagesStartFromId:msgId count:50 searchDirection:AgoraChatMessageSearchDirectionUp completion:^(NSArray *aMessages, AgoraChatError *aError) {
}];
```

</PlatformWrapper>
Original file line number Diff line number Diff line change
@@ -5,11 +5,13 @@
Sending a thread message is similar to sending a message in a chat group. The difference lies in the `isChatThread` field, as shown in the following code sample:

```typescript
// Sets `targetId` to the ID of the chat group that receives the message.
// Sets `chatThreadId` to the thread ID.
// Sets `content` to the message content.
// Sets `chatType` to a group chat as a thread that belongs to a chat group.
// Sets `chatType` to `GroupChat` as a thread belongs to a chat group.
// Sets `isChatThread` to `true` to mark this message as a thread message.
ChatMessage message = ChatMessage.createTextMessage(targetId, content, chatType, {isChatThread});
const message = ChatMessage.createTextMessage(chatThreadId, content, chatType, {
isChatThread: true,
});
// Implements `ChatMessageCallback` to listen for the message sending event.
const callback = new ChatMessageCallback();
// Sends the message.
@@ -77,8 +79,69 @@ class ChatMessageEvent implements ChatMessageEventListener {
```


### Retrieve thread messages from the server
### Retrieve thread messages

For details about how to retrieve messages from the server, see <Link to="/agora-chat/client-api/messages/retrieve-messages#retrieve-historical-messages-of-the-specified-conversation">Retrieve Conversations and Messages from Server</Link>.
You can retrieve thread messages locally or from the server, depending on your production environment.

You can check `ChatConversation#isChatThread()` to determine whether the current conversation is a thread conversation.

#### Retrieve messages of a thread from the server

You can call `asyncFetchHistoryMessage` to retrieve messages of a thread from the server. The only difference between retrieving messages of a thread from the server and retrieving group messages is that a thread ID needs to be passed in for the former and a group ID is required for the latter.

```typescript
// chatThreadID: The thread ID.
const chatThreadID = "chatThreadID";
// The chat type is set to ChatConversationType.GroupChat as a thread belongs to a group.
const convType = ChatConversationType.GroupChat;
// The number of thread messages that you expect to get on each page.
const pageSize = 10;
// The starting message ID for retrieving.
const startMsgId = "";
// The message search direction.
const direction = ChatSearchDirection.UP;
ChatClient.getInstance()
.chatManager.fetchHistoryMessages(chatThreadID, chatType, {
pageSize,
startMsgId,
direction,
})
.then((messages) => {
console.log("get message success: ", messages);
})
.catch((reason) => {
console.log("load conversions fail.", reason);
});
```

#### Retrieve messages of a thread locally

By calling [`getAllConversations`](/agora-chat/client-api/messages/manage-messages#retrieve-conversations), you can only retrieve local one-to-one chat conversations and group conversations. To retrieve messages of a thread locally, refer to the following code sample:

```typescript
// Gets a thread conversation.
ChatClient.getInstance()
.chatManager.getThreadConversation(chatThreadID, createIfNeed)
.then((conv) => {
// Gets messages of the thread from the local database. The SDK automatically loads and stores the retrieved messages to the memory.
conv
.getMessages(
chatThreadID,
ChatConversationType.GroupChat,
startMsgId,
direction,
loadCount
)
.then((messages) => {
console.log("success.", messages);
})
.catch((reason) => {
console.log("fail.", reason);
});
})
.catch((reason) => {
console.log("fail.", reason);
});
```

</PlatformWrapper>
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@
Send a thread message is similar to send a message in a chat group. The difference lies in the `IsThread` field, as shown in the following code sample:

```csharp
// Creates a text message. `content` contains the message content, and `chatThreadId` contains the thread ID.
// Creates a text message. Sets `chatThreadId` to the thread ID and `content` to the message content.
Message msg = Message.CreateTextSendMessage(chatThreadId, content);
// Sets the message type. For thread messages, set `ChatType` as `GroupChat`.
msg.MessageType = MessageType.Group
@@ -78,21 +78,38 @@ For more information about recalling a message, see <Link to="/agora-chat/client

### Retrieve thread messages

A single thread displays the earliest message by default, users can retrieve the history messages from the server. If you want to handle thread messages both locally and from the server (), you can retrieve thread messages locally.
You can retrieve thread messages locally or from the server, depending on your production environment.

You can check `Conversation#IsThread()` to determine whether the current conversation is a thread conversation.

#### Retrieve thread messages from the server

For details about how to retrieve messages from the server, see <Link to="/agora-chat/client-api/messages/retrieve-messages#retrieve-historical-messages-of-the-specified-conversation">Retrieve Conversations and Messages from Server</Link>.
#### Retrieve messages of a thread from the server

#### Retrieve local messages
You can call `ChatManager#FetchHistoryMessagesFromServer` to retrieve messages of a thread from the server. The only difference between retrieving messages of a thread from the server and retrieving group messages is that a thread ID needs to be passed in for the former and a group ID is required for the latter.

Calling `EMChatManager#getAllConversations()` returns peer-to-peer messages and chat group messages but not thread messages. You can get specified thread messages from local database, as shown in the following code sample:
```c#
SDKClient.Instance.ChatManager.FetchHistoryMessagesFromServer(threadId, ConversationType.Group, startMsgId, pageSize, MessageSearchDirection.DOWN, new ValueCallBack<CursorResult<Message>>(
onSuccess: (result) =>
{
foreach (var msg in result.Data)
{
//process every msg
}
},
onError: (code, desc) =>
{
}
));
```

#### Retrieve messages of a thread locally

By calling `ChatManager#LoadAllConversations`, you can only retrieve local one-to-one chat conversations and group conversations. To retrieve messages of a thread locally, refer to the following code sample:

```csharp
// Specifies the conversation type by setting `ConversationType.Group` and setting `isChatThread` as `true`.
Conversation conversation = SDKClient.Instance.ChatManager.GetConversation(chatThreadId, EMConversationType.GroupChat, createIfNotExists, isChatThread);
// If you want to handle thread messages from your local database, use the following methods to retrieve the messages. The SDK automatically saves these messages.
// If you want to handle thread messages from your local database, use the following methods to retrieve the messages. The SDK automatically loads and stores the retrieved messages to the memory.
conversation.LoadMessages(startMsgId, count, direct, new ValueCallBack<List<Message>>(
onSuccess: (list) => {
Console.WriteLine($"LoadMessages found {list.Count} messages");
@@ -107,7 +124,4 @@ conversation.LoadMessages(startMsgId, count, direct, new ValueCallBack<List<Mess
));
```

**Note:**
You can identify a thread message by `Conversation#IsThread()`.

</PlatformWrapper>
Original file line number Diff line number Diff line change
@@ -9,8 +9,8 @@ function sendTextMessage() {
let option = {
chatType: 'groupChat', // Sets `chatType` to `groupChat` as a thread belongs to a chat group.
type: 'txt', // Sets `type` to `txt` to create and send a text message.
to: chatThreadId, // Sets `to` to the ID of a thread that receives the text message.
msg: 'message content', // Sets `msg` to the content of the text message.
to: chatThreadId, // Sets `to` to the thread ID.
msg: 'message content', // Sets `msg` to the content of the text message.
isChatThread:true, // Sets `isChatThread` to `true` to mark this message as a thread message.
}
// Calls `create` to create a text message.
@@ -77,8 +77,32 @@ conn.addEventHandler('MESSAGES',{
For more information about recalling a message, see <Link to="/agora-chat/client-api/messages/send-receive-messages#recall-a-message">Recall Messages</Link>.


### Retrieve thread messages from the server
### Retrieve messages of a thread from the server

For details about how to retrieve messages from the server, see <Link to="/agora-chat/client-api/messages/retrieve-messages#retrieve-historical-messages-of-the-specified-conversation">Retrieve Historical Messages</Link>.
You can call `ChatManager#FetchHistoryMessagesFromServer` to retrieve messages of a thread from the server. The only difference between retrieving messages of a thread from the server and retrieving group messages is that a thread ID needs to be passed in for the former and a group ID is required for the latter.

```javascript
let options = {
// The thread ID.
targetId: "threadId",
// The number of thread messages that you expect to get on each page. The value range is [1,50], with `20` as the default.
pageSize: 20,
// The starting message ID for retrieving. If you set this parameter to `-1`, `null`, or an empty string, the SDK retrieves messages from the latest one.
cursor: -1,
// The chat type is set to `groupChat` as a thread belongs to a group chat.
chatType: "groupChat",
// The message search direction: (Default): `up`: The SDK retrieves messages in the descending order of the time when the server receives the messages. `down`: The SDK retrieves messages in the ascending order of the time when the server receives the messages.
searchDirection: "up",
};
conn
.getHistoryMessages(options)
.then((res) => {
// Succeed in getting historical messages.
console.log(res);
})
.catch((e) => {
// Fail to get historical messages.
});
```

</PlatformWrapper>
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@
Send a thread message is similar to send a message in a chat group. The difference lies in the `IsThread` field, as shown in the following code sample:

```csharp
// Creates a text message. `content` contains the message content, and `chatThreadId` contains the thread ID.
// Creates a text message. Sets `chatThreadId` to the thread ID and `content` to the message content.
Message msg = Message.CreateTextSendMessage(chatThreadId, content);
// Sets the message type. For thread messages, set `ChatType` as `GroupChat`.
msg.MessageType = MessageType.Group
@@ -78,21 +78,37 @@ For more information about recalling a message, see <Link to="/agora-chat/client

### Retrieve thread messages

A single thread displays the earliest message by default, users can retrieve the history messages from the server. If you want to handle thread messages both locally and from the server (), you can retrieve thread messages locally.
You can retrieve thread messages locally or from the server, depending on your production environment.

You can check `Conversation#IsThread()` to determine whether the current conversation is a thread conversation.

#### Retrieve thread messages from the server
#### Retrieve messages of a thread from the server

For details about how to retrieve messages from the server, see <Link to="/agora-chat/client-api/messages/retrieve-messages#retrieve-historical-messages-of-the-specified-conversation">Retrieve Conversations and Messages from Server</Link>.
You can call `ChatManager#FetchHistoryMessagesFromServer` to retrieve messages of a thread from the server. The only difference between retrieving messages of a thread from the server and retrieving group messages is that a thread ID needs to be passed in for the former and a group ID is required for the latter.

#### Retrieve local messages
```c#
SDKClient.Instance.ChatManager.FetchHistoryMessagesFromServer(threadId, ConversationType.Group, startMsgId, pageSize, MessageSearchDirection.DOWN, new ValueCallBack<CursorResult<Message>>(
onSuccess: (result) =>
{
foreach (var msg in result.Data)
{
//process every message
}
},
onError: (code, desc) =>
{
}
));
```

#### Retrieve messages of a thread locally

Calling `EMChatManager#getAllConversations()` returns peer-to-peer messages and chat group messages but not thread messages. You can get specified thread messages from local database, as shown in the following code sample:
By calling `ChatManager#LoadAllConversations`, you can only retrieve local one-to-one chat conversations and group conversations. To retrieve messages of a thread locally, refer to the following code sample:

```csharp
// Specifies the conversation type by setting `ConversationType.Group` and setting `isChatThread` as `true`.
Conversation conversation = SDKClient.Instance.ChatManager.GetConversation(chatThreadId, EMConversationType.GroupChat, createIfNotExists, isChatThread);
// If you want to handle thread messages from your local database, use the following methods to retrieve the messages. The SDK automatically saves these messages.
// If you want to handle thread messages from your local database, use the following methods to retrieve the messages. The SDK automatically loads and stores the retrieved messages to the memory.
conversation.LoadMessages(startMsgId, count, direct, new ValueCallBack<List<Message>>(
onSuccess: (list) => {
Console.WriteLine($"LoadMessages found {list.Count} messages");
@@ -107,7 +123,4 @@ conversation.LoadMessages(startMsgId, count, direct, new ValueCallBack<List<Mess
));
```

**Note:**
You can identify a thread message by `Conversation#IsThread()`.

</PlatformWrapper>
Original file line number Diff line number Diff line change
@@ -42,6 +42,19 @@ ChatClient.getInstance().userInfoManager().updateOwnInfoByAttribute(UserInfoType
});
```

When you call the [RESTful API](../restful-api/user-attributes-management#setting-user-attributes) to set the user's nickname, avatar, contact information, email address, gender, signature, birthday and extension fields, pass the following keys to make sure that the client can obtain the settings:

| Field | Type | Description |
| :---------- | :----- | :----------------------------------------------------------- |
| `nickname` | String | The user nickname, which can contain at most 64 characters. |
| `avatarurl` | String | The user avatar URL, which can contain at most 256 characters. |
| `phone` | String | The user's phone number, which can contain at most 32 characters. |
| `mail` | String | The user's email address, which can contain at most 64 characters. |
| `gender` | Number | The user gender: <ul><li>`1`:Male; </li><li>`2`:Female;</li><li>(Default) `0`: Unknown;</li><li>Other values are invalid.</li></ul> |
| `sign` | String | The user's signature, which can contain at most 256 characters. |
| `birth` | String | The user's birthday, which can contain at most 256 characters. |
| `ext` | String | The extension fields. |

### Retrieve user attributes

You can use `fetchUserInfoByUserId` to retrieve the user attributes of the specified users. For each method call, you can retrieve the user attributes of a maximum of 100 users.
Original file line number Diff line number Diff line change
@@ -12,7 +12,18 @@ try {
}
```


When you call the [RESTful API](../restful-api/user-attributes-management#setting-user-attributes) to set the user's nickname, avatar, contact information, email address, gender, signature, birthday and extension fields, you must pass the following keys to make sure that the client can obtain the settings:

| Field | Type | Description |
| :---------- | :----- | :----------------------------------------------------------- |
| `nickname` | String | The user nickname, which can contain at most 64 characters. |
| `avatarurl` | String | The user avatar URL, which can contain at most 256 characters. |
| `phone` | String | The user's phone number, which can contain at most 32 characters. |
| `mail` | String | The user's email address, which can contain at most 64 characters. |
| `gender` | Number | The user gender: <ul><li>`1`:Male; </li><li>`2`:Female;</li><li>(Default) `0`: Unknown;</li><li>Other values are invalid.</li></ul> |
| `sign` | String | The user's signature, which can contain at most 256 characters. |
| `birth` | String | The user's birthday, which can contain at most 256 characters. |
| `ext` | String | The extension fields. |

### Retrieve user attributes

Original file line number Diff line number Diff line change
@@ -32,6 +32,19 @@ NSString *url = @"https://download-sdk.oss-cn-beijing.aliyuncs.com/downloads/IMD
}];
```

When you call the [RESTful API](../restful-api/user-attributes-management#setting-user-attributes) to set the user's nickname, avatar, contact information, email address, gender, signature, birthday and extension fields, you must pass the following keys to make sure that the client can obtain the settings:

| Field | Type | Description |
| :---------- | :----- | :----------------------------------------------------------- |
| `nickname` | String | The user nickname, which can contain at most 64 characters. |
| `avatarurl` | String | The user avatar URL, which can contain at most 256 characters. |
| `phone` | String | The user's phone number, which can contain at most 32 characters. |
| `mail` | String | The user's email address, which can contain at most 64 characters. |
| `gender` | Number | The user gender: <ul><li>`1`:Male; </li><li>`2`:Female;</li><li>(Default) `0`: Unknown;</li><li>Other values are invalid.</li></ul> |
| `sign` | String | The user's signature, which can contain at most 256 characters. |
| `birth` | String | The user's birthday, which can contain at most 256 characters. |
| `ext` | String | The extension fields. |

### Retrieve user attributes

You can use `fetchUserInfoById` to retrieve the user attributes of the specified users. For each method call, you can retrieve the user attributes of a maximum of 100 users.
Original file line number Diff line number Diff line change
@@ -27,6 +27,19 @@ ChatClient.getInstance()
});
```

When you call the [RESTful API](../restful-api/user-attributes-management#setting-user-attributes) to set the user's nickname, avatar, contact information, email address, gender, signature, birthday and extension fields, you must pass the following keys to make sure that the client can obtain the settings:

| Field | Type | Description |
| :---------- | :----- | :----------------------------------------------------------- |
| `nickname` | String | The user nickname, which can contain at most 64 characters. |
| `avatarurl` | String | The user avatar URL, which can contain at most 256 characters. |
| `phone` | String | The user's phone number, which can contain at most 32 characters. |
| `mail` | String | The user's email address, which can contain at most 64 characters. |
| `gender` | Number | The user gender: <ul><li>`1`:Male; </li><li>`2`:Female;</li><li>(Default) `0`: Unknown;</li><li>Other values are invalid.</li></ul> |
| `sign` | String | The user's signature, which can contain at most 256 characters. |
| `birth` | String | The user's birthday, which can contain at most 256 characters. |
| `ext` | String | The extension fields. |

### Retrieve user attributes

You can use `fetchUserInfoById` to retrieve the user attributes of the specified users. For each method call, you can retrieve the user attributes of a maximum of 100 users.
Original file line number Diff line number Diff line change
@@ -23,6 +23,19 @@ SDKClient.Instance.UserInfoManager.UpdateOwnInfo(userInfo, new CallBack(
));
```

When you call the [RESTful API](../restful-api/user-attributes-management#setting-user-attributes) to set the user's nickname, avatar, contact information, email address, gender, signature, birthday and extension fields, you must pass the following keys to make sure that the client can obtain the settings:

| Field | Type | Description |
| :---------- | :----- | :----------------------------------------------------------- |
| `nickname` | String | The user nickname, which can contain at most 64 characters. |
| `avatarurl` | String | The user avatar URL, which can contain at most 256 characters. |
| `phone` | String | The user's phone number, which can contain at most 32 characters. |
| `mail` | String | The user's email address, which can contain at most 64 characters. |
| `gender` | Number | The user gender: <ul><li>`1`:Male; </li><li>`2`:Female;</li><li>(Default) `0`: Unknown;</li><li>Other values are invalid.</li></ul> |
| `sign` | String | The user's signature, which can contain at most 256 characters. |
| `birth` | String | The user's birthday, which can contain at most 256 characters. |
| `ext` | String | The extension fields. |

### Retrieve user attributes

You can use `FetchUserInfoByUserId` to retrieve the user attributes of the specified users. For each method call, you can retrieve the user attributes of a maximum of 100 users.
Original file line number Diff line number Diff line change
@@ -32,6 +32,19 @@ WebIM.conn.updateUserInfo('nickname', 'Your nickname').then((res) => {
})
```

When you call the [RESTful API](../restful-api/user-attributes-management#setting-user-attributes) to set the user's nickname, avatar, contact information, email address, gender, signature, birthday and extension fields, you must pass the following keys to make sure that the client can obtain the settings:

| Field | Type | Description |
| :---------- | :----- | :----------------------------------------------------------- |
| `nickname` | String | The user nickname, which can contain at most 64 characters. |
| `avatarurl` | String | The user avatar URL, which can contain at most 256 characters. |
| `phone` | String | The user's phone number, which can contain at most 32 characters. |
| `mail` | String | The user's email address, which can contain at most 64 characters. |
| `gender` | Number | The user gender: <ul><li>`1`:Male; </li><li>`2`:Female;</li><li>(Default) `0`: Unknown;</li><li>Other values are invalid.</li></ul> |
| `sign` | String | The user's signature, which can contain at most 256 characters. |
| `birth` | String | The user's birthday, which can contain at most 256 characters. |
| `ext` | String | The extension fields.

### Retrieve user attributes

You can use `fetchUserInfoById` to retrieve the user attributes of the specified users. For each method call, you can retrieve the user attributes of a maximum of 100 users.
Original file line number Diff line number Diff line change
@@ -23,6 +23,19 @@ SDKClient.Instance.UserInfoManager.UpdateOwnInfo(userInfo, new CallBack(
));
```

When you call the [RESTful API](../restful-api/user-attributes-management#setting-user-attributes) to set the user's nickname, avatar, contact information, email address, gender, signature, birthday and extension fields, you must pass the following keys to make sure that the client can obtain the settings:

| Field | Type | Description |
| :---------- | :----- | :----------------------------------------------------------- |
| `nickname` | String | The user nickname, which can contain at most 64 characters. |
| `avatarurl` | String | The user avatar URL, which can contain at most 256 characters. |
| `phone` | String | The user's phone number, which can contain at most 32 characters. |
| `mail` | String | The user's email address, which can contain at most 64 characters. |
| `gender` | Number | The user gender: <ul><li>`1`:Male; </li><li>`2`:Female;</li><li>(Default) `0`: Unknown;</li><li>Other values are invalid.</li></ul> |
| `sign` | String | The user's signature, which can contain at most 256 characters. |
| `birth` | String | The user's birthday, which can contain at most 256 characters. |
| `ext` | String | The extension fields. |

### Retrieve user attributes

You can use `FetchUserInfoByUserId` to retrieve the user attributes of the specified users. For each method call, you can retrieve the user attributes of a maximum of 100 users.
397 changes: 239 additions & 158 deletions shared/chat-sdk/develop/_authentication.mdx

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions shared/chat-sdk/develop/_cross_border_proxy.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
With the development of economic globalization and the advancement of Internet technologies, cross-border dedicated proxy is indispensable for many enterprises. It can help enterprises better cope with the pressure of international competition and expand overseas markets.

In order to improve the instant messaging experience for enterprises conducting global business and meet the communication needs of end users in the Chinese mainland and other regions, Agora has set up dedicated lines from the Chinese mainland to Hong Kong and vice versa.

Online education enterprises are typical cases, where teachers and students tend to be located in different countries and regions. For example, American teachers teach English courses to Chinese students through online videos. Enabling the dedicated proxy can greatly improve the use experience of Agora Chat.

This service is disabled by default. To enable it, contact [support@agora.io](mailto:support@agora.io).
25 changes: 13 additions & 12 deletions shared/chat-sdk/develop/_setup-webhooks.mdx
Original file line number Diff line number Diff line change
@@ -62,29 +62,30 @@ To receive the HTTP callbacks, you need to configure rules for the pre- or post-

1. Log in to Agora Console and find your project on the Project Management page, then click the edit button.
2. Find **Chat** on the project editing page, and click **Configure**.
3. Click **Add Target Url** in the **Real-time Callback** section on the configuration page.
3. Choose **Features** > **Callback** and click **Add Callback Address** on the **Callback** page.

![1645523175808](https://web-cdn.agora.io/docs-files/1645523175808)
![](/images/chat/callback_addr_list.png)

4. To add a rule for pre-delivery callbacks, fill the following fields under the **pre send** tab and then click **Save**.
4. To add a rule for pre-delivery callbacks, fill the following fields under the **Pre send** tab and then click **Save**.

- Rule Name: Enter a name for the rule. Under one project, each rule must have a unique name.
- Chat Type: Select the types of chat this rule applies to.
- Message Type: Select the types of messages this rule applies to.
- Timeout: (Optional) Specify the time (in ms) that the Chat server should wait for the HTTP responses. The default value is 200 ms. If the reponse times out, the Chat server continues with the fallback action.
- Fallback Action: (Optional) Select the action of the Chat server when the HTTP response times out or returns errors. The default option is pass.
- Target Url: Enter the URL of your app server for receiving the pre-delivery callbacks. Supports both HTTP and HTTPS URLs.
- Rejection Behaviour: (Optional) Set whether to notify the message sender when their message is rejected. The default option is to not notify the message sender.
- Timeout: (Optional) Specify the time (in ms) that the Agora Chat server should wait for the HTTP responses. The default value is 200 ms. If the response times out, the Agora Chat server continues with the fallback action.
- Fallback Action: (Optional) Select the action of the Agora Chat server when the HTTP response times out or an error is returned. The default value is **Passed**.
- Report Error: (Optional) Set whether to notify the message sender when their message is rejected. The default value is **No**, indicating that the sender is not notified of the message delivery failure.
- Status: Set whether to enable this rule. The default value is **Enabled**.
- Callback Address: Enter the URL of your app server for receiving the pre-delivery callbacks. Both HTTP and HTTPS URLs are allowed.

5. To add a rule for post-delivery callbacks, fill the following fields under the **post send** tab and then click **Save**.
5. To add a rule for post-delivery callbacks, fill the following fields under the **Post send** tab and then click **Save**.

- Rule Name: Enter a name for the rule. Under one project, each rule must have a unique name.
- Callback Service: Select the types of chat or events this rule applies to.
- Message Type: Select the types of messages this rule applies to.
- Message Status: Select whether this rule applies to chat or offline messages, or both.
- To synchronize the chat history on your own server, select chat messages. All messages sent by the users are chat messages, regardless of the online status of the message receiver.
- To push message notifications, select offline messages. Messages sent to an offline user are counted as offline messages.
- Target Url: Enter the URL of your app server for receiving the post-delivery callbacks. Supports both HTTP and HTTPS URLs.
- Status: Set whether to enable this rule. The default value is **Disabled**.
- Callback Address: Enter the URL of your app server for receiving the post-delivery callbacks. Both HTTP and HTTPS URLs are allowed.

The rules take effect immediately.

@@ -101,10 +102,10 @@ To enhance the security of the callbacks, Chat includes a signature in the reque
To verify the signature in a callback, do the following:

1. Retrieve the following information:
- The callback ID, which is the callId paramater in the request body of the callback.
- The callback ID, which is the callId parameter in the request body of the callback.
- The secret assigned to the callback rule. You can find this value on the Chat configuration page in Agora Console.

![1645523345319](https://web-cdn.agora.io/docs-files/1645523345319)
![1645523345319](/images/chat/callback_secret.png)

- The callback timestamp, which is the timestamp parameter in the request body of the callback.

Original file line number Diff line number Diff line change
@@ -197,6 +197,8 @@ During the call, you can also listen for the following callback events:
}
```

When receiving the `callDidJoinChannel:uid` or `remoteUserDidJoinChannel:uid:username:` callback, the user needs to look up the Chat user ID corresponding to the Agora UID in you app server. If the Chat user ID is found, construct a dictionary with Agora UID and Chat user ID and then set it to the app using `setUsers:channelName:`.
### End the call
A one-to-one call ends as soon as one of the two users hangs up, while a group call ends only after the local user hangs up. When the call ends, the SDK triggers the `callDidEnd` callback.
Original file line number Diff line number Diff line change
@@ -81,7 +81,7 @@ The following screenshot gives an example of the user interface after sending a

### Receive the invitation

Once a call invitaion is sent, if the callee is online and available for a call, the callee receives the invitation in the `onInvite` callback. You can pop out a user interface that allows the callee to accept or decline the invitation in this callback.
Once a call invitation is sent, if the callee is online and available for a call, the callee receives the invitation in the `onInvite` callback. You can pop out a user interface that allows the callee to accept or decline the invitation in this callback.

```javascript
/**
2 changes: 1 addition & 1 deletion shared/chat-sdk/develop/callkit/project-setup/web.mdx
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@
1. In your terminal, run the following command to install the call kit:

```bash
npm install AgoraChatCallKit
npm install chat-callkit
```

2. Add the following line to import the callkit:
6 changes: 4 additions & 2 deletions shared/chat-sdk/develop/callkit/reference/web.mdx
Original file line number Diff line number Diff line change
@@ -21,12 +21,14 @@ Callbacks:
| onInvite | Occurs when the call invitation is received. |
| onStateChange | Occurs when the call state changes. |

Attributes
Attributes:

| Attribute | Description |
| --- | --- |
| contactAvatar | The avatar displayed during one-to-one calls. |
| groupAvatar | The avatar displayed during group calls.
| groupAvatar | The avatar displayed during group calls. |
| ringingSource | The ringtone file. |


### Sample project

8 changes: 6 additions & 2 deletions shared/chat-sdk/get-started/_enable.mdx
Original file line number Diff line number Diff line change
@@ -50,7 +50,7 @@ For details about these advanced features, see the following:

<Vg k="CONSOLE" /> assigns the following information to each project that enables <Vg k="CHAT" />:

- **Data Center**: <Vg k="COMPANY" /> provides several data centers for the service in different regions, including Beijing1 (China), Beijing VIP (China), Singapore, Frankfurt (Germany), and Virginia (USA). After the plan is changed, the data center remains unchanged.
- **Data Center**: <Vg k="COMPANY" /> provides several data centers for the service in different regions, including Singapore, Frankfurt (Germany), and Virginia (USA). After the plan is changed, the data center remains unchanged.
- **AppKey**: The unique identifier that <Vg k="CHAT" /> assigns to each app. The **AppKey** is of the form `${OrgName}#{AppName}`.
- **OrgName**: The unique identifier that <Vg k="CHAT" /> assigns to each enterprise (organization).
- **AppName**: The name that <Vg k="CHAT" /> assigns to each app. Each app under the same enterprise (organization) must have a unique App Name.
@@ -88,6 +88,11 @@ To register a user, do the following:

![](https://web-cdn.agora.io/docs-files/1664531162872)

### Generate an app token

In the **Data Center** section of the **Application Information** page, click **Generate** next to **Chat App Temp Token** to generate a token with app privileges.

![token_generate_app_token](/images/chat/token_generate_app_token.png)

### Generate a user token

@@ -107,7 +112,6 @@ For testing purposes, <Vg k="CONSOLE" /> supports generating temporary tokens fo

![](https://web-cdn.agora.io/docs-files/1664531214169)


## Change the <Vg k="CHAT" /> plan

1. Log in to the [<Vg k="CONSOLE" />](https://console.agora.io).
Original file line number Diff line number Diff line change
@@ -205,6 +205,8 @@ To implement this workflow in your <Vpl k="CLIENT" />, take the following steps:
);
agoraChatClient = ChatClient.getInstance;
await agoraChatClient.init(options);
// Notify the SDK that the Ul is ready. After the following method is executed, callbacks within ChatRoomEventHandler and ChatGroupEventHandler can be triggered.
await ChatClient.getlnstance.startCallback();
}
```

@@ -315,19 +317,23 @@ To implement this workflow in your <Vpl k="CLIENT" />, take the following steps:
targetId: recipientId,
content: messageContent,
);
msg.setMessageStatusCallBack(MessageStatusCallBack(
onSuccess: () {
displayMessage(messageContent, true);
messageBoxController.text = "";
messageContent = "";
FocusManager.instance.primaryFocus?.unfocus();
},
onError: (e) {
showLog(
"Send message failed, code: ${e.code}, desc: ${e.description}",
);
},
));
ChatClient.getInstance.chatManager.addMessageEvent(
"UNIQUE_HANDLER_ID",
ChatMessageEvent(
onSuccess: (msgId, msg) {
_addLogToConsole("on message succeed");
},
onProgress: (msgId, progress) {
_addLogToConsole("on message progress");
},
onError: (msgId, msg, error) {
_addLogToConsole(
"on message failed, code: ${error.code}, desc: ${error.description}",
);
},
),
);
ChatClient.getInstance.chatManager.removeMessageEvent("UNIQUE_HANDLER_ID");
agoraChatClient.chatManager.sendMessage(msg);
}
```
Original file line number Diff line number Diff line change
@@ -117,6 +117,7 @@ To implement this workflow in your <Vpl k="CLIENT" />, take the following steps:
private string token = "";
private string appKey = "";
private bool isJoined = false;
SDKClient agoraChatClient;
```

1. **Set up <Vpd k="NAME" /> when the <Vpl k="CLIENT" /> starts**
Original file line number Diff line number Diff line change
@@ -24,7 +24,7 @@ To integrate <Vpd k="NAME"/> into your app, do the following:
https://github.com/AgoraIO/AgoraChat_iOS.git
```

You see the available <Vg k="COMPANY" /> packages. In **<Vpd k="IOS_PACKAGE_NAME" />**, specify the latest <Vpd k="SDK" /> version, for example `1.0.9`. You can obtain the latest version information using [Maven Central Repository Search](https://search.maven.org/search?q=g:io.agora.rtc%20AND%20a:chat-sdk).
You see the available <Vg k="COMPANY" /> packages. In **<Vpd k="IOS_PACKAGE_NAME" />**, specify the latest <Vpd k="SDK" /> version, for example `1.0.9`. You can obtain the latest version information in the [release notes](../reference/release-notes).

1. Click **Add Package**. In the new window, click **Add Package**.

25 changes: 25 additions & 0 deletions shared/chat-sdk/get-started/get-started-sdk/reference/ios.mdx
Original file line number Diff line number Diff line change
@@ -1,5 +1,30 @@
<PlatformWrapper platform="ios">

### Integrate the SDK through CocoaPods

1. Install CocoaPods. For details, see [Getting Started with CocoaPods](https://guides.cocoapods.org/using/getting-started.html#getting-started).

1. In the Terminal, navigate to the project root directory and run the `pod init` command to create a text file `Podfile` in the project folder.

1. Open the `Podfile` file and add the Agora Chat SDK. Remember to replace `Your project target` with the target name of your project.

```swift
platform :ios, '11.0'

target 'Your project target' do
pod 'Agora_Chat_iOS'
end
```
1. In the project root directory, run the following command to integrate the SDK:

```swift
pod install
```

When the SDK is installed successfully, you can see `Pod installation complete!` in the Terminal and an `xcworkspace` file in the project folder.

1. Open the xcworkspace file in Xcode.

### API reference

- <Link to="{{Global.CHAT_SDK_API_IOS}}/interface_agora_chat_client.html#aa628257db8692884cc69e39cc6d7a58b">AgoraChatClient.initializeSDKWithOptions</Link>
46 changes: 2 additions & 44 deletions shared/chat-sdk/get-started/get-started-uikit/next-steps/web.mdx
Original file line number Diff line number Diff line change
@@ -2,48 +2,6 @@

This section includes more advanced features you can implement in your project.

### Applicable use cases

As a conversation component, `EaseChat` can be applied in a wide range of use cases, for example, by popping up the dialogue box for a click event, or adding callback events after the user is logged in.

```javascript
import React, { useState } from "react";
import { EaseChat } from "agora-chat-uikit";
const addListen = (res) => {
if(res.isLogin){
const WebIM = EaseChat.getSdk()
WebIM.conn.addEventHandler('testListen',{
onTextMessage:()=>{},
onError:()=>{},
...
})
}
}
const chat = () => {
return (
<div>
<EaseChat
appkey={'xxx'}
username={'xxx'}
agoraToken={'xxx'}
to={'xxx'}
successLoginCallback={addListener}
/>
<div/>
)
}
const app = () =>{
const [showSession, setShowSession] = useState(false);
return(
<div>
{ showSession && chat()}
<button onClick={()=>setShowSession(true)}>Launch the session</button>
<button onClick={()=>setShowSession(false)}>Close the session</button>
<div/>
)
}
```

### Customizable attributes

`EaseChat` provides the following attributes for customization. You can customize the features and layout by setting these attributes. To ensure the functionality of `EaseChat`, ensure that you set all the required parameters.
@@ -54,7 +12,7 @@ import { EaseChat } from "agora-chat-uikit";
| `username` |String| Yes | The user ID. |
| `agoraToken` |String| Yes | The <Vg k="COMPANY" /> token. |
| `to` |String| Yes | In one-to-one messaging, it is the user ID of the recipient; in group chat, it is the group ID.|
| `showByselfAvatar`|Bool| No | Whether to display the avatar of the current user.<ul><li>`true`: Yes</li><li>(Default) `false`: No</li></ul> |
| `showByselfAvatar`|Boolean| No | Whether to display the avatar of the current user.<ul><li>`true`: Yes</li><li>(Default) `false`: No</li></ul> |
| `easeInputMenu`|String| No | The mode of the input menu.<ul><li>(Default) `all`: The complete mode.</li><li>`noAudio`: No audio.</li><li>`noEmoji`: No emoji.</li><li>`noAudioAndEmoji`: No audio or emoji.</li><li>`onlyText`: Only text.</li></ul>
|`menuList`|Array| No |The extensions of the input box on the right panel.<br/>(Default) `menuList`: `[ {name:'Send a pic', value:'img'},{name:'Send a file', value:'file'}]` |
|`handleMenuItem`|`function({item, key}`) | No | The callback event triggered by clicking on the right panel of the input box.|
@@ -68,7 +26,7 @@ In scenarios where you want to add your own business logic, you can use the vari
1. Get the SDK instance

```javascript
const WebIM = EaseChat.getSdk({ appkey: 'xxxx' })
const WebIM = EaseApp.getSdk({ appkey: 'xxxx' })
```

2. Add callback events
Original file line number Diff line number Diff line change
@@ -397,7 +397,7 @@ To enable your app to send and receive messages between individual users, do the
return;
}
// 1: single chat; 2: group chat; 3: chat room
EaseChatFragment fragment = new EaseChatFragment.Builder(toChatUsername, 1)
EaseChatFragment fragment = new EaseChatFragment.Builder(toChatUsername, EaseChatType.SINGLE_CHAT)
.useHeader(false)
.setOnChatExtendMenuItemClickListener(new OnChatExtendMenuItemClickListener() {
@Override
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
<PlatformWrapper platform="web">

The Chat UI Samples for Web has two components:

- `EaseApp`, which contains the conversation list and applies to use cases where you want to quickly launch a real-time chat app.
- `EaseChat`, which contains a conversation box and applies to most chat use cases such as sending and receiving messages, displaying the message on the UI, and managing unread messages.
The Web Chat UIKit contains the `EaseApp` component, which contains the conversation list and applies to use cases where you want to quickly launch a real-time chat app.

This section introduces the steps you need to take to quickly implement one-to-one messaging with `EaseApp`.

@@ -15,7 +12,7 @@ This section introduces the steps you need to take to quickly implement one-to-o
// App.js
import React, {Component} from 'react';
import { EaseApp } from "agora-chat-uikit"
import './App.scss';
import './App.css';

class App extends Component {
render() {
Original file line number Diff line number Diff line change
@@ -24,15 +24,15 @@ Follow the steps to create the environment necessary to add video call into your
}
```

<div class="alert note">The way to add the Maven Central dependency can be different if you set <a href="https://docs.gradle.org/current/userguide/declaring_repositories.html#sub:centralized-repository-declaration">dependencyResolutionManagement</a> in your Android project.</div>
<div class="alert note">After the project is created, <b>Android Studio</b> will automatically start gradle synchronization. Ensure that you proceed to the following operations only after the synchronization is successful.</div>

b. In `/Gradle Scripts/build.gradle(Module: <projectname>.app)`, add the following lines to integrate the Chat UI Samples into your Android project:

```java
android {
defaultConfig {
// The Android OS version should be 19 or higher.
minSdkVersion 19
// The Android OS version should be 21 or higher.
minSdkVersion 21
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
@@ -59,6 +59,8 @@ Follow the steps to create the environment necessary to add video call into your
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<!-- For Android 12, you need to add the following line to apply for the alarm clock permission. For Agora Chat 1.0.9 or later, this permission is optional.-->
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
```

These are the minimum permissions you need to add to start Chat. You can also add other permissions according to your use case.
44 changes: 24 additions & 20 deletions shared/chat-sdk/reference/_chat_receive_webhook.mdx
Original file line number Diff line number Diff line change
@@ -9,11 +9,15 @@ This page introduces the events and callbacks in Agora Chat.

## User login and logout events

When a user logs in to or logs out of the Agora Chat app, the Agora Chat server sends a callback to your app server.
A user's login to or logout of the Agora Chat app will cause the user's online status to change.

When a user logs in to or out of the Agora Chat app, the Agora Chat server sends a callback to your app server to synchronize the user's online or offline state and the reason for the status change, including `login`, `logout` and `replaced`. When receiving the callback, the app server will return a response to the Agora Chat server which deems that the user state is successfully synchronized to your app server only when the HTTP status code 200 is received. If no response is received within 60 seconds, the Agora Chat server sends the callback again. If there is still no response, the Agora Chat server no longer sends the callback, but records a callback sending failure. If a good many responses from the app server fail to be received during a short period, the Agora Chat server stops sending callbacks to your app server and you can change the callback address on the **Post Send** page in the **Add Callback Rules** dialog box under **Features > Callback** on the [Agora Console](https://console.agora.io/).

In special network conditions, for example, a user entering a tunnel, the user's state change may be caused by the heartbeat timeout. Specifically, if a user's app remains disconnected from the Agora Chat server for five minutes, the user gets offline.

### Log in to the app

When a user logs in to the Agora Chat app, the Agora Chat server sends a callback to your app server. The sample code is as follows:
When a user logs in to the Agora Chat app, the Agora Chat server sends a callback to your app server, notifying the user's online state and the reason `login`. The sample code is as follows:

```json
{
@@ -34,7 +38,7 @@ When a user logs in to the Agora Chat app, the Agora Chat server sends a callbac
| Field | Data Type | Description |
| --- | --- | --- |
| `callId` | String | The ID of the callback. The unique identifier assigned to each callback, in the format of `{appKey}_{file_uuid}`, where the value of `file_uuid` is randomly generated. |
| `reason` | String | The reason that triggers the callback. `login` indicates that a user logs in to the app. |
| `reason` | String | The reason `login` that triggers the callback. |
| `security` | String | The signature in the callback request used to confirm whether this callback is sent from the Agora Chat server. The signature is the MD5 hash of the `{callId} + {secret} + {timestamp}` string, where the value of `secret` can be found on [Agora Console](https://console.agora.io/).|
| `os` | String | The operating system of the device. Valid values: `ios`, `android`, `linux`, `win`, and `other.` |
| `ip` | String | The IP address of the user who logs in to the app. |
@@ -43,11 +47,11 @@ When a user logs in to the Agora Chat app, the Agora Chat server sends a callbac
| `user` | String | The ID of the user. The unique identifier of each user in the Agora Chat app, in the format of `{appKey}/{OS}_{deviceId}`. |
| `version` | String | The version of the Agora Chat SDK. |
| `timestamp` | Long | The Unix timestamp when the Agora Chat server receives the login request, in milliseconds. |
| `status` | String | The current status of the user. `online` indicates that the user is online. |
| `status` | String | The current status of the user. `online` indicates that the user is online and the app is connected to the Agora Chat server. |

### Log out of the app voluntarily

When a user logs out of the Agora Chat app, the Agora Chat server sends a callback to your app server. The sample code is as follows:
When a user logs out of the Agora Chat app, the Agora Chat server sends a callback to your app server, notifying the user's offline state and the reason `logout`. The sample code is as follows:

```json
{
@@ -68,7 +72,7 @@ When a user logs out of the Agora Chat app, the Agora Chat server sends a callba
| Field | Data Type | Description |
| --- | --- | --- |
| `callId` | String | The ID of the callback. The unique identifier assigned to each callback, in the format of `{appKey}_{file_uuid}`, where the value of `file_uuid` is randomly generated. |
| `reason` | String | The reason that triggers the callback. `logout` indicates that a user logs out of the app. |
| `reason` | String | The reason `logout` that triggers the callback. |
| `security` | String | The signature in the callback request used to confirm whether this callback is sent from the Agora Chat server. The signature is the MD5 hash of the `{callId} + {secret} + {timestamp}` string, where the value of `secret` can be found on [Agora Console](https://console.agora.io/).|
| `os` | String | The operating system of the device. Valid values: `ios`, `android`, `linux`, `win`, and `other.` |
| `ip` | String | The IP address of the user who logs out of the app. |
@@ -77,11 +81,11 @@ When a user logs out of the Agora Chat app, the Agora Chat server sends a callba
| `user` | String | The ID of the user. The unique identifier of each user in the Agora Chat app, in the format of `{appKey}/{OS}_{deviceId}`. |
| `version` | String | The version of the Agora Chat SDK. |
| `timestamp` | Long | The Unix timestamp when the Agora Chat server receives the logout request, in milliseconds. |
| `status` | String | The current status of the user. `offline` indicates that the user is offline. |
| `status` | String | The current status of the user. `offline` indicates that the user is offline and the app is disconnected from the Agora Chat server.

### Log out of the app passively

When a user logs out of the Agora Chat app due to being kicked out by another device, the Agora Chat server sends a callback to your app server. The sample code is as follows:
When a user is forced by the developer to go offline on the device or due to being kicked out by another device as the maximum number of login devices is reached, the Agora Chat server sends a callback to your app server, notifying the user's offline state and the reason `replaced`. The sample code is as follows:

```json
{
@@ -101,7 +105,7 @@ When a user logs out of the Agora Chat app due to being kicked out by another de
| Field | Data Type | Description |
| --- | --- | --- |
| `callId` | String | The ID of the callback. The unique identifier assigned to each callback, in the format of `{appKey}_{file_uuid}`, where the value of `file_uuid` is randomly generated. |
| `reason` | String | The reason that triggers the callback. `replaced` indicates that a user logs out of the app due to being kicked out by another device. |
| `reason` | String | The reason `replaced` that triggers the callback. |
| `security` | String | The signature in the callback request used to confirm whether this callback is sent from the Agora Chat server. The signature is the MD5 hash of the `{callId} + {secret} + {timestamp}` string, where the value of `secret` can be found on [Agora Console](https://console.agora.io/).|
| `os` | String | The operating system of the device. Valid values: `ios`, `android`, `linux`, `win`, and `other.` |
| `ip` | String | The IP address of the user. |
@@ -110,7 +114,7 @@ When a user logs out of the Agora Chat app due to being kicked out by another de
| `user` | String | The ID of the user. The unique identifier of each user in the Agora Chat app, in the format of `{appKey}/{OS}_{deviceId}`. |
| `version` | String | The version of the Agora Chat SDK. |
| `timestamp` | Long | The Unix timestamp when the Agora Chat server receives the logout request, in milliseconds. |
| `status` | String | The current status of the user. `offline` indicates that the user is offline. |
| `status` | String | The current status of the user. `offline` indicates that the app is disconnected from the Agora Chat server and the user is offline. |


## Message events
@@ -363,7 +367,7 @@ When a user sends a custom message in a one-to-one chat, chat group, or chat roo
| Field | Data Type | Description |
| --- | --- | --- |
| `customExts/v2:customExts` | Json | The attribute of the custom event, in the `Map<String, String>` format. The attribute can contain a maximum of 16 elements. |
| `customEvent`| String | The type of the custom event. The type can be 1 to 32 characters. |
| `customEvent`| String | The type of the custom event. The type can be 1 to 32 characters and must meet the following regular expression condition: [a-zA-Z0-9-_/.]{1,32}.|
| `type` | String | The type of the message. `custom` indicates a custom message. |

### Recall a message
@@ -980,15 +984,15 @@ When a user uploads a shared file to a chat group, the Agora Chat server sends a
"payload":
{
"muc_id": "XXXX#XXXX173560762007553XXXX",
"reason": "{
\"data\":{
\"file_id\":\"79ddf840-8e2f-11ec-bec3-ad40868b03f9\",
\"file_name\":\"a.csv\",
\"file_owner\":\"@ppAdmin\",
\"file_size\":6787,
\"created\":1644909510085
}
}",
"reason": {
"data": {
"file_id": "79ddf840-8e2f-11ec-bec3-ad40868b03f9",
"file_name": "a.csv",
"file_owner": "@ppAdmin",
"file_size": 6787,
"created": 1644909510085
}
},
"is_chatroom": false,
// "upload_file" indicates that the current operation is to upload a shared file to a chat group.
"operation": "upload_file",
2 changes: 1 addition & 1 deletion shared/chat-sdk/reference/_chatroom-overview.mdx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as data from '@site/data/variables';

Chat rooms enable real-time messaging among multiple users. Chat rooms do not have a strict membership and members do not have any relationship with each other. Once a chat room member exits the chat room, this member does not receive any push message from the chat room, and within 5 minutes, automatically leaves the chat room. Chat rooms are widely applied in live broadcast use cases as stream chat in Twitch.
Chat rooms enable real-time messaging among multiple users and are widely applied in live broadcast use cases as stream chat in Twitch. Chat rooms do not have a strict membership, and members do not retain any permanent relationship with each other. Once going offline, chat room members cannot receive any messages from the chat room and automatically leave the chat room after 2 minutes. If you want to adjust the time, contact [support@agora.io](mailto:support@agora.io).

## Chat room roles and privileges

11 changes: 7 additions & 4 deletions shared/chat-sdk/reference/_http-status-codes.mdx
Original file line number Diff line number Diff line change
@@ -46,10 +46,10 @@ This status code indicates that the authentication process could not be implemen

| Status code | Error code | Error message | Description |
| :----- | :------------ | :----------------------------------------------------------- | :------------------------------------------------|
| `401` | `unauthorized` | "Registration is not open, please contact the app admin." | The error message returned because the app token is not included in the request header when registering users. |
| `401` | `unauthorized` | "Unable to authenticate due to expired access token." | The error message returned because the token has expired. |
| `401` | `auth_bad_access_token` | "Unable to authenticate due to corrupt access token." | The error message returned because the token format is invalid. |
| `401` | `auth_bad_access_token` | "Unable to authenticate." | The error message returned because the token is not generated by the server that receives the request, and as a consequence the server cannot recognize the token. |
| `401` | `unauthorized` | "Registration is not open, please contact the app admin." |The error message returned because you pass in an incorrect app token or do not pass in an app token when you call the API of [registering a user](../restful-api/user-system-registration#registering-a-user) or [registering multiple users](../restful-api/user-system-registration#registering-multiple-users). For example, you pass in an app token that has already expired or is in incorrect format. |
| `401` | `unauthorized` | "Unable to authenticate due to expired access token." | This error message is returned because you pass in an expired app token or do not pass in an app token when you call any other RESTful API than the API of registering a user or registering multiple users. |
| `401` | `auth_bad_access_token` | "Unable to authenticate due to corrupt access token." | The error message returned because you pass in an app token that is in invalid format when you call any other RESTful API than the API of registering a user or registering multiple users. |
| `401` | `auth_bad_access_token` | "Unable to authenticate." | The error message returned because the server cannot recognize your app token that is in the correct format, but is not generated by the server that receives the request. This error occurs when you call any other RESTful API than the API of registering a user or registering multiple users. |

### 403 Forbidden
This status code indicates that the API request is rejected by the server due to forbidden operations.
@@ -63,6 +63,9 @@ This status code indicates that the API request is rejected by the server due to
| `403` | `forbidden_op` | "Forbidden operation on group owner!" | The error message returned because the specified operation cannot be performed on chat group owners, such as adding the chat group owner to block list. |
| `403` | `forbidden_op` | "Can not join this group, reason:user: `{username}` has joined too many groups/chatroom!" | The error message returned because the number of chat groups or chat rooms joined by a user has reached the limit. |
| `403` | `forbidden_op` | "This appKey has create too many groups/chatrooms!" | The number of chat groups or chat rooms created by using an App key has reached the limit. For details, see [Pricing plans](../reference/pricing-plan-details). |
| `403` | `exceed_limit` | "Invitee's contact max count" | The user receiving the friend request has reached the maximum number of contacts allowed.|
| `403` | `exceed_limit` | "Inviter's contact max count" | The user sending the friend request has reached the maximum number of contacts allowed. |


### 404 Not Found
This status code indicates that the specified resources of the API request could not be found by the server.
47 changes: 47 additions & 0 deletions shared/chat-sdk/reference/_ip_allowlist.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import * as data from '@site/data/variables';

For the communication between end users behind enterprise firewalls, Agora Chat allows all communications to always use TCP/TLS 443 with TLS headers. Agora Chat supports the IP allowlist function. If you have a strict security policy for end users and allow only certain absolute domain names or specified IP addresses/port ranges to communicate through TCP/TLS 443, you can add the allowed IP addresses or domain names to the IP allowlist. To ensure smooth communication via Agora Chat, you must add the IP addresses and ports of data centers of Agora Chat to the firewall allowlist.

### Add IP addresses and ports of data centers of Agora Chat to the firewall allowlist

1. Prepare the development environment. See [SDK quickstart](../get-started/get-started-sdk) for your platform.

1. Add the IP addresses and ports of Agora Chat access points to the firewall allowlist.

1. Test message sending and receiving in the development environment.

### List of domain names of Agora Chat data centers

For each Agora Chat data center, for example, Singapore, virginia US, or Frankfurt Germany, Agora Chat provides fully qualified domain names for the access points.

Agora fully controls the servers and the traffic on the IP addresses of the access points. The IP addresses are subject to change and any changes will be announced with a minimum of a 3-month notice to you, ensuring that you have enough time to update their firewalls to trust these IP addresses.

**virginia, US**

| Domain Name | IP Address | Port | Platform |
| :---------- | :------- | :----- | :------------- |
|[msync-api-41.chat.agora.io](http://msync-api-41.chat.agora.io/)|<ul><li>3.33.220.151</li><li>15.197.222.199</li></ul>| 443 | Client SDKs (excluding SDK for Web) |
|[msync-im-41-tls.chat.agora.io](http://msync-im-41-tls.chat.agora.io/)|<ul><li>52.223.55.237</li><li>35.71.161.179</li></ul>| 443 | Client SDKs (excluding SDK for Web) |
|[a41.chat.agora.io](http://a41.chat.agora.io/)|<ul><li>99.83.189.183,</li><li>75.2.75.207</li></ul>| 443 | RESTful API|
|ap-america.agora.io|<ul><li>106.14.12.130</li><li>47.107.39.93</li><li>118.190.148.38</li><li>112.126.96.46</li><li>52.58.56.244</li><li>35.178.208.187</li><li>52.52.84.170</li><li>50.17.126.121</li><li>3.0.163.78</li><li>52.194.158.59</li><li>54.65.86.72</li><li>13.127.149.196</li><li>15.206.47.129</li><li>123.56.235.221</li><li>101.132.108.165</li><li>52.28.239.238</li><li>3.9.120.239</li><li>52.54.85.111</li><li>184.72.18.217</li><li>13.250.89.184</li><li>18.176.162.64</li></ul>|<ul><li>UDP port: 8443, 5888-5889, 4000-4100 and 8130</li><li>UDP port: 443 and 8443</li></ul>| Client SDKs (excluding SDK for Web) |

**Singapore**

| Domain Name | IP Address | Port | Platform |
| :---------- | :------- | :----- | :------------- |
|[msync-api-61.chat.agora.io](http://msync-api-61.chat.agora.io/)|<ul><li>35.71.135.178,</li><li>52.223.50.200</li></ul>| 443 | Client SDKs (excluding SDK for Web) |
|[msync-im-61-tls.chat.agora.io](http://msync-im-61-tls.chat.agora.io/)|<ul><li>35.71.183.128,</li><li>52.223.36.218</li></ul>| 443 | Client SDKs (excluding SDK for Web) |
|[a61.chat.agora.io](http://a61.chat.agora.io/)|<ul><li>52.223.32.250,</li><li>35.71.139.186</li></ul>| 443 | RESTful API|
|ap-asia.agora.io|<ul><li>106.14.12.130</li><li>47.107.39.93</li><li>118.190.148.38</li><li>112.126.96.46</li><li>52.58.56.244</li><li>35.178.208.187</li><li>52.52.84.170</li><li>50.17.126.121</li><li>3.0.163.78</li><li>52.194.158.59</li><li>54.65.86.72</li><li>13.127.149.196</li><li>15.206.47.129</li><li>123.56.235.221</li><li>101.132.108.165</li><li>52.28.239.238</li><li>3.9.120.239</li><li>52.54.85.111</li><li>184.72.18.217</li><li>13.250.89.184</li><li>18.176.162.64</li></ul>|<ul><li>UDP port: 8443、5888-5889, 4000-4100 and 8130</li><li>TCP port: 443 and 8443</li></ul>| Client SDKs (excluding excluding SDK for Web) |

**Frankfurt Germany**

| Domain Name | IP Address | Port | Platform |
| :---------- | :------- | :----- | :------------- |
|[msync-api-71.chat.agora.io](http://msync-api-71.chat.agora.io/)|<ul><li>75.2.86.219,</li><li>99.83.214.138</li></ul>| 443 | Client SDKs (excluding SDK for Web)|
|[msync-im-71-tls.chat.agora.io](http://msync-im-71-tls.chat.agora.io/)|<ul><li>75.2.56.250,</li><li>99.83.180.145</li></ul>|443| Client SDKs (excluding SDK for Web) |
|[a71.chat.agora.io](http://a71.chat.agora.io/)|<ul><li>3.33.221.135,</li><li>15.197.253.209</li></ul>| 443 |RESTful API|
|ap-europe.agora.io|<ul><li>106.14.12.130</li><li>47.107.39.93</li><li>118.190.148.38</li><li>112.126.96.46</li><li>52.58.56.244</li><li>35.178.208.187</li><li>52.52.84.170</li><li>50.17.126.121</li><li>3.0.163.78</li><li>52.194.158.59</li><li>54.65.86.72</li><li>13.127.149.196</li><li>15.206.47.129</li><li>123.56.235.221</li><li>101.132.108.165</li><li>52.28.239.238</li><li>3.9.120.239</li><li>52.54.85.111</li><li>184.72.18.217</li><li>13.250.89.184</li><li>18.176.162.64</li></ul>|<ul><li>UDP port: 8443、5888-5889, 4000-4100 and 8130</li><li>TCP port: 443 and 8443</li></ul>| Client SDKs (excluding SDK for Web)|



10 changes: 10 additions & 0 deletions shared/chat-sdk/reference/_message-overview.mdx
Original file line number Diff line number Diff line change
@@ -96,6 +96,16 @@ Apart from the local device, you can also retrieve conversations from the server

The Chat SDK stores historical messages in the chat server, and you can retrieve historical messages in each conversation from the server with pagination. The time duration for storing historical messages varies according to your pricing plan. See [Limitations of message storage duration](#limitations).

### Message resending mechanism

- For Android and iOS, the message resending mechanism is as follows:

After the client calls the method of sending a message, it will wait for the server to return a response. The response timeout period is 10 seconds. If the sending fails due to a response timeout, the client will try to send the message again by reconnecting to the server through a persistent connection to send the message. If the sending fails again, the SDK considers the sending of the message failed, and returns error code 300 and the error message `SERVER_NOT_REACHABLE`, indicating that the server is unreachable.

- For Web, the message resending mechanism is as follows:

When sending a message, if the WebSocket is disconnected and is reconnecting to the server, the message will be resent after reconnection; if the WebSocket is disconnected during message sending, the SDK will display error code 510 and the error message `MESSAGE_WEBSOCKET_DISCONNECTED `, indicating that the network disconnection caused the message sending failure.

### Message delivery receipt

The SDK supports sending a message delivery receipt when the message is successfully sent.
11 changes: 6 additions & 5 deletions shared/chat-sdk/reference/_pricing-plan-details.mdx
Original file line number Diff line number Diff line change
@@ -4,11 +4,12 @@ This page lists the details of the pricing plans for Chat.

## User

| Description | Free | Starter | Pro | Enterprise |
| :------------------------------- | :--: | :-------: | :-------: | :--------: |
| Maximum number of contacts for a user | 100 | 250 | 1,000 | Custom (10,000 by default) |
| Total number of registered users | unlimited | unlimited | unlimited | unlimited |
| Peak concurrent connection* | 50 | 10% of MAU | 10% of MAU | Customizable (10% of MAU by default) |
| Description | Free | Starter | Pro | Enterprise |
| :---------------------------------------| :--------: | :-----------: | :-----------: | :---------------------------------------------------------------: |
| Maximum number of contacts for a user | 100 | 250 | 1,000 | Custom (10,000 by default) |
| Total number of registered users | unlimited | unlimited | unlimited | unlimited |
| Maximum number of monthly active users | 500 | 50,000 | 100,000 | Customizable (requires a minimum monthly commitment of 100,000 MAU)|
| Peak concurrent connection* | 50 | 10% of MAU | 10% of MAU | Customizable (10% of MAU by default) |

## Message

13 changes: 13 additions & 0 deletions shared/chat-sdk/reference/release-notes/android.mdx
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
<PlatformWrapper platform="android">

## v1.2.1

v1.2.1 was released on December 8, 2023.

#### Improvements

- Added support for dynamic registration broadcasts in Android 14, which requires setting the `RECEIVER_EXPORTED` or `RECEIVER_NOT_EXPORTED` flag.

#### Issues fixed

- Fixed the problem of losing chat room listener in some scenarios after logging out and logging in again.
- Fixed the problem of occasionally failing to save the token when logging in manually.

## v1.2.0

v1.2.0 was released on December 6, 2023.
12 changes: 6 additions & 6 deletions shared/chat-sdk/restful-api/_contact-management.mdx
Original file line number Diff line number Diff line change
@@ -97,7 +97,7 @@ curl -X POST -H 'Content-Type: application/json' -H 'Accept: application/json' -
```json
{
"path": "/users/4759aa70-XXXX-XXXX-925f-6fa0510823ba/contacts",
"uri": "https://XXXX/XXXX/XXXX/users/4759aa70-eba5-11e8-925f-6fa0510823ba/contacts",
"uri": "https://XXXX/XXXX/XXXX/users/4759aa70-XXXX-XXXX-925f-6fa0510823ba/contacts",
"timestamp": 1542598913819,
"organization": "XXXX",
"application": "8be024f0-XXXX-XXXX-b697-5d598d5f8402",
@@ -166,7 +166,7 @@ curl -X DELETE -H 'Accept: application/json' -H 'Authorization: Bearer {YourAppT
```json
{
"path": "/users/4759aa70-XXXX-XXXX-925f-6fa0510823ba/contacts",
"uri": "https://XXXX/XXXX/XXXX/users/4759aa70-eba5-11e8-925f-6fa0510823ba/contacts",
"uri": "https://XXXX/XXXX/XXXX/users/4759aa70-XXXX-XXXX-925f-6fa0510823ba/contacts",
"timestamp": 1542599266616,
"organization": "XXXX",
"application": "8be024f0-XXXX-XXXX-b697-5d598d5f8402",
@@ -243,7 +243,7 @@ curl -X GET -H 'Accept: application/json' -H 'Authorization: Bearer {YourAppToke
"uri": "http://XXXX/XXXX/XXXX/users/user1/contacts/users",
"timestamp": 1543819826513,
"entities": [],
"count": 2
"count": 2,
"action": "get",
"data": [
"user3",
@@ -283,7 +283,7 @@ The request body is a JSON object, which contains the following fields:

| Field | Type | Description | Required |
| :-------- | :--------- | :------------------------------------------------ | :------- |
| `usernames` | An array of usernames | The usernames to be added to the block list, such as ["user1", "user2"]. | Yes |
| `usernames` | An array of usernames | The usernames to be added to the block list, such as ["user1", "user2"]. You can pass in a maximum of 50 user IDs each time. | Yes |

### HTTP response

@@ -304,7 +304,7 @@ If the returned HTTP status code is not 200, the request fails. You can refer to
#### Request example

```shell
curl -X POST -H 'Content-Type: application/json' -H 'Accept: application/json' -H 'Authorization: Bearer {YourAppToken}' -d '{ "usernames": [ "user2" ] }' 'http://XXXX/XXXX/XXXX/users/user1/blocks/users'
curl -X POST -H 'Content-Type: application/json' -H 'Accept: application/json' -H 'Authorization: Bearer <YourAppToken>' -d '{ "usernames": [ "user2" ] }' 'http://XXXX/XXXX/XXXX/users/user1/blocks/users'
```

#### Response example
@@ -452,7 +452,7 @@ curl -X DELETE -H 'Accept: application/json' -H 'Authorization: Bearer {YourAppT
```json
{
"path": "/users/4759aa70-XXXX-XXXX-925f-6fa0510823ba/blocks",
"uri": "https://XXXX/XXXX/XXXX/users/4759aa70-eba5-11e8-925f-6fa0510823ba/blocks",
"uri": "https://XXXX/XXXX/XXXX/users/4759aa70-XXXX-XXXX-925f-6fa0510823ba/blocks",
"timestamp": 1542600712985,
"organization": "XXXX",
"application": "8be024f0-XXXX-XXXX-b697-5d598d5f8402",
12 changes: 6 additions & 6 deletions shared/chat-sdk/restful-api/_global-mute.mdx
Original file line number Diff line number Diff line change
@@ -54,7 +54,7 @@ POST https://{host}/{orgName}/{appName}/mutes

#### Path parameter

For parameters and the detailed descriptions, see [Commom parameters](#param).
For parameters and the detailed descriptions, see [Common parameters](#param).

#### Request parameter

@@ -136,7 +136,7 @@ GET https://{host}/{orgName}/{appName}/mutes/{username}
| --- | --- | --- | --- |
| `username` | String | Yes | The user ID whose global-mute settings you want to query. |

For other parameters and the detailed descriptions, see [Commom parameters](#param).
For other parameters and the detailed descriptions, see [Common parameters](#param).

#### Request header

@@ -207,7 +207,7 @@ GET https://{host}/{orgName}/{appName}/mutes

#### Path parameter

For parameters and the detailed descriptions, see [Commom parameters](#param).
For parameters and the detailed descriptions, see [Common parameters](#param).

#### Request header

@@ -216,12 +216,12 @@ For parameters and the detailed descriptions, see [Commom parameters](#param).
| `Content-Type` | String | The content type. Set is as `application/json`. |
| `Authorization` | String | The authentication token of the user or admin, in the format of `Bearer ${YourAppToken}`, where `Bearer` is a fixed character, followed by an English space, and then the obtained token value. |

#### Request body
#### Query parameter

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `pageNum` | Number | Yes | The number of page for querying the globally muted users in the app. |
| `pageSize` | Number | Yes | The number of data entries on each page. |
| `pageNum` | Number | No | The number of pages for querying the globally muted users in the app. |
| `pageSize` | Number | No | The number of data entries on each page. The value range is [1,50]. |

### HTTP response

19 changes: 11 additions & 8 deletions shared/chat-sdk/restful-api/_message-management.mdx
Original file line number Diff line number Diff line change
@@ -93,7 +93,8 @@ The request body is a JSON object, which contains the following parameters:
| `body` | JSON | The message content. For different message types, this parameter contains different fields. For details, see [Body of different message types](#body). | Yes |
| `sync_device` | Bool | Whether to synchronize the message to the message sender.<ul><li>`true`: Yes.</li><li>`false`: No.</li></ul> | No |
| `routetype` | String | The route type when the message is not online. <ul><li>To send the message only when the user is online, set this parameter as `ROUTE_TYPE`.</li><li>To send the message regardless of whether the user is online or not, do not set this parameter.</li></ul> | No |
| `ext` | JSON | The extension filed of the message. | No |
| `ext` | JSON | The extension field of the message. It cannot be `null`.| No |
| `ext.em_ignore_notification` | Whether to send a silent message: <ul><li>`true`: Yes;</li><li>(Default)`false`: No.</li></ul>Sending silent messages means that when the user is offline, Agora Chat will not push message notifications to the user's device through a third-party message push service. Therefore, users will not receive push notifications for messages. When the user goes online again, all messages sent from the offline period will be received. Unlike the Do Not Disturb mode which is set by the recipient to prevent notifications during a certain period, sending silent messages is set by the sender.| Boolean |

<a name="body"></a>

@@ -187,15 +188,14 @@ If the returned HTTP status code is not `200`, the request fails. You can refer

```shell
# Replace {YourToken} with the app token generated on your server
curl -X POST -i 'http://XXXX/XXXX/XXXX/messages/users' -H 'Content-Type: application/json' -H 'Accept: application/json' -H 'Authorization: Bearer {YourToken}' -d '{"from": "user1","to": ["user2"],"type": "txt","body": {"msg": "testmessages"}}'
curl -X POST -i 'http://XXXX/XXXX/XXXX/messages/users' -H 'Content-Type: application/json' -H 'Accept: application/json' -H 'Authorization: Bearer {YourToken}' -d '{"from": "user1","to": ["user2"],"type": "txt","body": {"msg": "testmessages"},"ext": {"em_ignore_notification": true}}'
```

- Send a text message to the online user while synchronizing the message with the sender

```shell
# Replace {YourToken} with the app token generated on your server
curl -X POST -i 'http://XXXX/XXXX/XXXX/messages/users' -H 'Content-Type: application/json' -H 'Accept: application/json' -H 'Authorization: Bearer {YourToken}' -d '{"from": "user1","to": ["user2"],"type": "txt","body": {"msg": "testmessages"},"routetype":"ROUTE_ONLINE", "sync_device":true}'
```
curl -X POST -i 'http://XXXX/XXXX/XXXX/messages/users' -H 'Content-Type: application/json' -H 'Accept: application/json' -H 'Authorization: Bearer {YourToken}' -d '{"from": "user1","to": ["user2"],"type": "txt","body": {"msg": "testmessages"},"ext": {"em_ignore_notification": true},"routetype":"ROUTE_ONLINE", "sync_device":true}' ```
- Send an image message
@@ -1118,10 +1118,10 @@ curl -X GET -H 'Accept: application/octet-stream' -H 'Authorization: Bearer {You
This method retrieves historical messages sent and received by the user.

- For each request, you can retrieve all the historical messages sent and received within one hour from the specified time.
- There is a certain delay when querying historical message records, which cannot be obtained in real time.
- Messages cannot be retrieved in real time. For example, at 9 a.m., you can retrieve messages that are sent or received at 8 a.m.
- The default storage time of historical messages differs by plan version. For details, see [package details](/agora-chat/reference/pricing-plan-details).

For each App Key, the call frequency limit of this method is 100 per second.
For each App Key, the call frequency limit of this method is 10 per minute.

### HTTP request

@@ -1471,11 +1471,14 @@ For the parameters and detailed descriptions, see [Common parameters](#param).

| Parameter | Type | Required | Description |
| :---------- | :------- | :------- | :----------------------------------------------------------- |
| `msg_id` | String | Yes | The ID of the recalled message. |
| `to` | String | No | The user, chat group, or chat room that receives the recalled message. You can specify a username, a chat group ID, or a chat room ID.<br/>**Note**: If the recalled message exceeds the message storage duration and no longer exists in the server, this message cannot be recalled on the server side. You can only recall the message on the receiver client instead. |
| `chat_type` | String | Yes | The type of the chat where the recalled message is located. <ul><li>`chat`: An one-on-one chat.</li><li>`groupchat`: A chat group.</li><li>`chatroom`: A chat room.</li></ul> |
| `msg_id` | String | Yes | The ID of the message to recall. As only one message can be recalled each time, you can pass in only one message ID. |
| `to` | String | No | The user, chat group, or chat room that receives the message to recall. You can specify a user ID, a chat group ID, or a chat room ID. **Note**: If the message to recall no longer exists on the server, only the message on the recipient client is recalled. |
| `chat_type` | String | Yes | The type of the chat where the message to recall is sent. <ul><li>`chat`: An one-on-one chat.</li><li>`groupchat`: A chat group.</li><li>`chatroom`: A chat room.</li></ul> |
| `from` | String | No | The user who recalls the message. By default, the recaller is the app admin. You can also specify another user as the recaller. |
| `force` | bool | No | Whether to allow to recall messages beyond the storage time on the server. For details on the message storage duration on the server, see [Message storage duration](https://docs.agora.io/en/agora-chat/reference/limitations#message-storage-duration).<ul><li>`true`: Yes. In this case, you can recall messages within the recall period or those beyond the storage time on the server. For the latter, this API recalls the messages locally saved by the recipient. If the message sending time is between your recall duration and the storage duration on the server, the recall fails. For example, if the recall duration is 2 minutes and the storage time on the server is 7 days, you can recall a message sent within 2 minutes or one that was sent more than 7 days ago; if the message is sent 3 minutes ago, the recall will fail.</li><li>`false`: No. You cannot recall messages beyond the storage time on the server. If you use the default recall time of 2 minutes or a custom duration, the server can only recall the messages sent within the specified time, and those beyond this time cannot be recalled. For example, if you set the recall time to 3 minutes and the message is sent 4 minutes ago, the recall will fail.</li></ul> |
| `force` | bool | Yes | Whether to allow to recall messages beyond the storage time on the server. For details on the message storage duration on the server, see [Message storage duration](https://docs.agora.io/en/agora-chat/reference/limitations#message-storage-duration).<ul><li>`true`: Yes. In this case, you can recall messages within the recall period or those beyond the storage time on the server. For the latter, this API recalls the messages locally saved by the recipient. If the message sending time is between your recall duration and the storage duration on the server, the recall fails. For example, if the recall duration is 2 minutes and the storage time on the server is 7 days, you can recall a message sent within 2 minutes or one that was sent more than 7 days ago; if the message is sent 3 minutes ago, the recall will fail.</li><li>`false`: No. You cannot recall messages beyond the storage time on the server. If you use the default recall time of 2 minutes or a custom duration, the server can only recall the messages sent within the specified time, and those beyond this time cannot be recalled. For example, if you set the recall time to 3 minutes and the message is sent 4 minutes ago, the recall will fail.</li></ul> |

### HTTP response

@@ -1845,4 +1848,4 @@ If the request fails, refer to [Status codes](/agora-chat/reference/http-status-

## Status codes

For details, see [HTTP Status Codes](/agora-chat/reference/http-status-codes).
For details, see [HTTP Status Codes](/agora-chat/reference/http-status-codes).
110 changes: 55 additions & 55 deletions shared/chat-sdk/restful-api/_offline-push-configuration.mdx
Original file line number Diff line number Diff line change
@@ -76,7 +76,7 @@ For the descriptions of path parameters, see [Common Parameters](#request).

| Parameter | Type | Description | Required |
| :----- | :----- | :------- | -------- |
| `nickname` | String | The nickname displayed in push notifications. The length of the nickname cannot exceed 100 characters, and the following character sets are supported:<li>26 lowercase English letters (a-z)</li><li>26 uppercase English letters (A-Z)</li><li>10 numbers (0-9)</li><li>Chinese characters</li><li>Special characters</li> <div class="alert note">The nickname can be different from the nickname in the user profile; however, Agora recommends that you use the same nickname for both. Therefore, if either nickname is updated, the other should be changed at the same time. To update the nickname in the user profile, see [Setting user attributes](/agora-chat/restful-api/user-attributes-management#setting-user-attributes).</div> | No |
| `nickname` | String | The nickname that is displayed in the push notification bar of the recipient's client when a message from the user is pushed. The length of the nickname cannot exceed 100 characters, and the following character sets are supported:<li>26 lowercase English letters (a-z)</li><li>26 uppercase English letters (A-Z)</li><li>10 numbers (0-9)</li><li>Chinese characters</li><li>Special characters </li> <br/>If no nickname is set, when a message from this user is pushed, the user ID of the message sender, instead of the nickname, is indicated in the notification details (`notification_display_style` is set to 1). <div class="alert note">The nickname can be different from the nickname in user attributes. However, Agora recommends that you use the same nickname for both. Therefore, if either nickname is updated, the other should be changed at the same time. To update the nickname in user attributes, see <a href="https://docs.agora.io/en/agora-chat/agora_chat_restful_user_attributes?platform=RESTful#setting-user-attributes">Setting user attributes</a>.</div> | No |

### HTTP response

@@ -103,20 +103,20 @@ If the returned HTTP status code is not `200`, the request fails. You can refer
#### Request example

```bash
curl -X PUT -H 'Content-Type: application/json' -H 'Accept: application/json' -H 'Authorization: Bearer YWMte3bGuOukEeiTkNP4grL7iwAAAAAAAAAAAAAAAAAAAAGL4CTw6XgR6LaXXVmNX4QCAgMAAAFnKdc-ZgBPGgBFTrLhhyK8woMEI005emtrLJFJV6aoxsZSioSIZkr5kw' -d '{ "nickname": "testuser" }' 'http://a1.agora.com/agora-demo/testapp/users/user1'
curl -X PUT -H 'Content-Type: application/json' -H 'Accept: application/json' -H 'Authorization: Bearer <YourAppToken>' -d '{ "nickname": "testuser" }' 'http://XXXX/XXXX/XXXX/users/user1'
```

#### Response example

```json
{
"action": "put",
"application": "8be024f0-e978-11e8-b697-5d598d5f8402",
"application": "8be024f0-XXXX-XXXX-b697-5d598d5f8402",
"path": "/users",
"uri": "https://a1.agora.com/agora-demo/testapp/users",
"uri": "https://XXXX/XXXX/XXXX/users",
"entities": [
{
"uuid": "4759aa70-eba5-11e8-925f-6fa0510823ba",
"uuid": "4759aa70-XXXX-XXXX-925f-6fa0510823ba",
"type": "user",
"created": 1542595573399,
"modified": 1542596083687,
@@ -187,20 +187,20 @@ If the returned HTTP status code is not `200`, the request fails. You can refer
#### Request example

```bash
curl -X PUT -H "Authorization: Bearer YWMtSozP9jHNEeSQegV9EKeAQAAAUlmBR2bTGr-GP2xNh8GhUCdKViBFDSEF2E" -i https://a1.agora.com/agora-demo/testapp/users/a -d '{"notification_display_style": "1"}'
curl -X PUT -H "Authorization: Bearer <YourAppToken>" -i https://XXXX/XXXX/XXXX/users/a -d '{"notification_display_style": "1"}'
```

#### Response example

```json
{
"action" : "put",
"application" : "17d59e50-0aee-11e8-8092-0dc80c0f5e99",
"application" : "17d59e50-XXXX-XXXX-8092-0dc80c0f5e99",
"path" : "/users",
"uri" : "https://a1.agora.com/agora-demo/testapp/users",
"uri" : "https://XXXX/XXXX/XXXX/users",
"entities" : [
{
"uuid" : "3b8c9890-7b9a-11e8-9d88-f50bf55cafad",
"uuid" : "3b8c9890-XXXX-XXXX-9d88-f50bf55cafad",
"type" : "user",
"created" : 1530276298905,
"modified" : 1534407146060,
@@ -212,8 +212,8 @@ curl -X PUT -H "Authorization: Bearer YWMtSozP9jHNEeSQegV9EKeAQAAAUlmBR2bTGr-GP2
} ],
"timestamp" : 1534407146058,
"duration" : 3,
"organization" : "1112171214115068",
"applicationName" : "testapp"
"organization" : "XXXX",
"applicationName" : "XXXX"
}
```

@@ -279,8 +279,8 @@ If the returned HTTP status code is not `200`, the request fails. You can refer
#### Request example

```bash
curl -L -X PUT '{url}/{org_name}/{app_name}/users/{username}/notification/user/{key}' \
-H 'Authorization: Bearer {token}' \
curl -L -X PUT 'http://XXXX/XXXX/XXXX/users/{username}/notification/user/{key}' \
-H 'Authorization: Bearer <YourAppToken>' \
-H 'Content-Type: application/json' \
--data-raw '{
"type":"NONE",
@@ -294,18 +294,18 @@ curl -L -X PUT '{url}/{org_name}/{app_name}/users/{username}/notification/user/{
```json
{
"path": "/users",
"uri": "https://localhost/hx/hxdemo/users/notification/user/hxtest",
"uri": "https://XXXX/XXXX/XXXX/users/notification/user/hxtest",
"timestamp": 1647503749918,
"organization": "hx",
"application": "17fe201b-ad9b-4a3a-83df-1ed1ebd7b227",
"organization": "XXX",
"application": "17fe201b-XXXX-XXXX-83df-1ed1ebd7b227",
"action": "put",
"data": {
"type": "NONE",
"ignoreDuration": 1647590149924,
"ignoreInterval": "21:30-08:00"
},
"duration": 20,
"applicationName": "hxdemo"
"applicationName": "XXXX"
}
```

@@ -319,7 +319,7 @@ For each App Key, the call frequency limit of this method is 100 per second.
### HTTP request

```html
GET https://{host}/{org}/{app}/users/{username}/notification/{chattype}/{key}
GET https://{host}/{org_name}/{app_name}/users/{username}/notification/{chattype}/{key}
```

#### Path parameter
@@ -358,27 +358,27 @@ If the returned HTTP status code is not `200`, the request fails. You can refer
#### Request example

```bash
curl -L -X GET '{url}/{org}/{app}/users/{username}/notification/chatgroup/{key}' \
-H 'Authorization: Bearer {token}'
curl -L -X GET 'https://XXXX/XXXX/XXXX/users/{username}/notification/chatgroup/{key}' \
-H 'Authorization: Bearer <YourAppToken>'
```

#### Response example

```json
{
"path": "/users",
"uri": "https://localhost/hx/hxdemo/users/notification/chatgroup/12312312321",
"uri": "https://XXXX/XXXX/XXXX/users/notification/chatgroup/12312312321",
"timestamp": 1647503749918,
"organization": "hx",
"application": "17fe201b-ad9b-4a3a-83df-1ed1ebd7b227",
"organization": "XXXX",
"application": "17fe201b-XXXX-XXXX-83df-1ed1ebd7b227",
"action": "get",
"data": {
"type": "NONE",
"ignoreDuration": 1647590149924,
"ignoreInterval": "21:30-08:00"
},
"duration": 20,
"applicationName": "hxdemo"
"applicationName": "XXXX"
}
```

@@ -392,7 +392,7 @@ For each App Key, the call frequency limit of this method is 100 per second.
### HTTP request

```html
PUT https://{host}/{org}/{app}/users/{username}/notification/language
PUT https://{host}/{org_name}/{app_name}/users/{username}/notification/language
```

#### Path parameter
@@ -431,8 +431,8 @@ If the returned HTTP status code is not `200`, the request fails. You can refer
#### Request example

```bash
curl -L -X PUT '{url}/{org}/{app}/users/{username}/notification/language' \
-H 'Authorization: Bearer {token}' \
curl -L -X PUT 'https://XXXX/XXXX/XXXX/users/{username}/notification/language' \
-H 'Authorization: Bearer <YourAppToken>' \
-H 'Content-Type: application/json' \
--data-raw '{
"translationLanguage":"EU"
@@ -444,16 +444,16 @@ curl -L -X PUT '{url}/{org}/{app}/users/{username}/notification/language' \
```json
{
"path": "/users",
"uri": "https://localhost/hx/hxdemo/users/notification/language",
"uri": "https://XXXX/XXXX/XXXX/users/notification/language",
"timestamp": 1648089630244,
"organization": "hx",
"application": "17fe201b-ad9b-4a3a-83df-1ed1ebd7b227",
"organization": "XXXX",
"application": "17fe201b-XXXX-XXXX-83df-1ed1ebd7b227",
"action": "put",
"data": {
"language": "EU"
},
"duration": 66,
"applicationName": "hxdemo"
"applicationName": "XXXX"
}
```

@@ -500,25 +500,25 @@ If the returned HTTP status code is not `200`, the request fails. You can refer
#### Request example

```bash
curl -L -X GET '{url}/{org}/{app}/users/{username}/notification/language' \
-H 'Authorization: Bearer {token}'
curl -L -X GET 'https://XXXX/XXXX/XXXX/users/{username}/notification/language' \
-H 'Authorization: Bearer <YourAppToken>'
```

#### Response example

```json
{
"path": "/users",
"uri": "https://localhost/hx/hxdemo/users/notification/language",
"uri": "https://XXXX/XXXX/XXXX/users/notification/language",
"timestamp": 1648089630244,
"organization": "hx",
"application": "17fe201b-ad9b-4a3a-83df-1ed1ebd7b227",
"organization": "XXXX",
"application": "17fe201b-XXXX-XXXX-83df-1ed1ebd7b227",
"action": "put",
"data": {
"language": "EU"
},
"duration": 66,
"applicationName": "hxdemo"
"applicationName": "XXXX"
}
```

@@ -577,8 +577,8 @@ If the returned HTTP status code is not `200`, the request fails. You can refer
#### Request example

```bash
curl -X POST '{url}/{org}/{app}/notification/template' \
-H 'Authorization: Bearer {token}' \
curl -X POST 'https://XXXX/XXXX/XXXX/notification/template' \
-H 'Authorization: Bearer <YourAppToken>' \
-H 'Content-Type: application/json' \
--data-raw '{
"name": "test7",
@@ -591,10 +591,10 @@ curl -X POST '{url}/{org}/{app}/notification/template' \

```json
{
"uri": "https://localhost/hx/hxdemo/notification/template",
"uri": "https://XXXX/XXXX/XXXX/notification/template",
"timestamp": 1646989584108,
"organization": "hx",
"application": "17fe201b-ad9b-4a3a-83df-1ed1ebd7b227",
"organization": "XXXX",
"application": "17fe201b-XXXX-XXXX-83df-1ed1ebd7b227",
"action": "post",
"data": {
"name": "test7",
@@ -604,7 +604,7 @@ curl -X POST '{url}/{org}/{app}/notification/template' \
"content_pattern": "Test,{0}"
},
"duration": 26,
"applicationName": "hxdemo"
"applicationName": "XXXX"
}
```

@@ -658,18 +658,18 @@ If the returned HTTP status code is not `200`, the request fails. You can refer
#### Request example

```bash
curl -X GET '{url}/{org}/{app}/notification/template/{name}' \
-H 'Authorization: Bearer {token}'
curl -X GET 'https://XXXX/XXXX/XXXX/notification/template/{name}' \
-H 'Authorization: Bearer <YourAppToken>'
```

#### Response example

```json
{
"uri": "https://localhost/hx/hxdemo/notification/template/test7",
"uri": "https://XXXX/XXXX/XXXX/notification/template/test7",
"timestamp": 1646989686393,
"organization": "hx",
"application": "17fe201b-ad9b-4a3a-83df-1ed1ebd7b227",
"organization": "XXXX",
"application": "17fe201b-XXXX-XXXX-83df-1ed1ebd7b227",
"action": "get",
"data": {
"name": "test7",
@@ -679,7 +679,7 @@ curl -X GET '{url}/{org}/{app}/notification/template/{name}' \
"content_pattern": "Test,{0}"
},
"duration": 11,
"applicationName": "hxdemo"
"applicationName": "XXXX"
}
```

@@ -733,18 +733,18 @@ If the returned HTTP status code is not `200`, the request fails. You can refer
#### Request example

```bash
curl -X DELETE '{url}/{org}/{app}/notification/template' \
-H 'Authorization: Bearer {token}'
curl -X DELETE 'https://XXXX/XXXX/XXXX/notification/template' \
-H 'Authorization: Bearer <YourAppToken>'
```

#### Response example

```json
{
"uri": "https://localhost/hx/hxdemo/notification/template",
"uri": "https://XXXX/XXXX/XXXX/notification/template",
"timestamp": 1646989686393,
"organization": "hx",
"application": "17fe201b-ad9b-4a3a-83df-1ed1ebd7b227",
"organization": "XXXX",
"application": "17fe201b-XXXX-XXXX-83df-1ed1ebd7b227",
"action": "delete",
"data": {
"name": "test7",
@@ -754,7 +754,7 @@ curl -X DELETE '{url}/{org}/{app}/notification/template' \
"content_pattern": "Test,{0}"
},
"duration": 11,
"applicationName": "hxdemo"
"applicationName": "XXXX"
}
```

Loading
You are viewing a condensed version of this merge commit. You can view the full changes here.