{
  "openapi": "3.1.0",
  "info": {
    "title": "Balance directory API",
    "version": "1.0.0",
    "summary": "Read-only JSON API of a Balance directory: circles of balanced wallets and the people in them.",
    "description": "Find circles and people. Everything is signed by its authors; the directory verifies and indexes. It can omit or be late; it cannot forge. **Never trust a directory alone for a balance:** verify against the circle’s own chain (see https://nostr-kinds.letsbalance.life/guide/ai/). Keys are 64 lowercase HEX characters, never npub. GET only, CORS open. Definitions 0.3.0 are a DRAFT. The examples are real answers captured on 27 Oct 2026.",
    "license": {
      "name": "Public information",
      "url": "https://nostr-kinds.letsbalance.life/"
    }
  },
  "servers": [
    {
      "url": "https://directory.letsbalance.world/v1",
      "description": "Balance directory 1 (pilot)"
    }
  ],
  "tags": [
    {
      "name": "circles"
    },
    {
      "name": "people"
    },
    {
      "name": "search"
    },
    {
      "name": "health"
    }
  ],
  "paths": {
    "/circles": {
      "get": {
        "operationId": "listCircles",
        "tags": [
          "circles"
        ],
        "summary": "Every verified circle",
        "parameters": [
          {
            "name": "unverified",
            "in": "query",
            "required": false,
            "schema": {
              "enum": [
                "1"
              ]
            },
            "description": "with 1, also the circles the collector has not verified (they have verified: false)"
          }
        ],
        "responses": {
          "200": {
            "description": "The circles",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string"
                },
                "description": "public, max-age=15"
              },
              "Access-Control-Allow-Origin": {
                "schema": {
                  "type": "string"
                },
                "description": "*"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CirclesAnswer"
                },
                "example": {
                  "indexBuiltAt": "2026-10-27T08:06:05.132Z",
                  "count": 1,
                  "circles": [
                    {
                      "birth": "5be0a734c3020470204d6907f34906771d81971cca22fdead3f550eda87f3f27",
                      "name": "Mejmo Se Fajn",
                      "code": "mejmo-se-fajn",
                      "currency": "EUR",
                      "tz": "Europe/Ljubljana",
                      "morning": 4,
                      "genesis": "ba5b8a67510893b3c46e7a8dbf2d43ddcf5709aa7d177a283ee9bb6495f565b0",
                      "founder": "a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1",
                      "circleKey": "6f68e576441b3bb5d9b9e235b7b3d2b29be9a0a346ea7a9633d40fe1bd15bc28",
                      "parent": null,
                      "heart": [
                        "a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1",
                        "c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3",
                        "d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4",
                        "ce896dcbf1568709c3d89086279d7dbf69e95dea9d22af110be78febc4731602"
                      ],
                      "heartRequired": 3,
                      "witnesses": [
                        {
                          "hex": "15062dde27ccde9b8ef24c4cc39e0ad3be93b3ec94249087ea0b47b862e32122",
                          "operator": "balance.mejmosefajn.org",
                          "sinceBlock": 1
                        }
                      ],
                      "quorum": {
                        "q": 1,
                        "n": 1
                      },
                      "node": "15062dde27ccde9b8ef24c4cc39e0ad3be93b3ec94249087ea0b47b862e32122",
                      "relays": [
                        {
                          "url": "wss://balance.mejmosefajn.org/relay",
                          "operator": "balance.mejmosefajn.org"
                        },
                        {
                          "url": "wss://relay2.balance.mejmosefajn.org",
                          "operator": "placeholder-2.balance.mejmosefajn.org"
                        },
                        {
                          "url": "wss://relay3.balance.mejmosefajn.org",
                          "operator": "placeholder-3.balance.mejmosefajn.org"
                        },
                        {
                          "url": "wss://relay4.balance.mejmosefajn.org",
                          "operator": "placeholder-3.balance.mejmosefajn.org"
                        }
                      ],
                      "archives": [],
                      "api": "https://balance.mejmosefajn.org",
                      "mirrorOf": 1,
                      "record": {
                        "id": "b00614b9bf6712a42f27063abafecb1f2a276c709f2d256e8c0234c3249ed26d",
                        "createdAt": 1793086389
                      },
                      "verified": true,
                      "verifiedAt": "2026-10-27T08:06:01.640Z",
                      "verifiedHeight": 3,
                      "recordVerified": true,
                      "latest": null,
                      "members": 1,
                      "membersUnchecked": 0
                    }
                  ]
                }
              }
            }
          },
          "503": {
            "description": "Starting: the collector has not finished its first round",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "the directory is starting (its first round) or its relay could not be read yet; try again shortly"
                }
              }
            }
          }
        }
      }
    },
    "/circles/{birth}": {
      "get": {
        "operationId": "getCircle",
        "tags": [
          "circles"
        ],
        "summary": "One circle with its present state and member list",
        "parameters": [
          {
            "name": "birth",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{64}$",
              "description": "64 lowercase HEX characters"
            },
            "description": "the circle id (birth number)"
          }
        ],
        "responses": {
          "200": {
            "description": "The circle",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string"
                },
                "description": "public, max-age=15"
              },
              "Access-Control-Allow-Origin": {
                "schema": {
                  "type": "string"
                },
                "description": "*"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CircleAnswer"
                },
                "example": {
                  "indexBuiltAt": "2026-10-27T08:06:05.132Z",
                  "circle": {
                    "birth": "5be0a734c3020470204d6907f34906771d81971cca22fdead3f550eda87f3f27",
                    "name": "Mejmo Se Fajn",
                    "code": "mejmo-se-fajn",
                    "currency": "EUR",
                    "tz": "Europe/Ljubljana",
                    "morning": 4,
                    "genesis": "ba5b8a67510893b3c46e7a8dbf2d43ddcf5709aa7d177a283ee9bb6495f565b0",
                    "founder": "a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1",
                    "circleKey": "6f68e576441b3bb5d9b9e235b7b3d2b29be9a0a346ea7a9633d40fe1bd15bc28",
                    "parent": null,
                    "heart": [
                      "a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1",
                      "c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3",
                      "d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4",
                      "ce896dcbf1568709c3d89086279d7dbf69e95dea9d22af110be78febc4731602"
                    ],
                    "heartRequired": 3,
                    "witnesses": [
                      {
                        "hex": "15062dde27ccde9b8ef24c4cc39e0ad3be93b3ec94249087ea0b47b862e32122",
                        "operator": "balance.mejmosefajn.org",
                        "sinceBlock": 1
                      }
                    ],
                    "quorum": {
                      "q": 1,
                      "n": 1
                    },
                    "node": "15062dde27ccde9b8ef24c4cc39e0ad3be93b3ec94249087ea0b47b862e32122",
                    "relays": [
                      {
                        "url": "wss://balance.mejmosefajn.org/relay",
                        "operator": "balance.mejmosefajn.org"
                      },
                      {
                        "url": "wss://relay2.balance.mejmosefajn.org",
                        "operator": "placeholder-2.balance.mejmosefajn.org"
                      },
                      {
                        "url": "wss://relay3.balance.mejmosefajn.org",
                        "operator": "placeholder-3.balance.mejmosefajn.org"
                      },
                      {
                        "url": "wss://relay4.balance.mejmosefajn.org",
                        "operator": "placeholder-3.balance.mejmosefajn.org"
                      }
                    ],
                    "archives": [],
                    "api": "https://balance.mejmosefajn.org",
                    "mirrorOf": 1,
                    "record": {
                      "id": "b00614b9bf6712a42f27063abafecb1f2a276c709f2d256e8c0234c3249ed26d",
                      "createdAt": 1793086389
                    },
                    "verified": true,
                    "verifiedAt": "2026-10-27T08:06:01.640Z",
                    "verifiedHeight": 3,
                    "recordVerified": true,
                    "latest": null,
                    "members": 1,
                    "membersUnchecked": 0,
                    "seals": [],
                    "memberList": [
                      {
                        "hex": "b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2",
                        "name": "",
                        "joinedAtBlock": 2,
                        "since": "2026-10-27",
                        "ledgerChecked": true
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Malformed birth number",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "a circle is named by its birth number: 64 lowercase HEX characters"
                }
              }
            }
          },
          "404": {
            "description": "Unknown birth number",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "the directory holds no circle record for this birth number"
                }
              }
            }
          }
        }
      }
    },
    "/people/{hex}": {
      "get": {
        "operationId": "getPerson",
        "tags": [
          "people"
        ],
        "summary": "One person by HEX key: profile, circle, block joined",
        "description": "When the directory holds nothing about the key it reads the key directly (its own relay by author, then the Lana relays, read only) and answers profileSource \"lana-relays\". Nothing is stored by that.",
        "parameters": [
          {
            "name": "hex",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{64}$",
              "description": "64 lowercase HEX characters"
            },
            "description": "64 lowercase HEX. npub is refused with 400."
          }
        ],
        "responses": {
          "200": {
            "description": "The person",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string"
                },
                "description": "public, max-age=15"
              },
              "Access-Control-Allow-Origin": {
                "schema": {
                  "type": "string"
                },
                "description": "*"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonAnswer"
                },
                "example": {
                  "indexBuiltAt": "2026-10-27T08:06:05.132Z",
                  "person": {
                    "hex": "b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2",
                    "profile": null,
                    "profileSource": null,
                    "inCircle": true,
                    "circle": {
                      "birth": "5be0a734c3020470204d6907f34906771d81971cca22fdead3f550eda87f3f27",
                      "name": "Mejmo Se Fajn",
                      "currency": "EUR",
                      "joinedAtBlock": 2,
                      "since": "2026-10-27",
                      "home": {
                        "id": "1947849c2b872f9751484fc0107a3a18c280173610bcd56a5fbf822626ab3fc5",
                        "createdAt": 1793087353
                      },
                      "ledgerChecked": true
                    },
                    "note": null
                  }
                }
              }
            }
          },
          "400": {
            "description": "Not 64 lowercase HEX (npub is refused)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "a person is named by the HEX key: 64 lowercase HEX characters (never npub)"
                }
              }
            }
          },
          "404": {
            "description": "No profile and no home found anywhere the directory looked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "neither the directory nor the Lana relays hold a profile or a member home of this key"
                }
              }
            }
          }
        }
      }
    },
    "/search": {
      "get": {
        "operationId": "search",
        "tags": [
          "search"
        ],
        "summary": "Find people and circles by name",
        "description": "Every word must match; accents and case are ignored; at most 50 results each. People only if their profile or home is on the directory; circles only if verified.",
        "parameters": [
          {
            "name": "name",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 2,
              "maxLength": 64
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The matches",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string"
                },
                "description": "public, max-age=15"
              },
              "Access-Control-Allow-Origin": {
                "schema": {
                  "type": "string"
                },
                "description": "*"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SearchAnswer"
                },
                "example": {
                  "indexBuiltAt": "2026-10-27T08:06:05.132Z",
                  "query": "mejmo",
                  "people": [],
                  "circles": [
                    {
                      "birth": "5be0a734c3020470204d6907f34906771d81971cca22fdead3f550eda87f3f27",
                      "name": "Mejmo Se Fajn",
                      "currency": "EUR"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "name is not 2 to 64 characters",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "name is 2 to 64 characters"
                }
              }
            }
          }
        }
      }
    },
    "/health": {
      "get": {
        "operationId": "health",
        "tags": [
          "health"
        ],
        "summary": "The directory relay, the index and the collector’s last round",
        "responses": {
          "200": {
            "description": "Healthy",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string"
                },
                "description": "public, max-age=15"
              },
              "Access-Control-Allow-Origin": {
                "schema": {
                  "type": "string"
                },
                "description": "*"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Health"
                },
                "example": {
                  "ok": true,
                  "directoryRelay": "ws://letsbalance-directory-relay:7777",
                  "ready": true,
                  "index": {
                    "builtAt": "2026-10-27T08:06:05.132Z",
                    "incomplete": [],
                    "circles": 1,
                    "homes": 1,
                    "profiles": 0,
                    "people": 1,
                    "refusedRecords": 0,
                    "refusedState": 0,
                    "refusedHomes": 0,
                    "refusedProfiles": 0
                  },
                  "indexError": null,
                  "collector": {
                    "at": "2026-10-27T08:06:01.640Z",
                    "dry": false,
                    "directoryReadable": true,
                    "error": null,
                    "sent": 0,
                    "planned": 0,
                    "refused": [],
                    "profiles": {
                      "keys": 1,
                      "lanaRelays": [
                        "wss://relay.lanavault.space",
                        "wss://relay.lana-eternity.com",
                        "wss://relay.lanaheartvoice.com",
                        "wss://relay.lovelana.org"
                      ],
                      "answered": 4,
                      "newer": 1,
                      "sent": 0,
                      "skipped": [
                        "b2b2b2b2b2b2…: carries contact data (email, phone): not copied (DIRECTORY_KIND0_CONTACT=skip)"
                      ],
                      "pausedUntil": null
                    },
                    "admitted": 1,
                    "circles": [
                      {
                        "birth": "5be0a734c3020470204d6907f34906771d81971cca22fdead3f550eda87f3f27",
                        "relays": [
                          "wss://balance.mejmosefajn.org/relay"
                        ],
                        "readable": true,
                        "verified": true,
                        "height": 3,
                        "record": "held",
                        "recordProblem": null,
                        "heads": 0,
                        "seals": 0,
                        "homes": 1,
                        "error": null,
                        "dropped": []
                      }
                    ]
                  },
                  "presentDays": 7
                }
              }
            }
          },
          "503": {
            "description": "Not ready yet (ok: false)"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string"
          }
        }
      },
      "Meta": {
        "type": "object",
        "required": [
          "indexBuiltAt"
        ],
        "properties": {
          "indexBuiltAt": {
            "type": "string",
            "format": "date-time"
          },
          "incompleteKinds": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "present when a kind could not be read completely (for example a crowd in one second); everything else is served"
          }
        }
      },
      "StateSummary": {
        "type": "object",
        "required": [
          "kind",
          "id",
          "day",
          "n",
          "seal",
          "height",
          "block",
          "stateRoot",
          "lines",
          "createdAt"
        ],
        "properties": {
          "kind": {
            "enum": [
              "head",
              "seal"
            ]
          },
          "id": {
            "type": "string",
            "pattern": "^[0-9a-f]{64}$",
            "description": "64 lowercase HEX characters"
          },
          "day": {
            "type": "string",
            "description": "YYYY-MM-DD, the local date of the morning"
          },
          "n": {
            "type": "integer",
            "description": "counts the seals from 1"
          },
          "seal": {
            "type": "string",
            "description": "the head's seal digest; '' for a seal"
          },
          "height": {
            "type": "integer",
            "description": "height of the last block the seal covers"
          },
          "block": {
            "type": "string",
            "pattern": "^[0-9a-f]{64}$",
            "description": "64 lowercase HEX characters"
          },
          "stateRoot": {
            "type": "string",
            "pattern": "^[0-9a-f]{64}$",
            "description": "root of the sparse Merkle tree over the whole decision state"
          },
          "lines": {
            "type": "integer"
          },
          "createdAt": {
            "type": "integer",
            "description": "unix seconds"
          }
        }
      },
      "CircleSummary": {
        "type": "object",
        "description": "A verified circle as the directory lists it. Every field is always present.",
        "required": [
          "birth",
          "name",
          "code",
          "currency",
          "tz",
          "morning",
          "genesis",
          "founder",
          "circleKey",
          "parent",
          "heart",
          "heartRequired",
          "witnesses",
          "quorum",
          "node",
          "relays",
          "archives",
          "api",
          "mirrorOf",
          "record",
          "verified",
          "verifiedAt",
          "verifiedHeight",
          "recordVerified",
          "latest",
          "members",
          "membersUnchecked"
        ],
        "properties": {
          "birth": {
            "type": "string",
            "pattern": "^[0-9a-f]{64}$",
            "description": "the birth number = the circle id = the event id of the circle’s found act"
          },
          "name": {
            "type": "string"
          },
          "code": {
            "type": "string"
          },
          "currency": {
            "enum": [
              "EUR",
              "USD",
              "GBP"
            ]
          },
          "tz": {
            "type": "string",
            "description": "IANA time zone"
          },
          "morning": {
            "type": "integer",
            "description": "local hour of the daily seal"
          },
          "genesis": {
            "type": "string",
            "pattern": "^[0-9a-f]{64}$",
            "description": "digest of block 1"
          },
          "founder": {
            "type": "string",
            "pattern": "^[0-9a-f]{64}$",
            "description": "64 lowercase HEX characters"
          },
          "circleKey": {
            "type": "string",
            "pattern": "^[0-9a-f]{64}$",
            "description": "64 lowercase HEX characters"
          },
          "parent": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "type": "object",
                "properties": {
                  "birth": {
                    "type": "string",
                    "pattern": "^[0-9a-f]{64}$",
                    "description": "64 lowercase HEX characters"
                  },
                  "genesis": {
                    "type": "string",
                    "pattern": "^[0-9a-f]{64}$",
                    "description": "64 lowercase HEX characters"
                  },
                  "checked": {
                    "type": "boolean",
                    "description": "this directory verified the parent chain with that first block"
                  }
                }
              }
            ]
          },
          "heart": {
            "type": "array",
            "items": {
              "type": "string",
              "pattern": "^[0-9a-f]{64}$",
              "description": "64 lowercase HEX characters"
            },
            "description": "Circle Heart keys"
          },
          "heartRequired": {
            "type": "integer",
            "description": "k: how many Heart members a Heart change needs"
          },
          "witnesses": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "hex": {
                  "type": "string",
                  "pattern": "^[0-9a-f]{64}$",
                  "description": "64 lowercase HEX characters"
                },
                "operator": {
                  "type": "string"
                },
                "sinceBlock": {
                  "type": "integer"
                }
              }
            }
          },
          "quorum": {
            "type": "object",
            "properties": {
              "q": {
                "type": "integer"
              },
              "n": {
                "type": "integer"
              }
            }
          },
          "node": {
            "type": "string",
            "pattern": "^[0-9a-f]{64}$",
            "description": "64 lowercase HEX characters"
          },
          "relays": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "url": {
                  "type": "string",
                  "format": "uri"
                },
                "operator": {
                  "type": "string"
                }
              }
            }
          },
          "archives": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "api": {
            "type": "string",
            "description": "the circle's own API, or ''"
          },
          "mirrorOf": {
            "type": "integer",
            "description": "the ledger height the record mirrors"
          },
          "record": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "pattern": "^[0-9a-f]{64}$",
                "description": "64 lowercase HEX characters"
              },
              "createdAt": {
                "type": "integer",
                "description": "unix seconds"
              }
            }
          },
          "verified": {
            "type": "boolean",
            "description": "the directory's collector verified the chain from block 1; NOT a verification by you"
          },
          "verifiedAt": {
            "oneOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ]
          },
          "verifiedHeight": {
            "type": [
              "integer",
              "null"
            ]
          },
          "recordVerified": {
            "type": "boolean"
          },
          "latest": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/StateSummary"
              }
            ],
            "description": "newest head or seal; null before the first seal"
          },
          "members": {
            "type": "integer",
            "description": "keys whose home the circle’s own ledger confirms"
          },
          "membersUnchecked": {
            "type": "integer",
            "description": "valid homes without a ledger verdict yet; not members until confirmed"
          }
        }
      },
      "CircleDetail": {
        "allOf": [
          {
            "$ref": "#/components/schemas/CircleSummary"
          },
          {
            "type": "object",
            "required": [
              "seals",
              "memberList"
            ],
            "properties": {
              "seals": {
                "type": "array",
                "description": "day seals of the newest days held (7 by default)",
                "items": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StateSummary"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "chunks": {
                          "type": "integer"
                        },
                        "chunksExpected": {
                          "type": "integer"
                        },
                        "snapshotVerified": {
                          "type": "boolean",
                          "description": "the chunks rebuild the sealed state: every chunk, the chunks root, the state root, the sum 0"
                        }
                      }
                    }
                  ]
                }
              },
              "memberList": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "hex": {
                      "type": "string",
                      "pattern": "^[0-9a-f]{64}$",
                      "description": "64 lowercase HEX characters"
                    },
                    "name": {
                      "type": "string",
                      "description": "name words from the member home; may be empty"
                    },
                    "joinedAtBlock": {
                      "type": "integer"
                    },
                    "since": {
                      "type": "string",
                      "description": "YYYY-MM-DD"
                    },
                    "ledgerChecked": {
                      "type": "boolean",
                      "description": "false = a valid home not (yet) confirmed by the circle’s own ledger"
                    }
                  }
                }
              }
            }
          }
        ]
      },
      "Profile": {
        "type": "object",
        "required": [
          "eventId",
          "createdAt"
        ],
        "description": "Only these fields are shown, strings cut to 2000 characters; read the event from the relay for the rest.",
        "properties": {
          "eventId": {
            "type": "string",
            "pattern": "^[0-9a-f]{64}$",
            "description": "64 lowercase HEX characters"
          },
          "createdAt": {
            "type": "integer",
            "description": "unix seconds"
          },
          "name": {
            "type": "string"
          },
          "display_name": {
            "type": "string"
          },
          "about": {
            "type": "string"
          },
          "picture": {
            "type": "string"
          },
          "banner": {
            "type": "string"
          },
          "website": {
            "type": "string"
          },
          "nip05": {
            "type": "string"
          },
          "lud16": {
            "type": "string"
          }
        }
      },
      "Person": {
        "type": "object",
        "required": [
          "hex",
          "profile",
          "profileSource",
          "inCircle",
          "circle",
          "note"
        ],
        "properties": {
          "hex": {
            "type": "string",
            "pattern": "^[0-9a-f]{64}$",
            "description": "64 lowercase HEX characters"
          },
          "profile": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/Profile"
              }
            ]
          },
          "profileSource": {
            "enum": [
              "directory",
              "lana-relays",
              null
            ]
          },
          "inCircle": {
            "type": "boolean"
          },
          "circle": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "type": "object",
                "properties": {
                  "birth": {
                    "type": "string",
                    "pattern": "^[0-9a-f]{64}$",
                    "description": "64 lowercase HEX characters"
                  },
                  "name": {
                    "type": "string"
                  },
                  "currency": {
                    "type": "string"
                  },
                  "joinedAtBlock": {
                    "type": "integer"
                  },
                  "since": {
                    "type": "string"
                  },
                  "home": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string",
                        "pattern": "^[0-9a-f]{64}$",
                        "description": "64 lowercase HEX characters"
                      },
                      "createdAt": {
                        "type": "integer",
                        "description": "unix seconds"
                      }
                    }
                  },
                  "ledgerChecked": {
                    "type": "boolean"
                  }
                }
              }
            ]
          },
          "note": {
            "type": [
              "string",
              "null"
            ],
            "description": "explains a key the ledger places elsewhere or nowhere"
          }
        }
      },
      "CirclesAnswer": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Meta"
          },
          {
            "type": "object",
            "required": [
              "count",
              "circles"
            ],
            "properties": {
              "count": {
                "type": "integer"
              },
              "circles": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/CircleSummary"
                }
              }
            }
          }
        ]
      },
      "CircleAnswer": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Meta"
          },
          {
            "type": "object",
            "required": [
              "circle"
            ],
            "properties": {
              "circle": {
                "$ref": "#/components/schemas/CircleDetail"
              }
            }
          }
        ]
      },
      "PersonAnswer": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Meta"
          },
          {
            "type": "object",
            "required": [
              "person"
            ],
            "properties": {
              "person": {
                "$ref": "#/components/schemas/Person"
              }
            }
          }
        ]
      },
      "SearchAnswer": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Meta"
          },
          {
            "type": "object",
            "required": [
              "query",
              "people",
              "circles"
            ],
            "properties": {
              "query": {
                "type": "string"
              },
              "people": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "hex": {
                      "type": "string",
                      "pattern": "^[0-9a-f]{64}$",
                      "description": "64 lowercase HEX characters"
                    },
                    "name": {
                      "type": "string"
                    },
                    "circle": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  }
                }
              },
              "circles": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "birth": {
                      "type": "string",
                      "pattern": "^[0-9a-f]{64}$",
                      "description": "64 lowercase HEX characters"
                    },
                    "name": {
                      "type": "string"
                    },
                    "currency": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        ]
      },
      "Health": {
        "type": "object",
        "description": "Operational status; shapes inside index and collector may gain fields.",
        "required": [
          "ok"
        ],
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "ready": {
            "type": "boolean"
          },
          "directoryRelay": {
            "type": "string"
          },
          "index": {
            "type": [
              "object",
              "null"
            ]
          },
          "indexError": {
            "type": [
              "string",
              "null"
            ]
          },
          "collector": {
            "type": [
              "object",
              "null"
            ]
          },
          "presentDays": {
            "type": "integer"
          }
        },
        "additionalProperties": true
      }
    }
  },
  "x-nostr-relay": {
    "url": "wss://directory.letsbalance.world/relay",
    "note": "The same data as signed Nostr events. Read with REQ. Accepted kinds: 0, 30910, 30915, 30916, 43917, 43918. At most 500 events per REQ: page with until (inclusive) and de-duplicate by id. See https://nostr-kinds.letsbalance.life/guide/ai/#22-nostr-req-on-the-directory-relay",
    "filters": [
      {
        "kinds": [
          30910
        ]
      },
      {
        "kinds": [
          30910
        ],
        "#d": [
          "<circle id>"
        ]
      },
      {
        "kinds": [
          30915
        ],
        "#d": [
          "<circle id>"
        ]
      },
      {
        "kinds": [
          43917
        ],
        "#c": [
          "<circle id>"
        ]
      },
      {
        "kinds": [
          43918
        ],
        "#c": [
          "<circle id>"
        ],
        "#m": [
          "<scope16>:<YYYY-MM-DD>"
        ]
      },
      {
        "kinds": [
          30916
        ],
        "#c": [
          "<circle id>"
        ]
      },
      {
        "kinds": [
          30916,
          0
        ],
        "authors": [
          "<hex>"
        ]
      }
    ]
  }
}
