Skip to main content
GET
/
organization
/
reports
List organization reports
curl --request GET \
  --url https://app.chainpatrol.io/api/v2/organization/reports \
  --header 'X-API-KEY: <api-key>'
{
  "reports": [
    {
      "id": 123,
      "title": "<string>",
      "description": "<string>",
      "status": "TODO",
      "createdAt": "<string>",
      "updatedAt": "<string>",
      "attachments": [
        {
          "id": 123,
          "url": "<string>"
        }
      ],
      "proposals": [
        {
          "reviewStatus": "PENDING",
          "asset": {
            "id": 123,
            "type": "URL",
            "content": "<string>",
            "status": "UNKNOWN",
            "scans": [
              {
                "id": 123,
                "status": "PENDING",
                "createdAt": "<string>",
                "enrichments": [
                  {
                    "id": 123,
                    "type": "<string>",
                    "status": "<string>",
                    "output": "<unknown>"
                  }
                ],
                "output": "<unknown>"
              }
            ]
          }
        }
      ],
      "reporter": {
        "id": 123,
        "role": "SUPERUSER",
        "fullName": "<string>",
        "avatarUrl": "<string>"
      },
      "externalReporter": {
        "id": 123,
        "displayName": "<string>",
        "avatarUrl": "<string>",
        "platform": "<string>"
      }
    }
  ],
  "nextCursor": 123
}

Overview

Retrieve security reports for your organization. This endpoint returns all reports submitted for your organization, including details about reported assets, proposals, and their current status. The organization is automatically inferred from your API key.

Quick Start

Authentication

Include your API key in the X-API-KEY header:
X-API-KEY: your_api_key_here

Example Request

const response = await fetch(
  "https://app.chainpatrol.io/api/v2/organization/reports?limit=50",
  {
    method: "GET",
    headers: {
      "X-API-KEY": "YOUR_API_KEY_HERE",
    },
  }
);

const data = await response.json();
console.log(data.reports);

Query Parameters

ParameterTypeRequiredDescription
limitnumberNoNumber of reports to return per page (1-100, default: 50)
cursorstringNoCursor for pagination. Pass the cursor from the previous response to get the next page.
startDatestringNoFilter reports created after this date (ISO 8601 format)
endDatestringNoFilter reports created before this date (ISO 8601 format)
onlyRejectedbooleanNoIf true, only return reports with rejected proposals (default: false)

Response

Success Response

{
  "reports": [
    {
      "id": "rpt_1234567890abcdef",
      "createdAt": "2024-01-15T10:30:00.000Z",
      "status": "APPROVED",
      "assets": [
        {
          "id": 12345,
          "content": "https://scam-site.com",
          "type": "URL",
          "status": "BLOCKED"
        }
      ],
      "proposals": [
        {
          "id": "prop_abc123",
          "status": "APPROVED",
          "reason": "phishing",
          "createdAt": "2024-01-15T10:30:00.000Z"
        }
      ]
    }
  ],
  "cursor": "next_page_cursor_string"
}

Response Fields

FieldTypeDescription
reportsarrayArray of report objects for your organization
reports[].idstringUnique identifier for the report
reports[].createdAtstringISO 8601 timestamp when the report was created
reports[].statusstringOverall status of the report (PENDING, APPROVED, REJECTED)
reports[].assetsarrayArray of assets included in the report
reports[].proposalsarrayArray of proposals associated with the report
cursorstringCursor for the next page of results (undefined if no more results)

Pagination

Use the cursor-based pagination to fetch all reports:
async function fetchAllReports() {
  let allReports = [];
  let cursor: string | undefined = undefined;

  while (true) {
    const params = new URLSearchParams({
      limit: "100",
      ...(cursor && { cursor }),
    });

    const response = await fetch(
      `https://app.chainpatrol.io/api/v2/organization/reports?${params}`,
      {
        method: "GET",
        headers: {
          "X-API-KEY": "YOUR_API_KEY_HERE",
        },
      }
    );

    const data = await response.json();
    allReports = allReports.concat(data.reports);
    cursor = data.cursor;

    if (!cursor) {
      break;
    }
  }

  return allReports;
}

fetchAllReports()
  .then((reports) => console.log(`Total reports: ${reports.length}`))
  .catch((error) => console.error("Error:", error));

Filtering Examples

Filter by Date Range

Get reports from a specific time period:
curl -X GET 'https://app.chainpatrol.io/api/v2/organization/reports?startDate=2024-01-01T00:00:00Z&endDate=2024-03-31T23:59:59Z' \
  -H 'X-API-KEY: YOUR_API_KEY_HERE'

