diff --git a/docs/10-Caveats.md b/docs/10-Caveats.md
index 7c8fbd9b..eeb493dc 100644
--- a/docs/10-Caveats.md
+++ b/docs/10-Caveats.md
@@ -14,4 +14,4 @@ To get rid of it, consider to disable it either globally via `bsconfig.json` or
---
-Next: **[API →](./10-API.md)**
+Next: **[API →](./11-API.md)**
diff --git a/docs/11-API.md b/docs/11-API.md
index 59327929..c8ec9736 100644
--- a/docs/11-API.md
+++ b/docs/11-API.md
@@ -1 +1,269 @@
# API
+
+- [Configuration](#configuration)
+ - [`type input`](#type-input)
+ - [`[@field.async]`](#fieldasync)
+ - [`[@field.collection]`](#fieldcollection)
+ - [`[@field.deps]`](#fielddeps)
+ - [`type output`](#type-output)
+ - [`type message`](#type-message)
+ - [`type submissionError`](#type-submissionerror)
+ - [`let debounceInterval`](#let-debounceinterval)
+ - [`let validators`](#let-validators)
+- [Rendering](#rendering)
+ - [`useForm`](#useform)
+ - [`submissionCallbacks`](#submissioncallbacks)
+ - [`interface`](#interface)
+ - general field handlers
+ - async field handlers
+ - field of collection handlers
+ - collection handlers
+ - `input`
+ - `status`
+ - `submitting`
+ - `dirty`
+ - `submit`
+ - `dismissSubmissionError`
+ - `dismissSubmissionResult`
+ - `mapSubmissionError`
+ - `reset`
+ - `valid`
+
+## Configuration
+Form configuration module can be created using `[%form]` extension:
+
+```reason
+module MyForm = [%form
+ type input;
+ type output;
+ ...
+];
+```
+
+### `type input`
+**Requirements:** Required. Must be a record.
+
+Form input data.
+
+```reason
+type input = {email: string};
+```
+
+See **[IO](./03-IO.md)** & **[Basic Usage](./04-BasicUsage.md)**.
+
+#### `input` field attributes
+##### `[@field.async]`
+**Requirements:** Optional.
+
+Attribute for a field with async validation.
+
+```reason
+type input = {email: [@field.async] string};
+
+// OnChange mode
+// Default, use it if you want to be explicit.
+type input = {email: [@field.async {mode: OnChange}] string};
+
+// OnBlur mode
+type input = {email: [@field.async {mode: OnBlur}] string};
+```
+
+See **[Async Validation](./05-AsyncValidation.md)**.
+
+##### `[@field.collection]`
+**Requirements:** Optional. If provided, must be an array.
+
+Attribute for a collection field.
+
+```reason
+type input = {
+ authors: [@field.collection] array(author),
+}
+and author = {name: string};
+```
+
+See **[Collections](./06-Collections.md)**.
+
+##### `[@field.deps]`
+**Requirements:** Optional.
+
+Dependent fields attribute.
+
+```reason
+type input = {
+ a: [@field.deps b] string,
+ b: string,
+};
+```
+
+See **[Dependent Fields](./07-DependentFields.md)**.
+
+### `type output`
+**Requirements:** Optional. If provided, must be a record with the same set of fields as in `input`.
+**Default:** `input`
+
+Form output data.
+
+```reason
+type output = {email: Email.t};
+```
+
+See **[IO](./03-IO.md)** & **[Basic Usage](./04-BasicUsage.md)**.
+
+### `type message`
+**Requirements:** Optional.
+**Default:** `string`
+
+Type of error messages.
+
+```reason
+type message = I18n.t;
+```
+
+See **[Basic Usage](./04-BasicUsage.md)** & **[I18n](./09-I18n.md)**.
+
+### `type submissionError`
+**Requirements:** Optional.
+**Default:** `unit`
+
+Type of submission error.
+
+```reason
+type submissionError =
+ | UserNotFound
+ | UnknownError;
+```
+
+See **[Form Submission](./08-FormSubmission.md)**.
+
+### `let debounceInterval`
+**Requirements:** Optional `int`.
+**Default:** `700`
+
+Debounce interval in ms for async validators in `OnChange` mode.
+
+```reason
+let debounceInterval = 1000;
+```
+
+See **[Async Validation](./05-AsyncValidation.md)**.
+
+### `let validators`
+**Requirements:** Required. Must be a record with the same set of fields as in `input`/`output`.
+
+Validators record.
+
+```reason
+// Pseudo code
+let validators = {
+ // General field
+ field: {
+ strategy: Strategy.t,
+ validate: input => result('outputValue, message),
+ },
+
+ // Field of collection
+ fieldOfCollection: {
+ collection: input => result(unit, message), // or None
+ fields: {
+ strategy: Strategy.t,
+ validate: (input, ~at: int) => result('outputValue, message),
+ },
+ },
+
+ // Async field
+ asyncField: {
+ strategy: Strategy.t,
+ validate: input => result('outputValue, message),
+ validateAsync: 'outputValue => Js.Promise.t(result('outputValue, message)),
+ },
+
+ // Async field of collection
+ asyncFieldOfCollection: {
+ strategy: Strategy.t,
+ validate: (input, ~at: int) => result('outputValue, message),
+ validateAsync: 'outputValue => Js.Promise.t(result('outputValue, message)),
+ },
+
+ // Async field with eq function
+ asyncFieldWithEq: {
+ strategy: Strategy.t,
+ validate: input => result('outputValue, message),
+ validateAsync: 'outputValue => Js.Promise.t(result('outputValue, message)),
+ eq: ('outputValue, 'outputValue) => bool,
+ },
+
+ // Field without validator
+ fieldWithoutValidator: None,
+};
+```
+
+See **[Validation Strategies](./02-ValidationStrategies.md)**, **[Basic Usage](./04-BasicUsage.md)**, **[Async Validation](./05-AsyncValidation.md)** & **[Collections](./06-Collections.md)**.
+
+## Rendering
+Module created via `[%form]` extension exposes `useForm` Rect hook.
+
+### `useForm`
+React hook.
+
+```reason
+MyForm.useForm(
+ ~initialInput: MyForm.input,
+ ~onSubmit: (output: MyForm.output, cb: Formality.submissionCallbacks) => unit,
+) => MyForm.interface;
+```
+
+#### `submissionCallbacks`
+Callbacks passed to `onSubmit` handler.
+
+```reason
+type submissionCallbacks = {
+ notifyOnSuccess: option(input) => unit,
+ notifyOnFailure: submissionError => unit,
+ reset: unit => unit,
+ dismissSubmissionResult: unit => unit,
+};
+```
+
+See **[Form Submission](./08-FormSubmission.md)**.
+
+### `interface`
+Interface to the hook.
+
+```reason
+type interface = {
+ input: input,
+ status: Formality.formStatus(submissionError),
+ submitting: bool,
+ dirty: unit => bool,
+ submit: unit => unit,
+ dismissSubmissionError: unit => unit,
+ dismissSubmissionResult: unit => unit,
+ mapSubmissionError: (submissionError => submissionError) => unit,
+ reset: unit => unit,
+
+ // General form
+ valid: unit => bool,
+ // Form with async fields
+ valid: unit => option(bool),
+
+ // General field
+ update[Field]: (input => input) => unit,
+ blur[Field]: unit => unit,
+ [field]Result: option(result('outputValue, message)),
+
+ // Async field
+ update[Field]: (input => input) => unit,
+ blur[Field]: unit => unit,
+ [field]Result: option(Formality.Async.exposedFieldStatus('outputValue, message)),
+
+ // Field of collection
+ update[CollectionEntry][Field]: (input => input, ~at: index) => unit,
+ blur[CollectionEntry][Field]: (~at: index) => unit,
+ [collectionEntry][Field]Result: (~at: index) => option(result(string, message)),
+
+ // Collection
+ add[CollectionEntry]: author => unit,
+ remove[CollectionEntry]: (~at: index) => unit,
+};
+```