diff --git a/content/buf.gen.yaml b/content/buf.gen.yaml
new file mode 100644
index 0000000..c4b6222
--- /dev/null
+++ b/content/buf.gen.yaml
@@ -0,0 +1,12 @@
+version: v1
+managed:
+ enabled: true
+ go_package_prefix:
+ default: github.com/harmony-development/shibshib/gen
+plugins:
+ - name: hdocs
+ out: docs
+ opt:
+ - paths=source_relative
+ - codicon=yes
+ - usehtml=yes
diff --git a/content/docs/Permissions.md b/content/docs/Permissions.md
index 084aede..74db1f3 120000
--- a/content/docs/Permissions.md
+++ b/content/docs/Permissions.md
@@ -1 +1 @@
-../protocol/chat/v1/Permissions.md
\ No newline at end of file
+../protocol/stable/chat/v1/Permissions.md
\ No newline at end of file
diff --git a/content/docs/REST.md b/content/docs/REST.md
deleted file mode 120000
index 31e56a5..0000000
--- a/content/docs/REST.md
+++ /dev/null
@@ -1 +0,0 @@
-../protocol/rest/rest.md
\ No newline at end of file
diff --git a/content/docs/google.protobuf.md b/content/docs/google.protobuf.md
index 06d343e..86c4edb 100644
--- a/content/docs/google.protobuf.md
+++ b/content/docs/google.protobuf.md
@@ -1,321 +1,1035 @@
---
title: "Reference: google.protobuf"
---
-## Message Types
-
-### FileDescriptorSet
-
-Fields
+# Standalone Message Types
-| Name | Type |
-| ---- | ---- |
-| file | [google.protobuf.FileDescriptorProto](#filedescriptorproto) |
+## FileDescriptorSet
+The protocol compiler can output a FileDescriptorSet containing the .proto
+files it parses.
-### FileDescriptorProto
-
-Fields
+Fields
+### file
+Type: repeated [google.protobuf.FileDescriptorProto](#filedescriptorproto)
-| Name | Type |
-| ---- | ---- |
-| name | `string` |
-| package | `string` |
-| dependency | `string` |
-| public_dependency | `int32` |
-| weak_dependency | `int32` |
-| message_type | [google.protobuf.DescriptorProto](#descriptorproto) |
-| enum_type | [google.protobuf.EnumDescriptorProto](#enumdescriptorproto) |
-| service | [google.protobuf.ServiceDescriptorProto](#servicedescriptorproto) |
-| extension | [google.protobuf.FieldDescriptorProto](#fielddescriptorproto) |
-| options | [google.protobuf.FileOptions](#fileoptions) |
-| source_code_info | [google.protobuf.SourceCodeInfo](#sourcecodeinfo) |
-| syntax | `string` |
-### DescriptorProto
-Fields
+------
+## FileDescriptorProto
+Describes a complete .proto file.
-| Name | Type |
-| ---- | ---- |
-| name | `string` |
-| field | [google.protobuf.FieldDescriptorProto](#fielddescriptorproto) |
-| extension | [google.protobuf.FieldDescriptorProto](#fielddescriptorproto) |
-| nested_type | [google.protobuf.DescriptorProto](#descriptorproto) |
-| enum_type | [google.protobuf.EnumDescriptorProto](#enumdescriptorproto) |
-| extension_range | [google.protobuf.DescriptorProto.ExtensionRange](#descriptorproto-extensionrange) |
-| oneof_decl | [google.protobuf.OneofDescriptorProto](#oneofdescriptorproto) |
-| options | [google.protobuf.MessageOptions](#messageoptions) |
-| reserved_range | [google.protobuf.DescriptorProto.ReservedRange](#descriptorproto-reservedrange) |
-| reserved_name | `string` |
-
-### ExtensionRangeOptions
-
-Fields
-
-| Name | Type |
-| ---- | ---- |
-| uninterpreted_option | [google.protobuf.UninterpretedOption](#uninterpretedoption) |
-
-### FieldDescriptorProto
-
-Fields
-
-| Name | Type |
-| ---- | ---- |
-| name | `string` |
-| number | `int32` |
-| UNHANDLED | TYPE |
-| UNHANDLED | TYPE |
-| type_name | `string` |
-| extendee | `string` |
-| default_value | `string` |
-| oneof_index | `int32` |
-| json_name | `string` |
-| options | [google.protobuf.FieldOptions](#fieldoptions) |
-| proto3_optional | `bool` |
-
-### OneofDescriptorProto
-
-Fields
-
-| Name | Type |
-| ---- | ---- |
-| name | `string` |
-| options | [google.protobuf.OneofOptions](#oneofoptions) |
-
-### EnumDescriptorProto
-
-Fields
-
-| Name | Type |
-| ---- | ---- |
-| name | `string` |
-| value | [google.protobuf.EnumValueDescriptorProto](#enumvaluedescriptorproto) |
-| options | [google.protobuf.EnumOptions](#enumoptions) |
-| reserved_range | [google.protobuf.EnumDescriptorProto.EnumReservedRange](#enumdescriptorproto-enumreservedrange) |
-| reserved_name | `string` |
-
-### EnumValueDescriptorProto
-
-Fields
-
-| Name | Type |
-| ---- | ---- |
-| name | `string` |
-| number | `int32` |
-| options | [google.protobuf.EnumValueOptions](#enumvalueoptions) |
-
-### ServiceDescriptorProto
-
-Fields
-
-| Name | Type |
-| ---- | ---- |
-| name | `string` |
-| method | [google.protobuf.MethodDescriptorProto](#methoddescriptorproto) |
-| options | [google.protobuf.ServiceOptions](#serviceoptions) |
-
-### MethodDescriptorProto
-
-Fields
-
-| Name | Type |
-| ---- | ---- |
-| name | `string` |
-| input_type | `string` |
-| output_type | `string` |
-| options | [google.protobuf.MethodOptions](#methodoptions) |
-| client_streaming | `bool` |
-| server_streaming | `bool` |
-
-### FileOptions
+Fields
+### name
+Type: optional `string`
-Fields
-| Name | Type |
-| ---- | ---- |
-| java_package | `string` |
-| java_outer_classname | `string` |
-| java_multiple_files | `bool` |
-| java_generate_equals_and_hash | `bool` |
-| java_string_check_utf8 | `bool` |
-| UNHANDLED | TYPE |
-| go_package | `string` |
-| cc_generic_services | `bool` |
-| java_generic_services | `bool` |
-| py_generic_services | `bool` |
-| php_generic_services | `bool` |
-| deprecated | `bool` |
-| cc_enable_arenas | `bool` |
-| objc_class_prefix | `string` |
-| csharp_namespace | `string` |
-| swift_prefix | `string` |
-| php_class_prefix | `string` |
-| php_namespace | `string` |
-| php_metadata_namespace | `string` |
-| ruby_package | `string` |
-| uninterpreted_option | [google.protobuf.UninterpretedOption](#uninterpretedoption) |
+### package
+Type: optional `string`
-### MessageOptions
-Fields
+### dependency
+Type: repeated `string`
-| Name | Type |
-| ---- | ---- |
-| message_set_wire_format | `bool` |
-| no_standard_descriptor_accessor | `bool` |
-| deprecated | `bool` |
-| map_entry | `bool` |
-| uninterpreted_option | [google.protobuf.UninterpretedOption](#uninterpretedoption) |
+Names of files imported by this file.
+### public_dependency
+Type: repeated `int32`
-### FieldOptions
+Indexes of the public imported files in the dependency list above.
+### weak_dependency
+Type: repeated `int32`
-Fields
+Indexes of the weak imported files in the dependency list.
+For Google-internal migration only. Do not use.
+### message_type
+Type: repeated [google.protobuf.DescriptorProto](#descriptorproto)
-| Name | Type |
-| ---- | ---- |
-| UNHANDLED | TYPE |
-| packed | `bool` |
-| UNHANDLED | TYPE |
-| lazy | `bool` |
-| deprecated | `bool` |
-| weak | `bool` |
-| uninterpreted_option | [google.protobuf.UninterpretedOption](#uninterpretedoption) |
+All top-level definitions in this file.
+### enum_type
+Type: repeated [google.protobuf.EnumDescriptorProto](#enumdescriptorproto)
-### OneofOptions
-Fields
+### service
+Type: repeated [google.protobuf.ServiceDescriptorProto](#servicedescriptorproto)
-| Name | Type |
-| ---- | ---- |
-| uninterpreted_option | [google.protobuf.UninterpretedOption](#uninterpretedoption) |
-### EnumOptions
+### extension
+Type: repeated [google.protobuf.FieldDescriptorProto](#fielddescriptorproto)
-Fields
-| Name | Type |
-| ---- | ---- |
-| allow_alias | `bool` |
-| deprecated | `bool` |
-| uninterpreted_option | [google.protobuf.UninterpretedOption](#uninterpretedoption) |
+### options
+Type: optional [google.protobuf.FileOptions](#fileoptions)
-### EnumValueOptions
-Fields
+### source_code_info
+Type: optional [google.protobuf.SourceCodeInfo](#sourcecodeinfo)
-| Name | Type |
-| ---- | ---- |
-| deprecated | `bool` |
-| uninterpreted_option | [google.protobuf.UninterpretedOption](#uninterpretedoption) |
+This field contains optional information about the original source code.
+You may safely remove this entire field without harming runtime
+functionality of the descriptors -- the information is needed only by
+development tools.
+### syntax
+Type: optional `string`
-### ServiceOptions
+The syntax of the proto file.
+The supported values are "proto2" and "proto3".
-Fields
+------
+## DescriptorProto
+Describes a message type.
-| Name | Type |
-| ---- | ---- |
-| deprecated | `bool` |
-| uninterpreted_option | [google.protobuf.UninterpretedOption](#uninterpretedoption) |
+Fields
+### name
+Type: optional `string`
-### MethodOptions
-Fields
+### field
+Type: repeated [google.protobuf.FieldDescriptorProto](#fielddescriptorproto)
-| Name | Type |
-| ---- | ---- |
-| deprecated | `bool` |
-| UNHANDLED | TYPE |
-| uninterpreted_option | [google.protobuf.UninterpretedOption](#uninterpretedoption) |
-### UninterpretedOption
+### extension
+Type: repeated [google.protobuf.FieldDescriptorProto](#fielddescriptorproto)
-Fields
-| Name | Type |
-| ---- | ---- |
-| name | [google.protobuf.UninterpretedOption.NamePart](#uninterpretedoption-namepart) |
-| identifier_value | `string` |
-| positive_int_value | `uint64` |
-| negative_int_value | `int64` |
-| double_value | `double` |
-| string_value | `bytes` |
-| aggregate_value | `string` |
+### nested_type
+Type: repeated [google.protobuf.DescriptorProto](#descriptorproto)
-### SourceCodeInfo
-Fields
+### enum_type
+Type: repeated [google.protobuf.EnumDescriptorProto](#enumdescriptorproto)
-| Name | Type |
-| ---- | ---- |
-| location | [google.protobuf.SourceCodeInfo.Location](#sourcecodeinfo-location) |
-### GeneratedCodeInfo
+### extension_range
+Type: repeated [google.protobuf.DescriptorProto.ExtensionRange](#descriptorprotoextensionrange)
-Fields
-| Name | Type |
-| ---- | ---- |
-| annotation | [google.protobuf.GeneratedCodeInfo.Annotation](#generatedcodeinfo-annotation) |
+### oneof_decl
+Type: repeated [google.protobuf.OneofDescriptorProto](#oneofdescriptorproto)
-### DescriptorProto.ExtensionRange
-Fields
+### options
+Type: optional [google.protobuf.MessageOptions](#messageoptions)
-| Name | Type |
-| ---- | ---- |
-| start | `int32` |
-| end | `int32` |
-| options | [google.protobuf.ExtensionRangeOptions](#extensionrangeoptions) |
-### DescriptorProto.ReservedRange
+### reserved_range
+Type: repeated [google.protobuf.DescriptorProto.ReservedRange](#descriptorprotoreservedrange)
-Fields
-| Name | Type |
-| ---- | ---- |
-| start | `int32` |
-| end | `int32` |
+### reserved_name
+Type: repeated `string`
-### EnumDescriptorProto.EnumReservedRange
+Reserved field names, which may not be used by fields in the same message.
+A given name may only be reserved once.
-Fields
+------
+## DescriptorProto.ExtensionRange
-| Name | Type |
-| ---- | ---- |
-| start | `int32` |
-| end | `int32` |
-### UninterpretedOption.NamePart
+Fields
+### start
+Type: optional `int32`
-Fields
-| Name | Type |
-| ---- | ---- |
-| name_part | `string` |
-| is_extension | `bool` |
+### end
+Type: optional `int32`
-### SourceCodeInfo.Location
-Fields
+### options
+Type: optional [google.protobuf.ExtensionRangeOptions](#extensionrangeoptions)
-| Name | Type |
-| ---- | ---- |
-| path | `int32` |
-| span | `int32` |
-| leading_comments | `string` |
-| trailing_comments | `string` |
-| leading_detached_comments | `string` |
-### GeneratedCodeInfo.Annotation
-Fields
+------
+## DescriptorProto.ReservedRange
-| Name | Type |
-| ---- | ---- |
-| path | `int32` |
-| source_file | `string` |
-| begin | `int32` |
-| end | `int32` |
-## Services
+Fields
+### start
+Type: optional `int32`
+
+
+### end
+Type: optional `int32`
+
+
+
+------
+## ExtensionRangeOptions
+
+
+Fields
+### uninterpreted_option
+Type: repeated [google.protobuf.UninterpretedOption](#uninterpretedoption)
+
+The parser stores options it doesn't recognize here. See above.
+
+------
+## FieldDescriptorProto
+Describes a field within a message.
+
+Fields
+### name
+Type: optional `string`
+
+
+### number
+Type: optional `int32`
+
+
+### label
+Type: UNHANDLED | TYPE
+
+
+### type
+Type: UNHANDLED | TYPE
+
+If type_name is set, this need not be set. If both this and type_name
+are set, this must be one of TYPE_ENUM, TYPE_MESSAGE or TYPE_GROUP.
+### type_name
+Type: optional `string`
+
+For message and enum types, this is the name of the type. If the name
+starts with a '.', it is fully-qualified. Otherwise, C++-like scoping
+rules are used to find the type (i.e. first the nested types within this
+message are searched, then within the parent, on up to the root
+namespace).
+### extendee
+Type: optional `string`
+
+For extensions, this is the name of the type being extended. It is
+resolved in the same manner as type_name.
+### default_value
+Type: optional `string`
+
+For numeric types, contains the original text representation of the value.
+For booleans, "true" or "false".
+For strings, contains the default text contents (not escaped in any way).
+For bytes, contains the C escaped value. All bytes >= 128 are escaped.
+TODO(kenton): Base-64 encode?
+### oneof_index
+Type: optional `int32`
+
+If set, gives the index of a oneof in the containing type's oneof_decl
+list. This field is a member of that oneof.
+### json_name
+Type: optional `string`
+
+JSON name of this field. The value is set by protocol compiler. If the
+user has set a "json_name" option on this field, that option's value
+will be used. Otherwise, it's deduced from the field's name by converting
+it to camelCase.
+### options
+Type: optional [google.protobuf.FieldOptions](#fieldoptions)
+
+
+### proto3_optional
+Type: optional `bool`
+
+If true, this is a proto3 "optional". When a proto3 field is optional, it
+tracks presence regardless of field type.
+
+When proto3_optional is true, this field must be belong to a oneof to
+signal to old proto3 clients that presence is tracked for this field. This
+oneof is known as a "synthetic" oneof, and this field must be its sole
+member (each proto3 optional field gets its own synthetic oneof). Synthetic
+oneofs exist in the descriptor only, and do not generate any API. Synthetic
+oneofs must be ordered after all "real" oneofs.
+
+For message fields, proto3_optional doesn't create any semantic change,
+since non-repeated message fields always track presence. However it still
+indicates the semantic detail of whether the user wrote "optional" or not.
+This can be useful for round-tripping the .proto file. For consistency we
+give message fields a synthetic oneof also, even though it is not required
+to track presence. This is especially important because the parser can't
+tell if a field is a message or an enum, so it must always create a
+synthetic oneof.
+
+Proto2 optional fields do not set this flag, because they already indicate
+optional with `LABEL_OPTIONAL`.
+
+------
+## OneofDescriptorProto
+Describes a oneof.
+
+Fields
+### name
+Type: optional `string`
+
+
+### options
+Type: optional [google.protobuf.OneofOptions](#oneofoptions)
+
+
+
+------
+## EnumDescriptorProto
+Describes an enum type.
+
+Fields
+### name
+Type: optional `string`
+
+
+### value
+Type: repeated [google.protobuf.EnumValueDescriptorProto](#enumvaluedescriptorproto)
+
+
+### options
+Type: optional [google.protobuf.EnumOptions](#enumoptions)
+
+
+### reserved_range
+Type: repeated [google.protobuf.EnumDescriptorProto.EnumReservedRange](#enumdescriptorprotoenumreservedrange)
+
+Range of reserved numeric values. Reserved numeric values may not be used
+by enum values in the same enum declaration. Reserved ranges may not
+overlap.
+### reserved_name
+Type: repeated `string`
+
+Reserved enum value names, which may not be reused. A given name may only
+be reserved once.
+
+------
+## EnumDescriptorProto.EnumReservedRange
+
+
+Fields
+### start
+Type: optional `int32`
+
+
+### end
+Type: optional `int32`
+
+
+
+------
+## EnumValueDescriptorProto
+Describes a value within an enum.
+
+Fields
+### name
+Type: optional `string`
+
+
+### number
+Type: optional `int32`
+
+
+### options
+Type: optional [google.protobuf.EnumValueOptions](#enumvalueoptions)
+
+
+
+------
+## ServiceDescriptorProto
+Describes a service.
+
+Fields
+### name
+Type: optional `string`
+
+
+### method
+Type: repeated [google.protobuf.MethodDescriptorProto](#methoddescriptorproto)
+
+
+### options
+Type: optional [google.protobuf.ServiceOptions](#serviceoptions)
+
+
+
+------
+## MethodDescriptorProto
+Describes a method of a service.
+
+Fields
+### name
+Type: optional `string`
+
+
+### input_type
+Type: optional `string`
+
+Input and output type names. These are resolved in the same way as
+FieldDescriptorProto.type_name, but must refer to a message type.
+### output_type
+Type: optional `string`
+
+
+### options
+Type: optional [google.protobuf.MethodOptions](#methodoptions)
+
+
+### client_streaming
+Type: optional `bool`
+
+Identifies if client streams multiple client messages
+### server_streaming
+Type: optional `bool`
+
+Identifies if server streams multiple server messages
+
+------
+## FileOptions
+
+
+Fields
+### java_package
+Type: optional `string`
+
+Sets the Java package where classes generated from this .proto will be
+placed. By default, the proto package is used, but this is often
+inappropriate because proto packages do not normally start with backwards
+domain names.
+### java_outer_classname
+Type: optional `string`
+
+Controls the name of the wrapper Java class generated for the .proto file.
+That class will always contain the .proto file's getDescriptor() method as
+well as any top-level extensions defined in the .proto file.
+If java_multiple_files is disabled, then all the other classes from the
+.proto file will be nested inside the single wrapper outer class.
+### java_multiple_files
+Type: optional `bool`
+
+If enabled, then the Java code generator will generate a separate .java
+file for each top-level message, enum, and service defined in the .proto
+file. Thus, these types will *not* be nested inside the wrapper class
+named by java_outer_classname. However, the wrapper class will still be
+generated to contain the file's getDescriptor() method as well as any
+top-level extensions defined in the file.
+### java_generate_equals_and_hash
+Type: optional `bool`
+
+This option does nothing.
+### java_string_check_utf8
+Type: optional `bool`
+
+If set true, then the Java2 code generator will generate code that
+throws an exception whenever an attempt is made to assign a non-UTF-8
+byte sequence to a string field.
+Message reflection will do the same.
+However, an extension field still accepts non-UTF-8 byte sequences.
+This option has no effect on when used with the lite runtime.
+### optimize_for
+Type: UNHANDLED | TYPE
+
+
+### go_package
+Type: optional `string`
+
+Sets the Go package where structs generated from this .proto will be
+placed. If omitted, the Go package will be derived from the following:
+ - The basename of the package import path, if provided.
+ - Otherwise, the package statement in the .proto file, if present.
+ - Otherwise, the basename of the .proto file, without extension.
+### cc_generic_services
+Type: optional `bool`
+
+Should generic services be generated in each language? "Generic" services
+are not specific to any particular RPC system. They are generated by the
+main code generators in each language (without additional plugins).
+Generic services were the only kind of service generation supported by
+early versions of google.protobuf.
+
+Generic services are now considered deprecated in favor of using plugins
+that generate code specific to your particular RPC system. Therefore,
+these default to false. Old code which depends on generic services should
+explicitly set them to true.
+### java_generic_services
+Type: optional `bool`
+
+
+### py_generic_services
+Type: optional `bool`
+
+
+### php_generic_services
+Type: optional `bool`
+
+
+### deprecated
+Type: optional `bool`
+
+Is this file deprecated?
+Depending on the target platform, this can emit Deprecated annotations
+for everything in the file, or it will be completely ignored; in the very
+least, this is a formalization for deprecating files.
+### cc_enable_arenas
+Type: optional `bool`
+
+Enables the use of arenas for the proto messages in this file. This applies
+only to generated classes for C++.
+### objc_class_prefix
+Type: optional `string`
+
+Sets the objective c class prefix which is prepended to all objective c
+generated classes from this .proto. There is no default.
+### csharp_namespace
+Type: optional `string`
+
+Namespace for generated classes; defaults to the package.
+### swift_prefix
+Type: optional `string`
+
+By default Swift generators will take the proto package and CamelCase it
+replacing '.' with underscore and use that to prefix the types/symbols
+defined. When this options is provided, they will use this value instead
+to prefix the types/symbols defined.
+### php_class_prefix
+Type: optional `string`
+
+Sets the php class prefix which is prepended to all php generated classes
+from this .proto. Default is empty.
+### php_namespace
+Type: optional `string`
+
+Use this option to change the namespace of php generated classes. Default
+is empty. When this option is empty, the package name will be used for
+determining the namespace.
+### php_metadata_namespace
+Type: optional `string`
+
+Use this option to change the namespace of php generated metadata classes.
+Default is empty. When this option is empty, the proto file name will be
+used for determining the namespace.
+### ruby_package
+Type: optional `string`
+
+Use this option to change the package of ruby generated classes. Default
+is empty. When this option is not set, the package name will be used for
+determining the ruby package.
+### uninterpreted_option
+Type: repeated [google.protobuf.UninterpretedOption](#uninterpretedoption)
+
+The parser stores options it doesn't recognize here.
+See the documentation for the "Options" section above.
+
+------
+## MessageOptions
+
+
+Fields
+### message_set_wire_format
+Type: optional `bool`
+
+Set true to use the old proto1 MessageSet wire format for extensions.
+This is provided for backwards-compatibility with the MessageSet wire
+format. You should not use this for any other reason: It's less
+efficient, has fewer features, and is more complicated.
+
+The message must be defined exactly as follows:
+ message Foo {
+ option message_set_wire_format = true;
+ extensions 4 to max;
+ }
+Note that the message cannot have any defined fields; MessageSets only
+have extensions.
+
+All extensions of your type must be singular messages; e.g. they cannot
+be int32s, enums, or repeated messages.
+
+Because this is an option, the above two restrictions are not enforced by
+the protocol compiler.
+### no_standard_descriptor_accessor
+Type: optional `bool`
+
+Disables the generation of the standard "descriptor()" accessor, which can
+conflict with a field of the same name. This is meant to make migration
+from proto1 easier; new code should avoid fields named "descriptor".
+### deprecated
+Type: optional `bool`
+
+Is this message deprecated?
+Depending on the target platform, this can emit Deprecated annotations
+for the message, or it will be completely ignored; in the very least,
+this is a formalization for deprecating messages.
+### map_entry
+Type: optional `bool`
+
+Whether the message is an automatically generated map entry type for the
+maps field.
+
+For maps fields:
+ map map_field = 1;
+The parsed descriptor looks like:
+ message MapFieldEntry {
+ option map_entry = true;
+ optional KeyType key = 1;
+ optional ValueType value = 2;
+ }
+ repeated MapFieldEntry map_field = 1;
+
+Implementations may choose not to generate the map_entry=true message, but
+use a native map in the target language to hold the keys and values.
+The reflection APIs in such implementations still need to work as
+if the field is a repeated message field.
+
+NOTE: Do not set the option in .proto files. Always use the maps syntax
+instead. The option should only be implicitly set by the proto compiler
+parser.
+### uninterpreted_option
+Type: repeated [google.protobuf.UninterpretedOption](#uninterpretedoption)
+
+The parser stores options it doesn't recognize here. See above.
+
+------
+## FieldOptions
+
+
+Fields
+### ctype
+Type: UNHANDLED | TYPE
+
+The ctype option instructs the C++ code generator to use a different
+representation of the field than it normally would. See the specific
+options below. This option is not yet implemented in the open source
+release -- sorry, we'll try to include it in a future version!
+### packed
+Type: optional `bool`
+
+The packed option can be enabled for repeated primitive fields to enable
+a more efficient representation on the wire. Rather than repeatedly
+writing the tag and type for each element, the entire array is encoded as
+a single length-delimited blob. In proto3, only explicit setting it to
+false will avoid using packed encoding.
+### jstype
+Type: UNHANDLED | TYPE
+
+The jstype option determines the JavaScript type used for values of the
+field. The option is permitted only for 64 bit integral and fixed types
+(int64, uint64, sint64, fixed64, sfixed64). A field with jstype JS_STRING
+is represented as JavaScript string, which avoids loss of precision that
+can happen when a large value is converted to a floating point JavaScript.
+Specifying JS_NUMBER for the jstype causes the generated JavaScript code to
+use the JavaScript "number" type. The behavior of the default option
+JS_NORMAL is implementation dependent.
+
+This option is an enum to permit additional types to be added, e.g.
+goog.math.Integer.
+### lazy
+Type: optional `bool`
+
+Should this field be parsed lazily? Lazy applies only to message-type
+fields. It means that when the outer message is initially parsed, the
+inner message's contents will not be parsed but instead stored in encoded
+form. The inner message will actually be parsed when it is first accessed.
+
+This is only a hint. Implementations are free to choose whether to use
+eager or lazy parsing regardless of the value of this option. However,
+setting this option true suggests that the protocol author believes that
+using lazy parsing on this field is worth the additional bookkeeping
+overhead typically needed to implement it.
+
+This option does not affect the public interface of any generated code;
+all method signatures remain the same. Furthermore, thread-safety of the
+interface is not affected by this option; const methods remain safe to
+call from multiple threads concurrently, while non-const methods continue
+to require exclusive access.
+
+
+Note that implementations may choose not to check required fields within
+a lazy sub-message. That is, calling IsInitialized() on the outer message
+may return true even if the inner message has missing required fields.
+This is necessary because otherwise the inner message would have to be
+parsed in order to perform the check, defeating the purpose of lazy
+parsing. An implementation which chooses not to check required fields
+must be consistent about it. That is, for any particular sub-message, the
+implementation must either *always* check its required fields, or *never*
+check its required fields, regardless of whether or not the message has
+been parsed.
+### deprecated
+Type: optional `bool`
+
+Is this field deprecated?
+Depending on the target platform, this can emit Deprecated annotations
+for accessors, or it will be completely ignored; in the very least, this
+is a formalization for deprecating fields.
+### weak
+Type: optional `bool`
+
+For Google-internal migration only. Do not use.
+### uninterpreted_option
+Type: repeated [google.protobuf.UninterpretedOption](#uninterpretedoption)
+
+The parser stores options it doesn't recognize here. See above.
+
+------
+## OneofOptions
+
+
+Fields
+### uninterpreted_option
+Type: repeated [google.protobuf.UninterpretedOption](#uninterpretedoption)
+
+The parser stores options it doesn't recognize here. See above.
+
+------
+## EnumOptions
+
+
+Fields
+### allow_alias
+Type: optional `bool`
+
+Set this option to true to allow mapping different tag names to the same
+value.
+### deprecated
+Type: optional `bool`
+
+Is this enum deprecated?
+Depending on the target platform, this can emit Deprecated annotations
+for the enum, or it will be completely ignored; in the very least, this
+is a formalization for deprecating enums.
+### uninterpreted_option
+Type: repeated [google.protobuf.UninterpretedOption](#uninterpretedoption)
+
+The parser stores options it doesn't recognize here. See above.
+
+------
+## EnumValueOptions
+
+
+Fields
+### deprecated
+Type: optional `bool`
+
+Is this enum value deprecated?
+Depending on the target platform, this can emit Deprecated annotations
+for the enum value, or it will be completely ignored; in the very least,
+this is a formalization for deprecating enum values.
+### uninterpreted_option
+Type: repeated [google.protobuf.UninterpretedOption](#uninterpretedoption)
+
+The parser stores options it doesn't recognize here. See above.
+
+------
+## ServiceOptions
+
+
+Fields
+### deprecated
+Type: optional `bool`
+
+Is this service deprecated?
+Depending on the target platform, this can emit Deprecated annotations
+for the service, or it will be completely ignored; in the very least,
+this is a formalization for deprecating services.
+### uninterpreted_option
+Type: repeated [google.protobuf.UninterpretedOption](#uninterpretedoption)
+
+The parser stores options it doesn't recognize here. See above.
+
+------
+## MethodOptions
+
+
+Fields
+### deprecated
+Type: optional `bool`
+
+Is this method deprecated?
+Depending on the target platform, this can emit Deprecated annotations
+for the method, or it will be completely ignored; in the very least,
+this is a formalization for deprecating methods.
+### idempotency_level
+Type: UNHANDLED | TYPE
+
+
+### uninterpreted_option
+Type: repeated [google.protobuf.UninterpretedOption](#uninterpretedoption)
+
+The parser stores options it doesn't recognize here. See above.
+
+------
+## UninterpretedOption
+A message representing a option the parser does not recognize. This only
+appears in options protos created by the compiler::Parser class.
+DescriptorPool resolves these when building Descriptor objects. Therefore,
+options protos in descriptor objects (e.g. returned by Descriptor::options(),
+or produced by Descriptor::CopyTo()) will never have UninterpretedOptions
+in them.
+
+Fields
+### name
+Type: repeated [google.protobuf.UninterpretedOption.NamePart](#uninterpretedoptionnamepart)
+
+
+### identifier_value
+Type: optional `string`
+
+The value of the uninterpreted option, in whatever type the tokenizer
+identified it as during parsing. Exactly one of these should be set.
+### positive_int_value
+Type: optional `uint64`
+
+
+### negative_int_value
+Type: optional `int64`
+
+
+### double_value
+Type: optional `double`
+
+
+### string_value
+Type: optional `bytes`
+
+
+### aggregate_value
+Type: optional `string`
+
+
+
+------
+## UninterpretedOption.NamePart
+
+
+Fields
+### name_part
+Type: `string`
+
+
+### is_extension
+Type: `bool`
+
+
+
+------
+## SourceCodeInfo
+Encapsulates information about the original source file from which a
+FileDescriptorProto was generated.
+
+Fields
+### location
+Type: repeated [google.protobuf.SourceCodeInfo.Location](#sourcecodeinfolocation)
+
+A Location identifies a piece of source code in a .proto file which
+corresponds to a particular definition. This information is intended
+to be useful to IDEs, code indexers, documentation generators, and similar
+tools.
+
+For example, say we have a file like:
+ message Foo {
+ optional string foo = 1;
+ }
+Let's look at just the field definition:
+ optional string foo = 1;
+ ^ ^^ ^^ ^ ^^^
+ a bc de f ghi
+We have the following locations:
+ span path represents
+ [a,i) [ 4, 0, 2, 0 ] The whole field definition.
+ [a,b) [ 4, 0, 2, 0, 4 ] The label (optional).
+ [c,d) [ 4, 0, 2, 0, 5 ] The type (string).
+ [e,f) [ 4, 0, 2, 0, 1 ] The name (foo).
+ [g,h) [ 4, 0, 2, 0, 3 ] The number (1).
+
+Notes:
+- A location may refer to a repeated field itself (i.e. not to any
+ particular index within it). This is used whenever a set of elements are
+ logically enclosed in a single code segment. For example, an entire
+ extend block (possibly containing multiple extension definitions) will
+ have an outer location whose path refers to the "extensions" repeated
+ field without an index.
+- Multiple locations may have the same path. This happens when a single
+ logical declaration is spread out across multiple places. The most
+ obvious example is the "extend" block again -- there may be multiple
+ extend blocks in the same scope, each of which will have the same path.
+- A location's span is not always a subset of its parent's span. For
+ example, the "extendee" of an extension declaration appears at the
+ beginning of the "extend" block and is shared by all extensions within
+ the block.
+- Just because a location's span is a subset of some other location's span
+ does not mean that it is a descendant. For example, a "group" defines
+ both a type and a field in a single declaration. Thus, the locations
+ corresponding to the type and field and their components will overlap.
+- Code which tries to interpret locations should probably be designed to
+ ignore those that it doesn't understand, as more types of locations could
+ be recorded in the future.
+
+------
+## SourceCodeInfo.Location
+
+
+Fields
+### path
+Type: repeated `int32`
+
+
+### span
+Type: repeated `int32`
+
+
+### leading_comments
+Type: optional `string`
+
+
+### trailing_comments
+Type: optional `string`
+
+
+### leading_detached_comments
+Type: repeated `string`
+
+
+
+------
+## GeneratedCodeInfo
+Describes the relationship between generated code and its original source
+file. A GeneratedCodeInfo message is associated with only one generated
+source file, but may contain references to different source .proto files.
+
+Fields
+### annotation
+Type: repeated [google.protobuf.GeneratedCodeInfo.Annotation](#generatedcodeinfoannotation)
+
+An Annotation connects some span of text in generated code to an element
+of its generating .proto file.
+
+------
+## GeneratedCodeInfo.Annotation
+
+
+Fields
+### path
+Type: repeated `int32`
+
+
+### source_file
+Type: optional `string`
+
+
+### begin
+Type: optional `int32`
+
+
+### end
+Type: optional `int32`
+
+
+
+# Enums
+
+## Type
+
+
+### TYPE_DOUBLE
+
+
+### TYPE_FLOAT
+
+
+### TYPE_INT64
+
+
+### TYPE_UINT64
+
+
+### TYPE_INT32
+
+
+### TYPE_FIXED64
+
+
+### TYPE_FIXED32
+
+
+### TYPE_BOOL
+
+
+### TYPE_STRING
+
+
+### TYPE_GROUP
+
+
+### TYPE_MESSAGE
+
+
+### TYPE_BYTES
+
+
+### TYPE_UINT32
+
+
+### TYPE_ENUM
+
+
+### TYPE_SFIXED32
+
+
+### TYPE_SFIXED64
+
+
+### TYPE_SINT32
+
+
+### TYPE_SINT64
+
+
+------
+## Label
+
+
+### LABEL_OPTIONAL
+
+
+### LABEL_REQUIRED
+
+
+### LABEL_REPEATED
+
+
+------
+## OptimizeMode
+
+
+### SPEED
+
+
+### CODE_SIZE
+
+
+### LITE_RUNTIME
+
+
+------
+## CType
+
+
+### STRING
+
+
+### CORD
+
+
+### STRING_PIECE
+
+
+------
+## JSType
+
+
+### JS_NORMAL
+
+
+### JS_STRING
+
+
+### JS_NUMBER
+
+
+------
+## IdempotencyLevel
+
+
+### IDEMPOTENCY_UNKNOWN
+
+
+### NO_SIDE_EFFECTS
+
+
+### IDEMPOTENT
+
diff --git a/content/docs/name-resolution.md b/content/docs/name-resolution.md
index b25b0b0..c50aa6c 120000
--- a/content/docs/name-resolution.md
+++ b/content/docs/name-resolution.md
@@ -1 +1 @@
-../protocol/name-resolution/name-resolution.md
\ No newline at end of file
+../protocol/stable/name-resolution/name-resolution.md
\ No newline at end of file
diff --git a/content/docs/protocol.auth.v1.md b/content/docs/protocol.auth.v1.md
index 3d88cda..32c2843 100644
--- a/content/docs/protocol.auth.v1.md
+++ b/content/docs/protocol.auth.v1.md
@@ -1,247 +1,453 @@
---
title: "Reference: protocol.auth.v1"
---
-## Message Types
+# Services
-### BeginAuthRequest
+## AuthService
-Fields
+The service containing authorization/entication methods
+Fields
+#### Federate
+[protocol.auth.v1.FederateRequest](#federaterequest) -> [protocol.auth.v1.FederateResponse](#federateresponse)
-| Name | Type |
-| ---- | ---- |
+Federate with a foreignserver, obtaining a token
+you can use to call LoginFederated on it
-### BeginAuthResponse
+
-Fields
+##### FederateRequest
+The request to federate with a foreign server.
-| Name | Type |
-| ---- | ---- |
-| auth_id | `string` |
+Fields
+###### server_id
+Type: optional `string`
-### Session
+The server ID foreign server you want to federate with
-Fields
-| Name | Type |
-| ---- | ---- |
-| user_id | `uint64` |
-| session_token | `string` |
+
-### AuthStep
+##### FederateResponse
+The reply to a successful federation request,
+containing the token you need to present to the
+foreign server.
-Fields
+Fields
+###### token
+Type: optional [protocol.harmonytypes.v1.Token]({{< ref "protocol.harmonytypes.v1.md" >}}#token)
-| Name | Type |
-| ---- | ---- |
-| fallback_url | `string` |
-| can_go_back | `bool` |
-| choice | [protocol.auth.v1.AuthStep.Choice](#authstep-choice) |
-| form | [protocol.auth.v1.AuthStep.Form](#authstep-form) |
-| session | [protocol.auth.v1.Session](#session) |
-| waiting | [protocol.auth.v1.AuthStep.Waiting](#authstep-waiting) |
+A `harmonytypes.v1.Token` whose `data` field is a serialized `TokenData` message.
+It is signed with the homeserver's private key.
-### NextStepRequest
+------
+#### LoginFederated
+[protocol.auth.v1.LoginFederatedRequest](#loginfederatedrequest) -> [protocol.auth.v1.LoginFederatedResponse](#loginfederatedresponse)
-Fields
+Present a token to a foreignserver from a Federate call
+on your homeserver in order to login
-| Name | Type |
-| ---- | ---- |
-| auth_id | `string` |
-| choice | [protocol.auth.v1.NextStepRequest.Choice](#nextsteprequest-choice) |
-| form | [protocol.auth.v1.NextStepRequest.Form](#nextsteprequest-form) |
+
-### NextStepResponse
+##### LoginFederatedRequest
+Log into a foreignserver using a token
+from your homeserver, obtained through a FederateRequest
-Fields
+Fields
+###### auth_token
+Type: optional [protocol.harmonytypes.v1.Token]({{< ref "protocol.harmonytypes.v1.md" >}}#token)
-| Name | Type |
-| ---- | ---- |
-| step | [protocol.auth.v1.AuthStep](#authstep) |
+A `harmonytypes.v1.Token` whose `data` field is a serialized `TokenData` message.
+It is signed with the homeserver's private key.
+###### server_id
+Type: optional `string`
-### StepBackRequest
+The server ID of the homeserver that the auth token is from
-Fields
-| Name | Type |
-| ---- | ---- |
-| auth_id | `string` |
+
-### StepBackResponse
+##### LoginFederatedResponse
+Used in `LoginFederated` endpoint.
-Fields
+Fields
+###### session
+Type: optional [protocol.auth.v1.Session](#session)
-| Name | Type |
-| ---- | ---- |
-| step | [protocol.auth.v1.AuthStep](#authstep) |
+The user's session.
-### StreamStepsRequest
+------
+#### Key
+[protocol.auth.v1.KeyRequest](#keyrequest) -> [protocol.auth.v1.KeyResponse](#keyresponse)
-Fields
+Returns the public key of this server
-| Name | Type |
-| ---- | ---- |
-| auth_id | `string` |
+
-### StreamStepsResponse
+##### KeyRequest
+Used in `Key` endpoint.
-Fields
+This item has no fields.
-| Name | Type |
-| ---- | ---- |
-| step | [protocol.auth.v1.AuthStep](#authstep) |
-### FederateRequest
+
-Fields
+##### KeyResponse
+Contains a key's bytes.
-| Name | Type |
-| ---- | ---- |
-| server_id | `string` |
+Fields
+###### key
+Type: optional `bytes`
-### FederateResponse
+key: the bytes of the public key.
-Fields
+------
+#### BeginAuth
+[protocol.auth.v1.BeginAuthRequest](#beginauthrequest) -> [protocol.auth.v1.BeginAuthResponse](#beginauthresponse)
-| Name | Type |
-| ---- | ---- |
-| token | [protocol.harmonytypes.v1.Token]({{< ref "protocol.harmonytypes.v1.md" >}}#token) |
+Begins an authentication session
-### KeyRequest
+
-Fields
+##### BeginAuthRequest
+Used in `BeginAuth` endpoint.
-| Name | Type |
-| ---- | ---- |
+Fields
+###### for_guest_token
+Type: optional `string`
-### KeyResponse
+If provided, this is the guest token
+for the account being upgraded from
+a guest account to a full account
+during the auth flow.
-Fields
+This token is provided by the server
+at the end of the auth flow that
+created the guest account.
-| Name | Type |
-| ---- | ---- |
-| key | `bytes` |
-### LoginFederatedRequest
+
-Fields
+##### BeginAuthResponse
+BeginAuthResponse
+The return type of BeginAuth, containing the
+auth_id that will be used for the authentication
+section
-| Name | Type |
-| ---- | ---- |
-| auth_token | [protocol.harmonytypes.v1.Token]({{< ref "protocol.harmonytypes.v1.md" >}}#token) |
-| server_id | `string` |
+Fields
+###### auth_id
+Type: optional `string`
-### LoginFederatedResponse
+auth_id: the ID of this auth session
-Fields
+------
+#### NextStep
+[protocol.auth.v1.NextStepRequest](#nextsteprequest) -> [protocol.auth.v1.NextStepResponse](#nextstepresponse)
-| Name | Type |
-| ---- | ---- |
-| session | [protocol.auth.v1.Session](#session) |
+Goes to the next step of the authentication session,
+possibly presenting user input
+##### NextStepResponse
+Used in `NextStep` endpoint.
-### TokenData
+Fields
+###### step
+Type: optional [protocol.auth.v1.AuthStep](#authstep)
-Fields
+step: the next step in the authentication process
-| Name | Type |
-| ---- | ---- |
-| user_id | `uint64` |
-| server_id | `string` |
-| username | `string` |
-| avatar | `string` |
+------
+#### StepBack
+[protocol.auth.v1.StepBackRequest](#stepbackrequest) -> [protocol.auth.v1.StepBackResponse](#stepbackresponse)
-### CheckLoggedInRequest
+Goes to the previous step of the authentication session
+if possible
-Fields
+
-| Name | Type |
-| ---- | ---- |
+##### StepBackRequest
+StepBackRequest
+A request to go back 1 step
-### CheckLoggedInResponse
+Fields
+###### auth_id
+Type: optional `string`
-Fields
+auth_id: the authentication session the user
+wants to go back in
-| Name | Type |
-| ---- | ---- |
-### AuthStep.Choice
+
-Fields
+##### StepBackResponse
+Used in `StepBack` endpoint.
-| Name | Type |
-| ---- | ---- |
-| title | `string` |
-| options | `string` |
+Fields
+###### step
+Type: optional [protocol.auth.v1.AuthStep](#authstep)
-### AuthStep.Form
+step: the previous step in the authentication process
-Fields
+------
+#### StreamSteps
+[protocol.auth.v1.StreamStepsRequest](#streamstepsrequest) -> streaming [protocol.auth.v1.StreamStepsResponse](#streamstepsresponse)
-| Name | Type |
-| ---- | ---- |
-| title | `string` |
-| fields | [protocol.auth.v1.AuthStep.Form.FormField](#authstep-form-formfield) |
+Consume the steps of an authentication session
+as a stream
-### AuthStep.Waiting
+
-Fields
+##### StreamStepsRequest
+StreamStepsRequest
+Required to be initiated by all authenticating clients
+Allows the server to send steps
-| Name | Type |
-| ---- | ---- |
-| title | `string` |
-| description | `string` |
+Fields
+###### auth_id
+Type: optional `string`
-### AuthStep.Form.FormField
+auth_id: the authorization session
+who's steps you want to stream
-Fields
-| Name | Type |
-| ---- | ---- |
-| name | `string` |
-| type | `string` |
+
-### NextStepRequest.Choice
+##### StreamStepsResponse
+Used in `StreamSteps` endpoint.
-Fields
+Fields
+###### step
+Type: optional [protocol.auth.v1.AuthStep](#authstep)
-| Name | Type |
-| ---- | ---- |
-| choice | `string` |
+step: the next step in the authentication process
-### NextStepRequest.FormFields
+------
+#### CheckLoggedIn
+[protocol.auth.v1.CheckLoggedInRequest](#checkloggedinrequest) -> [protocol.auth.v1.CheckLoggedInResponse](#checkloggedinresponse)
-Fields
+Check whether or not you're logged in and the session is valid
-| Name | Type |
-| ---- | ---- |
-| bytes | `bytes` |
-| string | `string` |
-| number | `int64` |
+
-### NextStepRequest.Form
+##### CheckLoggedInRequest
+Used in `CheckLoggedIn` endpoint.
-Fields
+This item has no fields.
-| Name | Type |
-| ---- | ---- |
-| fields | [protocol.auth.v1.NextStepRequest.FormFields](#nextsteprequest-formfields) |
-## Services
+
-### AuthService
+##### CheckLoggedInResponse
+Used in `CheckLoggedIn` endpoint.
-#### Unary Methods
+This item has no fields.
-| Name | Request | Response |
-| ---- | ------- | -------- |
-|Federate|[protocol.auth.v1.FederateRequest](#federaterequest)|[protocol.auth.v1.FederateResponse](#federateresponse)|
-|LoginFederated|[protocol.auth.v1.LoginFederatedRequest](#loginfederatedrequest)|[protocol.auth.v1.LoginFederatedResponse](#loginfederatedresponse)|
-|Key|[protocol.auth.v1.KeyRequest](#keyrequest)|[protocol.auth.v1.KeyResponse](#keyresponse)|
-|BeginAuth|[protocol.auth.v1.BeginAuthRequest](#beginauthrequest)|[protocol.auth.v1.BeginAuthResponse](#beginauthresponse)|
-|NextStep|[protocol.auth.v1.NextStepRequest](#nextsteprequest)|[protocol.auth.v1.NextStepResponse](#nextstepresponse)|
-|StepBack|[protocol.auth.v1.StepBackRequest](#stepbackrequest)|[protocol.auth.v1.StepBackResponse](#stepbackresponse)|
-|CheckLoggedIn|[protocol.auth.v1.CheckLoggedInRequest](#checkloggedinrequest)|[protocol.auth.v1.CheckLoggedInResponse](#checkloggedinresponse)|
+# Standalone Message Types
-#### Streaming Methods
+## Session
+Session
+Session contains the information for a new session;
+the user_id you logged in as and the session_token
+which should be passed to authorisation
-| Name | Client Streams | Server Streams |
-| ---- | -------------- | -------------- |
+Fields
+### user_id
+Type: optional `uint64`
+
+user_id: the ID of the user you logged in as
+### session_token
+Type: optional `string`
+
+session_token: the session token to use in authorization
+### guest_token
+Type: optional `string`
+
+A token allowing for this account to be upgraded to a
+"full" account by beginning an auth session and providing
+this token.
+
+The guest token only exists to upgrade a guest account to a full
+account, and does not permit logging in with a guest account
+on more than one session.
+
+A "guest token" MAY be provided to BeginAuth to begin
+an authorization process that will upgrade the guest account
+to a full account if completed successfully.
+This MUST only affect now being able to log
+into the account with more than one session, and MUST not
+change other information about the account, such as username
+and password.
+
+------
+## AuthStep
+AuthStep
+A step in the authentication process
+Contains a variety of different types of views
+It is recommended to have a fallback_url specified
+For non-trivial authentication procedures (such as captchas)
+
+Fields
+### fallback_url
+Type: optional `string`
+
+fallback_url: unused
+### can_go_back
+Type: optional `bool`
+
+can_go_back: whether or not the client can request the
+server to send the previous step
+### choice
+Type: optional [protocol.auth.v1.AuthStep.Choice](#authstepchoice)
+
+choice: the user must pick a thing out of a list of options
+### form
+Type: optional [protocol.auth.v1.AuthStep.Form](#authstepform)
+
+form: the user must complete a form
+### session
+Type: optional [protocol.auth.v1.Session](#session)
+
+session: you've completed auth, and have a session
+### waiting
+Type: optional [protocol.auth.v1.AuthStep.Waiting](#authstepwaiting)
+
+waiting: you're waiting on something
+
+------
+## AuthStep.Choice
+
+
+Fields
+### title
+Type: optional `string`
+
+
+### options
+Type: repeated `string`
+
+
+
+------
+## AuthStep.Form
+
+
+Fields
+### title
+Type: optional `string`
+
+
+### fields
+Type: repeated [protocol.auth.v1.AuthStep.Form.FormField](#authstepformformfield)
+
+
+
+------
+## AuthStep.Form.FormField
+
+
+Fields
+### name
+Type: optional `string`
+
+
+### type
+Type: optional `string`
+
+
+
+------
+## AuthStep.Waiting
+
+
+Fields
+### title
+Type: optional `string`
+
+
+### description
+Type: optional `string`
+
+
+
+------
+## NextStepRequest
+NextStepRequest
+contains the client's response to the server's challenge
+This needs to be called first with no arguments to
+receive the first step
+
+Fields
+### auth_id
+Type: optional `string`
+
+auth_id: the authentication session you want
+the next step of
+### choice
+Type: optional [protocol.auth.v1.NextStepRequest.Choice](#nextsteprequestchoice)
+
+choice: the choice the user picked
+### form
+Type: optional [protocol.auth.v1.NextStepRequest.Form](#nextsteprequestform)
+
+form: the form the user filled out
+
+------
+## NextStepRequest.Choice
+
+
+Fields
+### choice
+Type: optional `string`
+
+
+
+------
+## NextStepRequest.FormFields
+
+
+Fields
+### bytes
+Type: optional `bytes`
+
+
+### string
+Type: optional `string`
+
+
+### number
+Type: optional `int64`
+
+
+
+------
+## NextStepRequest.Form
+
+
+Fields
+### fields
+Type: repeated [protocol.auth.v1.NextStepRequest.FormFields](#nextsteprequestformfields)
+
+
+
+------
+## TokenData
+Information sent by a client's homeserver, in a `harmonytypes.v1.Token`.
+It will be sent to a foreignserver by the client.
+
+Fields
+### user_id
+Type: optional `uint64`
+
+The client's user ID on the homeserver.
+### server_id
+Type: optional `string`
+
+The foreignserver's server ID.
+### username
+Type: optional `string`
+
+The username of the client.
+### avatar
+Type: optional `string`
+
+The avatar of the client.
+
+------
diff --git a/content/docs/protocol.batch.v1.md b/content/docs/protocol.batch.v1.md
index 7d88832..3b8ed26 100644
--- a/content/docs/protocol.batch.v1.md
+++ b/content/docs/protocol.batch.v1.md
@@ -1,62 +1,77 @@
---
title: "Reference: protocol.batch.v1"
---
-## Message Types
+# Services
-### AnyRequest
+## BatchService
-Fields
+Service to batch requests.
+Fields
+#### Batch
+[protocol.batch.v1.BatchRequest](#batchrequest) -> [protocol.batch.v1.BatchResponse](#batchresponse)
-| Name | Type |
-| ---- | ---- |
-| endpoint | `string` |
-| request | `bytes` |
+Batch requests.
+Does not support batching stream requests.
+Batched requests should be verified and an error should be thrown if they
+are invalid.
-### BatchRequest
+
-Fields
+##### BatchRequest
+Used in `Batch` endpoint.
-| Name | Type |
-| ---- | ---- |
-| requests | [protocol.batch.v1.AnyRequest](#anyrequest) |
+Fields
+###### requests
+Type: repeated [protocol.batch.v1.AnyRequest](#anyrequest)
-### BatchResponse
+The list of requests to be executed in the batch.
-Fields
-| Name | Type |
-| ---- | ---- |
-| responses | `bytes` |
+
-### BatchSameRequest
+##### BatchResponse
+Used in `Batch` endpoint.
-Fields
+Fields
+###### responses
+Type: repeated `bytes`
-| Name | Type |
-| ---- | ---- |
-| endpoint | `string` |
-| requests | `bytes` |
+The list of responses to the requests.
-### BatchSameResponse
+------
+#### BatchSame
+[protocol.batch.v1.BatchSameRequest](#batchsamerequest) -> [protocol.batch.v1.BatchSameResponse](#batchsameresponse)
-Fields
+BatchSame allows batching for requests using the same endpoint.
+This allows for additional network optimizations since the endpoint doesn't
+have to be sent for every request.
-| Name | Type |
-| ---- | ---- |
-| responses | `bytes` |
+
-## Services
+##### BatchSameRequest
+Used in `BatchSame` endpoint.
-### BatchService
+Fields
+###### endpoint
+Type: optional `string`
-#### Unary Methods
+The endpoint to call for all requests.
+###### requests
+Type: repeated `bytes`
-| Name | Request | Response |
-| ---- | ------- | -------- |
-|Batch|[protocol.batch.v1.BatchRequest](#batchrequest)|[protocol.batch.v1.BatchResponse](#batchresponse)|
-|BatchSame|[protocol.batch.v1.BatchSameRequest](#batchsamerequest)|[protocol.batch.v1.BatchSameResponse](#batchsameresponse)|
+The list of requests to be executed in the batch.
-#### Streaming Methods
-| Name | Client Streams | Server Streams |
-| ---- | -------------- | -------------- |
+
+
+##### BatchSameResponse
+Used in `BatchSame` endpoint.
+
+Fields
+###### responses
+Type: repeated `bytes`
+
+The list of responses to the requests.
+
+# Standalone Message Types
+
diff --git a/content/docs/protocol.bots.v1.md b/content/docs/protocol.bots.v1.md
new file mode 100644
index 0000000..d9f8696
--- /dev/null
+++ b/content/docs/protocol.bots.v1.md
@@ -0,0 +1,255 @@
+---
+title: "Reference: protocol.bots.v1"
+---
+## Bot Invite Codes
+
+Bot invite codes work similarly to HMC URLs.
+They can either be server+code or just code,
+to refer to a bot on the current homeserver.
+
+The format for an invite code is:
+> [url[:port]/]code
+
+where `code` is a purely alphanumeric code.
+
+# Services
+
+## BotsService
+
+The Bots service allows the management of bot accounts
+Fields
+#### MyBots
+[protocol.bots.v1.MyBotsRequest](#mybotsrequest) -> [protocol.bots.v1.MyBotsResponse](#mybotsresponse)
+
+Gets the list of bots that you own
+
+
+
+##### MyBotsRequest
+Request type for MyBots
+
+This item has no fields.
+
+
+
+
+##### MyBotsResponse
+Response type for MyBots
+
+Fields
+###### bots
+Type: repeated [protocol.bots.v1.Bot](#bot)
+
+The list of owned bots
+
+------
+#### GetBot
+[protocol.bots.v1.GetBotRequest](#getbotrequest) -> [protocol.bots.v1.GetBotResponse](#getbotresponse)
+
+Gets information on a given bot
+
+
+
+##### GetBotRequest
+Request type for GetBot
+
+Fields
+###### bot_id
+Type: optional `uint64`
+
+The bot to get the information of
+
+
+
+
+##### GetBotResponse
+Response type for GetBot
+
+Fields
+###### bot
+Type: optional [protocol.bots.v1.Bot](#bot)
+
+The requested bot
+
+------
+#### CreateBot
+[protocol.bots.v1.CreateBotRequest](#createbotrequest) -> [protocol.bots.v1.CreateBotResponse](#createbotresponse)
+
+Creates a new bot account
+
+
+
+##### CreateBotRequest
+Request type for CreateBot
+
+Fields
+###### display_name
+Type: optional `string`
+
+The bot's display name
+###### avatar_url
+Type: optional `string`
+
+The bot's avatar URL
+###### invite
+Type: optional `string`
+
+The bot's invite code, if it has one
+
+
+
+
+##### CreateBotResponse
+Response type for CreateBot
+
+Fields
+###### bot_id
+Type: optional `uint64`
+
+The newly minted ID of the bot
+
+------
+#### EditBot
+[protocol.bots.v1.EditBotRequest](#editbotrequest) -> [protocol.bots.v1.EditBotResponse](#editbotresponse)
+
+Modifies a bot account that you own
+
+
+
+##### EditBotRequest
+Request type for EditBot
+
+Fields
+###### bot_id
+Type: optional `uint64`
+
+The ID of the bot to edit
+###### new_display_name
+Type: optional `string`
+
+The bot's new display name
+###### new_avatar_url
+Type: optional `string`
+
+The bot's new avatar URL
+###### invite
+Type: optional `string`
+
+The bot's new invite code
+
+
+
+
+##### EditBotResponse
+Response type for EditBot
+
+This item has no fields.
+
+------
+#### DeleteBot
+[protocol.bots.v1.DeleteBotRequest](#deletebotrequest) -> [protocol.bots.v1.DeleteBotResponse](#deletebotresponse)
+
+Deletes a bot account that you own
+
+
+
+##### DeleteBotRequest
+Request type for DeleteBot
+
+Fields
+###### bot_id
+Type: optional `uint64`
+
+The bot to delete
+
+
+
+
+##### DeleteBotResponse
+Response type for DeleteBot
+
+This item has no fields.
+
+------
+#### Policies
+[protocol.bots.v1.PoliciesRequest](#policiesrequest) -> [protocol.bots.v1.PoliciesResponse](#policiesresponse)
+
+Server policies for bot accounts that the client
+may display in its UI or restrict actions to prevent
+request errors
+
+
+
+##### PoliciesRequest
+Request type for Policies
+
+This item has no fields.
+
+
+
+
+##### PoliciesResponse
+Response type for Policies
+
+Fields
+###### max_bots
+Type: optional `uint32`
+
+How many bots an individual account is allowed to own
+
+------
+#### AddBot
+[protocol.bots.v1.AddBotRequest](#addbotrequest) -> [protocol.bots.v1.AddBotResponse](#addbotresponse)
+
+Requests a bot to add itself to the guild.
+
+For cross-server bots, this dispatches a UserInvited
+request across sync, inviting the bot to the guild.
+
+
+
+##### AddBotRequest
+Request type for AddBot
+
+Fields
+###### guild_id
+Type: optional `uint64`
+
+The guild to add the bot to
+###### invite_code
+Type: optional `string`
+
+The bot's invite code.
+
+
+
+
+##### AddBotResponse
+Response type for AddBot
+
+This item has no fields.
+
+# Standalone Message Types
+
+## Bot
+A description of a bot account
+
+Fields
+### bot_id
+Type: optional `uint64`
+
+The ID of the bot
+### display_name
+Type: optional `string`
+
+The bot's display name
+### avatar_url
+Type: optional `string`
+
+The bot's avatar URL
+### invite
+Type: optional `string`
+
+The bot's invite code, if it has one
+
+------
diff --git a/content/docs/protocol.chat.v1.md b/content/docs/protocol.chat.v1.md
index 24a1446..0f368f5 100644
--- a/content/docs/protocol.chat.v1.md
+++ b/content/docs/protocol.chat.v1.md
@@ -1,1046 +1,3697 @@
---
title: "Reference: protocol.chat.v1"
---
-## Message Types
+# Services
-### GetUserRequest
+## ChatService
-Fields
+The core of Harmony's chat operations.
+Fields
+#### CreateGuild
+[protocol.chat.v1.CreateGuildRequest](#createguildrequest) -> [protocol.chat.v1.CreateGuildResponse](#createguildresponse)
-| Name | Type |
-| ---- | ---- |
-| user_id | `uint64` |
+Endpoint to create a guild.
-### GetUserResponse
+
-Fields
+##### CreateGuildRequest
+Request type used in `CreateGuild` endpoint.
-| Name | Type |
-| ---- | ---- |
-| user_name | `string` |
-| user_avatar | `string` |
-| UNHANDLED | TYPE |
-| is_bot | `bool` |
+Fields
+###### name
+Type: optional `string`
-### GetUserBulkRequest
+The name of the guild.
+###### picture
+Type: optional `string`
-Fields
+The picture HMC of the guild.
+###### metadata
+Type: optional [protocol.harmonytypes.v1.Metadata]({{< ref "protocol.harmonytypes.v1.md" >}}#metadata)
-| Name | Type |
-| ---- | ---- |
-| user_ids | `uint64` |
+Metadata of the guild.
-### GetUserBulkResponse
-Fields
+
-| Name | Type |
-| ---- | ---- |
-| users | [protocol.chat.v1.GetUserResponse](#getuserresponse) |
+##### CreateGuildResponse
+Used in the `CreateGuild` endpoint.
-### GetUserMetadataRequest
+Fields
+###### guild_id
+Type: optional `uint64`
-Fields
+Guild ID of the guild that was created.
-| Name | Type |
-| ---- | ---- |
-| app_id | `string` |
+------
+#### CreateRoom
+[protocol.chat.v1.CreateRoomRequest](#createroomrequest) -> [protocol.chat.v1.CreateRoomResponse](#createroomresponse)
-### GetUserMetadataResponse
+Endpoint to create a "room" guild.
-Fields
+
-| Name | Type |
-| ---- | ---- |
-| metadata | `string` |
+##### CreateRoomRequest
+Request type used in `CreateRoom` endpoint.
-### ProfileUpdateRequest
+Fields
+###### name
+Type: optional `string`
-Fields
+The name of the guild.
+###### picture
+Type: optional `string`
-| Name | Type |
-| ---- | ---- |
-| new_username | `string` |
-| update_username | `bool` |
-| new_avatar | `string` |
-| update_avatar | `bool` |
-| UNHANDLED | TYPE |
-| update_status | `bool` |
-| is_bot | `bool` |
-| update_is_bot | `bool` |
+The picture HMC of the guild.
+###### metadata
+Type: optional [protocol.harmonytypes.v1.Metadata]({{< ref "protocol.harmonytypes.v1.md" >}}#metadata)
-### CreateGuildRequest
+Metadata of the guild.
-Fields
-| Name | Type |
-| ---- | ---- |
-| metadata | [protocol.harmonytypes.v1.Metadata]({{< ref "protocol.harmonytypes.v1.md" >}}#metadata) |
-| guild_name | `string` |
-| picture_url | `string` |
+
-### CreateGuildResponse
+##### CreateRoomResponse
+Used in the `CreateRoom` endpoint.
-Fields
+Fields
+###### guild_id
+Type: optional `uint64`
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
+Guild ID of the guild that was created.
-### CreateInviteRequest
+------
+#### CreateDirectMessage
+[protocol.chat.v1.CreateDirectMessageRequest](#createdirectmessagerequest) -> [protocol.chat.v1.CreateDirectMessageResponse](#createdirectmessageresponse)
-Fields
+Endpoint to create a "direct message" guild.
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
-| name | `string` |
-| possible_uses | `int32` |
+- The inviter and the invitee that join the created guild will both be owners.
+- The guild should be created on the server that inviter is on.
+- The server should send a guild invite to the invitee (specified in the request),
+using the `UserInvited` postbox event if the invitee is on another server,
+otherwise see the below item.
+- The server should process this as follows: adding the invite to their pending
+invite list and sending an `InviteReceived` event over their event stream if
+the invitee is on this server.
+- The invitee may or may not use the invite. Only the invitee may use the invite.
-### CreateInviteResponse
+
-Fields
+##### CreateDirectMessageRequest
+Used in the `CreateDirectMessage` endpoint.
-| Name | Type |
-| ---- | ---- |
-| name | `string` |
+Fields
+###### user_name
+Type: optional `string`
-### GetGuildListRequest
+The user name of the user to DM with.
+###### server_id
+Type: optional `string`
-Fields
+The server ID of the server the user is on.
-| Name | Type |
-| ---- | ---- |
+Should be left unspecified if it's a user on the homeserver.
-### GetGuildListResponse
-Fields
+
-| Name | Type |
-| ---- | ---- |
-| guilds | [protocol.chat.v1.GetGuildListResponse.GuildListEntry](#getguildlistresponse-guildlistentry) |
+##### CreateDirectMessageResponse
+Used in the `CreateDirectMessage` endpoint.
-### GetGuildRequest
+Fields
+###### guild_id
+Type: optional `uint64`
-Fields
+Guild ID of the just created "direct message" guild.
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
+------
+#### UpgradeRoomToGuild
+[protocol.chat.v1.UpgradeRoomToGuildRequest](#upgraderoomtoguildrequest) -> [protocol.chat.v1.UpgradeRoomToGuildResponse](#upgraderoomtoguildresponse)
-### GetGuildResponse
+Endpoint to upgrade a "room" guild to a "normal" guild.
-Fields
+
-| Name | Type |
-| ---- | ---- |
-| metadata | [protocol.harmonytypes.v1.Metadata]({{< ref "protocol.harmonytypes.v1.md" >}}#metadata) |
-| guild_name | `string` |
-| guild_owner | `uint64` |
-| guild_picture | `string` |
+##### UpgradeRoomToGuildRequest
+Used in the `UpgradeRoomToGuild` endpoint.
-### GetGuildInvitesRequest
+Fields
+###### guild_id
+Type: optional `uint64`
-Fields
+Guild ID of the "room" guild to upgrade to a "normal" guild.
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
-### GetGuildInvitesResponse
+
-Fields
+##### UpgradeRoomToGuildResponse
+Used in the `UpgradeRoomToGuild` endpoint.
-| Name | Type |
-| ---- | ---- |
-| invites | [protocol.chat.v1.GetGuildInvitesResponse.Invite](#getguildinvitesresponse-invite) |
+This item has no fields.
-### GetGuildMembersRequest
+------
+#### CreateInvite
+[protocol.chat.v1.CreateInviteRequest](#createinviterequest) -> [protocol.chat.v1.CreateInviteResponse](#createinviteresponse)
-Fields
+Endpoint to create an invite.
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
+
-### GetGuildMembersResponse
+##### CreateInviteRequest
+Used in the `CreateInvite` endpoint.
-Fields
+Fields
+###### guild_id
+Type: optional `uint64`
-| Name | Type |
-| ---- | ---- |
-| members | `uint64` |
+Guild ID of the guild to create an invite in.
+###### name
+Type: optional `string`
-### UpdateGuildInformationRequest
+The name of the invite.
+###### possible_uses
+Type: optional `uint32`
-Fields
+The possible uses of the invite.
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
-| new_guild_name | `string` |
-| update_guild_name | `bool` |
-| new_guild_picture | `string` |
-| update_guild_picture | `bool` |
-| metadata | [protocol.harmonytypes.v1.Metadata]({{< ref "protocol.harmonytypes.v1.md" >}}#metadata) |
-| update_metadata | `bool` |
+A possible use of `0` means that the invite can be used infinitely many times.
-### DeleteGuildRequest
-Fields
+
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
+##### CreateInviteResponse
+Used in the `CreateInvite` endpoint.
-### DeleteInviteRequest
+Fields
+###### invite_id
+Type: optional `string`
-Fields
+The invite ID of the invite that was created.
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
-| invite_id | `string` |
+------
+#### CreateChannel
+[protocol.chat.v1.CreateChannelRequest](#createchannelrequest) -> [protocol.chat.v1.CreateChannelResponse](#createchannelresponse)
-### JoinGuildRequest
+Endpoint to create a channel.
-Fields
+
-| Name | Type |
-| ---- | ---- |
-| invite_id | `string` |
+##### CreateChannelRequest
+Channel Kinds:
-### JoinGuildResponse
+Channel kinds specified in an official Harmony protocol will start with a
+"h." prefix. Third-party extensions should not use the "h." prefix. If no
+kind is specified, the channel is a text channel.
-Fields
+Kinds indicate additional functionality a channel may have: for example,
+h.voice can indicate that a channel has voice functionalities alongside
+the usual text fare.
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
+Used in the `CreateChannel` endpoint.
-### PreviewGuildRequest
+Fields
+###### guild_id
+Type: optional `uint64`
-Fields
+Guild ID of the guild to create a channel in.
+###### channel_name
+Type: optional `string`
-| Name | Type |
-| ---- | ---- |
-| invite_id | `string` |
+The name of this channel.
+###### kind
+Type: UNHANDLED | TYPE
-### PreviewGuildResponse
+The kind of this channel.
+###### metadata
+Type: optional [protocol.harmonytypes.v1.Metadata]({{< ref "protocol.harmonytypes.v1.md" >}}#metadata)
-Fields
+The metadata of this channel.
+###### position
+Type: optional [protocol.harmonytypes.v1.ItemPosition]({{< ref "protocol.harmonytypes.v1.md" >}}#itemposition)
-| Name | Type |
-| ---- | ---- |
-| name | `string` |
-| avatar | `string` |
-| member_count | `uint64` |
+The position of your new channel in the channel list.
-### LeaveGuildRequest
+If not specified, it will be put at the bottom of the channel list.
-Fields
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
+
-### BanUserRequest
+##### CreateChannelResponse
+Used in the `CreateChannel` endpoint.
-Fields
+Fields
+###### channel_id
+Type: optional `uint64`
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
-| user_id | `uint64` |
+ID of the channel that was created.
-### KickUserRequest
+------
+#### GetGuildList
+[protocol.chat.v1.GetGuildListRequest](#getguildlistrequest) -> [protocol.chat.v1.GetGuildListResponse](#getguildlistresponse)
-Fields
+Endpoint to get your guild list.
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
-| user_id | `uint64` |
+
-### UnbanUserRequest
+##### GetGuildListRequest
+Used in the `GetGuildList` endpoint.
-Fields
+This item has no fields.
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
-| user_id | `uint64` |
-### GetGuildListResponse.GuildListEntry
+
-Fields
+##### GetGuildListResponse
+Used in the `GetGuildList` endpoint.
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
-| host | `string` |
+Fields
+###### guilds
+Type: repeated [protocol.chat.v1.GuildListEntry](#guildlistentry)
-### GetGuildInvitesResponse.Invite
+Guild list returned by the server.
-Fields
+------
+#### InviteUserToGuild
+[protocol.chat.v1.InviteUserToGuildRequest](#inviteusertoguildrequest) -> [protocol.chat.v1.InviteUserToGuildResponse](#inviteusertoguildresponse)
-| Name | Type |
-| ---- | ---- |
-| invite_id | `string` |
-| possible_uses | `int32` |
-| use_count | `int32` |
+Endpoint to invite a user to a guild.
-### CreateChannelRequest
+
-Fields
+##### InviteUserToGuildRequest
+Used in `InviteUserToGuild` endpoint.
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
-| channel_name | `string` |
-| is_category | `bool` |
-| previous_id | `uint64` |
-| next_id | `uint64` |
-| metadata | [protocol.harmonytypes.v1.Metadata]({{< ref "protocol.harmonytypes.v1.md" >}}#metadata) |
+Fields
+###### user_name
+Type: optional `string`
-### CreateChannelResponse
+User name of the user to invite.
+###### server_id
+Type: optional `string`
-Fields
+Server ID of the user if they are on another server.
+###### guild_id
+Type: optional `uint64`
-| Name | Type |
-| ---- | ---- |
-| channel_id | `uint64` |
+Guild ID of the guild to invite to.
-### GetGuildChannelsRequest
-Fields
+
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
+##### InviteUserToGuildResponse
+Used in `InviteUserToGuild` endpoint.
-### GetGuildChannelsResponse
+This item has no fields.
-Fields
+------
+#### GetPendingInvites
+[protocol.chat.v1.GetPendingInvitesRequest](#getpendinginvitesrequest) -> [protocol.chat.v1.GetPendingInvitesResponse](#getpendinginvitesresponse)
-| Name | Type |
-| ---- | ---- |
-| channels | [protocol.chat.v1.GetGuildChannelsResponse.Channel](#getguildchannelsresponse-channel) |
+Endpoint to get your pending invites.
-### UpdateChannelInformationRequest
+
-Fields
+##### GetPendingInvitesRequest
+Used in `GetPendingInvites` endpoint.
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
-| channel_id | `uint64` |
-| name | `string` |
-| update_name | `bool` |
-| metadata | [protocol.harmonytypes.v1.Metadata]({{< ref "protocol.harmonytypes.v1.md" >}}#metadata) |
-| update_metadata | `bool` |
+This item has no fields.
-### UpdateChannelOrderRequest
-Fields
+
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
-| channel_id | `uint64` |
-| previous_id | `uint64` |
-| next_id | `uint64` |
+##### GetPendingInvitesResponse
+Used in `GetPendingInvites` endpoint.
-### DeleteChannelRequest
+Fields
+###### pending_invites
+Type: repeated [protocol.chat.v1.PendingInvite](#pendinginvite)
-Fields
+The pending invite(s).
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
-| channel_id | `uint64` |
+------
+#### RejectPendingInvite
+[protocol.chat.v1.RejectPendingInviteRequest](#rejectpendinginviterequest) -> [protocol.chat.v1.RejectPendingInviteResponse](#rejectpendinginviteresponse)
-### TypingRequest
+Endpoint to reject (delete with notification to the inviter) an invite
+from your pending invite list.
-Fields
+If the invitee is on a different server than the inviter, the invitee's
+server should send a `UserRejectedInvite` postbox event to the inviter's
+server.
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
-| channel_id | `uint64` |
+The "notification" is sending a `InviteRejected` stream event to the
+inviter. If the guild's kind is `DirectMessage`, the server should also
+set the `rejected` field of the guild's kind to `true`.
-### GetGuildChannelsResponse.Channel
+
-Fields
+##### RejectPendingInviteRequest
+Used in `RejectPendingInvite` endpoint.
-| Name | Type |
-| ---- | ---- |
-| metadata | [protocol.harmonytypes.v1.Metadata]({{< ref "protocol.harmonytypes.v1.md" >}}#metadata) |
-| channel_id | `uint64` |
-| channel_name | `string` |
-| is_category | `bool` |
+Fields
+###### invite_id
+Type: optional `string`
-### GetChannelMessagesRequest
+Invite ID of the pending invite to reject.
+###### server_id
+Type: optional `string`
-Fields
+Server ID of the pending invite to reject.
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
-| channel_id | `uint64` |
-| before_message | `uint64` |
-### GetChannelMessagesResponse
+
-Fields
+##### RejectPendingInviteResponse
+Used in `RejectPendingInvite` endpoint.
-| Name | Type |
-| ---- | ---- |
-| reached_top | `bool` |
-| messages | [protocol.harmonytypes.v1.Message]({{< ref "protocol.harmonytypes.v1.md" >}}#message) |
+This item has no fields.
-### GetMessageRequest
+------
+#### IgnorePendingInvite
+[protocol.chat.v1.IgnorePendingInviteRequest](#ignorependinginviterequest) -> [protocol.chat.v1.IgnorePendingInviteResponse](#ignorependinginviteresponse)
-Fields
+Endpoint to ignore (delete without notification to the inviter) an
+invite from your pending invite list.
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
-| channel_id | `uint64` |
-| message_id | `uint64` |
+
-### GetMessageResponse
+##### IgnorePendingInviteRequest
+Used in `IgnorePendingInvite` endpoint.
-Fields
+Fields
+###### invite_id
+Type: optional `string`
-| Name | Type |
-| ---- | ---- |
-| message | [protocol.harmonytypes.v1.Message]({{< ref "protocol.harmonytypes.v1.md" >}}#message) |
+ID of the pending invite to ignore.
+###### server_id
+Type: optional `string`
-### DeleteMessageRequest
+Server ID of the pending invite to reject.
-Fields
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
-| channel_id | `uint64` |
-| message_id | `uint64` |
+
-### TriggerActionRequest
+##### IgnorePendingInviteResponse
+Used in `IgnorePendingInvite` endpoint.
-Fields
+This item has no fields.
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
-| channel_id | `uint64` |
-| message_id | `uint64` |
-| action_id | `string` |
-| action_data | `string` |
+------
+#### GetGuild
+[protocol.chat.v1.GetGuildRequest](#getguildrequest) -> [protocol.chat.v1.GetGuildResponse](#getguildresponse)
-### SendMessageRequest
+Endpoint to get information about a guild.
-Fields
+
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
-| channel_id | `uint64` |
-| content | [protocol.harmonytypes.v1.Content]({{< ref "protocol.harmonytypes.v1.md" >}}#content) |
-| echo_id | `uint64` |
-| metadata | [protocol.harmonytypes.v1.Metadata]({{< ref "protocol.harmonytypes.v1.md" >}}#metadata) |
-| overrides | [protocol.harmonytypes.v1.Override]({{< ref "protocol.harmonytypes.v1.md" >}}#override) |
-| in_reply_to | `uint64` |
+##### GetGuildRequest
+Used in the `GetGuild` endpoint.
-### SendMessageResponse
+Fields
+###### guild_id
+Type: optional `uint64`
-Fields
+Guild ID of the guild to get information about.
-| Name | Type |
-| ---- | ---- |
-| message_id | `uint64` |
-### UpdateMessageTextRequest
+
-Fields
+##### GetGuildResponse
+Used in the `GetGuild` endpoint.
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
-| channel_id | `uint64` |
-| message_id | `uint64` |
-| new_content | `string` |
+Fields
+###### guild
+Type: optional [protocol.chat.v1.Guild](#guild)
-### CreateEmotePackRequest
+The information of the guild requested.
-Fields
+------
+#### GetGuildInvites
+[protocol.chat.v1.GetGuildInvitesRequest](#getguildinvitesrequest) -> [protocol.chat.v1.GetGuildInvitesResponse](#getguildinvitesresponse)
-| Name | Type |
-| ---- | ---- |
-| pack_name | `string` |
+Endpoint to get the invites of a guild.
-### CreateEmotePackResponse
+This requires the "invites.view" permission.
-Fields
+
-| Name | Type |
-| ---- | ---- |
-| pack_id | `uint64` |
+##### GetGuildInvitesRequest
+Used in the `GetGuildInvites` endpoint.
-### GetEmotePacksRequest
+Fields
+###### guild_id
+Type: optional `uint64`
-Fields
+Guild ID of the guild you want to get invites of.
-| Name | Type |
-| ---- | ---- |
-### GetEmotePacksResponse
+
-Fields
+##### GetGuildInvitesResponse
+Used in the `GetGuildInvites` endpoint.
-| Name | Type |
-| ---- | ---- |
-| packs | [protocol.chat.v1.GetEmotePacksResponse.EmotePack](#getemotepacksresponse-emotepack) |
+Fields
+###### invites
+Type: repeated [protocol.chat.v1.InviteWithId](#invitewithid)
-### GetEmotePackEmotesRequest
+The invites of the guild, with IDs.
-Fields
+------
+#### GetGuildMembers
+[protocol.chat.v1.GetGuildMembersRequest](#getguildmembersrequest) -> [protocol.chat.v1.GetGuildMembersResponse](#getguildmembersresponse)
-| Name | Type |
-| ---- | ---- |
-| pack_id | `uint64` |
+Endpoint to get the members of a guild.
-### GetEmotePackEmotesResponse
+
-Fields
+##### GetGuildMembersRequest
+Used in the `GetGuildMembers` endpoint.
-| Name | Type |
-| ---- | ---- |
-| emotes | [protocol.chat.v1.GetEmotePackEmotesResponse.Emote](#getemotepackemotesresponse-emote) |
+Fields
+###### guild_id
+Type: optional `uint64`
-### AddEmoteToPackRequest
+Guild ID of the guild you want to get members of.
-Fields
-| Name | Type |
-| ---- | ---- |
-| pack_id | `uint64` |
-| image_id | `string` |
-| name | `string` |
+
-### DeleteEmoteFromPackRequest
+##### GetGuildMembersResponse
+Used in the `GetGuildMembers` endpoint.
-Fields
+Fields
+###### members
+Type: repeated `uint64`
-| Name | Type |
-| ---- | ---- |
-| pack_id | `uint64` |
-| image_id | `string` |
+User IDs of all the guild members.
-### DeleteEmotePackRequest
+------
+#### GetGuildChannels
+[protocol.chat.v1.GetGuildChannelsRequest](#getguildchannelsrequest) -> [protocol.chat.v1.GetGuildChannelsResponse](#getguildchannelsresponse)
-Fields
+Endpoint to get the channels of a guild.
-| Name | Type |
-| ---- | ---- |
-| pack_id | `uint64` |
+You will only be informed of channels you have the "messages.view"
+permission for.
-### DequipEmotePackRequest
+
-Fields
+##### GetGuildChannelsRequest
+Used in the `GetGuildChannels` endpoint.
-| Name | Type |
-| ---- | ---- |
-| pack_id | `uint64` |
+Fields
+###### guild_id
+Type: optional `uint64`
-### GetEmotePacksResponse.EmotePack
+Guild ID of the guild you want to get channels from.
-Fields
-| Name | Type |
-| ---- | ---- |
-| pack_id | `uint64` |
-| pack_owner | `uint64` |
-| pack_name | `string` |
+
-### GetEmotePackEmotesResponse.Emote
+##### GetGuildChannelsResponse
+Used in the `GetGuildChannels` endpoint.
-Fields
+Fields
+###### channels
+Type: repeated [protocol.chat.v1.ChannelWithId](#channelwithid)
-| Name | Type |
-| ---- | ---- |
-| image_id | `string` |
-| name | `string` |
+Channels' data and ID the server responded with.
-### QueryPermissionsRequest
+------
+#### GetChannelMessages
+[protocol.chat.v1.GetChannelMessagesRequest](#getchannelmessagesrequest) -> [protocol.chat.v1.GetChannelMessagesResponse](#getchannelmessagesresponse)
-Fields
+Endpoint to get the messages from a guild channel.
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
-| channel_id | `uint64` |
-| check_for | `string` |
-| as | `uint64` |
+
-### QueryPermissionsResponse
+##### GetChannelMessagesRequest
+Used in the `GetChannelMessages` endpoint.
-Fields
+Fields
+###### guild_id
+Type: optional `uint64`
-| Name | Type |
-| ---- | ---- |
-| ok | `bool` |
+Guild ID of the guild that has the channel.
+###### channel_id
+Type: optional `uint64`
-### Permission
+Channel ID of the channel to get messages from.
+###### message_id
+Type: optional `uint64`
-Fields
+The ID of the message that will be used as an "anchor" point to figure out
+where to get the messages.
+If not specified, the `direction` will be ignored and the newest messages
+will be returned.
+###### direction
+Type: UNHANDLED | TYPE
-| Name | Type |
-| ---- | ---- |
-| matches | `string` |
-| UNHANDLED | TYPE |
+On which direction to get the messages.
-### PermissionList
+- By default, it is "before", which means you will get messages before the
+`message_id` message.
+- If it is "around", you will get the messages around the `message_id`
+message. This will include the `message_id` message itself, as the middle
+item of the list returned.
+- If it is "after", you will get the messages after the `message_id`
+message.
+###### count
+Type: optional `uint32`
-Fields
+How many messages to get.
-| Name | Type |
-| ---- | ---- |
-| permissions | [protocol.chat.v1.Permission](#permission) |
+- If `0`, a recommended message count to return is 25. If the direction is
+"around", the recommended value is 12.
+- If the direction to get the messages is "around", this count will not be
+the *total* count of messages to return, but instead the count of messages
+to return *for each direction*, before and after.
+- Servers should enforce their own maximum limit, and clamp this value to
+the limit.
-### SetPermissionsRequest
-Fields
+
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
-| channel_id | `uint64` |
-| role_id | `uint64` |
-| perms | [protocol.chat.v1.PermissionList](#permissionlist) |
+##### GetChannelMessagesResponse
+Used in the `GetChannelMessages` endpoint.
-### GetPermissionsRequest
+Fields
+###### reached_top
+Type: optional `bool`
-Fields
+Has reached the top (first message) of the message history.
+###### reached_bottom
+Type: optional `bool`
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
-| channel_id | `uint64` |
-| role_id | `uint64` |
+Has reached the bottom (last message) of the message history.
+###### messages
+Type: repeated [protocol.chat.v1.MessageWithId](#messagewithid)
-### GetPermissionsResponse
+The messages requested.
-Fields
+------
+#### GetMessage
+[protocol.chat.v1.GetMessageRequest](#getmessagerequest) -> [protocol.chat.v1.GetMessageResponse](#getmessageresponse)
-| Name | Type |
-| ---- | ---- |
-| perms | [protocol.chat.v1.PermissionList](#permissionlist) |
+Endpoint to get a single message from a guild channel.
-### Role
+
-Fields
+##### GetMessageRequest
+Used in the `GetMessage` endpoint.
-| Name | Type |
-| ---- | ---- |
-| role_id | `uint64` |
-| name | `string` |
-| color | `int32` |
-| hoist | `bool` |
-| pingable | `bool` |
+Fields
+###### guild_id
+Type: optional `uint64`
-### MoveRoleRequest
+Guild ID of the guild where the channel is.
+###### channel_id
+Type: optional `uint64`
-Fields
+Channel ID of the channel where the message is.
+###### message_id
+Type: optional `uint64`
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
-| role_id | `uint64` |
-| before_id | `uint64` |
-| after_id | `uint64` |
+Message ID of the message you want to get.
-### MoveRoleResponse
-Fields
+
-| Name | Type |
-| ---- | ---- |
+##### GetMessageResponse
+Used in the `GetMessage` endpoint.
-### GetGuildRolesRequest
+Fields
+###### message
+Type: optional [protocol.chat.v1.Message](#message)
-Fields
+The message requested.
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
+------
+#### UpdateGuildInformation
+[protocol.chat.v1.UpdateGuildInformationRequest](#updateguildinformationrequest) -> [protocol.chat.v1.UpdateGuildInformationResponse](#updateguildinformationresponse)
-### GetGuildRolesResponse
+Endpoint to update a guild's information.
-Fields
+
-| Name | Type |
-| ---- | ---- |
-| roles | [protocol.chat.v1.Role](#role) |
+##### UpdateGuildInformationRequest
+Used in the `UpdateGuildInformation` endpoint.
-### AddGuildRoleRequest
+Fields
+###### guild_id
+Type: optional `uint64`
-Fields
+Guild ID of the guild you want to update the information of.
+###### new_name
+Type: optional `string`
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
-| role | [protocol.chat.v1.Role](#role) |
+New name for the guild.
+###### new_picture
+Type: optional `string`
-### AddGuildRoleResponse
+New picture for the guild.
+###### new_metadata
+Type: optional [protocol.harmonytypes.v1.Metadata]({{< ref "protocol.harmonytypes.v1.md" >}}#metadata)
-Fields
+New metadata for the guild.
-| Name | Type |
-| ---- | ---- |
-| role_id | `uint64` |
-### DeleteGuildRoleRequest
+
-Fields
+##### UpdateGuildInformationResponse
+Used in the `UpdateGuildInformation` endpoint.
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
-| role_id | `uint64` |
+This item has no fields.
-### ModifyGuildRoleRequest
+------
+#### UpdateChannelInformation
+[protocol.chat.v1.UpdateChannelInformationRequest](#updatechannelinformationrequest) -> [protocol.chat.v1.UpdateChannelInformationResponse](#updatechannelinformationresponse)
-Fields
+Endpoint to update a channel's information.
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
-| role | [protocol.chat.v1.Role](#role) |
-| modify_name | `bool` |
-| modify_color | `bool` |
-| modify_hoist | `bool` |
-| modify_pingable | `bool` |
+
-### ManageUserRolesRequest
+##### UpdateChannelInformationRequest
+Used in the `UpdateChannelInformation` endpoint.
-Fields
+Fields
+###### guild_id
+Type: optional `uint64`
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
-| user_id | `uint64` |
-| give_role_ids | `uint64` |
-| take_role_ids | `uint64` |
+Guild ID of the guild where the channel is.
+###### channel_id
+Type: optional `uint64`
-### GetUserRolesRequest
+Channel ID of the channel you want to change the information of.
+###### new_name
+Type: optional `string`
-Fields
+New name to set for this channel.
+###### new_metadata
+Type: optional [protocol.harmonytypes.v1.Metadata]({{< ref "protocol.harmonytypes.v1.md" >}}#metadata)
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
-| user_id | `uint64` |
+New metadata to set for this channel.
-### GetUserRolesResponse
-Fields
+
-| Name | Type |
-| ---- | ---- |
-| roles | `uint64` |
+##### UpdateChannelInformationResponse
+Used in the `UpdateChannelInformation` endpoint.
-### StreamEventsRequest
+This item has no fields.
-Fields
+------
+#### UpdateChannelOrder
+[protocol.chat.v1.UpdateChannelOrderRequest](#updatechannelorderrequest) -> [protocol.chat.v1.UpdateChannelOrderResponse](#updatechannelorderresponse)
-| Name | Type |
-| ---- | ---- |
-| subscribe_to_guild | [protocol.chat.v1.StreamEventsRequest.SubscribeToGuild](#streameventsrequest-subscribetoguild) |
-| subscribe_to_actions | [protocol.chat.v1.StreamEventsRequest.SubscribeToActions](#streameventsrequest-subscribetoactions) |
-| subscribe_to_homeserver_events | [protocol.chat.v1.StreamEventsRequest.SubscribeToHomeserverEvents](#streameventsrequest-subscribetohomeserverevents) |
+Endpoint to change the position of a channel in the channel list.
-### Event
+
-Fields
+##### UpdateChannelOrderRequest
+Used in the `UpdateChannelOrder` endpoint.
-| Name | Type |
-| ---- | ---- |
-| guild_added_to_list | [protocol.chat.v1.Event.GuildAddedToList](#event-guildaddedtolist) |
-| guild_removed_from_list | [protocol.chat.v1.Event.GuildRemovedFromList](#event-guildremovedfromlist) |
-| action_performed | [protocol.chat.v1.Event.ActionPerformed](#event-actionperformed) |
-| sent_message | [protocol.chat.v1.Event.MessageSent](#event-messagesent) |
-| edited_message | [protocol.chat.v1.Event.MessageUpdated](#event-messageupdated) |
-| deleted_message | [protocol.chat.v1.Event.MessageDeleted](#event-messagedeleted) |
-| created_channel | [protocol.chat.v1.Event.ChannelCreated](#event-channelcreated) |
-| edited_channel | [protocol.chat.v1.Event.ChannelUpdated](#event-channelupdated) |
-| deleted_channel | [protocol.chat.v1.Event.ChannelDeleted](#event-channeldeleted) |
-| edited_guild | [protocol.chat.v1.Event.GuildUpdated](#event-guildupdated) |
-| deleted_guild | [protocol.chat.v1.Event.GuildDeleted](#event-guilddeleted) |
-| joined_member | [protocol.chat.v1.Event.MemberJoined](#event-memberjoined) |
-| left_member | [protocol.chat.v1.Event.MemberLeft](#event-memberleft) |
-| role_moved | [protocol.chat.v1.Event.RoleMoved](#event-rolemoved) |
-| profile_updated | [protocol.chat.v1.Event.ProfileUpdated](#event-profileupdated) |
-| typing | [protocol.chat.v1.Event.Typing](#event-typing) |
+Fields
+###### guild_id
+Type: optional `uint64`
-### StreamEventsRequest.SubscribeToGuild
+Guild ID of the guild that has the channel.
+###### channel_id
+Type: optional `uint64`
-Fields
+Channel ID of the channel that you want to move.
+###### new_position
+Type: optional [protocol.harmonytypes.v1.ItemPosition]({{< ref "protocol.harmonytypes.v1.md" >}}#itemposition)
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
+The new position of this channel.
-### StreamEventsRequest.SubscribeToActions
-Fields
+
-| Name | Type |
-| ---- | ---- |
+##### UpdateChannelOrderResponse
+Used in the `UpdateChannelOrder` endpoint.
-### StreamEventsRequest.SubscribeToHomeserverEvents
+This item has no fields.
-Fields
+------
+#### UpdateAllChannelOrder
+[protocol.chat.v1.UpdateAllChannelOrderRequest](#updateallchannelorderrequest) -> [protocol.chat.v1.UpdateAllChannelOrderResponse](#updateallchannelorderresponse)
-| Name | Type |
-| ---- | ---- |
+Endpoint to change the position of all channels in the guild;
+must specifcy all channels or fails
-### Event.MessageSent
+
-Fields
+##### UpdateAllChannelOrderRequest
+Request specifiying the order of all channels in a guild at once
-| Name | Type |
-| ---- | ---- |
-| echo_id | `uint64` |
-| message | [protocol.harmonytypes.v1.Message]({{< ref "protocol.harmonytypes.v1.md" >}}#message) |
+Fields
+###### guild_id
+Type: optional `uint64`
-### Event.MessageUpdated
+guild_id: the guild to specify the new channel order for
+###### channel_ids
+Type: repeated `uint64`
-Fields
+channel_ids: the new order of channel ids
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
-| channel_id | `uint64` |
-| message_id | `uint64` |
-| edited_at | [google.protobuf.Timestamp]({{< ref "google.protobuf.md" >}}#timestamp) |
-| content | `string` |
-### Event.MessageDeleted
+
-Fields
+##### UpdateAllChannelOrderResponse
+Used in the `UpdateAllChannelOrder` endpoint.
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
-| channel_id | `uint64` |
-| message_id | `uint64` |
+This item has no fields.
-### Event.ChannelCreated
+------
+#### UpdateMessageText
+[protocol.chat.v1.UpdateMessageTextRequest](#updatemessagetextrequest) -> [protocol.chat.v1.UpdateMessageTextResponse](#updatemessagetextresponse)
-Fields
+Endpoint to change the text of a message.
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
-| channel_id | `uint64` |
-| name | `string` |
-| previous_id | `uint64` |
-| next_id | `uint64` |
-| is_category | `bool` |
-| metadata | [protocol.harmonytypes.v1.Metadata]({{< ref "protocol.harmonytypes.v1.md" >}}#metadata) |
+
-### Event.ChannelUpdated
+##### UpdateMessageTextRequest
+Used in the `UpdateMessageText` endpoint.
-Fields
+Fields
+###### guild_id
+Type: optional `uint64`
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
-| channel_id | `uint64` |
-| name | `string` |
-| update_name | `bool` |
-| previous_id | `uint64` |
-| next_id | `uint64` |
-| update_order | `bool` |
-| metadata | [protocol.harmonytypes.v1.Metadata]({{< ref "protocol.harmonytypes.v1.md" >}}#metadata) |
-| update_metadata | `bool` |
+Guild ID of the guild where the channel is.
+###### channel_id
+Type: optional `uint64`
-### Event.ChannelDeleted
+Channel ID of the channel where the message is.
+###### message_id
+Type: optional `uint64`
-Fields
+Message ID of the message you want to edit the text of.
+###### new_content
+Type: optional [protocol.chat.v1.FormattedText](#formattedtext)
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
-| channel_id | `uint64` |
+New content for this message.
-### Event.GuildUpdated
-Fields
+
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
-| name | `string` |
-| update_name | `bool` |
-| picture | `string` |
-| update_picture | `bool` |
-| metadata | [protocol.harmonytypes.v1.Metadata]({{< ref "protocol.harmonytypes.v1.md" >}}#metadata) |
-| update_metadata | `bool` |
+##### UpdateMessageTextResponse
+Used in the `UpdateMessageText` endpoint.
-### Event.GuildDeleted
+This item has no fields.
-Fields
+------
+#### DeleteGuild
+[protocol.chat.v1.DeleteGuildRequest](#deleteguildrequest) -> [protocol.chat.v1.DeleteGuildResponse](#deleteguildresponse)
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
+Endpoint to delete a guild.
+Can only be invoked if there's one owner.
-### Event.MemberJoined
+
-Fields
+##### DeleteGuildRequest
+Used in the `DeleteGuild` endpoint.
-| Name | Type |
-| ---- | ---- |
-| member_id | `uint64` |
-| guild_id | `uint64` |
+Fields
+###### guild_id
+Type: optional `uint64`
+
+Guild ID of the guild you want to delete.
+
+
+
+
+##### DeleteGuildResponse
+Used in the `DeleteGuild` endpoint.
+
+This item has no fields.
+
+------
+#### DeleteInvite
+[protocol.chat.v1.DeleteInviteRequest](#deleteinviterequest) -> [protocol.chat.v1.DeleteInviteResponse](#deleteinviteresponse)
+
+Endpoint to delete an invite.
+
+
+
+##### DeleteInviteRequest
+Used in the `DeleteInvite` endpoint.
+
+Fields
+###### guild_id
+Type: optional `uint64`
+
+Guild ID of the guild where the invite is located.
+###### invite_id
+Type: optional `string`
+
+Invite ID of the invite you want to delete.
+
+
+
+
+##### DeleteInviteResponse
+Used in the `DeleteInvite` endpoint.
+
+This item has no fields.
+
+------
+#### DeleteChannel
+[protocol.chat.v1.DeleteChannelRequest](#deletechannelrequest) -> [protocol.chat.v1.DeleteChannelResponse](#deletechannelresponse)
+
+Endpoint to delete a channel.
+
+
+
+##### DeleteChannelRequest
+Used in the `DeleteChannel` endpoint.
+
+Fields
+###### guild_id
+Type: optional `uint64`
+
+Guild ID of the guild that has the channel.
+###### channel_id
+Type: optional `uint64`
+
+Channel ID of the channel you want to delete.
+
+
+
+
+##### DeleteChannelResponse
+Used in the `DeleteChannel` endpoint.
+
+This item has no fields.
+
+------
+#### DeleteMessage
+[protocol.chat.v1.DeleteMessageRequest](#deletemessagerequest) -> [protocol.chat.v1.DeleteMessageResponse](#deletemessageresponse)
+
+Endpoint to delete a message.
+
+This requires the "messages.manage.delete" permission if you are not the
+message author.
+
+
+
+##### DeleteMessageRequest
+Used in the `DeleteMessage` endpoint.
+
+Fields
+###### guild_id
+Type: optional `uint64`
+
+Guild ID of the guild where the channel is.
+###### channel_id
+Type: optional `uint64`
+
+Channel ID of the channel where the message is.
+###### message_id
+Type: optional `uint64`
+
+Message ID of the message you want to delete.
+
+
+
+
+##### DeleteMessageResponse
+Used in the `DeleteMessage` endpoint.
+
+This item has no fields.
+
+------
+#### JoinGuild
+[protocol.chat.v1.JoinGuildRequest](#joinguildrequest) -> [protocol.chat.v1.JoinGuildResponse](#joinguildresponse)
+
+Endpoint to join a guild.
+
+- If the invite used is in a user's "pending invites" list, it should be
+removed from there.
+
+
+
+##### JoinGuildRequest
+Used in the `JoinGuild` endpoint.
+
+Fields
+###### invite_id
+Type: optional `string`
+
+Invite ID of the guild you want to join.
+
+
+
+
+##### JoinGuildResponse
+Used in the `JoinGuild` endpoint.
+
+Fields
+###### guild_id
+Type: optional `uint64`
+
+Guild ID of the guild you joined.
+
+------
+#### LeaveGuild
+[protocol.chat.v1.LeaveGuildRequest](#leaveguildrequest) -> [protocol.chat.v1.LeaveGuildResponse](#leaveguildresponse)
+
+Endpoint to leave a guild.
+
+- If you're the only owner, you can't leave a guild. Exception to this
+rule are "direct message" guilds.
+- When the last member in a "direct message" guild leaves it, that guild
+should be deleted.
+
+
+
+##### LeaveGuildRequest
+Used in the `LeaveGuild` endpoint.
+
+Fields
+###### guild_id
+Type: optional `uint64`
+
+Guild ID of the guild you want to leave.
+
+
+
+
+##### LeaveGuildResponse
+Used in the `LeaveGuild` endpoint.
+
+This item has no fields.
+
+------
+#### TriggerAction
+[protocol.chat.v1.TriggerActionRequest](#triggeractionrequest) -> [protocol.chat.v1.TriggerActionResponse](#triggeractionresponse)
+
+Endpont to trigger an action.
+
+
+
+##### TriggerActionRequest
+Used in the `TriggerAction` endpoint.
+
+Fields
+###### guild_id
+Type: optional `uint64`
+
+Guild ID of the guild where the channel is.
+###### channel_id
+Type: optional `uint64`
+
+Channel ID of the channel where the message is.
+###### message_id
+Type: optional `uint64`
+
+Message ID of the message you want to trigger an action in.
+###### payload
+Type: optional [protocol.chat.v1.ActionPayload](#actionpayload)
+
+Payload of action data.
+
+
+
+
+##### TriggerActionResponse
+Used in the `TriggerAction` endpoint.
+
+This item has no fields.
+
+------
+#### SendMessage
+[protocol.chat.v1.SendMessageRequest](#sendmessagerequest) -> [protocol.chat.v1.SendMessageResponse](#sendmessageresponse)
+
+Endpoint to send a message.
+
+
+
+##### SendMessageRequest
+Used in the `SendMessage` endpoint.
+
+Fields
+###### guild_id
+Type: optional `uint64`
+
+Guild ID of the guild where the channel is.
+###### channel_id
+Type: optional `uint64`
+
+Channel ID of the channel you want to send a message in.
+###### content
+Type: optional [protocol.chat.v1.Content](#content)
+
+Content of the new message.
+###### echo_id
+Type: optional `uint64`
+
+Echo ID of the new message. This can be used by clients to
+determine whether a message is sent.
+###### overrides
+Type: optional [protocol.chat.v1.Overrides](#overrides)
+
+The overrides of this new message.
+###### in_reply_to
+Type: optional `uint64`
+
+The message this new message is a reply to.
+###### metadata
+Type: optional [protocol.harmonytypes.v1.Metadata]({{< ref "protocol.harmonytypes.v1.md" >}}#metadata)
+
+The metadata of this new message.
+
+
+
+
+##### SendMessageResponse
+Used in the `SendMessage` endpoint.
+
+Fields
+###### message_id
+Type: optional `uint64`
+
+Message ID of the message sent.
+
+------
+#### QueryHasPermission
+[protocol.chat.v1.QueryHasPermissionRequest](#queryhaspermissionrequest) -> [protocol.chat.v1.QueryHasPermissionResponse](#queryhaspermissionresponse)
+
+Endpoint to query if a user has a permission.
+
+
+
+##### QueryHasPermissionRequest
+Used in the `QueryHasPermission` endpoint.
+
+Fields
+###### guild_id
+Type: optional `uint64`
+
+the guild ID to query permissions for
+###### channel_id
+Type: optional `uint64`
+
+the channel ID to query permissions for. If not set, it will query
+permissions for the guild.
+###### as
+Type: optional `uint64`
+
+the user ID to query permissions for (if not provided, the current user is
+assumed).
+###### check_for
+Type: optional `string`
+
+the permission node to check for.
+
+
+
+
+##### QueryHasPermissionResponse
+Used in the `QueryHasPermission` endpoint.
+
+Fields
+###### ok
+Type: optional `bool`
+
+the permissions for the given node.
+
+------
+#### SetPermissions
+[protocol.chat.v1.SetPermissionsRequest](#setpermissionsrequest) -> [protocol.chat.v1.SetPermissionsResponse](#setpermissionsresponse)
+
+Endpoint to set permissions for a role in a guild.
+
+
+
+##### SetPermissionsRequest
+Used in the `SetPermissions` endpoint.
+
+Fields
+###### guild_id
+Type: optional `uint64`
+
+the guild ID to set permissions for.
+###### channel_id
+Type: optional `uint64`
+
+the channel ID to set permissions for. Only set if the role is for a
+channel.
+###### role_id
+Type: optional `uint64`
+
+the role ID to set permissions for.
+###### perms_to_give
+Type: repeated [protocol.chat.v1.Permission](#permission)
+
+the permission list to give.
+
+There is no "perms_to_take" because not given permissions are by
+default not allowed.
+
+
+
+
+##### SetPermissionsResponse
+Used in the `SetPermissions` endpoint.
+
+This item has no fields.
+
+------
+#### GetPermissions
+[protocol.chat.v1.GetPermissionsRequest](#getpermissionsrequest) -> [protocol.chat.v1.GetPermissionsResponse](#getpermissionsresponse)
+
+Endpoint to get permissions for a role in a guild.
+
+
+
+##### GetPermissionsRequest
+Used in the `GetPermissions` endpoint.
+
+Fields
+###### guild_id
+Type: optional `uint64`
+
+the guild ID to get permissions for.
+###### channel_id
+Type: optional `uint64`
+
+the channel ID to get permissions for. Only applicable for roles in a
+channel.
+###### role_id
+Type: optional `uint64`
+
+the role ID to get permissions for.
+
+
+
+
+##### GetPermissionsResponse
+Used in the `GetPermissions` endpoint.
+
+Fields
+###### perms
+Type: repeated [protocol.chat.v1.Permission](#permission)
+
+the permissions list for the given role.
+
+------
+#### MoveRole
+[protocol.chat.v1.MoveRoleRequest](#moverolerequest) -> [protocol.chat.v1.MoveRoleResponse](#moveroleresponse)
+
+Endpoint to change the position of a role in the role list in a guild.
+
+
+
+##### MoveRoleRequest
+Used in the `MoveRole` endpoint.
+
+Fields
+###### guild_id
+Type: optional `uint64`
+
+the guild ID to move the role in.
+###### role_id
+Type: optional `uint64`
+
+the role ID to move.
+###### new_position
+Type: optional [protocol.harmonytypes.v1.ItemPosition]({{< ref "protocol.harmonytypes.v1.md" >}}#itemposition)
+
+the new position of the role.
+
+
+
+
+##### MoveRoleResponse
+Used in the `MoveRole` endpoint.
+
+This item has no fields.
+
+------
+#### GetGuildRoles
+[protocol.chat.v1.GetGuildRolesRequest](#getguildrolesrequest) -> [protocol.chat.v1.GetGuildRolesResponse](#getguildrolesresponse)
+
+Endpoint to get the roles from a guild.
+
+
+
+##### GetGuildRolesRequest
+Used in the `GetGuildRoles` endpoint.
+
+Fields
+###### guild_id
+Type: optional `uint64`
+
+the guild ID to get roles for.
+
+
+
+
+##### GetGuildRolesResponse
+Used in the `GetGuildRoles` endpoint.
+
+Fields
+###### roles
+Type: repeated [protocol.chat.v1.RoleWithId](#rolewithid)
+
+the list of roles in the guild.
+
+------
+#### AddGuildRole
+[protocol.chat.v1.AddGuildRoleRequest](#addguildrolerequest) -> [protocol.chat.v1.AddGuildRoleResponse](#addguildroleresponse)
+
+Endpoint to add a role to a guild.
+
+
+
+##### AddGuildRoleRequest
+Used in the `AddGuildRole` endpoint.
+
+Fields
+###### guild_id
+Type: optional `uint64`
+
+the guild ID to add the role to.
+###### name
+Type: optional `string`
+
+the role name.
+###### color
+Type: optional `int32`
+
+the role color.
+###### hoist
+Type: optional `bool`
+
+whether the role is hoisted or not.
+###### pingable
+Type: optional `bool`
+
+whether the role is mentionable or not.
+
+
+
+
+##### AddGuildRoleResponse
+Used in the `AddGuildRole` endpoint.
+
+Fields
+###### role_id
+Type: optional `uint64`
+
+the ID of the newly created role.
+
+------
+#### ModifyGuildRole
+[protocol.chat.v1.ModifyGuildRoleRequest](#modifyguildrolerequest) -> [protocol.chat.v1.ModifyGuildRoleResponse](#modifyguildroleresponse)
+
+Endpoint to a modify a role from a guild.
+
+
+
+##### ModifyGuildRoleRequest
+Used in the `ModifyGuildRole` endpoint.
+
+Fields
+###### guild_id
+Type: optional `uint64`
+
+the ID of the guild where the role is located
+###### role_id
+Type: optional `uint64`
+
+the ID of the role to modify
+###### new_name
+Type: optional `string`
+
+the new name of the role
+###### new_color
+Type: optional `int32`
+
+the new color of the role
+###### new_hoist
+Type: optional `bool`
+
+the new hoist status of the role
+###### new_pingable
+Type: optional `bool`
+
+the new pingable status of the role
+
+
+
+
+##### ModifyGuildRoleResponse
+Used in the `ModifyGuildRole` endpoint.
+
+This item has no fields.
+
+------
+#### DeleteGuildRole
+[protocol.chat.v1.DeleteGuildRoleRequest](#deleteguildrolerequest) -> [protocol.chat.v1.DeleteGuildRoleResponse](#deleteguildroleresponse)
+
+Endpoint to delete a role from a guild.
+
+
+
+##### DeleteGuildRoleRequest
+Used in the `DeleteGuildRole` endpoint.
+
+Fields
+###### guild_id
+Type: optional `uint64`
+
+the guild ID to delete the role from.
+###### role_id
+Type: optional `uint64`
+
+the role ID to delete.
+
+
+
+
+##### DeleteGuildRoleResponse
+Used in the `DeleteGuildRole` endpoint.
+
+This item has no fields.
+
+------
+#### ManageUserRoles
+[protocol.chat.v1.ManageUserRolesRequest](#manageuserrolesrequest) -> [protocol.chat.v1.ManageUserRolesResponse](#manageuserrolesresponse)
+
+Endpoint to manage the roles of a guild member.
+
+
+
+##### ManageUserRolesRequest
+Used in the `ManageUserRoles` endpoint.
+
+Fields
+###### guild_id
+Type: optional `uint64`
+
+the ID of the guild where the user is being managed
+###### user_id
+Type: optional `uint64`
+
+the ID of the user to modify
+###### give_role_ids
+Type: repeated `uint64`
+
+the IDs of the roles to add
+###### take_role_ids
+Type: repeated `uint64`
+
+the IDs of the roles to remove
+
+
+
+
+##### ManageUserRolesResponse
+Used in the `ManageUserRoles` endpoint.
+
+This item has no fields.
+
+------
+#### GetUserRoles
+[protocol.chat.v1.GetUserRolesRequest](#getuserrolesrequest) -> [protocol.chat.v1.GetUserRolesResponse](#getuserrolesresponse)
+
+Endpoint to get the roles a guild member has.
+
+
+
+##### GetUserRolesRequest
+Used in the `GetUserRoles` endpoint.
+
+Fields
+###### guild_id
+Type: optional `uint64`
+
+the ID of the guild where the user is located
+###### user_id
+Type: optional `uint64`
+
+the ID of the user to get roles for
+
+
+
+
+##### GetUserRolesResponse
+Used in the `GetUserRoles` endpoint.
+
+Fields
+###### roles
+Type: repeated `uint64`
+
+a list of IDs of the roles the user has
+
+------
+#### Typing
+[protocol.chat.v1.TypingRequest](#typingrequest) -> [protocol.chat.v1.TypingResponse](#typingresponse)
+
+Endpoint to send a typing notification in a guild channel.
+
+
+
+##### TypingRequest
+Used in `Typing` endpoint.
+
+Fields
+###### guild_id
+Type: optional `uint64`
+
+The guild id of the channel the user is typing in.
+###### channel_id
+Type: optional `uint64`
+
+The channel id of the channel the user is typing in.
+
+
+
+
+##### TypingResponse
+Used in `Typing` endpoint.
+
+This item has no fields.
+
+------
+#### PreviewGuild
+[protocol.chat.v1.PreviewGuildRequest](#previewguildrequest) -> [protocol.chat.v1.PreviewGuildResponse](#previewguildresponse)
+
+Endpoint to "preview" a guild, which returns some information about a
+guild.
+
+- Guilds with the "direct message" kind can only be previewed
+by the user who is invited to the guild.
+
+
+
+##### PreviewGuildRequest
+Used in the `PreviewGuild` endpoint.
+
+Fields
+###### invite_id
+Type: optional `string`
+
+Invite ID of the guild you want to get information from.
+
+
+
+
+##### PreviewGuildResponse
+Used in the `PreviewGuild` endpoint.
+
+Fields
+###### name
+Type: optional `string`
+
+Name of the guild requested.
+###### picture
+Type: optional `string`
+
+Picture of the guild requested.
+###### member_count
+Type: optional `uint64`
+
+Member count of the guild requested.
+
+------
+#### GetBannedUsers
+[protocol.chat.v1.GetBannedUsersRequest](#getbannedusersrequest) -> [protocol.chat.v1.GetBannedUsersResponse](#getbannedusersresponse)
+
+Endpoint to get banned users in a guild.
+
+
+
+##### GetBannedUsersRequest
+Used in `GetBannedUsers` endpoint.
+
+Fields
+###### guild_id
+Type: optional `uint64`
+
+Guild ID to get banned users for.
+
+
+
+
+##### GetBannedUsersResponse
+Used in `GetBannedUsers` endpoint.
+
+Fields
+###### banned_users
+Type: repeated `uint64`
+
+The user IDs of banned users.
+
+------
+#### BanUser
+[protocol.chat.v1.BanUserRequest](#banuserrequest) -> [protocol.chat.v1.BanUserResponse](#banuserresponse)
+
+Endpoint to ban a user from a guild.
+
+
+
+##### BanUserRequest
+Used in `BanUser` endpoint.
+
+Fields
+###### guild_id
+Type: optional `uint64`
+
+The guild ID of the guild to ban the user from.
+###### user_id
+Type: optional `uint64`
+
+The ID of the user to ban.
+
+
+
+
+##### BanUserResponse
+Used in `BanUser` endpoint.
+
+This item has no fields.
+
+------
+#### KickUser
+[protocol.chat.v1.KickUserRequest](#kickuserrequest) -> [protocol.chat.v1.KickUserResponse](#kickuserresponse)
+
+Endpoint to kick a user from a guild.
+
+
+
+##### KickUserRequest
+Used in `KickUser` endpoint.
+
+Fields
+###### guild_id
+Type: optional `uint64`
+
+The guild ID of the guild to kick the user from.
+###### user_id
+Type: optional `uint64`
+
+The user ID of the user to kick.
+
+
+
+
+##### KickUserResponse
+Used in `KickUser` endpoint.
+
+This item has no fields.
+
+------
+#### UnbanUser
+[protocol.chat.v1.UnbanUserRequest](#unbanuserrequest) -> [protocol.chat.v1.UnbanUserResponse](#unbanuserresponse)
+
+Endpoint to unban a user from a guild.
+
+
+
+##### UnbanUserRequest
+Used in `UnbanUser` endpoint.
+
+Fields
+###### guild_id
+Type: optional `uint64`
+
+The guild ID of the guild to unban the user from.
+###### user_id
+Type: optional `uint64`
+
+The user ID of the user to unban.
+
+
+
+
+##### UnbanUserResponse
+Used in `UnbanUser` endpoint.
+
+This item has no fields.
+
+------
+#### GetPinnedMessages
+[protocol.chat.v1.GetPinnedMessagesRequest](#getpinnedmessagesrequest) -> [protocol.chat.v1.GetPinnedMessagesResponse](#getpinnedmessagesresponse)
+
+Endpoint to get all pinned messages in a guild channel.
+
+
+
+##### GetPinnedMessagesRequest
+Used in the `GetPinnedMessages` endpoint.
+
+Fields
+###### guild_id
+Type: optional `uint64`
+
+Guild ID of the guild where the channel is.
+###### channel_id
+Type: optional `uint64`
+
+Channel ID of the channel we want to get pins of.
+
+
+
+
+##### GetPinnedMessagesResponse
+Used in the `GetPinnedMessages` endpoint.
+
+Fields
+###### pinned_message_ids
+Type: repeated `uint64`
+
+The IDs of the pinned messages.
+
+------
+#### PinMessage
+[protocol.chat.v1.PinMessageRequest](#pinmessagerequest) -> [protocol.chat.v1.PinMessageResponse](#pinmessageresponse)
+
+Endpoint to pin a message in a guild channel.
+
+
+
+##### PinMessageRequest
+Used in the `PinMessage` endpoint.
+
+Fields
+###### guild_id
+Type: optional `uint64`
+
+Guild ID of the guild where the channel is.
+###### channel_id
+Type: optional `uint64`
+
+Channel ID of the channel where the message is.
+###### message_id
+Type: optional `uint64`
+
+Message ID of the message we want to pin.
+
+
+
+
+##### PinMessageResponse
+Used in the `UnpinMessage` endpoint.
+
+This item has no fields.
+
+------
+#### UnpinMessage
+[protocol.chat.v1.UnpinMessageRequest](#unpinmessagerequest) -> [protocol.chat.v1.UnpinMessageResponse](#unpinmessageresponse)
+
+Endpoint to unpin a message in a guild channel.
+
+
+
+##### UnpinMessageRequest
+Used in the `UnpinMessage` endpoint.
+
+Fields
+###### guild_id
+Type: optional `uint64`
+
+Guild ID of the guild where the channel is.
+###### channel_id
+Type: optional `uint64`
+
+Channel ID of the channel where the message is.
+###### message_id
+Type: optional `uint64`
+
+Message ID of the message we want to unpin.
+
+
+
+
+##### UnpinMessageResponse
+Used in the `UnpinMessage` endpoint.
+
+This item has no fields.
+
+------
+#### StreamEvents
+streaming [protocol.chat.v1.StreamEventsRequest](#streameventsrequest) -> streaming [protocol.chat.v1.StreamEventsResponse](#streameventsresponse)
+
+Endpoint to stream events from the homeserver.
+By default, this endpoint will subscribe to all events.
+Any guilds joined in the future will be added to the subscription as well.
+Use the UnsubscribeFromAll event for unsubscribing from all current subscriptions and disable the automatic guild subscriptions
+##### StreamEventsResponse
+Used in the `StreamEvents` endpoint.
+
+Fields
+###### chat
+Type: optional [protocol.chat.v1.StreamEvent](#streamevent)
+
+A chat event.
+###### emote
+Type: optional [protocol.emote.v1.StreamEvent]({{< ref "protocol.emote.v1.md" >}}#streamevent)
+
+A emote event.
+###### profile
+Type: optional [protocol.profile.v1.StreamEvent]({{< ref "protocol.profile.v1.md" >}}#streamevent)
+
+A profile event.
+
+------
+#### AddReaction
+[protocol.chat.v1.AddReactionRequest](#addreactionrequest) -> [protocol.chat.v1.AddReactionResponse](#addreactionresponse)
+
+Endpoint to add a reaction to a message.
+
+
+
+##### AddReactionRequest
+Used in `AddReaction` endpoint.
+
+Fields
+###### guild_id
+Type: optional `uint64`
+
+Guild ID of the guild where the channel is.
+###### channel_id
+Type: optional `uint64`
+
+Channel ID of the channel where the message is.
+###### message_id
+Type: optional `uint64`
+
+Message ID of the message we want to add a reaction to.
+###### emote
+Type: optional [protocol.emote.v1.Emote]({{< ref "protocol.emote.v1.md" >}}#emote)
+
+The emote we want to react with.
+
+
+
+
+##### AddReactionResponse
+Used in `AddReaction` endpoint.
+
+This item has no fields.
+
+------
+#### RemoveReaction
+[protocol.chat.v1.RemoveReactionRequest](#removereactionrequest) -> [protocol.chat.v1.RemoveReactionResponse](#removereactionresponse)
+
+Endpoint to remove a reaction from a message.
+
+
+
+##### RemoveReactionRequest
+Used in `RemoveReaction` endpoint.
+
+Fields
+###### guild_id
+Type: optional `uint64`
+
+Guild ID of the guild where the channel is.
+###### channel_id
+Type: optional `uint64`
+
+Channel ID of the channel where the message is.
+###### message_id
+Type: optional `uint64`
+
+Message ID of the message we want to remove a reaction.
+###### emote
+Type: optional [protocol.emote.v1.Emote]({{< ref "protocol.emote.v1.md" >}}#emote)
+
+The emote we want to remove the react of.
+
+
+
+
+##### RemoveReactionResponse
+Used in `RemoveReaction` endpoint.
+
+This item has no fields.
+
+------
+#### GrantOwnership
+[protocol.chat.v1.GrantOwnershipRequest](#grantownershiprequest) -> [protocol.chat.v1.GrantOwnershipResponse](#grantownershipresponse)
+
+Endpoint to give ownership to someone else.
+
+
+
+##### GrantOwnershipRequest
+Request for GrantOwnership
+
+Fields
+###### guild_id
+Type: optional `uint64`
+
+Guild ID of the guild to give a user ownership on.
+###### new_owner_id
+Type: optional `uint64`
+
+The ID of the new owner to add.
+
+
+
+
+##### GrantOwnershipResponse
+Response for GrantOwnership
+
+This item has no fields.
+
+------
+#### GiveUpOwnership
+[protocol.chat.v1.GiveUpOwnershipRequest](#giveupownershiprequest) -> [protocol.chat.v1.GiveUpOwnershipResponse](#giveupownershipresponse)
+
+Endpoint to give up your own ownership.
+Requires that at least one other person will still be owner.
+
+
+
+##### GiveUpOwnershipRequest
+Request for GiveUpOwnership
+
+Fields
+###### guild_id
+Type: optional `uint64`
+
+Guild ID to give up your ownership on.
+
+
+
+
+##### GiveUpOwnershipResponse
+Response for GiveUpOwnership
+
+This item has no fields.
+
+# Standalone Message Types
+
+## Channel
+An object representing a channel, without the ID.
+
+Fields
+### channel_name
+Type: optional `string`
+
+The name of this channel.
+### kind
+Type: UNHANDLED | TYPE
+
+The kind of channel this is.
+Data does not get inherently stored in the Channel type
+Instead, clients who understand a certain ChannelKind should
+fetch them from a separate RPC.
+### metadata
+Type: optional [protocol.harmonytypes.v1.Metadata]({{< ref "protocol.harmonytypes.v1.md" >}}#metadata)
+
+The metadata of this channel.
+
+------
+## ChannelWithId
+The channel alongside with an ID.
+
+Fields
+### channel_id
+Type: optional `uint64`
+
+ID of the channel.
+### channel
+Type: optional [protocol.chat.v1.Channel](#channel)
+
+The channel data.
+
+------
+## GuildKind
+The kind of a guild.
+
+Fields
+### normal
+Type: optional [protocol.chat.v1.GuildKind.Normal](#guildkindnormal)
+
+A "normal" guild.
+### room
+Type: optional [protocol.chat.v1.GuildKind.Room](#guildkindroom)
+
+A "room" guild.
+### direct_message
+Type: optional [protocol.chat.v1.GuildKind.DirectMessage](#guildkinddirectmessage)
+
+A "direct message" guild.
+
+------
+## GuildKind.Normal
+
+
+This item has no fields.
+
+------
+## GuildKind.Room
+
+
+This item has no fields.
+
+------
+## GuildKind.DirectMessage
+
+
+Fields
+### rejected
+Type: optional `bool`
+
+
+
+------
+## Guild
+Object representing a guild without the ID part.
+
+Fields
+### name
+Type: optional `string`
+
+The name of the guild.
+
+This will be empty if the guild kind is "direct message". See
+the documentation of "direct message" guild kind on how to display
+a name for those guilds.
+### picture
+Type: optional `string`
+
+The picture HMC of the guild.
+### owner_ids
+Type: repeated `uint64`
+
+User ID of the owners of the guild.
+### kind
+Type: optional [protocol.chat.v1.GuildKind](#guildkind)
+
+The kind of this guild.
+### metadata
+Type: optional [protocol.harmonytypes.v1.Metadata]({{< ref "protocol.harmonytypes.v1.md" >}}#metadata)
+
+Metadata of the guild.
+
+------
+## GuildWithId
+Object representing a guild with the ID part.
+
+Fields
+### guild_id
+Type: optional `uint64`
+
+The ID of the guild.
+### guild
+Type: optional [protocol.chat.v1.Guild](#guild)
+
+The guild.
+
+------
+## Invite
+Object representing an invite without the ID part.
+
+Fields
+### possible_uses
+Type: optional `uint32`
+
+Possible uses of this invite. A use of `0` means infinite uses.
+### use_count
+Type: optional `uint32`
+
+Total use count of this invite.
+
+------
+## InviteWithId
+Invite with ID.
+
+Fields
+### invite_id
+Type: optional `string`
+
+ID of the invite.
+### invite
+Type: optional [protocol.chat.v1.Invite](#invite)
+
+The invite data.
+
+------
+## PendingInvite
+A pending invite.
+
+Fields
+### invite_id
+Type: optional `string`
+
+Invite ID of the invite.
+### server_id
+Type: optional `string`
+
+Server ID of the server the inviter is on.
+### inviter_id
+Type: optional `uint64`
+
+User ID of the inviter.
+
+------
+## GuildListEntry
+Object representing a guild list entry.
+
+Fields
+### guild_id
+Type: optional `uint64`
+
+Guild ID of this guild entry.
+### server_id
+Type: optional `string`
+
+Server ID of the homeserver of this guild.
+
+------
+## Overrides
+Overrides provide a way to override the name and avatar of a message.
+
+Fields
+### username
+Type: optional `string`
+
+the overridden username.
+### avatar
+Type: optional `string`
+
+the overridden avatar.
+### user_defined
+Type: optional `string`
+
+a custom reason in case the builtin ones don't fit
+### webhook
+Type: optional [protocol.harmonytypes.v1.Empty]({{< ref "protocol.harmonytypes.v1.md" >}}#empty)
+
+the override occured because of a webhook
+### system_plurality
+Type: optional [protocol.harmonytypes.v1.Empty]({{< ref "protocol.harmonytypes.v1.md" >}}#empty)
+
+plurality, not system as in computer
+### system_message
+Type: optional [protocol.harmonytypes.v1.Empty]({{< ref "protocol.harmonytypes.v1.md" >}}#empty)
+
+the override occured because it was made by the server
+
+Servers should reject messages sent by users with this override.
+### bridge
+Type: optional [protocol.harmonytypes.v1.Empty]({{< ref "protocol.harmonytypes.v1.md" >}}#empty)
+
+the override occured because of bridging
+
+------
+## ActionPayload
+The payload sent to the bot when an action is triggered.
+
+Fields
+### button
+Type: optional [protocol.chat.v1.ActionPayload.Button](#actionpayloadbutton)
+
+Payload for a button
+### dropdown
+Type: optional [protocol.chat.v1.ActionPayload.Dropdown](#actionpayloaddropdown)
+
+Payload for a dropdown
+### input
+Type: optional [protocol.chat.v1.ActionPayload.Input](#actionpayloadinput)
+
+Payload for a text input
+
+------
+## ActionPayload.Button
+
+
+Fields
+### data
+Type: optional `bytes`
+
+
+
+------
+## ActionPayload.Dropdown
+
+
+Fields
+### choice
+Type: optional `bytes`
+
+
+
+------
+## ActionPayload.Input
+
+
+Fields
+### input
+Type: optional `string`
+
+
+### data
+Type: optional `bytes`
+
+
+
+------
+## Action
+Actions are interactive elements that can exist within an embed.
+
+Fields
+### action_type
+Type: UNHANDLED | TYPE
+
+Type of the action.
+### button
+Type: optional [protocol.chat.v1.Action.Button](#actionbutton)
+
+Button action.
+### dropdown
+Type: optional [protocol.chat.v1.Action.Dropdown](#actiondropdown)
+
+Dropdown action.
+### input
+Type: optional [protocol.chat.v1.Action.Input](#actioninput)
+
+Input action.
+
+------
+## Action.Button
+The action type. This is primarily used to change the look of the action to
+the user (example: Destructive actions will have a red background).
+
+Fields
+### text
+Type: optional `string`
+
+a normal action.
+### data
+Type: optional `bytes`
+
+a primary action.
+### url
+Type: optional `string`
+
+A destructive / dangerous action.
+
+------
+## Action.Dropdown
+
+
+Fields
+### label
+Type: optional `string`
+
+
+### entries
+Type: repeated [protocol.chat.v1.Action.Dropdown.Entry](#actiondropdownentry)
+
+
+
+------
+## Action.Dropdown.Entry
+
+
+Fields
+### label
+Type: optional `string`
+
+
+### data
+Type: optional `bytes`
+
+
+
+------
+## Action.Input
+
+
+Fields
+### label
+Type: optional `string`
+
+
+### multiline
+Type: optional `bool`
+
+
+### data
+Type: optional `bytes`
+
+
+
+------
+## Embed
+Object representing a message embed.
+
+Fields
+### title
+Type: optional `string`
+
+Title of this embed.
+### body
+Type: optional [protocol.chat.v1.FormattedText](#formattedtext)
+
+Body text of this embed.
+### color
+Type: optional `int32`
+
+Color of this embed.
+### header
+Type: optional [protocol.chat.v1.Embed.EmbedHeading](#embedembedheading)
+
+Embed heading for the header.
+### footer
+Type: optional [protocol.chat.v1.Embed.EmbedHeading](#embedembedheading)
+
+Embed heading for the footer.
+### fields
+Type: repeated [protocol.chat.v1.Embed.EmbedField](#embedembedfield)
+
+Fields of this embed.
+
+------
+## Embed.EmbedHeading
+
+
+Fields
+### text
+Type: optional `string`
+
+
+### subtext
+Type: optional `string`
+
+
+### url
+Type: optional `string`
+
+
+### icon
+Type: optional `string`
+
+
+
+------
+## Embed.EmbedField
+
+
+Fields
+### title
+Type: optional `string`
+
+
+### subtitle
+Type: optional `string`
+
+
+### body
+Type: optional [protocol.chat.v1.FormattedText](#formattedtext)
+
+
+### image_url
+Type: optional `string`
+
+
+### presentation
+Type: UNHANDLED | TYPE
+
+
+### actions
+Type: repeated [protocol.chat.v1.Action](#action)
+
+
+
+------
+## Minithumbnail
+Minithumbnail is an extremely low-quality JPEG thumbnail.
+
+The resolution is usually no larger than 64x64.
+
+Fields
+### width
+Type: optional `uint32`
+
+The width of the minithumbnail
+### height
+Type: optional `uint32`
+
+The height of the minithumbnail
+### data
+Type: optional `bytes`
+
+The JPEG data of the minithumbnail
+
+------
+## Photo
+Photo contains data about a photo.
+
+Photo are always JPEG, and are
+constrained to the following rules:
+
+- width+height <= 10_000
+- width <= height*20
+- height <= width*20
+
+Photos are preferably no more than 10MB
+in size, and servers may compress as necessary.
+
+Fields
+### hmc
+Type: optional `string`
+
+The HMC URL of the photo.
+### name
+Type: optional `string`
+
+The filename of the photo.
+### file_size
+Type: optional `uint32`
+
+The size of the photo.
+### height
+Type: optional `uint32`
+
+The height of the photo, in pixels.
+### width
+Type: optional `uint32`
+
+The width of the photo, in pixels.
+### caption
+Type: optional [protocol.chat.v1.FormattedText](#formattedtext)
+
+The photo's caption.
+### minithumbnail
+Type: optional [protocol.chat.v1.Minithumbnail](#minithumbnail)
+
+A thumbnail representing the photo.
+
+------
+## Attachment
+Object representing a generic message attachment.
+
+Fields
+### id
+Type: optional `string`
+
+File ID of this attachment.
+### name
+Type: optional `string`
+
+Filename of this attachment.
+### mimetype
+Type: optional `string`
+
+Mimetype of this attachment.
+### size
+Type: optional `uint32`
+
+Size of this attachment.
+### caption
+Type: optional [protocol.chat.v1.FormattedText](#formattedtext)
+
+Caption of this attachment.
+
+------
+## Content
+Object representing a message's content.
+
+Fields
+### text_message
+Type: optional [protocol.chat.v1.Content.TextContent](#contenttextcontent)
+
+Text content.
+### embed_message
+Type: optional [protocol.chat.v1.Content.EmbedContent](#contentembedcontent)
+
+Embed content.
+### attachment_message
+Type: optional [protocol.chat.v1.Content.AttachmentContent](#contentattachmentcontent)
+
+Attachment content.
+### photo_message
+Type: optional [protocol.chat.v1.Content.PhotoContent](#contentphotocontent)
+
+Photo content.
+### invite_rejected
+Type: optional [protocol.chat.v1.Content.InviteRejected](#contentinviterejected)
+
+A user rejected an invite.
+### invite_accepted
+Type: optional [protocol.chat.v1.Content.InviteAccepted](#contentinviteaccepted)
+
+A user accepted an invite.
+### room_upgraded_to_guild
+Type: optional [protocol.chat.v1.Content.RoomUpgradedToGuild](#contentroomupgradedtoguild)
+
+A user upgraded a guild from "room" to "normal".
+
+------
+## Content.TextContent
+
+
+Fields
+### content
+Type: optional [protocol.chat.v1.FormattedText](#formattedtext)
+
+
+
+------
+## Content.EmbedContent
+
+
+Fields
+### embeds
+Type: repeated [protocol.chat.v1.Embed](#embed)
+
+
+
+------
+## Content.AttachmentContent
+
+
+Fields
+### files
+Type: repeated [protocol.chat.v1.Attachment](#attachment)
+
+
+
+------
+## Content.PhotoContent
+
+
+Fields
+### photos
+Type: repeated [protocol.chat.v1.Photo](#photo)
+
+
+
+------
+## Content.InviteRejected
+
+
+Fields
+### invitee_id
+Type: optional `uint64`
+
+
+### inviter_id
+Type: optional `uint64`
+
+
+
+------
+## Content.InviteAccepted
+
+
+Fields
+### invitee_id
+Type: optional `uint64`
+
+
+### inviter_id
+Type: optional `uint64`
+
+
+
+------
+## Content.RoomUpgradedToGuild
+
+
+Fields
+### upgraded_by
+Type: optional `uint64`
+
+
+
+------
+## Reaction
+Object representing a reaction.
+
+Fields
+### emote
+Type: optional [protocol.emote.v1.Emote]({{< ref "protocol.emote.v1.md" >}}#emote)
+
+Emote data for this reaction.
+
+Emote's image ID is used as an identifier for unique reactions.
+Emotes with the same names should be "deduplicated" by a client, by suffixing
+their names with `~1`, `~2` and so on.
+### count
+Type: optional `uint32`
+
+How many reactions this reaction has.
+
+------
+## Format
+A format for text
+
+Fields
+### start
+Type: optional `uint32`
+
+where the format begins to apply to
+### length
+Type: optional `uint32`
+
+how many characters the format is
+### bold
+Type: optional [protocol.chat.v1.Format.Bold](#formatbold)
+
+a text format for bold text
+### italic
+Type: optional [protocol.chat.v1.Format.Italic](#formatitalic)
+
+a text format for italic text
+### underline
+Type: optional [protocol.chat.v1.Format.Underline](#formatunderline)
+
+a text format for underline text
+### monospace
+Type: optional [protocol.chat.v1.Format.Monospace](#formatmonospace)
+
+a text format for monospace text
+### superscript
+Type: optional [protocol.chat.v1.Format.Superscript](#formatsuperscript)
+
+a text format for superscript text
+### subscript
+Type: optional [protocol.chat.v1.Format.Subscript](#formatsubscript)
+
+a text format for subscript text
+### code_block
+Type: optional [protocol.chat.v1.Format.CodeBlock](#formatcodeblock)
+
+a text format for a codeblock
+### user_mention
+Type: optional [protocol.chat.v1.Format.UserMention](#formatusermention)
+
+a text format for a user mention
+### role_mention
+Type: optional [protocol.chat.v1.Format.RoleMention](#formatrolemention)
+
+a text format for a role mention
+### channel_mention
+Type: optional [protocol.chat.v1.Format.ChannelMention](#formatchannelmention)
+
+a text format for a channel mention
+### guild_mention
+Type: optional [protocol.chat.v1.Format.GuildMention](#formatguildmention)
+
+a text format for a guild mention
+### emoji
+Type: optional [protocol.chat.v1.Format.Emoji](#formatemoji)
+
+a text format for an emoji
+### color
+Type: optional [protocol.chat.v1.Format.Color](#formatcolor)
+
+a text format for coloured text
+### localization
+Type: optional [protocol.chat.v1.Format.Localization](#formatlocalization)
+
+a text format for localization
+
+------
+## Format.Bold
+
+
+This item has no fields.
+
+------
+## Format.Italic
+
+
+This item has no fields.
+
+------
+## Format.Underline
+
+
+This item has no fields.
+
+------
+## Format.Monospace
+
+
+This item has no fields.
+
+------
+## Format.Superscript
+
+
+This item has no fields.
+
+------
+## Format.Subscript
+
+
+This item has no fields.
+
+------
+## Format.CodeBlock
+
+
+Fields
+### language
+Type: optional `string`
+
+
+
+------
+## Format.UserMention
+
+
+Fields
+### user_id
+Type: optional `uint64`
+
+
+
+------
+## Format.RoleMention
+
+
+Fields
+### role_id
+Type: optional `uint64`
+
+
+
+------
+## Format.ChannelMention
+
+
+Fields
+### channel_id
+Type: optional `uint64`
+
+
+
+------
+## Format.GuildMention
+
+
+Fields
+### guild_id
+Type: optional `uint64`
+
+
+### homeserver
+Type: optional `string`
+
+
+
+------
+## Format.Emoji
+
+
+Fields
+### image_hmc
+Type: optional `string`
+
+
+### pack_id
+Type: optional `uint64`
+
+
+
+------
+## Format.Color
+
+
+Fields
+### kind
+Type: UNHANDLED | TYPE
+
+
+
+------
+## Format.Localization
+
+
+Fields
+### i18n_code
+Type: optional `string`
+
+
+
+------
+## FormattedText
+Formatted text
+
+Fields
+### text
+Type: optional `string`
+
+The textual content of a message
+### format
+Type: repeated [protocol.chat.v1.Format](#format)
+
+The formats for a message
+
+------
+## Message
+Object representing a message without the ID part.
+
+Fields
+### metadata
+Type: optional [protocol.harmonytypes.v1.Metadata]({{< ref "protocol.harmonytypes.v1.md" >}}#metadata)
+
+Metadata of this message.
+### overrides
+Type: optional [protocol.chat.v1.Overrides](#overrides)
+
+Overrides of this message.
+### author_id
+Type: optional `uint64`
+
+User ID of the user who sent this message.
+### created_at
+Type: optional `uint64`
+
+When this message was created, in miliseconds since unix epoch
+### edited_at
+Type: optional `uint64`
+
+The most recent time this message was edited, in milliseconds since unix epoch
+### in_reply_to
+Type: optional `uint64`
+
+The message this message is a reply to.
+### content
+Type: optional [protocol.chat.v1.Content](#content)
+
+The content of the message.
+### reactions
+Type: repeated [protocol.chat.v1.Reaction](#reaction)
+
+The reactions of the message.
+
+------
+## MessageWithId
+Object representing a message with it's ID.
+
+Fields
+### message_id
+Type: optional `uint64`
+
+ID of the message.
+### message
+Type: optional [protocol.chat.v1.Message](#message)
+
+The message data.
+
+------
+## Permission
+Object representing a single permission node.
+
+Fields
+### matches
+Type: optional `string`
+
+the permission matcher. (example: roles.manage)
+### ok
+Type: optional `bool`
+
+whether the permission is allowed or not.
+
+------
+## Role
+Object representing a role without the ID.
+
+Fields
+### name
+Type: optional `string`
+
+the role name.
+### color
+Type: optional `int32`
+
+the role color.
+### hoist
+Type: optional `bool`
+
+whether the role is hoisted or not.
+### pingable
+Type: optional `bool`
+
+whether the role is mentionable or not.
+
+------
+## RoleWithId
+Object representing a role with it's ID.
+
+The role ID for the default role in a guild should always be 0.
+
+Fields
+### role_id
+Type: optional `uint64`
+
+ID of the role.
+### role
+Type: optional [protocol.chat.v1.Role](#role)
+
+The role data.
+
+------
+## StreamEventsRequest
+Request type for use in the `StreamEvents` endpoint.
+By default, this endpoint will subscribe to all events.
+Any guilds joined in the future will be added to the subscription as well.
+Use the UnsubscribeFromAll event for unsubscribing from all current subscriptions and disable the automatic guild subscriptions
+
+Fields
+### subscribe_to_guild
+Type: optional [protocol.chat.v1.StreamEventsRequest.SubscribeToGuild](#streameventsrequestsubscribetoguild)
+
+Subscribe to the guild event source.
+### subscribe_to_actions
+Type: optional [protocol.chat.v1.StreamEventsRequest.SubscribeToActions](#streameventsrequestsubscribetoactions)
+
+Subscribe to the action event source.
+### subscribe_to_homeserver_events
+Type: optional [protocol.chat.v1.StreamEventsRequest.SubscribeToHomeserverEvents](#streameventsrequestsubscribetohomeserverevents)
+
+Subscribe to the homeserver event source.
+### unsubscribe_from_all
+Type: optional [protocol.chat.v1.StreamEventsRequest.UnsubscribeFromAll](#streameventsrequestunsubscribefromall)
+
+Unsubscribe from all events.
+
+------
+## StreamEventsRequest.SubscribeToGuild
+
+
+Fields
+### guild_id
+Type: optional `uint64`
+
+
+
+------
+## StreamEventsRequest.SubscribeToActions
+
+
+This item has no fields.
+
+------
+## StreamEventsRequest.SubscribeToHomeserverEvents
+
+
+This item has no fields.
+
+------
+## StreamEventsRequest.UnsubscribeFromAll
+
+
+This item has no fields.
+
+------
+## StreamEvent
+Describes an event.
+
+Fields
+### guild_added_to_list
+Type: optional [protocol.chat.v1.StreamEvent.GuildAddedToList](#streameventguildaddedtolist)
+
+Send the guild added to list event.
+### guild_removed_from_list
+Type: optional [protocol.chat.v1.StreamEvent.GuildRemovedFromList](#streameventguildremovedfromlist)
+
+Send the guild removed from list event.
+### action_performed
+Type: optional [protocol.chat.v1.StreamEvent.ActionPerformed](#streameventactionperformed)
+
+Send the action performed event.
+### sent_message
+Type: optional [protocol.chat.v1.StreamEvent.MessageSent](#streameventmessagesent)
+
+Send the message sent event.
+### edited_message
+Type: optional [protocol.chat.v1.StreamEvent.MessageUpdated](#streameventmessageupdated)
+
+Send the message updated event.
+### deleted_message
+Type: optional [protocol.chat.v1.StreamEvent.MessageDeleted](#streameventmessagedeleted)
+
+Send the message deleted event.
+### created_channel
+Type: optional [protocol.chat.v1.StreamEvent.ChannelCreated](#streameventchannelcreated)
+
+Send the channel created event.
+### edited_channel
+Type: optional [protocol.chat.v1.StreamEvent.ChannelUpdated](#streameventchannelupdated)
+
+Send the channel updated event.
+### deleted_channel
+Type: optional [protocol.chat.v1.StreamEvent.ChannelDeleted](#streameventchanneldeleted)
+
+Send the channel deleted event.
+### edited_guild
+Type: optional [protocol.chat.v1.StreamEvent.GuildUpdated](#streameventguildupdated)
+
+Send the guild updated event.
+### deleted_guild
+Type: optional [protocol.chat.v1.StreamEvent.GuildDeleted](#streameventguilddeleted)
+
+Send the guild deleted event.
+### joined_member
+Type: optional [protocol.chat.v1.StreamEvent.MemberJoined](#streameventmemberjoined)
+
+Send the member joined event.
+### left_member
+Type: optional [protocol.chat.v1.StreamEvent.MemberLeft](#streameventmemberleft)
+
+Send the member left event.
+### typing
+Type: optional [protocol.chat.v1.StreamEvent.Typing](#streameventtyping)
+
+Send the typing event.
+### role_created
+Type: optional [protocol.chat.v1.StreamEvent.RoleCreated](#streameventrolecreated)
+
+Send the role created event.
+### role_deleted
+Type: optional [protocol.chat.v1.StreamEvent.RoleDeleted](#streameventroledeleted)
+
+Send the role deleted event.
+### role_moved
+Type: optional [protocol.chat.v1.StreamEvent.RoleMoved](#streameventrolemoved)
+
+Send the role moved event.
+### role_updated
+Type: optional [protocol.chat.v1.StreamEvent.RoleUpdated](#streameventroleupdated)
+
+Send the role updated event.
+### role_perms_updated
+Type: optional [protocol.chat.v1.StreamEvent.RolePermissionsUpdated](#streameventrolepermissionsupdated)
+
+Send the role perms updated event.
+### user_roles_updated
+Type: optional [protocol.chat.v1.StreamEvent.UserRolesUpdated](#streameventuserrolesupdated)
+
+Send the user roles updated event.
+### permission_updated
+Type: optional [protocol.chat.v1.StreamEvent.PermissionUpdated](#streameventpermissionupdated)
+
+Send the permission updated event.
+### channels_reordered
+Type: optional [protocol.chat.v1.StreamEvent.ChannelsReordered](#streameventchannelsreordered)
+
+The channels have been completely reordered.
+### edited_channel_position
+Type: optional [protocol.chat.v1.StreamEvent.ChannelPositionUpdated](#streameventchannelpositionupdated)
+
+Send the channel position updated event.
+### message_pinned
+Type: optional [protocol.chat.v1.StreamEvent.MessagePinned](#streameventmessagepinned)
+
+Send the message pinned event.
+### message_unpinned
+Type: optional [protocol.chat.v1.StreamEvent.MessageUnpinned](#streameventmessageunpinned)
+
+Send the message unpinned event.
+### reaction_updated
+Type: optional [protocol.chat.v1.StreamEvent.ReactionUpdated](#streameventreactionupdated)
+
+Send the reaction updated event.
+### owner_added
+Type: optional [protocol.chat.v1.StreamEvent.OwnerAdded](#streameventowneradded)
+
+Send the owner added event.
+### owner_removed
+Type: optional [protocol.chat.v1.StreamEvent.OwnerRemoved](#streameventownerremoved)
+
+Send the owner removed event.
+### invite_received
+Type: optional [protocol.chat.v1.StreamEvent.InviteReceived](#streameventinvitereceived)
+
+Send the guild invite received event.
+### invite_rejected
+Type: optional [protocol.chat.v1.StreamEvent.InviteRejected](#streameventinviterejected)
+
+Send the guild invite rejected event.
+
+------
+## StreamEvent.MessageSent
+
+
+Fields
+### echo_id
+Type: optional `uint64`
+
+
+### guild_id
+Type: optional `uint64`
+
+
+### channel_id
+Type: optional `uint64`
+
+
+### message_id
+Type: optional `uint64`
+
+
+### message
+Type: optional [protocol.chat.v1.Message](#message)
+
+
+
+------
+## StreamEvent.MessageUpdated
+
+
+Fields
+### guild_id
+Type: optional `uint64`
+
+
+### channel_id
+Type: optional `uint64`
+
+
+### message_id
+Type: optional `uint64`
+
+
+### edited_at
+Type: optional `uint64`
+
+
+### new_content
+Type: optional [protocol.chat.v1.FormattedText](#formattedtext)
+
+
+
+------
+## StreamEvent.MessageDeleted
+
+
+Fields
+### guild_id
+Type: optional `uint64`
+
+
+### channel_id
+Type: optional `uint64`
+
+
+### message_id
+Type: optional `uint64`
+
+
+
+------
+## StreamEvent.ChannelCreated
+
+
+Fields
+### guild_id
+Type: optional `uint64`
+
+
+### channel_id
+Type: optional `uint64`
+
+
+### name
+Type: optional `string`
+
+
+### position
+Type: optional [protocol.harmonytypes.v1.ItemPosition]({{< ref "protocol.harmonytypes.v1.md" >}}#itemposition)
+
+
+### kind
+Type: UNHANDLED | TYPE
+
+
+### metadata
+Type: optional [protocol.harmonytypes.v1.Metadata]({{< ref "protocol.harmonytypes.v1.md" >}}#metadata)
+
+
+
+------
+## StreamEvent.ChannelUpdated
+
+
+Fields
+### guild_id
+Type: optional `uint64`
+
+
+### channel_id
+Type: optional `uint64`
+
+
+### new_name
+Type: optional `string`
+
+
+### new_metadata
+Type: optional [protocol.harmonytypes.v1.Metadata]({{< ref "protocol.harmonytypes.v1.md" >}}#metadata)
+
+
+
+------
+## StreamEvent.ChannelPositionUpdated
+
+
+Fields
+### guild_id
+Type: optional `uint64`
+
+
+### channel_id
+Type: optional `uint64`
+
+
+### new_position
+Type: optional [protocol.harmonytypes.v1.ItemPosition]({{< ref "protocol.harmonytypes.v1.md" >}}#itemposition)
+
+
+
+------
+## StreamEvent.ChannelsReordered
+
+
+Fields
+### guild_id
+Type: optional `uint64`
+
+
+### channel_ids
+Type: repeated `uint64`
+
+
+
+------
+## StreamEvent.ChannelDeleted
+
+
+Fields
+### guild_id
+Type: optional `uint64`
+
+
+### channel_id
+Type: optional `uint64`
+
+
+
+------
+## StreamEvent.GuildUpdated
+
+
+Fields
+### guild_id
+Type: optional `uint64`
+
+
+### new_name
+Type: optional `string`
+
+
+### new_picture
+Type: optional `string`
+
+
+### new_metadata
+Type: optional [protocol.harmonytypes.v1.Metadata]({{< ref "protocol.harmonytypes.v1.md" >}}#metadata)
+
+
+
+------
+## StreamEvent.GuildDeleted
+
+
+Fields
+### guild_id
+Type: optional `uint64`
+
+
+
+------
+## StreamEvent.MemberJoined
+
+
+Fields
+### member_id
+Type: optional `uint64`
+
+
+### guild_id
+Type: optional `uint64`
+
+
+
+------
+## StreamEvent.MemberLeft
+
+
+Fields
+### member_id
+Type: optional `uint64`
+
+
+### guild_id
+Type: optional `uint64`
+
+
+### leave_reason
+Type: UNHANDLED | TYPE
+
+
+
+------
+## StreamEvent.GuildAddedToList
+
+
+Fields
+### guild_id
+Type: optional `uint64`
+
+
+### homeserver
+Type: optional `string`
+
+
+
+------
+## StreamEvent.GuildRemovedFromList
+
+
+Fields
+### guild_id
+Type: optional `uint64`
+
+
+### homeserver
+Type: optional `string`
+
+
+
+------
+## StreamEvent.ActionPerformed
+
+
+Fields
+### guild_id
+Type: optional `uint64`
+
+
+### channel_id
+Type: optional `uint64`
+
+
+### message_id
+Type: optional `uint64`
+
+
+### user_id
+Type: optional `uint64`
+
+
+### payload
+Type: optional [protocol.chat.v1.ActionPayload](#actionpayload)
+
+
+
+------
+## StreamEvent.RoleMoved
+
+
+Fields
+### guild_id
+Type: optional `uint64`
+
+
+### role_id
+Type: optional `uint64`
+
+
+### new_position
+Type: optional [protocol.harmonytypes.v1.ItemPosition]({{< ref "protocol.harmonytypes.v1.md" >}}#itemposition)
+
+
+
+------
+## StreamEvent.RoleDeleted
+
+
+Fields
+### guild_id
+Type: optional `uint64`
+
+
+### role_id
+Type: optional `uint64`
+
+
+
+------
+## StreamEvent.RoleCreated
+
+
+Fields
+### guild_id
+Type: optional `uint64`
+
+
+### role_id
+Type: optional `uint64`
+
+
+### name
+Type: optional `string`
+
+
+### color
+Type: optional `int32`
+
+
+### hoist
+Type: optional `bool`
+
+
+### pingable
+Type: optional `bool`
+
+
+
+------
+## StreamEvent.RoleUpdated
+
+
+Fields
+### guild_id
+Type: optional `uint64`
+
+
+### role_id
+Type: optional `uint64`
+
+
+### new_name
+Type: optional `string`
+
+
+### new_color
+Type: optional `int32`
+
+
+### new_hoist
+Type: optional `bool`
+
+
+### new_pingable
+Type: optional `bool`
+
+
+
+------
+## StreamEvent.RolePermissionsUpdated
+
+
+Fields
+### guild_id
+Type: optional `uint64`
+
+
+### channel_id
+Type: optional `uint64`
+
+
+### role_id
+Type: optional `uint64`
+
+
+### new_perms
+Type: repeated [protocol.chat.v1.Permission](#permission)
+
+
+
+------
+## StreamEvent.UserRolesUpdated
+
+
+Fields
+### guild_id
+Type: optional `uint64`
+
+
+### user_id
+Type: optional `uint64`
+
+
+### new_role_ids
+Type: repeated `uint64`
+
+
+
+------
+## StreamEvent.Typing
+
+
+Fields
+### user_id
+Type: optional `uint64`
+
+
+### guild_id
+Type: optional `uint64`
+
+
+### channel_id
+Type: optional `uint64`
+
+
+
+------
+## StreamEvent.PermissionUpdated
+
+
+Fields
+### guild_id
+Type: optional `uint64`
+
+
+### channel_id
+Type: optional `uint64`
+
+
+### query
+Type: optional `string`
+
+
+### ok
+Type: optional `bool`
+
+
+
+------
+## StreamEvent.MessagePinned
+
+
+Fields
+### guild_id
+Type: optional `uint64`
+
+
+### channel_id
+Type: optional `uint64`
+
+
+### message_id
+Type: optional `uint64`
+
+
+
+------
+## StreamEvent.MessageUnpinned
+
+
+Fields
+### guild_id
+Type: optional `uint64`
+
+
+### channel_id
+Type: optional `uint64`
+
+
+### message_id
+Type: optional `uint64`
+
+
+
+------
+## StreamEvent.ReactionUpdated
+
+
+Fields
+### guild_id
+Type: optional `uint64`
+
+
+### channel_id
+Type: optional `uint64`
+
+
+### message_id
+Type: optional `uint64`
+
+
+### reaction
+Type: optional [protocol.chat.v1.Reaction](#reaction)
+
+
+
+------
+## StreamEvent.OwnerAdded
+
+
+Fields
+### user_id
+Type: optional `uint64`
+
+
+
+------
+## StreamEvent.OwnerRemoved
+
+
+Fields
+### user_id
+Type: optional `uint64`
+
+
+
+------
+## StreamEvent.InviteReceived
+
+
+Fields
+### invite_id
+Type: optional `string`
+
+
+### server_id
+Type: optional `string`
+
+
+### inviter_id
+Type: optional `uint64`
+
+
+
+------
+## StreamEvent.InviteRejected
+
+
+Fields
+### guild_id
+Type: optional `uint64`
+
+
+### invite_id
+Type: optional `string`
+
+
+### user_id
+Type: optional `uint64`
+
+
+
+# Enums
+
+## ChannelKind
+
+What kind the channel is.
+### CHANNEL_KIND_TEXT_UNSPECIFIED
+A text channel. Allows you to simply send messages to a group of people.
+
+### CHANNEL_KIND_VOICE_MEDIA
+A voice channel. Allows you to talk to other people with voice.
+
+### CHANNEL_KIND_CATEGORY
+A category channel. All channels under this channel down to another
+category channel belongs to this category channel.
+
+------
+## LeaveReason
+
+A reason for why a user has left a guild.
+### LEAVE_REASON_WILLINGLY_UNSPECIFIED
+The user left the guild willingly.
+
+### LEAVE_REASON_BANNED
+The user was banned from the guild.
+
+### LEAVE_REASON_KICKED
+The user was kicked from the guild.
+
+------
+## Type
+
+
+### TYPE_NORMAL_UNSPECIFIED
+
+
+### TYPE_PRIMARY
+
+
+### TYPE_DESTRUCTIVE
+
+
+------
+## Direction
+
+
+### DIRECTION_BEFORE_UNSPECIFIED
+
+
+### DIRECTION_AROUND
+
+
+### DIRECTION_AFTER
+
+
+------
+## Embed.Presentation
+
+
+### PRESENTATION_DATA_UNSPECIFIED
+
+
+### PRESENTATION_CAPTIONED_IMAGE
+
+
+### PRESENTATION_ROW
+
+
+------
+## Format.Kind
+
+
+### KIND_DIM_UNSPECIFIED
+
+
+### KIND_BRIGHT
+
+
+### KIND_NEGATIVE
+
+
+### KIND_POSITIVE
+
+
+### KIND_INFO
+
+
+### KIND_WARNING
-### Event.MemberLeft
-Fields
-
-| Name | Type |
-| ---- | ---- |
-| member_id | `uint64` |
-| guild_id | `uint64` |
-| UNHANDLED | TYPE |
-
-### Event.GuildAddedToList
-
-Fields
-
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
-| homeserver | `string` |
-
-### Event.GuildRemovedFromList
-
-Fields
-
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
-| homeserver | `string` |
-
-### Event.ActionPerformed
-
-Fields
-
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
-| channel_id | `uint64` |
-| message_id | `uint64` |
-| action_id | `string` |
-| action_data | `string` |
-
-### Event.RoleMoved
-
-Fields
-
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
-| role_id | `uint64` |
-
-### Event.ProfileUpdated
-
-Fields
-
-| Name | Type |
-| ---- | ---- |
-| user_id | `uint64` |
-| new_username | `string` |
-| update_username | `bool` |
-| new_avatar | `string` |
-| update_avatar | `bool` |
-| UNHANDLED | TYPE |
-| update_status | `bool` |
-| is_bot | `bool` |
-| update_is_bot | `bool` |
-
-### Event.Typing
-
-Fields
-
-| Name | Type |
-| ---- | ---- |
-| user_id | `uint64` |
-| guild_id | `uint64` |
-| channel_id | `uint64` |
-
-## Services
-
-### ChatService
-
-#### Unary Methods
-
-| Name | Request | Response |
-| ---- | ------- | -------- |
-|CreateGuild|[protocol.chat.v1.CreateGuildRequest](#createguildrequest)|[protocol.chat.v1.CreateGuildResponse](#createguildresponse)|
-|CreateInvite|[protocol.chat.v1.CreateInviteRequest](#createinviterequest)|[protocol.chat.v1.CreateInviteResponse](#createinviteresponse)|
-|CreateChannel|[protocol.chat.v1.CreateChannelRequest](#createchannelrequest)|[protocol.chat.v1.CreateChannelResponse](#createchannelresponse)|
-|CreateEmotePack|[protocol.chat.v1.CreateEmotePackRequest](#createemotepackrequest)|[protocol.chat.v1.CreateEmotePackResponse](#createemotepackresponse)|
-|GetGuildList|[protocol.chat.v1.GetGuildListRequest](#getguildlistrequest)|[protocol.chat.v1.GetGuildListResponse](#getguildlistresponse)|
-|GetGuild|[protocol.chat.v1.GetGuildRequest](#getguildrequest)|[protocol.chat.v1.GetGuildResponse](#getguildresponse)|
-|GetGuildInvites|[protocol.chat.v1.GetGuildInvitesRequest](#getguildinvitesrequest)|[protocol.chat.v1.GetGuildInvitesResponse](#getguildinvitesresponse)|
-|GetGuildMembers|[protocol.chat.v1.GetGuildMembersRequest](#getguildmembersrequest)|[protocol.chat.v1.GetGuildMembersResponse](#getguildmembersresponse)|
-|GetGuildChannels|[protocol.chat.v1.GetGuildChannelsRequest](#getguildchannelsrequest)|[protocol.chat.v1.GetGuildChannelsResponse](#getguildchannelsresponse)|
-|GetChannelMessages|[protocol.chat.v1.GetChannelMessagesRequest](#getchannelmessagesrequest)|[protocol.chat.v1.GetChannelMessagesResponse](#getchannelmessagesresponse)|
-|GetMessage|[protocol.chat.v1.GetMessageRequest](#getmessagerequest)|[protocol.chat.v1.GetMessageResponse](#getmessageresponse)|
-|GetEmotePacks|[protocol.chat.v1.GetEmotePacksRequest](#getemotepacksrequest)|[protocol.chat.v1.GetEmotePacksResponse](#getemotepacksresponse)|
-|GetEmotePackEmotes|[protocol.chat.v1.GetEmotePackEmotesRequest](#getemotepackemotesrequest)|[protocol.chat.v1.GetEmotePackEmotesResponse](#getemotepackemotesresponse)|
-|UpdateGuildInformation|[protocol.chat.v1.UpdateGuildInformationRequest](#updateguildinformationrequest)|[google.protobuf.Empty]({{< ref "google.protobuf.md" >}}#empty)|
-|UpdateChannelInformation|[protocol.chat.v1.UpdateChannelInformationRequest](#updatechannelinformationrequest)|[google.protobuf.Empty]({{< ref "google.protobuf.md" >}}#empty)|
-|UpdateChannelOrder|[protocol.chat.v1.UpdateChannelOrderRequest](#updatechannelorderrequest)|[google.protobuf.Empty]({{< ref "google.protobuf.md" >}}#empty)|
-|UpdateMessageText|[protocol.chat.v1.UpdateMessageTextRequest](#updatemessagetextrequest)|[google.protobuf.Empty]({{< ref "google.protobuf.md" >}}#empty)|
-|AddEmoteToPack|[protocol.chat.v1.AddEmoteToPackRequest](#addemotetopackrequest)|[google.protobuf.Empty]({{< ref "google.protobuf.md" >}}#empty)|
-|DeleteGuild|[protocol.chat.v1.DeleteGuildRequest](#deleteguildrequest)|[google.protobuf.Empty]({{< ref "google.protobuf.md" >}}#empty)|
-|DeleteInvite|[protocol.chat.v1.DeleteInviteRequest](#deleteinviterequest)|[google.protobuf.Empty]({{< ref "google.protobuf.md" >}}#empty)|
-|DeleteChannel|[protocol.chat.v1.DeleteChannelRequest](#deletechannelrequest)|[google.protobuf.Empty]({{< ref "google.protobuf.md" >}}#empty)|
-|DeleteMessage|[protocol.chat.v1.DeleteMessageRequest](#deletemessagerequest)|[google.protobuf.Empty]({{< ref "google.protobuf.md" >}}#empty)|
-|DeleteEmoteFromPack|[protocol.chat.v1.DeleteEmoteFromPackRequest](#deleteemotefrompackrequest)|[google.protobuf.Empty]({{< ref "google.protobuf.md" >}}#empty)|
-|DeleteEmotePack|[protocol.chat.v1.DeleteEmotePackRequest](#deleteemotepackrequest)|[google.protobuf.Empty]({{< ref "google.protobuf.md" >}}#empty)|
-|DequipEmotePack|[protocol.chat.v1.DequipEmotePackRequest](#dequipemotepackrequest)|[google.protobuf.Empty]({{< ref "google.protobuf.md" >}}#empty)|
-|JoinGuild|[protocol.chat.v1.JoinGuildRequest](#joinguildrequest)|[protocol.chat.v1.JoinGuildResponse](#joinguildresponse)|
-|LeaveGuild|[protocol.chat.v1.LeaveGuildRequest](#leaveguildrequest)|[google.protobuf.Empty]({{< ref "google.protobuf.md" >}}#empty)|
-|TriggerAction|[protocol.chat.v1.TriggerActionRequest](#triggeractionrequest)|[google.protobuf.Empty]({{< ref "google.protobuf.md" >}}#empty)|
-|SendMessage|[protocol.chat.v1.SendMessageRequest](#sendmessagerequest)|[protocol.chat.v1.SendMessageResponse](#sendmessageresponse)|
-|QueryHasPermission|[protocol.chat.v1.QueryPermissionsRequest](#querypermissionsrequest)|[protocol.chat.v1.QueryPermissionsResponse](#querypermissionsresponse)|
-|SetPermissions|[protocol.chat.v1.SetPermissionsRequest](#setpermissionsrequest)|[google.protobuf.Empty]({{< ref "google.protobuf.md" >}}#empty)|
-|GetPermissions|[protocol.chat.v1.GetPermissionsRequest](#getpermissionsrequest)|[protocol.chat.v1.GetPermissionsResponse](#getpermissionsresponse)|
-|MoveRole|[protocol.chat.v1.MoveRoleRequest](#moverolerequest)|[protocol.chat.v1.MoveRoleResponse](#moveroleresponse)|
-|GetGuildRoles|[protocol.chat.v1.GetGuildRolesRequest](#getguildrolesrequest)|[protocol.chat.v1.GetGuildRolesResponse](#getguildrolesresponse)|
-|AddGuildRole|[protocol.chat.v1.AddGuildRoleRequest](#addguildrolerequest)|[protocol.chat.v1.AddGuildRoleResponse](#addguildroleresponse)|
-|ModifyGuildRole|[protocol.chat.v1.ModifyGuildRoleRequest](#modifyguildrolerequest)|[google.protobuf.Empty]({{< ref "google.protobuf.md" >}}#empty)|
-|DeleteGuildRole|[protocol.chat.v1.DeleteGuildRoleRequest](#deleteguildrolerequest)|[google.protobuf.Empty]({{< ref "google.protobuf.md" >}}#empty)|
-|ManageUserRoles|[protocol.chat.v1.ManageUserRolesRequest](#manageuserrolesrequest)|[google.protobuf.Empty]({{< ref "google.protobuf.md" >}}#empty)|
-|GetUserRoles|[protocol.chat.v1.GetUserRolesRequest](#getuserrolesrequest)|[protocol.chat.v1.GetUserRolesResponse](#getuserrolesresponse)|
-|GetUser|[protocol.chat.v1.GetUserRequest](#getuserrequest)|[protocol.chat.v1.GetUserResponse](#getuserresponse)|
-|GetUserBulk|[protocol.chat.v1.GetUserBulkRequest](#getuserbulkrequest)|[protocol.chat.v1.GetUserBulkResponse](#getuserbulkresponse)|
-|GetUserMetadata|[protocol.chat.v1.GetUserMetadataRequest](#getusermetadatarequest)|[protocol.chat.v1.GetUserMetadataResponse](#getusermetadataresponse)|
-|ProfileUpdate|[protocol.chat.v1.ProfileUpdateRequest](#profileupdaterequest)|[google.protobuf.Empty]({{< ref "google.protobuf.md" >}}#empty)|
-|Typing|[protocol.chat.v1.TypingRequest](#typingrequest)|[google.protobuf.Empty]({{< ref "google.protobuf.md" >}}#empty)|
-|PreviewGuild|[protocol.chat.v1.PreviewGuildRequest](#previewguildrequest)|[protocol.chat.v1.PreviewGuildResponse](#previewguildresponse)|
-|BanUser|[protocol.chat.v1.BanUserRequest](#banuserrequest)|[google.protobuf.Empty]({{< ref "google.protobuf.md" >}}#empty)|
-|KickUser|[protocol.chat.v1.KickUserRequest](#kickuserrequest)|[google.protobuf.Empty]({{< ref "google.protobuf.md" >}}#empty)|
-|UnbanUser|[protocol.chat.v1.UnbanUserRequest](#unbanuserrequest)|[google.protobuf.Empty]({{< ref "google.protobuf.md" >}}#empty)|
-
-#### Streaming Methods
-
-| Name | Client Streams | Server Streams |
-| ---- | -------------- | -------------- |
-|StreamEvents|[protocol.chat.v1.StreamEventsRequest](#streameventsrequest)|[protocol.chat.v1.Event](#event)|
diff --git a/content/docs/protocol.emote.v1.md b/content/docs/protocol.emote.v1.md
new file mode 100644
index 0000000..8f839d1
--- /dev/null
+++ b/content/docs/protocol.emote.v1.md
@@ -0,0 +1,341 @@
+---
+title: "Reference: protocol.emote.v1"
+---
+# Services
+
+## EmoteService
+
+Harmony's Emote service manages the emotes and emote packs.
+Fields
+#### CreateEmotePack
+[protocol.emote.v1.CreateEmotePackRequest](#createemotepackrequest) -> [protocol.emote.v1.CreateEmotePackResponse](#createemotepackresponse)
+
+Endpoint to create an emote pack.
+
+
+
+##### CreateEmotePackRequest
+Used in the `CreateEmotePack` endpoint.
+
+Fields
+###### pack_name
+Type: optional `string`
+
+the name of the pack.
+
+
+
+
+##### CreateEmotePackResponse
+Used in the `CreateEmotePack` endpoint.
+
+Fields
+###### pack_id
+Type: optional `uint64`
+
+The ID of the pack.
+
+------
+#### GetEmotePacks
+[protocol.emote.v1.GetEmotePacksRequest](#getemotepacksrequest) -> [protocol.emote.v1.GetEmotePacksResponse](#getemotepacksresponse)
+
+Endpoint to get the emote packs you have equipped.
+
+
+
+##### GetEmotePacksRequest
+Used in the `GetEmotePacks` endpoint.
+
+This item has no fields.
+
+
+
+
+##### GetEmotePacksResponse
+Used in the `GetEmotePacks` endpoint.
+
+Fields
+###### packs
+Type: repeated [protocol.emote.v1.EmotePack](#emotepack)
+
+The list of emote packs.
+
+------
+#### GetEmotePackEmotes
+[protocol.emote.v1.GetEmotePackEmotesRequest](#getemotepackemotesrequest) -> [protocol.emote.v1.GetEmotePackEmotesResponse](#getemotepackemotesresponse)
+
+Endpoint to get the emotes in an emote pack.
+
+
+
+##### GetEmotePackEmotesRequest
+Used in the `GetEmotes` endpoint.
+
+Fields
+###### pack_id
+Type: optional `uint64`
+
+The ID of the pack.
+
+
+
+
+##### GetEmotePackEmotesResponse
+Used in the `GetEmotes` endpoint.
+
+Fields
+###### emotes
+Type: repeated [protocol.emote.v1.Emote](#emote)
+
+The list of emotes in the pack.
+
+------
+#### AddEmoteToPack
+[protocol.emote.v1.AddEmoteToPackRequest](#addemotetopackrequest) -> [protocol.emote.v1.AddEmoteToPackResponse](#addemotetopackresponse)
+
+Endpoint to add an emote to an emote pack that you own.
+
+
+
+##### AddEmoteToPackRequest
+Used in the `AddEmoteToPack` endpoint.
+
+Fields
+###### pack_id
+Type: optional `uint64`
+
+The ID of the pack.
+###### emote
+Type: optional [protocol.emote.v1.Emote](#emote)
+
+The emote to add.
+
+
+
+
+##### AddEmoteToPackResponse
+Used in the `AddEmoteToPack` endpoint.
+
+This item has no fields.
+
+------
+#### DeleteEmotePack
+[protocol.emote.v1.DeleteEmotePackRequest](#deleteemotepackrequest) -> [protocol.emote.v1.DeleteEmotePackResponse](#deleteemotepackresponse)
+
+Endpoint to delete an emote pack that you own.
+
+
+
+##### DeleteEmotePackRequest
+Used in the `DeleteEmotePack` endpoint.
+
+Fields
+###### pack_id
+Type: optional `uint64`
+
+The ID of the pack.
+
+
+
+
+##### DeleteEmotePackResponse
+Used in the `DeleteEmotePack` endpoint.
+
+This item has no fields.
+
+------
+#### DeleteEmoteFromPack
+[protocol.emote.v1.DeleteEmoteFromPackRequest](#deleteemotefrompackrequest) -> [protocol.emote.v1.DeleteEmoteFromPackResponse](#deleteemotefrompackresponse)
+
+Endpoint to delete an emote from an emote pack.
+
+
+
+##### DeleteEmoteFromPackRequest
+Used in the `DeleteEmoteFromPack` endpoint.
+
+Fields
+###### pack_id
+Type: optional `uint64`
+
+The ID of the pack.
+###### name
+Type: optional `string`
+
+The name of the emote to delete.
+
+
+
+
+##### DeleteEmoteFromPackResponse
+Used in the `DeleteEmoteFromPack` endpoint.
+
+This item has no fields.
+
+------
+#### DequipEmotePack
+[protocol.emote.v1.DequipEmotePackRequest](#dequipemotepackrequest) -> [protocol.emote.v1.DequipEmotePackResponse](#dequipemotepackresponse)
+
+Endpoint to dequip an emote pack that you have equipped.
+
+
+
+##### DequipEmotePackRequest
+Used in the `DequipEmotePack` endpoint.
+
+Fields
+###### pack_id
+Type: optional `uint64`
+
+The ID of the pack.
+
+
+
+
+##### DequipEmotePackResponse
+Used in the `DequipEmotePack` endpoint.
+
+This item has no fields.
+
+------
+#### EquipEmotePack
+[protocol.emote.v1.EquipEmotePackRequest](#equipemotepackrequest) -> [protocol.emote.v1.EquipEmotePackResponse](#equipemotepackresponse)
+
+Endpoint to equip an emote pack.
+
+
+
+##### EquipEmotePackRequest
+Used in the `EquipEmotePack` endpoint.
+
+Fields
+###### pack_id
+Type: optional `uint64`
+
+The ID of the pack.
+
+
+
+
+##### EquipEmotePackResponse
+Used in the `EquipEmotePack` endpoint.
+
+This item has no fields.
+
+# Standalone Message Types
+
+## EmotePack
+Data for a single pack of emotes.
+
+Fields
+### pack_id
+Type: optional `uint64`
+
+The ID of the pack.
+### pack_owner
+Type: optional `uint64`
+
+The ID of the user who created the pack.
+### pack_name
+Type: optional `string`
+
+The name of the pack.
+
+------
+## Emote
+Data for a single emote.
+
+Fields
+### image_id
+Type: optional `string`
+
+The image ID of the emote. This is the ID of the image in the image store
+(same place attachments are stored).
+### name
+Type: optional `string`
+
+The name of the emote.
+
+------
+## EmotePackUpdated
+Event sent when an emote pack's information is changed.
+
+Should only be sent to users who have the pack equipped.
+
+Fields
+### pack_id
+Type: optional `uint64`
+
+ID of the pack that was updated.
+### new_pack_name
+Type: optional `string`
+
+New pack name of the pack.
+
+------
+## EmotePackDeleted
+Event sent when an emote pack is deleted.
+
+Should only be sent to users who have the pack equipped.
+Should also be sent if a user dequips an emote pack, only to the user that dequipped it.
+
+Fields
+### pack_id
+Type: optional `uint64`
+
+ID of the pack that was deleted.
+
+------
+## EmotePackAdded
+Event sent when an emote pack is added.
+
+Should only be sent to the user who equipped the pack.
+
+Fields
+### pack
+Type: optional [protocol.emote.v1.EmotePack](#emotepack)
+
+Emote pack that was equipped by the user.
+
+------
+## EmotePackEmotesUpdated
+Event sent when an emote pack's emotes were changed.
+
+Should only be sent to users who have the pack equipped.
+
+Fields
+### pack_id
+Type: optional `uint64`
+
+ID of the pack to update the emotes of.
+### added_emotes
+Type: repeated [protocol.emote.v1.Emote](#emote)
+
+The added emotes.
+### deleted_emotes
+Type: repeated `string`
+
+The names of the deleted emotes.
+
+------
+## StreamEvent
+Describes an emote service event.
+
+Fields
+### emote_pack_added
+Type: optional [protocol.emote.v1.EmotePackAdded](#emotepackadded)
+
+Send the emote pack added event.
+### emote_pack_updated
+Type: optional [protocol.emote.v1.EmotePackUpdated](#emotepackupdated)
+
+Send the emote pack updated event.
+### emote_pack_deleted
+Type: optional [protocol.emote.v1.EmotePackDeleted](#emotepackdeleted)
+
+Send the emote pack deleted event.
+### emote_pack_emotes_updated
+Type: optional [protocol.emote.v1.EmotePackEmotesUpdated](#emotepackemotesupdated)
+
+Send the emote pack emotes updated event.
+
diff --git a/content/docs/protocol.harmonytypes.v1.md b/content/docs/protocol.harmonytypes.v1.md
index 0a1f00c..d58e834 100644
--- a/content/docs/protocol.harmonytypes.v1.md
+++ b/content/docs/protocol.harmonytypes.v1.md
@@ -1,79 +1,138 @@
---
title: "Reference: protocol.harmonytypes.v1"
---
-## Message Types
+# Standalone Message Types
-### HarmonyMethodMetadata
+## HarmonyMethodMetadata
+Metadata for methods. These are set in individual RPC endpoints and are
+typically used by servers.
-Fields
+Fields
+### requires_authentication
+Type: optional `bool`
-| Name | Type |
-| ---- | ---- |
-| requires_authentication | `bool` |
-| requires_local | `bool` |
-| requires_permission_node | `string` |
+whether the method requires authentication.
+### requires_local
+Type: optional `bool`
-### Anything
+whether the method allows federation or not.
+### requires_permission_node
+Type: optional `string`
-Fields
+the permission nodes required to invoke the method.
+### requires_owner
+Type: optional `bool`
-| Name | Type |
-| ---- | ---- |
-| kind | `string` |
-| body | `bytes` |
+whether the method requires owner
-### Metadata
+------
+## Anything
+Anything holds anything
-Fields
+Fields
+### kind
+Type: optional `string`
-| Name | Type |
-| ---- | ---- |
-| kind | `string` |
-| extension | [protocol.harmonytypes.v1.Metadata.ExtensionEntry](#metadata-extensionentry) |
+Kind is the kind of the message
+### body
+Type: optional `bytes`
-### Error
+Body is the serialised bytes
-Fields
+------
+## Metadata
+Metadata type used by many messages.
-| Name | Type |
-| ---- | ---- |
-| identifier | `string` |
-| human_message | `string` |
-| more_details | `bytes` |
+Fields
+### kind
+Type: optional `string`
-### Token
+Kind of this metadata.
+### extension
+Type: repeated [protocol.harmonytypes.v1.Metadata.ExtensionEntry](#metadataextensionentry)
-Fields
+A map containing information.
-| Name | Type |
-| ---- | ---- |
-| sig | `bytes` |
-| data | `bytes` |
+------
+## Metadata.ExtensionEntry
-### Empty
-Fields
+Fields
+### key
+Type: optional `string`
-| Name | Type |
-| ---- | ---- |
-### ItemPosition
+### value
+Type: optional [protocol.harmonytypes.v1.Anything](#anything)
-Fields
-| Name | Type |
-| ---- | ---- |
-| item_id | `uint64` |
-| UNHANDLED | TYPE |
-### Metadata.ExtensionEntry
+------
+## Error
+Error type that will be returned by servers.
-Fields
+Fields
+### identifier
+Type: optional `string`
-| Name | Type |
-| ---- | ---- |
-| key | `string` |
-| value | [protocol.harmonytypes.v1.Anything](#anything) |
+The identifier of this error, can be used as an i18n key.
+### human_message
+Type: optional `string`
+
+A (usually english) human message for this error.
+### more_details
+Type: optional `bytes`
+
+More details about this message. Is dependent on the endpoint.
+
+------
+## Token
+Token that will be used for authentication.
+
+Fields
+### sig
+Type: optional `bytes`
+
+Ed25519 signature of the following serialized protobuf data, signed
+with a private key. Which private key used to sign will be described
+in the documentation.
+
+Has to be 64 bytes long, otherwise it will be rejected.
+### data
+Type: optional `bytes`
+
+Serialized protobuf data.
+The protobuf type of this serialized data is dependent on the API endpoint
+used.
+
+------
+## Empty
+An empty message
+
+This item has no fields.
+
+------
+## ItemPosition
+An object representing an item position between two other items.
+
+Fields
+### item_id
+Type: optional `uint64`
+
+The ID of the item the position is relative to
+### position
+Type: UNHANDLED | TYPE
+
+Whether the position is before or after the given ID
+
+# Enums
+
+## Position
+
+
+### POSITION_BEFORE_UNSPECIFIED
+
+
+### POSITION_AFTER
-## Services
diff --git a/content/docs/protocol.mediaproxy.v1.md b/content/docs/protocol.mediaproxy.v1.md
index 614b716..d043924 100644
--- a/content/docs/protocol.mediaproxy.v1.md
+++ b/content/docs/protocol.mediaproxy.v1.md
@@ -1,94 +1,161 @@
---
title: "Reference: protocol.mediaproxy.v1"
---
-## Message Types
+# Services
-### SiteMetadata
+## MediaProxyService
-Fields
+Harmony service for fetching metadata and generating instant view for URLs.
+Fields
+#### FetchLinkMetadata
+[protocol.mediaproxy.v1.FetchLinkMetadataRequest](#fetchlinkmetadatarequest) -> [protocol.mediaproxy.v1.FetchLinkMetadataResponse](#fetchlinkmetadataresponse)
-| Name | Type |
-| ---- | ---- |
-| site_title | `string` |
-| page_title | `string` |
-| kind | `string` |
-| description | `string` |
-| url | `string` |
-| image | `string` |
+Endpoint to fetch metadata for a URL.
-### MediaMetadata
+
-Fields
+##### FetchLinkMetadataRequest
+Used in the `FetchLinkMetadata` endpoint.
-| Name | Type |
-| ---- | ---- |
-| mimetype | `string` |
-| filename | `string` |
+Fields
+###### url
+Type: optional `string`
-### FetchLinkMetadataRequest
+URL to fetch metadata from.
-Fields
-| Name | Type |
-| ---- | ---- |
-| url | `string` |
+
-### FetchLinkMetadataResponse
+##### FetchLinkMetadataResponse
+Used in the `FetchLinkMetadata` endpoint.
-Fields
+Fields
+###### is_site
+Type: optional [protocol.mediaproxy.v1.SiteMetadata](#sitemetadata)
-| Name | Type |
-| ---- | ---- |
-| is_site | [protocol.mediaproxy.v1.SiteMetadata](#sitemetadata) |
-| is_media | [protocol.mediaproxy.v1.MediaMetadata](#mediametadata) |
+Site metadata for the URL.
+###### is_media
+Type: optional [protocol.mediaproxy.v1.MediaMetadata](#mediametadata)
-### InstantViewRequest
+Media metadata for the URL.
-Fields
+------
+#### InstantView
+[protocol.mediaproxy.v1.InstantViewRequest](#instantviewrequest) -> [protocol.mediaproxy.v1.InstantViewResponse](#instantviewresponse)
-| Name | Type |
-| ---- | ---- |
-| url | `string` |
+Endpoint to instant view a website URL.
-### InstantViewResponse
+
-Fields
+##### InstantViewRequest
+Used in the `InstantView` endpoint.
-| Name | Type |
-| ---- | ---- |
-| metadata | [protocol.mediaproxy.v1.SiteMetadata](#sitemetadata) |
-| content | `string` |
-| is_valid | `bool` |
+Fields
+###### url
+Type: optional `string`
-### CanInstantViewRequest
+URL to get instant view for.
-Fields
-| Name | Type |
-| ---- | ---- |
-| url | `string` |
+
-### CanInstantViewResponse
+##### InstantViewResponse
+Used in the `InstantView` endpoint.
-Fields
+Fields
+###### metadata
+Type: optional [protocol.mediaproxy.v1.SiteMetadata](#sitemetadata)
-| Name | Type |
-| ---- | ---- |
-| can_instant_view | `bool` |
+Site metadata for the URL.
+###### content
+Type: optional `string`
-## Services
+Instant view content.
+###### is_valid
+Type: optional `bool`
-### MediaProxyService
+Whether the instant view is valid.
-#### Unary Methods
+------
+#### CanInstantView
+[protocol.mediaproxy.v1.CanInstantViewRequest](#caninstantviewrequest) -> [protocol.mediaproxy.v1.CanInstantViewResponse](#caninstantviewresponse)
-| Name | Request | Response |
-| ---- | ------- | -------- |
-|FetchLinkMetadata|[protocol.mediaproxy.v1.FetchLinkMetadataRequest](#fetchlinkmetadatarequest)|[protocol.mediaproxy.v1.FetchLinkMetadataResponse](#fetchlinkmetadataresponse)|
-|InstantView|[protocol.mediaproxy.v1.InstantViewRequest](#instantviewrequest)|[protocol.mediaproxy.v1.InstantViewResponse](#instantviewresponse)|
-|CanInstantView|[protocol.mediaproxy.v1.CanInstantViewRequest](#caninstantviewrequest)|[protocol.mediaproxy.v1.CanInstantViewResponse](#caninstantviewresponse)|
+Endpoint to query if the server can generate an instant view for a website URL.
-#### Streaming Methods
+
-| Name | Client Streams | Server Streams |
-| ---- | -------------- | -------------- |
+##### CanInstantViewRequest
+Used in the `CanInstantView` endpoint.
+
+Fields
+###### url
+Type: optional `string`
+
+URL to query if server can instant view the website.
+
+
+
+
+##### CanInstantViewResponse
+Used in the `CanInstantView` endpoint.
+
+Fields
+###### can_instant_view
+Type: optional `bool`
+
+Whether the server generate an instant view for the URL queried.
+
+# Standalone Message Types
+
+## SiteMetadata
+Object representing the metadata of a website.
+
+Fields
+### site_title
+Type: optional `string`
+
+Title of the website.
+### page_title
+Type: optional `string`
+
+Page title of the website page.
+### kind
+Type: optional `string`
+
+Kind of the website.
+### description
+Type: optional `string`
+
+Description of the website page.
+### url
+Type: optional `string`
+
+URL of the website.
+### image
+Type: optional `string`
+
+A thumbnail image of the website.
+
+------
+## MediaMetadata
+Object represeting the metadata of a media.
+
+Fields
+### mimetype
+Type: optional `string`
+
+Mimetype of the media.
+### filename
+Type: optional `string`
+
+Filename of the media.
+### size
+Type: optional `uint32`
+
+Sıze of the media.
+
+This should (usually) be the size taken from the `Content-Length` header
+(for HTTP requests).
+If this is not included, then it means the size could not be determined.
+
+------
diff --git a/content/docs/protocol.profile.v1.md b/content/docs/protocol.profile.v1.md
new file mode 100644
index 0000000..90767b6
--- /dev/null
+++ b/content/docs/protocol.profile.v1.md
@@ -0,0 +1,299 @@
+---
+title: "Reference: protocol.profile.v1"
+---
+# Services
+
+## ProfileService
+
+Harmony's Profile service manages the profiles of the users.
+Fields
+#### GetProfile
+[protocol.profile.v1.GetProfileRequest](#getprofilerequest) -> [protocol.profile.v1.GetProfileResponse](#getprofileresponse)
+
+Gets a user's profile.
+
+
+
+##### GetProfileRequest
+Used in `GetProfile` endpoint.
+
+Fields
+###### user_id
+Type: optional `uint64`
+
+The id of the user to get.
+
+
+
+
+##### GetProfileResponse
+Used in `GetProfile` endpoint.
+
+Fields
+###### profile
+Type: optional [protocol.profile.v1.Profile](#profile)
+
+The user's profile
+
+------
+#### UpdateProfile
+[protocol.profile.v1.UpdateProfileRequest](#updateprofilerequest) -> [protocol.profile.v1.UpdateProfileResponse](#updateprofileresponse)
+
+Updates the user's profile.
+
+
+
+##### UpdateProfileRequest
+Used in `UpdateProfile` endpoint.
+
+Fields
+###### new_user_name
+Type: optional `string`
+
+new name of the user.
+###### new_user_avatar
+Type: optional `string`
+
+new user avatar. The avatar will be removed if the string is empty.
+###### new_user_status
+Type: UNHANDLED | TYPE
+
+new status of the user.
+###### new_is_bot
+Type: optional `bool`
+
+new whether the user is a bot or not
+
+Deprecated; see bot service and guest handling
+in auth.
+
+
+
+
+##### UpdateProfileResponse
+Used in `UpdateProfile` endpoint.
+
+This item has no fields.
+
+------
+#### GetAppData
+[protocol.profile.v1.GetAppDataRequest](#getappdatarequest) -> [protocol.profile.v1.GetAppDataResponse](#getappdataresponse)
+
+Gets app data for a user (this can be used to store user preferences which
+is synchronized across devices).
+
+
+
+##### GetAppDataRequest
+Used in `GetAppData` endpoint.
+
+Fields
+###### app_id
+Type: optional `string`
+
+the app id.
+
+
+
+
+##### GetAppDataResponse
+Used in `GetAppData` endpoint.
+
+Fields
+###### app_data
+Type: optional `bytes`
+
+the app data.
+
+------
+#### SetAppData
+[protocol.profile.v1.SetAppDataRequest](#setappdatarequest) -> [protocol.profile.v1.SetAppDataResponse](#setappdataresponse)
+
+Sets the app data for a user.
+
+
+
+##### SetAppDataRequest
+Used in `SetAppData` endpoint.
+
+Fields
+###### app_id
+Type: optional `string`
+
+the app id.
+###### app_data
+Type: optional `bytes`
+
+the app data.
+
+
+
+
+##### SetAppDataResponse
+Used in `SetAppData` endpoint.
+
+This item has no fields.
+
+# Standalone Message Types
+
+## OverrideTag
+A tag for an override. This is used as a
+standard shorthand for sending a message with
+an override. If a message starts with before and
+ends with after, clients should send a message
+with the override the tag belongs to, stripping
+the tag indicators.
+
+Fields
+### before
+Type: optional `string`
+
+The portion of the tag before the messge.
+### after
+Type: optional `string`
+
+The portion of the tag after the messge.
+
+------
+## ProfileOverride
+An individual override
+
+Fields
+### username
+Type: optional `string`
+
+The username for this override
+### avatar
+Type: optional `string`
+
+The avatar for this override
+### tags
+Type: repeated [protocol.profile.v1.OverrideTag](#overridetag)
+
+The tags for this override.
+### user_defined
+Type: optional `string`
+
+a custom reason in case the builtin ones don't fit
+### system_plurality
+Type: optional [protocol.harmonytypes.v1.Empty]({{< ref "protocol.harmonytypes.v1.md" >}}#empty)
+
+plurality, not system as in computer
+
+------
+## AppDataOverrides
+The message used for the 'h.overrides' key
+of appdata.
+
+Fields
+### overrides
+Type: repeated [protocol.profile.v1.ProfileOverride](#profileoverride)
+
+The list of overrides.
+
+------
+## Profile
+Data for a single profile, without the user's ID.
+
+Fields
+### user_name
+Type: optional `string`
+
+the name of the user.
+### user_avatar
+Type: optional `string`
+
+the user's avatar.
+### user_status
+Type: UNHANDLED | TYPE
+
+the status of the user.
+### is_bot
+Type: optional `bool`
+
+whether the user is a bot or not
+### account_kind
+Type: UNHANDLED | TYPE
+
+what kind of account the user is, e.g. full, guest, bot
+
+------
+## ProfileUpdated
+Event sent when a user's profile is updated.
+
+Servers should sent this event only to users that can "see" (eg. they are
+in the same guild) the user this event was triggered by.
+
+Fields
+### user_id
+Type: optional `uint64`
+
+User ID of the user that had it's profile updated.
+### new_username
+Type: optional `string`
+
+New username for this user.
+### new_avatar
+Type: optional `string`
+
+New avatar for this user.
+### new_status
+Type: UNHANDLED | TYPE
+
+New status for this user.
+### new_is_bot
+Type: optional `bool`
+
+New is bot or not for this user.
+Deprecated, prefer new_account_kind if set.
+### new_account_kind
+Type: UNHANDLED | TYPE
+
+The new account kind for this account
+
+------
+## StreamEvent
+Describes an emote service event.
+
+Fields
+### profile_updated
+Type: optional [protocol.profile.v1.ProfileUpdated](#profileupdated)
+
+Send the profile updated event.
+
+# Enums
+
+## UserStatus
+
+The possible statuses a user can have.
+### USER_STATUS_OFFLINE_UNSPECIFIED
+User is offline (not connected to the server).
+
+### USER_STATUS_ONLINE
+User is online (this is the default value if ommitted).
+
+### USER_STATUS_IDLE
+User is away.
+
+### USER_STATUS_DO_NOT_DISTURB
+User does not want to be disturbed.
+
+### USER_STATUS_MOBILE
+User is on mobile.
+
+### USER_STATUS_STREAMING
+User is streaming
+
+------
+## AccountKind
+
+The possible kinds of an account
+### ACCOUNT_KIND_FULL_UNSPECIFIED
+The account is a full-fledged account controlled by a human
+
+### ACCOUNT_KIND_BOT
+The account is an account controlled by a bot
+
+### ACCOUNT_KIND_GUEST
+The account is a guest account controlled by a human
+
diff --git a/content/docs/protocol.sync.v1.md b/content/docs/protocol.sync.v1.md
index f3c0ec3..c3a5232 100644
--- a/content/docs/protocol.sync.v1.md
+++ b/content/docs/protocol.sync.v1.md
@@ -1,102 +1,231 @@
---
title: "Reference: protocol.sync.v1"
---
-## Message Types
+# Services
-### AuthData
+## PostboxService
-Fields
+# Postbox
-| Name | Type |
-| ---- | ---- |
-| server_id | `string` |
-| time | `uint64` |
+The postbox service forms the core of Harmony's server <-> server communications.
-### Event
+It concerns the transfer of Events between servers, as well as ensuring reliable
+delivery of them.
-Fields
+The semantics of events are documented in the event types. The postbox service
+is solely reliable for reliable pushing and pulling.
-| Name | Type |
-| ---- | ---- |
-| user_removed_from_guild | [protocol.sync.v1.Event.UserRemovedFromGuild](#event-userremovedfromguild) |
-| user_added_to_guild | [protocol.sync.v1.Event.UserAddedToGuild](#event-useraddedtoguild) |
+## Server Identification
-### PullRequest
+Servers are identified using their domain, and the port which they serve. This is
+called the "server ID", and must be formatted as `domain:port`. The port is NOT
+optional. Converting this ID to a URL for communicating can simply be done via
+prefixing the ID with a protocol, eg. `https://`.
-Fields
+## Authorisation
-| Name | Type |
-| ---- | ---- |
+Requests are authorised using a serialized `harmonytypes.v1.Token` in the Authorization HTTP header.
+The `data` field of the token will be a serialized `AuthData` message.
+The private key used to sign is the homeserver's private key.
-### PullResponse
+## Events
-Fields
+In this section, we will use sender and recipient to refer to the servers
+sending the events and the server receiving the events respectively.
-| Name | Type |
-| ---- | ---- |
-| event_queue | [protocol.sync.v1.Event](#event) |
+At PostboxService startup, a sender should first Pull all receivers it had
+federated from before. If a receiver makes a Push to the sender while a Pull
+is going on, the Push should be processed after the Pull is completed.
-### PushRequest
+The sender will attempt to Push to the receiver. If the Push RPC fails more
+than X times (a recommended retry count is 5), the event will be dispatched
+to the sender's queue for the receiver. Unless the receiver pulls these events,
+all new events should be dispatched to the queue. No new Push RPC should be made
+before the queue is emptied. This ensures that events are always received in the
+right order.
-Fields
+It is recommended that receivers try pulling periodically, for example, every
+1 minute after the last Push RPC by the sender. This ensures that events are recieved.
+Fields
+#### Pull
+[protocol.sync.v1.PullRequest](#pullrequest) -> [protocol.sync.v1.PullResponse](#pullresponse)
-| Name | Type |
-| ---- | ---- |
-| event | [protocol.sync.v1.Event](#event) |
+Endpoint to pull events.
-### PushResponse
+
-Fields
+##### PullRequest
+Used in `Pull` endpoint.
-| Name | Type |
-| ---- | ---- |
+This item has no fields.
-### NotifyNewIdRequest
-Fields
+
-| Name | Type |
-| ---- | ---- |
-| new_server_id | `string` |
+##### PullResponse
+Used in `Pull` endpoint.
-### NotifyNewIdResponse
+Fields
+###### event_queue
+Type: repeated [protocol.sync.v1.Event](#event)
-Fields
+The events that were not processed yet.
-| Name | Type |
-| ---- | ---- |
+------
+#### Push
+[protocol.sync.v1.PushRequest](#pushrequest) -> [protocol.sync.v1.PushResponse](#pushresponse)
-### Event.UserRemovedFromGuild
+Endpoint to push events.
-Fields
+
-| Name | Type |
-| ---- | ---- |
-| user_id | `uint64` |
-| guild_id | `uint64` |
+##### PushRequest
+Used in `Push` endpoint.
-### Event.UserAddedToGuild
+Fields
+###### event
+Type: optional [protocol.sync.v1.Event](#event)
-Fields
+The event to push to the server.
-| Name | Type |
-| ---- | ---- |
-| user_id | `uint64` |
-| guild_id | `uint64` |
-## Services
+
-### PostboxService
+##### PushResponse
+Used in `Push` endpoint.
-#### Unary Methods
+This item has no fields.
-| Name | Request | Response |
-| ---- | ------- | -------- |
-|Pull|[protocol.sync.v1.PullRequest](#pullrequest)|[protocol.sync.v1.PullResponse](#pullresponse)|
-|Push|[protocol.sync.v1.PushRequest](#pushrequest)|[protocol.sync.v1.PushResponse](#pushresponse)|
-|NotifyNewId|[protocol.sync.v1.NotifyNewIdRequest](#notifynewidrequest)|[protocol.sync.v1.NotifyNewIdResponse](#notifynewidresponse)|
+------
+#### NotifyNewId
+[protocol.sync.v1.NotifyNewIdRequest](#notifynewidrequest) -> [protocol.sync.v1.NotifyNewIdResponse](#notifynewidresponse)
-#### Streaming Methods
+Endpoint to notify a server of a server ID change. It is called by the server
+that had it's server ID changed for all servers it has federated with.
-| Name | Client Streams | Server Streams |
-| ---- | -------------- | -------------- |
+
+
+##### NotifyNewIdRequest
+Used in `NotifyNewId` endpoint.
+
+Fields
+###### new_server_id
+Type: optional `string`
+
+The new server ID of the server.
+
+
+
+
+##### NotifyNewIdResponse
+Used in `NotifyNewId` endpoint.
+
+This item has no fields.
+
+# Standalone Message Types
+
+## AuthData
+Authentication data that will be sent in a `harmonytypes.v1.Token`.
+
+Fields
+### server_id
+Type: optional `string`
+
+The server ID of the server initiating the transaction. For Pull,
+this tells the server being connected to which homeservers' events it should send.
+For Push, this tells the server being connected to which homeservers' events it is
+receiving.
+### time
+Type: optional `uint64`
+
+The UTC UNIX time in seconds of when the request is started. Servers should reject
+tokens with a time too far from the current time, at their discretion. A recommended
+variance is 1 minute.
+
+------
+## Event
+Object representing a postbox event.
+
+Fields
+### user_removed_from_guild
+Type: optional [protocol.sync.v1.Event.UserRemovedFromGuild](#eventuserremovedfromguild)
+
+User removed from a guild.
+### user_added_to_guild
+Type: optional [protocol.sync.v1.Event.UserAddedToGuild](#eventuseraddedtoguild)
+
+User added to a guild.
+### user_invited
+Type: optional [protocol.sync.v1.Event.UserInvited](#eventuserinvited)
+
+User invited to a guild.
+### user_rejected_invite
+Type: optional [protocol.sync.v1.Event.UserRejectedInvite](#eventuserrejectedinvite)
+
+User rejected a guild invitation.
+
+------
+## Event.UserRemovedFromGuild
+
+
+Fields
+### user_id
+Type: optional `uint64`
+
+
+### guild_id
+Type: optional `uint64`
+
+
+
+------
+## Event.UserAddedToGuild
+
+
+Fields
+### user_id
+Type: optional `uint64`
+
+
+### guild_id
+Type: optional `uint64`
+
+
+
+------
+## Event.UserInvited
+
+
+Fields
+### user_id
+Type: optional `uint64`
+
+
+### inviter_id
+Type: optional `uint64`
+
+
+### invite_id
+Type: optional `string`
+
+
+
+------
+## Event.UserRejectedInvite
+
+
+Fields
+### guild_id
+Type: optional `uint64`
+
+
+### user_id
+Type: optional `uint64`
+
+
+### invite_id
+Type: optional `string`
+
+
+
+------
diff --git a/content/docs/protocol.voice.v1.md b/content/docs/protocol.voice.v1.md
index d7e5ccb..f1af82f 100644
--- a/content/docs/protocol.voice.v1.md
+++ b/content/docs/protocol.voice.v1.md
@@ -1,63 +1,262 @@
---
title: "Reference: protocol.voice.v1"
---
-## Message Types
+# Services
-### Signal
+## VoiceService
-Fields
+Harmony service for facilitating voice operations using WebRTC.
-| Name | Type |
-| ---- | ---- |
-| ice_candidate | `string` |
-| renegotiation_needed | [protocol.harmonytypes.v1.Empty]({{< ref "protocol.harmonytypes.v1.md" >}}#empty) |
+# Usage (for client)
-### ConnectRequest
+0. Call StreamMessage to be able to send RTC commands to server
+1. Send Initialize over stream with guild_id and channel_id of the request set to the channel you want to join
+2. Init device by using the RTP capabilities sent in the response message, which should be Initialized
+3. Send PrepareForJoinChannel over stream with client rtp capabilities
+4. Wait for PreparedForJoinChannel, which contains transport options
+5. Connect both transports using the transport options on client
+6. Send JoinChannel over stream containing RTP paramaters for your Audio track
+and DTLS paramaters for both consumer and producer
+7. Wait for JoinedChannel, which confirms you have successfully joined the voice channel;
+handle other_users which will be described in 8 (UserJoined handling)
+8. Handle UserJoined and UserLeft events appropiately
+ - For UserJoined; use the received consumer ID, producer ID and RTP parameters on your
+ consumer transport to consume the producer, afterwards send ResumeConsumer message
+ with the consumer ID, then if that's successful add the track to a `user ID -> Track` map
+ - For UserLeft, remove the user track from the `user ID -> Track` map
-Fields
+## How this looks for servers
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
-| channel_id | `uint64` |
-| offer | `string` |
+0. Receives StreamMessage, starts the socket
+1. Waits for Initialize
+2. Sends Initialized over stream with it's RTP capabilities
+3. Receives PrepareForJoinChannel with client RTP capabilities
+4. Sends PreparedForJoinChannel over stream with consumer and producer transport options
+5. Receives JoinChannel, checks for DTLS parameters for consumer and producer transports
+and uses the RTP paramaters to create a producer for the client
+6. Sends JoinedChannel over stream with the created producer ID and all other users' data (UserData)
+7. When another user does 1 to 7, sends UserJoined over stream to all other users;
+when a user leaves the channel (when their stream ends), sends UserLeft to all other users
+8. When receiving a ResumeConsumer message, unpauses the consumer corresponding to the consumer ID
+Fields
+#### StreamMessage
+streaming [protocol.voice.v1.StreamMessageRequest](#streammessagerequest) -> streaming [protocol.voice.v1.StreamMessageResponse](#streammessageresponse)
-### ConnectResponse
+Endpoint to stream messages between client and server.
-Fields
+- One StreamMessage stream corresponds to being in one voice channel.
+- It's recommended that users should not be able to be in more than one voice channel,
+but this limitation is left up to the server implementation.
+# Standalone Message Types
-| Name | Type |
-| ---- | ---- |
-| answer | `string` |
+## UserConsumerOptions
+Data containing all the necessary information to
+create a consumer for a user in a voice channel
-### StreamStateRequest
+This corresponds to https://mediasoup.org/documentation/v3/mediasoup-client/api/#ConsumerOptions on client:
+- `consumer_id` -> `id`
+- `producer_id` -> `producerId`
+- `rtp_parameters` -> `rtpParameters`
+- and `kind` should be set to "audio".
-Fields
+Fields
+### user_id
+Type: optional `uint64`
-| Name | Type |
-| ---- | ---- |
-| guild_id | `uint64` |
-| channel_id | `uint64` |
+User ID of the user.
+### producer_id
+Type: optional `string`
-### StreamStateResponse
+Producer ID of the producer being consumed.
+### consumer_id
+Type: optional `string`
-Fields
+Consumer ID for the user's producer consumer.
+### rtp_parameters
+Type: optional `string`
-| Name | Type |
-| ---- | ---- |
-| signal | [protocol.voice.v1.Signal](#signal) |
+RTP paramaters for the user's audio track. Corresponds to `RtpParameters` in mediasoup's TypeScript API.
-## Services
+------
+## TransportOptions
+Object containing all the necessary information about transport options required
+from the server to establish transport connection on the client
-### VoiceService
+This corresponds to https://mediasoup.org/documentation/v3/mediasoup-client/api/#TransportOptions on client:
+- `id` -> `id`
+- `ice_parameters` -> `iceParameters`
+- `dtls_parameters` -> `dtlsParameters`
+- `ice_candidates` -> `iceCandidates`
-#### Unary Methods
+Fields
+### id
+Type: optional `string`
+
+The transport ID.
+### dtls_parameters
+Type: optional `string`
+
+DTLS paramaters in JSON. Corresponds to `DtlsParameters` in mediasoup's TypeScript API.
+### ice_candidates
+Type: repeated `string`
+
+ICE candidates in JSON. Corresponds to `IceCandidate` in mediasoup's TypeScript API.
+### ice_parameters
+Type: optional `string`
+
+ICE paramaters in JSON. Corresponds to `IceParameters` in mediasoup's TypeScript API.
+
+------
+## StreamMessageRequest
+Used in `StreamMessage` endpoint.
+
+Fields
+### initialize
+Type: optional [protocol.voice.v1.StreamMessageRequest.Initialize](#streammessagerequestinitialize)
+
+Sent to initialize the WS and receive necessary information
+### prepare_for_join_channel
+Type: optional [protocol.voice.v1.StreamMessageRequest.PrepareForJoinChannel](#streammessagerequestprepareforjoinchannel)
+
+Sent to prepare for joining channel
+### join_channel
+Type: optional [protocol.voice.v1.StreamMessageRequest.JoinChannel](#streammessagerequestjoinchannel)
+
+Sent to join a channel
+### resume_consumer
+Type: optional [protocol.voice.v1.StreamMessageRequest.ResumeConsumer](#streammessagerequestresumeconsumer)
+
+Sent to resume a consumer
+
+------
+## StreamMessageRequest.Initialize
+
+
+Fields
+### guild_id
+Type: optional `uint64`
+
+
+### channel_id
+Type: optional `uint64`
+
+
+
+------
+## StreamMessageRequest.PrepareForJoinChannel
+
+
+Fields
+### rtp_capabilities
+Type: optional `string`
+
+
+
+------
+## StreamMessageRequest.JoinChannel
+
+
+Fields
+### rtp_paramaters
+Type: optional `string`
+
+
+### producer_dtls_paramaters
+Type: optional `string`
+
+
+### consumer_dtls_paramaters
+Type: optional `string`
+
+
+
+------
+## StreamMessageRequest.ResumeConsumer
+
+
+Fields
+### consumer_id
+Type: optional `string`
+
+
+
+------
+## StreamMessageResponse
+Used in `StreamMessage` endpoint.
+
+Fields
+### initialized
+Type: optional [protocol.voice.v1.StreamMessageResponse.Initialized](#streammessageresponseinitialized)
+
+Sent when connection is started
+### prepared_for_join_channel
+Type: optional [protocol.voice.v1.StreamMessageResponse.PreparedForJoinChannel](#streammessageresponsepreparedforjoinchannel)
+
+Sent when preparing to join a channel is successful
+### joined_channel
+Type: optional [protocol.voice.v1.StreamMessageResponse.JoinedChannel](#streammessageresponsejoinedchannel)
+
+Sent when joining a channel is successful
+### user_joined
+Type: optional [protocol.voice.v1.StreamMessageResponse.UserJoined](#streammessageresponseuserjoined)
+
+Sent when another user joins the channel
+### user_left
+Type: optional [protocol.voice.v1.StreamMessageResponse.UserLeft](#streammessageresponseuserleft)
+
+Sent when another user leaves the channel
+
+------
+## StreamMessageResponse.Initialized
+
+
+Fields
+### rtp_capabilities
+Type: optional `string`
+
+
+
+------
+## StreamMessageResponse.PreparedForJoinChannel
+
+
+Fields
+### consumer_transport_options
+Type: optional [protocol.voice.v1.TransportOptions](#transportoptions)
+
+
+### producer_transport_options
+Type: optional [protocol.voice.v1.TransportOptions](#transportoptions)
+
+
+
+------
+## StreamMessageResponse.JoinedChannel
+
+
+Fields
+### other_users
+Type: repeated [protocol.voice.v1.UserConsumerOptions](#userconsumeroptions)
+
+
+
+------
+## StreamMessageResponse.UserJoined
+
+
+Fields
+### data
+Type: optional [protocol.voice.v1.UserConsumerOptions](#userconsumeroptions)
+
+
+
+------
+## StreamMessageResponse.UserLeft
+
+
+Fields
+### user_id
+Type: optional `uint64`
-| Name | Request | Response |
-| ---- | ------- | -------- |
-|Connect|[protocol.voice.v1.ConnectRequest](#connectrequest)|[protocol.voice.v1.ConnectResponse](#connectresponse)|
-#### Streaming Methods
-| Name | Client Streams | Server Streams |
-| ---- | -------------- | -------------- |
diff --git a/content/docs/rest.md b/content/docs/rest.md
new file mode 120000
index 0000000..37e7a2e
--- /dev/null
+++ b/content/docs/rest.md
@@ -0,0 +1 @@
+../protocol/stable/rest/rest.md
\ No newline at end of file
diff --git a/content/gendocs.sh b/content/gendocs.sh
deleted file mode 100755
index 388b0c1..0000000
--- a/content/gendocs.sh
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/usr/bin/env bash
-mkdir -p "docs"
-
-for dir in $(find "protocol" -name '*.proto' -print0 | xargs -0 -n1 dirname | sort | uniq); do
- echo "Generating files in ${dir}..."
- find "${dir}" -name '*.proto'
-
- protoc \
- --proto_path=protocol \
- --hdocs_out=./docs \
- --hdocs_opt=markdown,reference.md \
- $(find "${dir}" -name '*.proto')
-
-done
diff --git a/content/projects/_index.md b/content/projects/_index.md
new file mode 100644
index 0000000..b3152a5
--- /dev/null
+++ b/content/projects/_index.md
@@ -0,0 +1,3 @@
+---
+title: "Projects"
+---
\ No newline at end of file
diff --git a/content/protocol b/content/protocol
index 819b217..2aef2cc 160000
--- a/content/protocol
+++ b/content/protocol
@@ -1 +1 @@
-Subproject commit 819b217cb5e9d41af607c3296905917a82361970
+Subproject commit 2aef2cca047c6f3db76af543b06133ee4bd15028
diff --git a/data/bots b/data/bots
new file mode 120000
index 0000000..d213f8c
--- /dev/null
+++ b/data/bots
@@ -0,0 +1 @@
+../projects-listing/bots/
\ No newline at end of file
diff --git a/data/bridges b/data/bridges
new file mode 120000
index 0000000..29a280f
--- /dev/null
+++ b/data/bridges
@@ -0,0 +1 @@
+../projects-listing/bridges/
\ No newline at end of file
diff --git a/data/clients b/data/clients
new file mode 120000
index 0000000..4981c29
--- /dev/null
+++ b/data/clients
@@ -0,0 +1 @@
+../projects-listing/clients/
\ No newline at end of file
diff --git a/data/libraries b/data/libraries
new file mode 120000
index 0000000..04cebb5
--- /dev/null
+++ b/data/libraries
@@ -0,0 +1 @@
+../projects-listing/libraries/
\ No newline at end of file
diff --git a/data/servers b/data/servers
new file mode 120000
index 0000000..33d8120
--- /dev/null
+++ b/data/servers
@@ -0,0 +1 @@
+../projects-listing/servers/
\ No newline at end of file
diff --git a/layouts/_default/list.html b/layouts/_default/list.html
index cc4f8ea..31d59ac 100644
--- a/layouts/_default/list.html
+++ b/layouts/_default/list.html
@@ -1,17 +1,19 @@
{{ define "main" }}
-{{ end }}
\ No newline at end of file
+{{ end }}
diff --git a/layouts/_default/single.html b/layouts/_default/single.html
index 33decc6..d0796a5 100644
--- a/layouts/_default/single.html
+++ b/layouts/_default/single.html
@@ -1,14 +1,16 @@
{{ define "main" }}
-
-
+
+
+
-
{{ .Title }}
- {{ .Content }}
+
{{ .Title }}
+ {{ .Content }}
+
-{{ end }}
\ No newline at end of file
+{{ end }}
diff --git a/layouts/partials/footer.html b/layouts/partials/footer.html
index c6bfe1f..7b21045 100644
--- a/layouts/partials/footer.html
+++ b/layouts/partials/footer.html
@@ -1,3 +1,3 @@
-
\ No newline at end of file
+
diff --git a/layouts/partials/head.html b/layouts/partials/head.html
index 95b4caf..92ff575 100644
--- a/layouts/partials/head.html
+++ b/layouts/partials/head.html
@@ -5,6 +5,8 @@
+
+
{{ $styles := resources.Get "css/main.css" | postCSS }}
{{ if .Site.IsServer }}
diff --git a/layouts/partials/header.html b/layouts/partials/header.html
index 167dc36..d256e88 100644
--- a/layouts/partials/header.html
+++ b/layouts/partials/header.html
@@ -1,16 +1,30 @@
-
+ This is a collection of user-submitted projects that use Harmony. A project being in that list does not mean that it is "official", but we don't
+ like to make that distinction anyways.
+
+
+
+ You can submit new projects on our GitHub repo.
+
+
+
Clients
+
+ {{ range $.Site.Data.clients }}
+ {{ template "item" . }}
+ {{ end }}
+
+
Servers
+
+ {{ range $.Site.Data.servers }}
+ {{ template "item" . }}
+ {{ end }}
+
+
Bots
+
+ {{ range $.Site.Data.bots }}
+ {{ template "item" . }}
+ {{ end }}
+
+
Bridges
+
+ {{ range $.Site.Data.bridges }}
+ {{ template "item" . }}
+ {{ end }}
+
+
Libraries
+
+ {{ range $.Site.Data.libraries }}
+ {{ template "item" . }}
+ {{ end }}
+
+
+
+
+{{ end }}
\ No newline at end of file
diff --git a/layouts/shortcodes/index/button.html b/layouts/shortcodes/index/button.html
index a7a78bd..42fdc5b 100644
--- a/layouts/shortcodes/index/button.html
+++ b/layouts/shortcodes/index/button.html
@@ -1,4 +1 @@
-
-
- An open protocol for open, harmonious communication.
+
+ An open protocol for open, harmonious communication.
- Harmony facilitates easy, simple communication between people regardless of who or where they are.
+ Harmony facilitates easy, simple communication between people regardless
+ of who or where they are.