curl --fail-with-body --max-time 30 -X POST 'https://app.reflections.ai/oauth/register' \
-H "Content-Type: application/json" \
--data-raw '{
"client_name": "Fieldnote",
"client_uri": "https://fieldnote.example",
"redirect_uris": [
"http://127.0.0.1:33418/oauth/callback"
],
"grant_types": [
"authorization_code",
"refresh_token"
],
"response_types": [
"code"
],
"token_endpoint_auth_method": "none",
"scope": "talent:read licenses:read checks:write generations:write",
"software_id": "com.fieldnote.desktop",
"software_version": "4.2.0"
}'import { exit } from "node:process";
const response = await fetch("https://app.reflections.ai/oauth/register", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
"client_name": "Fieldnote",
"client_uri": "https://fieldnote.example",
"redirect_uris": [
"http://127.0.0.1:33418/oauth/callback"
],
"grant_types": [
"authorization_code",
"refresh_token"
],
"response_types": [
"code"
],
"token_endpoint_auth_method": "none",
"scope": "talent:read licenses:read checks:write generations:write",
"software_id": "com.fieldnote.desktop",
"software_version": "4.2.0"
}),
signal: AbortSignal.timeout(30_000),
});
const responseBody = await response.text();
if (!response.ok) {
console.error(`HTTP ${response.status}: ${responseBody}`);
exit(1);
}
console.log(responseBody);
import json
from urllib.error import HTTPError
from urllib.request import Request, urlopen
headers = {
"Content-Type": "application/json",
}
data = json.dumps({
"client_name": "Fieldnote",
"client_uri": "https://fieldnote.example",
"redirect_uris": ["http://127.0.0.1:33418/oauth/callback"],
"grant_types": ["authorization_code", "refresh_token"],
"response_types": ["code"],
"token_endpoint_auth_method": "none",
"scope": "talent:read licenses:read checks:write generations:write",
"software_id": "com.fieldnote.desktop",
"software_version": "4.2.0",
}).encode("utf-8")
request = Request("https://app.reflections.ai/oauth/register",
method="POST", headers=headers, data=data)
try:
with urlopen(request, timeout=30) as response:
print(response.read().decode("utf-8"))
except HTTPError as error:
error_body = error.read().decode("utf-8")
raise RuntimeError(f"HTTP {error.code}: {error_body}") from error
package main
import (
"fmt"
"io"
"net/http"
"strings"
"time"
)
func main() {
body := strings.NewReader(`{
"client_name": "Fieldnote",
"client_uri": "https://fieldnote.example",
"redirect_uris": [
"http://127.0.0.1:33418/oauth/callback"
],
"grant_types": [
"authorization_code",
"refresh_token"
],
"response_types": [
"code"
],
"token_endpoint_auth_method": "none",
"scope": "talent:read licenses:read checks:write generations:write",
"software_id": "com.fieldnote.desktop",
"software_version": "4.2.0"
}`)
request, err := http.NewRequest("POST", "https://app.reflections.ai/oauth/register", body)
if err != nil {
panic(err)
}
request.Header.Set("Content-Type", "application/json")
client := &http.Client{Timeout: 30 * time.Second}
response, err := client.Do(request)
if err != nil {
panic(err)
}
defer response.Body.Close()
responseBody, err := io.ReadAll(response.Body)
if err != nil {
panic(err)
}
if response.StatusCode < 200 || response.StatusCode >= 300 {
panic(fmt.Sprintf("HTTP %d: %s", response.StatusCode, responseBody))
}
fmt.Print(string(responseBody))
}
{
"client_id": "cl_ra8t5tsberxpax0351jdyqgrb7",
"client_id_issued_at": 1792312320,
"client_name": "Fieldnote",
"client_uri": "https://fieldnote.example",
"redirect_uris": [
"http://127.0.0.1:33418/oauth/callback"
],
"grant_types": [
"authorization_code",
"refresh_token"
],
"response_types": [
"code"
],
"token_endpoint_auth_method": "none",
"scope": "talent:read licenses:read checks:write generations:write",
"software_id": "com.fieldnote.desktop",
"software_version": "4.2.0",
"account": null
}Register a client
Planned contract — unavailable in test and live modes. This operation is a protocol reference, not a callable endpoint. Start with the working sandbox quickstart.
Registers an OAuth client, as Dynamic Client Registration (RFC 7591) defines. MCP clients call it on their own the first time they connect, so a person needs only the server’s URL.
Sent without a key, it registers a public client: token_endpoint_auth_method must be
none, and the grants are authorization_code and refresh_token. A public client acts
for whoever signs in on the authorization page.
Sent with your secret key, it registers a confidential client that belongs to your account
and receives a client_secret, shown only in this response. Use one for an
RSL client that requests License tokens with
client_credentials, or for a content host that checks them with
POST /oauth/introspect. A License token
issued to it draws on your account’s licenses.
A client can also skip registration and use the HTTPS URL of a client metadata document as
its client_id; Reflections reads the document when the person reaches the authorization
page. Platforms do not register: their client is created with the account.
Public for a public client. A confidential client needs an unrestricted key.
curl --fail-with-body --max-time 30 -X POST 'https://app.reflections.ai/oauth/register' \
-H "Content-Type: application/json" \
--data-raw '{
"client_name": "Fieldnote",
"client_uri": "https://fieldnote.example",
"redirect_uris": [
"http://127.0.0.1:33418/oauth/callback"
],
"grant_types": [
"authorization_code",
"refresh_token"
],
"response_types": [
"code"
],
"token_endpoint_auth_method": "none",
"scope": "talent:read licenses:read checks:write generations:write",
"software_id": "com.fieldnote.desktop",
"software_version": "4.2.0"
}'import { exit } from "node:process";
const response = await fetch("https://app.reflections.ai/oauth/register", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
"client_name": "Fieldnote",
"client_uri": "https://fieldnote.example",
"redirect_uris": [
"http://127.0.0.1:33418/oauth/callback"
],
"grant_types": [
"authorization_code",
"refresh_token"
],
"response_types": [
"code"
],
"token_endpoint_auth_method": "none",
"scope": "talent:read licenses:read checks:write generations:write",
"software_id": "com.fieldnote.desktop",
"software_version": "4.2.0"
}),
signal: AbortSignal.timeout(30_000),
});
const responseBody = await response.text();
if (!response.ok) {
console.error(`HTTP ${response.status}: ${responseBody}`);
exit(1);
}
console.log(responseBody);
import json
from urllib.error import HTTPError
from urllib.request import Request, urlopen
headers = {
"Content-Type": "application/json",
}
data = json.dumps({
"client_name": "Fieldnote",
"client_uri": "https://fieldnote.example",
"redirect_uris": ["http://127.0.0.1:33418/oauth/callback"],
"grant_types": ["authorization_code", "refresh_token"],
"response_types": ["code"],
"token_endpoint_auth_method": "none",
"scope": "talent:read licenses:read checks:write generations:write",
"software_id": "com.fieldnote.desktop",
"software_version": "4.2.0",
}).encode("utf-8")
request = Request("https://app.reflections.ai/oauth/register",
method="POST", headers=headers, data=data)
try:
with urlopen(request, timeout=30) as response:
print(response.read().decode("utf-8"))
except HTTPError as error:
error_body = error.read().decode("utf-8")
raise RuntimeError(f"HTTP {error.code}: {error_body}") from error
package main
import (
"fmt"
"io"
"net/http"
"strings"
"time"
)
func main() {
body := strings.NewReader(`{
"client_name": "Fieldnote",
"client_uri": "https://fieldnote.example",
"redirect_uris": [
"http://127.0.0.1:33418/oauth/callback"
],
"grant_types": [
"authorization_code",
"refresh_token"
],
"response_types": [
"code"
],
"token_endpoint_auth_method": "none",
"scope": "talent:read licenses:read checks:write generations:write",
"software_id": "com.fieldnote.desktop",
"software_version": "4.2.0"
}`)
request, err := http.NewRequest("POST", "https://app.reflections.ai/oauth/register", body)
if err != nil {
panic(err)
}
request.Header.Set("Content-Type", "application/json")
client := &http.Client{Timeout: 30 * time.Second}
response, err := client.Do(request)
if err != nil {
panic(err)
}
defer response.Body.Close()
responseBody, err := io.ReadAll(response.Body)
if err != nil {
panic(err)
}
if response.StatusCode < 200 || response.StatusCode >= 300 {
panic(fmt.Sprintf("HTTP %d: %s", response.StatusCode, responseBody))
}
fmt.Print(string(responseBody))
}
{
"client_id": "cl_ra8t5tsberxpax0351jdyqgrb7",
"client_id_issued_at": 1792312320,
"client_name": "Fieldnote",
"client_uri": "https://fieldnote.example",
"redirect_uris": [
"http://127.0.0.1:33418/oauth/callback"
],
"grant_types": [
"authorization_code",
"refresh_token"
],
"response_types": [
"code"
],
"token_endpoint_auth_method": "none",
"scope": "talent:read licenses:read checks:write generations:write",
"software_id": "com.fieldnote.desktop",
"software_version": "4.2.0",
"account": null
}Authorizations
Your secret key, rk_test_… or rk_live_…, sent as Authorization: Bearer <key>. Keep it
on your server. Restricted keys carry only the scopes you give them.
Body
Client metadata, as RFC 7591 defines it.
Shown to the person on the authorization page.
80The client's home page, linked on the authorization page.
A square logo shown on the authorization page, PNG or SVG.
Where the authorization page may send the person back. Each is an HTTPS URL, or an
http://127.0.0.1 or http://[::1] loopback URL for a native app, which may use any
port (RFC 8252). Required when grant_types includes authorization_code.
The grants the client will use. client_credentials needs a secret key on the request.
authorization_code, refresh_token, client_credentials Defaults to ["code"] when grant_types includes authorization_code, and to []
otherwise.
code none for a public client, such as a desktop or command-line agent.
client_secret_basic or client_secret_post for a confidential client, which needs a
secret key on the request.
none, client_secret_basic, client_secret_post Space-separated scopes the client may ask for. Defaults to every MCP scope.
Identifies the client software across its installations, such as a reverse domain name.
The version of the client software.
Response
The registered client.
A registered OAuth client, as RFC 7591 returns it.
Unique identifier for the client, cl_….
^cl_[0-9a-hjkmnp-tv-z]{26}$Unix seconds when the client was registered.
The registered name.
The registered redirect URIs.
The grants the client may use.
authorization_code, refresh_token, client_credentials The response types the client may use.
code How the client authenticates at the token endpoint.
none, client_secret_basic, client_secret_post The account that registered a confidential client, whose licenses its License tokens
draw on. null for a public client.
^acct_[0-9a-hjkmnp-tv-z]{26}$A confidential client's secret, rcs_…. Shown only in this response: store it with your
other secrets.
0: the secret does not expire.
The registered home page.
The registered logo.
The scopes the client may ask for.
The registered software ID.
The registered software version.