Filter Only Rejected Reports

Get reports that have rejected proposals:
curl -X GET 'https://app.chainpatrol.io/api/v2/organization/reports?onlyRejected=true' \
  -H 'X-API-KEY: YOUR_API_KEY_HERE'

Combine Filters

Get rejected reports from a specific date range:
curl -X GET 'https://app.chainpatrol.io/api/v2/organization/reports?startDate=2024-01-01T00:00:00Z&endDate=2024-03-31T23:59:59Z&onlyRejected=true&limit=100' \
  -H 'X-API-KEY: YOUR_API_KEY_HERE'

Error Responses

401 Unauthorized

Returned when the API key is missing, invalid, or doesn’t have organization access:
{
  "error": {
    "code": "UNAUTHORIZED",
    "message": "API key with organization access required"
  }
}

400 Bad Request

Returned when query parameters are invalid:
{
  "error": {
    "code": "BAD_REQUEST",
    "message": "Invalid date format. Use ISO 8601 format."
  }
}

Use Cases

Monitor Recent Reports

async function getRecentReports(days: number = 7) {
  const startDate = new Date();
  startDate.setDate(startDate.getDate() - days);

  const response = await fetch(
    `https://app.chainpatrol.io/api/v2/organization/reports?startDate=${startDate.toISOString()}&limit=100`,
    {
      headers: { "X-API-KEY": "YOUR_API_KEY_HERE" },
    }
  );

  const { reports } = await response.json();
  console.log(`Found ${reports.length} reports in the last ${days} days`);
  return reports;
}

Track Rejected Reports

async function analyzeRejectedReports() {
  const response = await fetch(
    "https://app.chainpatrol.io/api/v2/organization/reports?onlyRejected=true",
    {
      headers: { "X-API-KEY": "YOUR_API_KEY_HERE" },
    }
  );

  const { reports } = await response.json();

  // Analyze rejection reasons
  const rejectionReasons = reports.flatMap((report) =>
    report.proposals
      .filter((p) => p.status === "REJECTED")
      .map((p) => p.rejectionReason)
  );

  console.log("Common rejection reasons:", rejectionReasons);
  return rejectionReasons;
}

Export Reports to CSV

async function exportReportsToCSV(startDate: string, endDate: string) {
  const response = await fetch(
    `https://app.chainpatrol.io/api/v2/organization/reports?startDate=${startDate}&endDate=${endDate}&limit=100`,
    {
      headers: { "X-API-KEY": "YOUR_API_KEY_HERE" },
    }
  );

  const { reports } = await response.json();

  const csvHeader = "Report ID,Created At,Status,Assets,Proposals\n";
  const csvRows = reports
    .map(
      (r) =>
        `${r.id},${r.createdAt},${r.status},${r.assets.length},${r.proposals.length}`
    )
    .join("\n");

  const csv = csvHeader + csvRows;

  // Save or return CSV
  return csv;
}

Best Practices

Pagination

  • Use limit=100 for bulk data retrieval to minimize API calls
  • Always check for the cursor field to determine if more results exist
  • Store the cursor if you need to resume pagination later

Date Filtering

  • Always use ISO 8601 format for dates: YYYY-MM-DDTHH:mm:ss.sssZ
  • Include timezone information (typically UTC with Z suffix)
  • Use both startDate and endDate for precise time ranges

Performance

  • Cache report data when appropriate to reduce API calls
  • Use date filters to limit the result set size
  • Consider polling intervals if monitoring for new reports (5-10 minutes recommended)

Notes

  • Organization is automatically determined from your API key
  • All timestamps are in ISO 8601 format with UTC timezone
  • The onlyRejected filter shows reports with at least one rejected proposal, but the report may contain other approved proposals
  • Reports are ordered by creation date (newest first)
  • The cursor is opaque and should not be parsed or modified

Authorizations

X-API-KEY
string
header
required

Your API key. This is required by most endpoints to access our API programatically. Reach out to us at support@chainpatrol.io to get an API key for your use.

Query Parameters

limit
number
required
Required range: 1 <= x <= 20
cursor
number | null
status
enum<string>
Available options:
TODO,
IN_PROGRESS,
CLOSED
searchQuery
string
reporterQuery
string
excludeAutomation
boolean
default:false
onlyRejected
boolean
default:false
startDate
string
endDate
string

Response

Successful response

reports
object[]
required
nextCursor
number | null
required