or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

accounts.mdauthentication.mdconversations.mdfilters.mdindex.mdinstance.mdlists.mdmedia.mdnotifications.mdpolls.mdreports.mdsearch.mdstatuses.mdstreaming.mdtags.mdtimelines.mdtypes.md
tile.json

reports.mddocs/

Reports

User reporting and moderation operations.

Overview

The reporting system allows users to report problematic accounts or content to instance moderators. Reports are reviewed by instance administrators.

Types

Report

type Report struct {
    ID          ID
    ActionTaken bool
}

Report holds information for a Mastodon report.

Fields:

  • ID - Unique report identifier
  • ActionTaken - Whether moderators have acted on this report

Report Operations

GetReports { .api }

func (c *Client) GetReports(ctx context.Context) ([]*Report, error)

Returns reports filed by the current user.

Parameters:

  • ctx - Context for cancellation/timeout

Returns: Slice of Report objects or error

Example:

reports, err := client.GetReports(ctx)
if err != nil {
    log.Fatal(err)
}

fmt.Printf("You have filed %d report(s):\n", len(reports))
for _, report := range reports {
    status := "Pending"
    if report.ActionTaken {
        status = "Action Taken"
    }
    fmt.Printf("  Report %s: %s\n", report.ID, status)
}

Report { .api }

func (c *Client) Report(ctx context.Context, accountID ID, ids []ID, comment string) (*Report, error)

Creates a report against an account.

Parameters:

  • ctx - Context for cancellation/timeout
  • accountID - ID of account to report
  • ids - Slice of status IDs as evidence (can be empty)
  • comment - Explanation of why you're reporting (required)

Returns: Created Report object or error

Example:

accountID := "123456"
statusIDs := []mastodon.ID{"789012", "345678"} // Problematic statuses
comment := "This account is posting spam and harassment"

report, err := client.Report(ctx, accountID, statusIDs, comment)
if err != nil {
    log.Fatal(err)
}

fmt.Printf("Report filed successfully. Report ID: %s\n", report.ID)

Usage Examples

Example: Report Spam Account

func reportSpammer(client *mastodon.Client, accountID mastodon.ID) error {
    ctx := context.Background()

    // Get recent statuses from the account as evidence
    statuses, err := client.GetAccountStatuses(ctx, accountID, &mastodon.Pagination{Limit: 5})
    if err != nil {
        return fmt.Errorf("failed to get account statuses: %w", err)
    }

    // Collect status IDs
    var statusIDs []mastodon.ID
    for _, status := range statuses {
        statusIDs = append(statusIDs, status.ID)
    }

    // File report
    comment := "This account is posting spam links repeatedly"
    report, err := client.Report(ctx, accountID, statusIDs, comment)
    if err != nil {
        return fmt.Errorf("failed to file report: %w", err)
    }

    fmt.Printf("Report filed successfully (ID: %s)\n", report.ID)
    fmt.Printf("Moderators will review the account and take appropriate action.\n")

    return nil
}

Example: Report Harassment

func reportHarassment(client *mastodon.Client, accountID mastodon.ID, offendingStatusIDs []mastodon.ID) error {
    ctx := context.Background()

    comment := `This account has been sending harassing messages and making threatening statements.
The attached statuses contain personal attacks and violate the instance's code of conduct.`

    report, err := client.Report(ctx, accountID, offendingStatusIDs, comment)
    if err != nil {
        return err
    }

    fmt.Printf("Harassment report filed (ID: %s)\n", report.ID)
    return nil
}

Example: Check Report Status

func checkReportStatus(client *mastodon.Client, reportID mastodon.ID) error {
    ctx := context.Background()

    reports, err := client.GetReports(ctx)
    if err != nil {
        return err
    }

    for _, report := range reports {
        if report.ID == reportID {
            if report.ActionTaken {
                fmt.Printf("Report %s: Action has been taken by moderators\n", reportID)
            } else {
                fmt.Printf("Report %s: Pending review\n", reportID)
            }
            return nil
        }
    }

    return fmt.Errorf("report %s not found", reportID)
}

Example: List All Reports

