The feedback board - ideas and private requests, votes, follows (replaces Fider at feedback.noti.bot).

── WHO SEES WHAT ────────────────────────────────────────────────────────── Reads work logged out: pass auth ONLY when the user is logged in. With a session the server answers for that user (premium-only boards, their own hidden posts, staff view) and marks the response private, no-store; without one it answers the public view and lets it be cached. Never cache a logged-in response on the page side as if it were public.

Behind the feedback launch flag: while it is hidden for the caller every method 404s. A post the viewer may not see is 404 too, never 403 - do not show "forbidden", show "not found".

── REFUSALS ─────────────────────────────────────────────────────────────── A refused write is { status, error: { code } }, code from FeedbackErrorCode. voteRefusal / commentRefusal on a post's viewer tell you up front why the buttons are off (banned, new account, archived board, locked post), so the page can say so instead of letting the click fail.

── TEXT ─────────────────────────────────────────────────────────────────── title is plain text. body is MARKDOWN, stored raw: render it with an allowlist (no raw HTML, images only from Noti's own host, links rel="nofollow ugc noopener"). The server does not sanitise HTML for you.

Constructors

Methods

  • Comment, or reply with parentId (a top-level comment only). uploadIds from createFeedbackUpload. 10/minute. Returns the thread.

    Parameters

    • __namedParameters: {
          auth: string;
          comment: {
              body: string;
              parentId?: string;
              uploadIds?: string[];
          };
          number: number;
      }
      • auth: string
      • comment: {
            body: string;
            parentId?: string;
            uploadIds?: string[];
        }
        • body: string
        • OptionalparentId?: string
        • OptionaluploadIds?: string[]
      • number: number

    Returns Promise<WebResponse<FeedbackThread>>

  • Parameters

    • __namedParameters: {
          auth: string;
          commentId: string;
          kind:
              | "heart"
              | "thumbsUp"
              | "thumbsDown"
              | "fire";
      }
      • auth: string
      • commentId: string
      • kind:
            | "heart"
            | "thumbsUp"
            | "thumbsDown"
            | "fire"

    Returns Promise<WebResponse<{
        reactions: FeedbackReactions;
    }>>

  • Mark notifications read: the given ids, or all of them when omitted.

    Parameters

    • __namedParameters: {
          auth: string;
          ids?: string[];
      }
      • auth: string
      • Optionalids?: string[]

    Returns Promise<WebResponse<{
        read: number;
    }>>

  • Post an idea / request. The author votes and follows it automatically. 5 per hour. uploadIds from createFeedbackUpload.

    Parameters

    • __namedParameters: {
          auth: string;
          post: {
              boardId: string;
              body?: string;
              tagIds?: string[];
              title: string;
              uploadIds?: string[];
          };
      }
      • auth: string
      • post: {
            boardId: string;
            body?: string;
            tagIds?: string[];
            title: string;
            uploadIds?: string[];
        }
        • boardId: string
        • Optionalbody?: string
        • OptionaltagIds?: string[]
        • title: string
        • OptionaluploadIds?: string[]

    Returns Promise<WebResponse<FeedbackPostView>>

  • React to a post. Answers the post's reactions. reactions_off (404) when the switch is off.

    Parameters

    • __namedParameters: {
          auth: string;
          kind:
              | "heart"
              | "thumbsUp"
              | "thumbsDown"
              | "fire";
          number: number;
      }
      • auth: string
      • kind:
            | "heart"
            | "thumbsUp"
            | "thumbsDown"
            | "fire"
      • number: number

    Returns Promise<WebResponse<{
        reactions: FeedbackReactions;
    }>>

  • Upload one image (field image: png, jpeg, webp or gif, up to 8 MB). It comes back as webp, at most 2000px, with its metadata (GPS, camera) removed. Put url in the markdown as ![alt](url) and send uploadId in uploadIds when saving the post or comment; unattached uploads are deleted after 24h. 20 per day. Refusals: uploads_off, image_too_large, unsupported_image, invalid_image, upload_quota.

    Parameters

    • __namedParameters: {
          auth: string;
          formData: FormData;
      }
      • auth: string
      • formData: FormData

    Returns Promise<WebResponse<FeedbackUpload>>

  • Parameters

    • __namedParameters: {
          auth: string;
          commentId: string;
          kind:
              | "heart"
              | "thumbsUp"
              | "thumbsDown"
              | "fire";
      }
      • auth: string
      • commentId: string
      • kind:
            | "heart"
            | "thumbsUp"
            | "thumbsDown"
            | "fire"

    Returns Promise<WebResponse<{
        reactions: FeedbackReactions;
    }>>

  • Delete your own post - only while nobody else has voted on it (ask_staff otherwise).

    Parameters

    • __namedParameters: {
          auth: string;
          number: number;
      }
      • auth: string
      • number: number

    Returns Promise<WebResponse<{
        deleted: true;
    }>>

  • Parameters

    • __namedParameters: {
          auth: string;
          kind:
              | "heart"
              | "thumbsUp"
              | "thumbsDown"
              | "fire";
          number: number;
      }
      • auth: string
      • kind:
            | "heart"
            | "thumbsUp"
            | "thumbsDown"
            | "fire"
      • number: number

    Returns Promise<WebResponse<{
        reactions: FeedbackReactions;
    }>>

  • A comment's edit history, as getFeedbackPostRevisions (no title). A deleted comment's history is staff only.

    Parameters

    • __namedParameters: {
          auth?: string;
          commentId: string;
      }
      • Optionalauth?: string
      • commentId: string

    Returns Promise<WebResponse<{
        revisions: FeedbackRevision[];
    }>>

  • The thread: the official staff answer first, then comments oldest first with their replies (one level). Staff notes (internal) only reach staff. A deleted comment shows as deleted: true with no body while it still has replies.

    Parameters

    • __namedParameters: {
          auth?: string;
          number: number;
      }
      • Optionalauth?: string
      • number: number

    Returns Promise<WebResponse<FeedbackThread>>

  • Posts staff featured for the top of the feedback page (up to 10, in their order).

    Parameters

    • __namedParameters: {
          auth?: string;
      } = {}
      • Optionalauth?: string

    Returns Promise<WebResponse<{
        posts: {
            post: FeedbackPost & {
                commentCount: number;
            };
            viewer: {
                following: boolean;
                voted: boolean;
            };
        }[];
    }>>

  • The bell's number. Counts up to 100 (capped then true - show "99+").

    Parameters

    • __namedParameters: {
          auth: string;
      }
      • auth: string

    Returns Promise<WebResponse<{
        capped: boolean;
        unread: number;
    }>>

  • The inbox (the bell): newest first. Visibility is checked when you read it, so a post that has gone private is simply not there. Page with before = the previous page's next.

    Parameters

    • __namedParameters: {
          auth: string;
          before?: string;
          limit?: number;
      }
      • auth: string
      • Optionalbefore?: string
      • Optionallimit?: number

    Returns Promise<WebResponse<FeedbackNotificationList>>

  • One post. A merged post answers { post: null, viewer: null, mergedInto }: send the user to mergedInto (its old number keeps working this way).

    Parameters

    • __namedParameters: {
          auth?: string;
          number: number;
      }
      • Optionalauth?: string
      • number: number

    Returns Promise<WebResponse<FeedbackPostView>>

  • A post's edit history ("View history"): newest first, the current version included, at most 50. Same visibility as the post (404 otherwise). After a staff / developer edit, non-staff see that version and later ones only.

    Parameters

    • __namedParameters: {
          auth?: string;
          number: number;
      }
      • Optionalauth?: string
      • number: number

    Returns Promise<WebResponse<{
        revisions: FeedbackRevision[];
    }>>

  • The list. board / tag take a slug or id; sort is top (default, pinned first inside a board), new or trending (votes in the last 14 days). limit up to 50. Searching logged out is rate limited.

    Parameters

    • __namedParameters: {
          auth?: string;
          board?: string;
          limit?: number;
          offset?: number;
          q?: string;
          sort?: FeedbackSort;
          status?:
              | "done"
              | "open"
              | "underReview"
              | "planned"
              | "inProgress"
              | "declined";
          tag?: string;
      } = {}
      • Optionalauth?: string
      • Optionalboard?: string
      • Optionallimit?: number
      • Optionaloffset?: number
      • Optionalq?: string
      • Optionalsort?: FeedbackSort
      • Optionalstatus?:
            | "done"
            | "open"
            | "underReview"
            | "planned"
            | "inProgress"
            | "declined"
      • Optionaltag?: string

    Returns Promise<WebResponse<FeedbackPostList>>

  • Shipped posts, newest first, each with the public changelog entry it shipped in (if staff linked one).

    Parameters

    • __namedParameters: {
          auth?: string;
          limit?: number;
          offset?: number;
      } = {}
      • Optionalauth?: string
      • Optionallimit?: number
      • Optionaloffset?: number

    Returns Promise<WebResponse<FeedbackTimeline>>

  • My KLIPY customer_id for the GIF picker: stable per user, not the Discord id. The dashboard calls KLIPY itself (their terms: API requests come from the user's browser) and sends this on search, trending and share.

    Parameters

    • __namedParameters: {
          auth: string;
      }
      • auth: string

    Returns Promise<WebResponse<{
        customerId: string;
    }>>

  • Edit your own post. Only while it is open / under review and has 10 or fewer votes (viewer.canEdit).

    Parameters

    • __namedParameters: {
          auth: string;
          number: number;
          post: {
              body?: string;
              tagIds?: string[];
              title?: string;
              uploadIds?: string[];
          };
      }
      • auth: string
      • number: number
      • post: {
            body?: string;
            tagIds?: string[];
            title?: string;
            uploadIds?: string[];
        }
        • Optionalbody?: string
        • OptionaltagIds?: string[]
        • Optionaltitle?: string
        • OptionaluploadIds?: string[]

    Returns Promise<WebResponse<FeedbackPostView>>