func listMyReports(client *mastodon.Client) error {
    ctx := context.Background()

    reports, err := client.GetReports(ctx)
    if err != nil {
        return err
    }

    if len(reports) == 0 {
        fmt.Println("You have not filed any reports")
        return nil
    }

    fmt.Printf("Your Reports (%d total)\n", len(reports))
    fmt.Println(strings.Repeat("=", 50))

    pending := 0
    resolved := 0

    for _, report := range reports {
        status := "⏳ Pending"
        if report.ActionTaken {
            status = "✓ Action Taken"
            resolved++
        } else {
            pending++
        }
        fmt.Printf("Report %s: %s\n", report.ID, status)
    }

    fmt.Printf("\nSummary: %d pending, %d resolved\n", pending, resolved)
    return nil
}

Example: Report with Context

type ReportContext struct {
    AccountID      mastodon.ID
    Reason         string
    StatusIDs      []mastodon.ID
    AdditionalInfo string
}

func fileDetailedReport(client *mastodon.Client, ctx ReportContext) error {
    context := context.Background()

    // Build comprehensive comment
    comment := fmt.Sprintf("Reason: %s\n\n", ctx.Reason)
    if ctx.AdditionalInfo != "" {
        comment += fmt.Sprintf("Additional Information:\n%s\n\n", ctx.AdditionalInfo)
    }
    comment += fmt.Sprintf("Number of problematic posts: %d", len(ctx.StatusIDs))

    report, err := client.Report(context, ctx.AccountID, ctx.StatusIDs, comment)
    if err != nil {
        return err
    }

    fmt.Printf("Detailed report filed: %s\n", report.ID)
    return nil
}

// Usage
reportCtx := ReportContext{
    AccountID:      "123456",
    Reason:         "Spam and misleading information",
    StatusIDs:      []mastodon.ID{"789", "012", "345"},
    AdditionalInfo: "Account created recently and only posts promotional content",
}
err := fileDetailedReport(client, reportCtx)

Example: Report Manager

type ReportManager struct {
    client *mastodon.Client
}

func (rm *ReportManager) FileReport(ctx context.Context, accountID mastodon.ID, reason string, statusIDs []mastodon.ID) (*mastodon.Report, error) {
    report, err := rm.client.Report(ctx, accountID, statusIDs, reason)
    if err != nil {
        return nil, fmt.Errorf("failed to file report: %w", err)
    }

    log.Printf("Report filed: %s against account %s", report.ID, accountID)
    return report, nil
}

func (rm *ReportManager) GetPendingReports(ctx context.Context) ([]*mastodon.Report, error) {
    reports, err := rm.client.GetReports(ctx)
    if err != nil {
        return nil, err
    }

    var pending []*mastodon.Report
    for _, report := range reports {
        if !report.ActionTaken {
            pending = append(pending, report)
        }
    }

    return pending, nil
}

func (rm *ReportManager) GetResolvedReports(ctx context.Context) ([]*mastodon.Report, error) {
    reports, err := rm.client.GetReports(ctx)
    if err != nil {
        return nil, err
    }

    var resolved []*mastodon.Report
    for _, report := range reports {
        if report.ActionTaken {
            resolved = append(resolved, report)
        }
    }

    return resolved, nil
}

func (rm *ReportManager) Summary(ctx context.Context) error {
    reports, err := rm.client.GetReports(ctx)
    if err != nil {
        return err
    }

    fmt.Println("Report Summary")
    fmt.Println(strings.Repeat("=", 50))
    fmt.Printf("Total reports filed: %d\n", len(reports))

    pending := 0
    resolved := 0
    for _, report := range reports {
        if report.ActionTaken {
            resolved++
        } else {
            pending++
        }
    }

    fmt.Printf("Pending review: %d\n", pending)
    fmt.Printf("Action taken: %d\n", resolved)

    if len(reports) > 0 {
        resolvedPercent := float64(resolved) / float64(len(reports)) * 100
        fmt.Printf("Resolution rate: %.1f%%\n", resolvedPercent)
    }

    return nil
}

Example: Interactive Report Filing

func interactiveReport(client *mastodon.Client, reader *bufio.Reader) error {
    ctx := context.Background()

    fmt.Println("File a Report")
    fmt.Println(strings.Repeat("=", 50))

    // Get account ID
    fmt.Print("Enter account ID or username: ")
    input, _ := reader.ReadString('\n')
    input = strings.TrimSpace(input)

    var accountID mastodon.ID
    if strings.HasPrefix(input, "@") || strings.Contains(input, "@") {
        // Lookup by username
        account, err := client.AccountLookup(ctx, input)
        if err != nil {
            return fmt.Errorf("account not found: %w", err)
        }
        accountID = account.ID
        fmt.Printf("Found: @%s (%s)\n", account.Acct, account.DisplayName)
    } else {
        accountID = mastodon.ID(input)
    }

    // Get status IDs
    fmt.Print("Enter status IDs (comma-separated, or press Enter to skip): ")
    statusInput, _ := reader.ReadString('\n')
    statusInput = strings.TrimSpace(statusInput)

    var statusIDs []mastodon.ID
    if statusInput != "" {
        ids := strings.Split(statusInput, ",")
        for _, id := range ids {
            statusIDs = append(statusIDs, mastodon.ID(strings.TrimSpace(id)))
        }
    }

    // Get reason
    fmt.Print("Enter reason for report: ")
    reason, _ := reader.ReadString('\n')
    reason = strings.TrimSpace(reason)

    if reason == "" {
        return fmt.Errorf("reason is required")
    }

    // Confirm
    fmt.Printf("\nReview Report:\n")
    fmt.Printf("  Account: %s\n", accountID)
    fmt.Printf("  Statuses: %d\n", len(statusIDs))
    fmt.Printf("  Reason: %s\n", reason)
    fmt.Print("\nFile this report? (yes/no): ")
    confirm, _ := reader.ReadString('\n')
    confirm = strings.TrimSpace(strings.ToLower(confirm))

    if confirm != "yes" && confirm != "y" {
        fmt.Println("Report cancelled")
        return nil
    }

    // File report
    report, err := client.Report(ctx, accountID, statusIDs, reason)
    if err != nil {
        return err
    }

    fmt.Printf("\n✓ Report filed successfully (ID: %s)\n", report.ID)
    return nil
}

Report Reasons

Common reasons for filing reports:

Spam

comment := "This account is posting unsolicited advertisements and spam links"

Harassment

comment := "This account is sending harassing messages and personal attacks"

Hate Speech

comment := "This account is posting hate speech and discriminatory content"

Impersonation

comment := "This account is impersonating another user or public figure"

Privacy Violation

comment := "This account is sharing private information without consent"

Illegal Content

comment := "This account is posting illegal or prohibited content"

Misinformation

comment := "This account is deliberately spreading false information"

Best Practices

1. Provide Clear Evidence

Include specific status IDs that violate rules:

// Good: Specific problematic statuses
statusIDs := []mastodon.ID{"123", "456", "789"}

// Less helpful: No evidence
statusIDs := []mastodon.ID{}

2. Write Detailed Comments

Explain the issue clearly for moderators:

// Good: Detailed explanation
comment := `This account is repeatedly posting spam links to external sites.
The pattern started 3 days ago with multiple posts per hour containing
identical links. The content appears to be commercial advertising that
violates the instance's spam policy.`

// Less helpful: Vague
comment := "spam"

3. Report Appropriately

Only report actual violations:

// Report actual violations
if isSpam || isHarassment || isHateSpeech {
    client.Report(ctx, accountID, statusIDs, reason)
}

// Don't report disagreements
// Use mute/block instead

4. Use Block/Mute First

For personal issues, use block or mute instead of reporting:

// For annoying but not rule-breaking content
client.AccountMute(ctx, accountID)

// For harassment or rule violations
client.Report(ctx, accountID, statusIDs, "Harassment: ...")

5. One Report Per Issue

Don't file multiple reports for the same issue:

// File once with all evidence
client.Report(ctx, accountID, allStatusIDs, detailedReason)

// Don't file multiple reports for same account

6. Follow Up Appropriately

Check status but don't spam moderators:

// Check after reasonable time
time.Sleep(24 * time.Hour)
checkReportStatus(client, reportID)

// Don't repeatedly check

Moderator Actions

After filing a report, moderators may:

  • Warning: Send warning to account owner
  • Silence: Hide account from public view
  • Suspension: Completely ban the account
  • No Action: Determine report doesn't warrant action

The ActionTaken field indicates whether moderators have processed the report, not necessarily that punitive action was taken.

Related Types

See also:

  • Accounts - For account blocking and muting
  • Statuses - For status information in reports
  • Types - For ID and other common types