> ## Documentation Index
> Fetch the complete documentation index at: https://docs.endorlabs.com/llms.txt
> Use this file to discover all available pages before exploring further.

# api

> Use the api command to interact with the Endor Labs API.

export const YamlTable = ({children, data: propData, content}) => {
  const KV_RE = /^([A-Za-z][A-Za-z0-9_()/#\s-]+?):\s*(.+)$/;
  const INLINE_MD_RE = /(\[([^\]]+)\]\(([^)]+)\))|(`([^`]+)`)|(\*\*([^*]+)\*\*)|(\*([^*]+)\*)/g;
  const YES_RE = /^-yes-$/i;
  const NO_RE = /^-no-$/i;
  const LIMITED_RE = /^-(limited|partial)-$/i;
  const NA_RE = /^-(na|none)-$/i;
  const NA2_RE = /^-na2-$/i;
  const SIMPLE_TAG_RE = /(<br\s*\/?>)|(<p\s*\/?>)|(-note-)|(-warning-)/gi;
  const tryParseKV = trimmed => {
    const m = KV_RE.exec(trimmed);
    return m ? {
      key: m[1],
      value: m[2].trim()
    } : null;
  };
  const registerKey = (key, seenKeys, orderedKeys) => {
    if (!seenKeys.has(key)) {
      orderedKeys.push(key);
      seenKeys.add(key);
    }
  };
  const flushEntry = (currentEntry, entries) => {
    if (Object.keys(currentEntry).length > 0) entries.push(currentEntry);
  };
  const parseDashPrefixed = (lines, entries, orderedKeys, seenKeys) => {
    let currentEntry = {};
    let inEntry = false;
    for (const line of lines) {
      const trimmed = line.trim();
      if (trimmed.startsWith('- ')) {
        if (inEntry) entries.push(currentEntry);
        currentEntry = {};
        inEntry = true;
        const kv = tryParseKV(trimmed.substring(2).trim());
        if (kv) {
          registerKey(kv.key, seenKeys, orderedKeys);
          currentEntry[kv.key] = kv.value;
        }
      } else if (inEntry && trimmed !== '') {
        const kv = tryParseKV(trimmed);
        if (kv) {
          registerKey(kv.key, seenKeys, orderedKeys);
          currentEntry[kv.key] = kv.value;
        }
      }
    }
    flushEntry(currentEntry, entries);
  };
  const parseBlankSeparated = (lines, entries, orderedKeys, seenKeys) => {
    let currentEntry = {};
    let inEntry = false;
    for (const line of lines) {
      const trimmed = line.trim();
      if (trimmed === '') {
        if (inEntry) {
          flushEntry(currentEntry, entries);
          currentEntry = {};
          inEntry = false;
        }
        continue;
      }
      const kv = tryParseKV(trimmed);
      if (!kv) continue;
      const isNewEntry = !line.startsWith(' ') && !line.startsWith('\t');
      if (isNewEntry && inEntry && Object.keys(currentEntry).length > 0) {
        entries.push(currentEntry);
        currentEntry = {};
      }
      registerKey(kv.key, seenKeys, orderedKeys);
      currentEntry[kv.key] = kv.value;
      inEntry = true;
    }
    flushEntry(currentEntry, entries);
  };
  const normalizeEntries = (entries, orderedKeys) => entries.map(entry => {
    const filled = {};
    for (const key of orderedKeys) filled[key] = entry[key] || '';
    return filled;
  });
  const parseYamlTableContent = contentStr => {
    if (!contentStr) return [];
    const entries = [];
    const orderedKeys = [];
    const seenKeys = new Set();
    const lines = contentStr.split('\n');
    if (lines.some(line => line.trim().startsWith('- '))) {
      parseDashPrefixed(lines, entries, orderedKeys, seenKeys);
    } else {
      parseBlankSeparated(lines, entries, orderedKeys, seenKeys);
    }
    return normalizeEntries(entries, orderedKeys);
  };
  const processText = text => {
    if (!text) return text;
    const parts = [];
    let keyIndex = 0;
    let lastIndex = 0;
    let match;
    while ((match = INLINE_MD_RE.exec(text)) !== null) {
      if (match.index > lastIndex) parts.push(text.slice(lastIndex, match.index));
      if (match[1]) {
        parts.push(<a key={keyIndex++} href={match[3]}>{match[2]}</a>);
      } else if (match[4]) {
        parts.push(<code key={keyIndex++}>{match[5]}</code>);
      } else if (match[6]) {
        parts.push(<strong key={keyIndex++}>{match[7]}</strong>);
      } else if (match[8]) {
        parts.push(<em key={keyIndex++}>{match[9]}</em>);
      }
      lastIndex = match.index + match[0].length;
    }
    if (lastIndex < text.length) parts.push(text.slice(lastIndex));
    if (parts.length === 0) return text;
    const keyRef = {
      current: keyIndex
    };
    return expandHtmlTags(parts, keyRef);
  };
  const processBadges = text => {
    if (!text || typeof text !== 'string') return text;
    if (YES_RE.test(text)) return <span className="yt-badge-yes" role="img" aria-label="Supported" title="Supported">✓</span>;
    if (NO_RE.test(text)) return <span className="yt-badge-no" role="img" aria-label="Not supported" title="Not supported">✗</span>;
    if (LIMITED_RE.test(text)) return <span className="yt-badge-limited" role="img" aria-label="Partially supported" title="Partially supported">◐</span>;
    if (NA_RE.test(text) || NA2_RE.test(text)) return <span className="yt-sr-only" title="Not applicable">Not applicable</span>;
    return processText(text);
  };
  const cellClassName = text => {
    if (!text || typeof text !== 'string') return undefined;
    if (NA_RE.test(text)) return 'yt-cell-na';
    if (NA2_RE.test(text)) return 'yt-cell-na2';
    return undefined;
  };
  const expandSimpleTags = (str, keyRef) => {
    const result = [];
    let last = 0;
    SIMPLE_TAG_RE.lastIndex = 0;
    let m;
    while ((m = SIMPLE_TAG_RE.exec(str)) !== null) {
      if (m.index > last) result.push(str.slice(last, m.index));
      if (m[1]) {
        result.push(<br key={keyRef.current++} />);
      } else if (m[2]) {
        result.push(<br key={keyRef.current++} />, <br key={keyRef.current++} />);
      } else if (m[3]) {
        result.push(<span key={keyRef.current++} className="yt-badge-note" style={{
          fontWeight: 600
        }}>Note: </span>);
      } else if (m[4]) {
        result.push(<span key={keyRef.current++} className="yt-badge-warning" style={{
          fontWeight: 600
        }}>Warning: </span>);
      }
      last = m.index + m[0].length;
    }
    if (last < str.length) result.push(str.slice(last));
    return result;
  };
  const expandHtmlTags = (chunks, keyRef) => {
    const out = [];
    for (const chunk of chunks) {
      if (typeof chunk === 'string') {
        out.push(...expandSimpleTags(chunk, keyRef));
      } else {
        out.push(chunk);
      }
    }
    return out;
  };
  const extractText = node => {
    if (node === null || node === undefined) return '';
    if (typeof node === 'string') return node;
    if (typeof node === 'number') return String(node);
    if (typeof node === 'boolean') return '';
    if (Array.isArray(node)) return node.map(extractText).join('');
    if (node && typeof node === 'object' && node.type) {
      const props = node.props || ({});
      if (typeof props.children === 'string') return props.children;
      if (props.children) return extractText(props.children);
      return '';
    }
    return String(node || '');
  };
  const [mounted, setMounted] = useState(false);
  useEffect(() => {
    setMounted(true);
  }, []);
  const data = useMemo(() => {
    if (propData) return propData;
    if (content && typeof content === 'string') return parseYamlTableContent(content);
    if (!children) return [];
    if (typeof children === 'string') return parseYamlTableContent(children);
    const childrenArray = Array.isArray(children) ? children : [children];
    return parseYamlTableContent(childrenArray.map(extractText).join('').trim());
  }, [children, propData, content]);
  const columns = useMemo(() => {
    if (!data || data.length === 0) return [];
    const firstRow = data[0];
    if (!firstRow || typeof firstRow !== 'object') return [];
    return Object.keys(firstRow);
  }, [data]);
  if (!mounted) return null;
  if (!data || data.length === 0) return null;
  const rowKey = row => columns.map(c => row[c] || '').join('|');
  return <table>
      <thead>
        <tr>
          {columns.map(col => <th key={col}>{col.replaceAll('_', ' ')}</th>)}
        </tr>
      </thead>
      <tbody>
        {data.map(row => <tr key={rowKey(row)}>
            {columns.map(col => <td key={col} className={cellClassName(row[col])}>{processBadges(row[col])}</td>)}
          </tr>)}
      </tbody>
    </table>;
};

The `endorctl api` command allows you to interact with the Endor Labs API directly through the command line interface.

## Usage

The syntax of the `endorctl api` command is:

```bash theme={null}
endorctl api [subcommand] [flags]
```

The `endorctl api` command supports the following subcommands:

* `create` creates a specified object in a namespace.
* `delete` deletes a specified object in a namespace.
* `get` gets a specified object in a namespace.
* `list` lists a specified group of objects in a namespace.
* `update` updates a specified object in a namespace.

### Flags and variables

The `endorctl api` subcommands support the following flags, unless specified otherwise:

<YamlTable>
  {`


    - Flag: \`d\`, \`data\`
    Environment_Variable: \`ENDOR_API_DATA\`
    Type: string
    Description: Define the object you want to create or update in json format.

    - Flag: \`field-mask\`
    Environment_Variable: \`ENDOR_API_FIELD_MASK\`
    Type: string
    Description: Specify a list of fields to return or update.

    - Flag: \`header\`
    Environment_Variable: \`ENDOR_API_HEADER\`
    Type: string
    Description: Specify request header information in the following format: \`key:value\`.

    - Flag: \`i\`, \`interactive\`
    Environment_Variable: \`ENDOR_API_INTERACTIVE\`
    Type: boolean
    Description: Create or update an object interactively. Requires you to set the \`EDITOR\` environment variable (for example, \`export EDITOR=vim\`).

    - Flag: \`name\`
    Environment_Variable: \`ENDOR_API_NAME\`
    Type: string
    Description: Specify the name of the resource that you want to interact with.

    - Flag: \`o\`, \`output-type\`
    Environment_Variable: \`ENDOR_API_OUTPUT_TYPE\`
    Type: string
    Description: Specify the output format of the response. The default output type is \`json\`, but you can also use \`yaml\` or \`table\`.

    - Flag: \`r\`, \`resource\`
    Environment_Variable: \`ENDOR_API_RESOURCE\`
    Type: string
    Description: Specify the resource type that you want to interact with. See [commonly used resource types](#commonly-used-resource-types) below for a list of supported resource types.

    - Flag: \`t\`, \`timeout\`
    Environment_Variable: \`ENDOR_API_TIMEOUT\`
    Type: string
    Description: Set the timeout limit for the command. The default is \`20s\`, but larger or more complex requests might need additional time, which might lead to a "context deadline exceeded" error.

    - Flag: \`uuid\`
    Environment_Variable: \`ENDOR_API_UUID\`
    Type: string
    Description: Specify the UUID of the resource that you want to interact with.


    `}
</YamlTable>

### Commonly used resource types

The following table lists resource types that are commonly used in the API. See [resource kind](/developers-api/rest-api/using-the-rest-api/data-model/resource-kinds) for more information.

<Note>
  Resource kinds are case sensitive.
</Note>

<YamlTable>
  {`


    - Resource_Kind: \`Project\`
    Description: A project represents a configuration for ingesting source control repositories. List all projects by calling \`endorctl api list -r Project\`.

    - Resource_Kind: \`Repository\`
    Description: A repository represents information about a source control repository that hosts source code. List all repositories for a project by filtering on \`meta.parent_uuid==<project-uuid>\`.

    - Resource_Kind: \`RepositoryVersion\`
    Description: A repository version represents information about a specific version of code in source control, such as commit SHAs, tags or branches. List all repository versions for a project by filtering on \`meta.parent_uuid==<project-uuid>\`.

    - Resource_Kind: \`PackageVersion\`
    Description: A package version represents information about a named version of a package. List all package versions for a project by filtering on \`spec.project_uuid==<project-uuid>\`.

    - Resource_Kind: \`DependencyMetadata\`
    Description: A dependency metadata object represents the relationship between the root package version (importer) and a given dependency. List all dependency metadata objects for a project by filtering on \`spec.importer_data.project_uuid==<project-uuid>\`.

    - Resource_Kind: \`Metric\`
    Description: A metric object contains the output of a given analytic. List all metric objects for a project by filtering on \`spec.project_uuid==<project-uuid>\`.

    - Resource_Kind: \`Finding\`
    Description: A finding represents a result of an evaluation method used to evaluate code against a rule. List all findings for a project by filtering on \`spec.project_uuid==<project-uuid>\`.

    - Resource_Kind: \`ScanResult\`
    Description: A scan result contains metadata about a particular scan (like configuration and results). List all scan results for a project by filtering on \`meta.parent_uuid==<project-uuid>\`.

    - Resource_Kind: \`AuthorizationPolicy\`
    Description: An authorization policy represents a policy for access control. List all authorization policies by calling \`endorctl api list -r AuthorizationPolicy\`.


    `}
</YamlTable>

## endorctl api create

The `endorctl api create` command creates an object of a specified resource type.

```shell theme={null}
endorctl api create -r [resource] [flags]
```

### endorctl api create interactive mode

* Use `--interactive` or `-i` to create an object with an interactive code editor.
  * Define your editor using `export EDITOR=<editor>` where the editor is the command you use to edit files. For example, `export EDITOR=vi` allows you to edit in vi and `export EDITOR=code` opens the file with the code command in VS Code.

### endorctl api create examples

To create a package manager integration that uses the repository `https://example.replaceme.com` for dependency resolution in Python with the top priority for dependency resolution use the following command.

```shell theme={null}
endorctl api create -r PackageManager \
    --data '{"meta":{"name":"pypi PackageManager"},"spec":{"pypi":{"url":"https://example.replaceme.com ","priority":0}}}'
```

## endorctl api delete

The `endorctl api delete` command deletes a given object of a specified resource type.

```shell theme={null}
endorctl api delete -r [resource] [flags]
```

### endorctl api delete example

Use the following command to delete the project with the UUID, '62aa1cfadfa47d9ccb754d22', that is no longer needed.

```shell theme={null}
endorctl api delete -r Project --uuid 62aa1cfadfa47d9ccb754d22
```

## endorctl api get

The `endorctl api get` command retrieves a given object of a specified resource type.

```shell theme={null}
endorctl api get -r [resource] [flags]
```

### endorctl api get examples

* Get a specific project by its UUID.

```shell theme={null}
endorctl api get -r Project --uuid <UUID>
```

* Get a specific package version.

```bash theme={null}
endorctl api get --resource "PackageVersion" --name "<ecosystem>://<name>@<version>"
```

## endorctl api list

The `endorctl api list` command lists all objects of a specified resource type, based on the specified filters, field-masks and/or other options.

```shell theme={null}
endorctl api list -r [resource] [flags]
```

### endorctl api list flags and variables

The `endorctl api list` command supports the following additional flags and environment variables:

<YamlTable>
  {`


    - Flag: \`archive\`
    Environment_Variable: \`ENDOR_API_ARCHIVE\`
    Type: boolean
    Description: Fetch resources from the archive.

    - Flag: \`count\`
    Environment_Variable: \`ENDOR_API_COUNT\`
    Type: boolean
    Description: Get the number of items in the list.

    - Flag: \`f\`, \`filter\`
    Environment_Variable: \`ENDOR_API_FILTER\`
    Type: json
    Description: Specify query parameters used to filter resources.

    - Flag: \`group-aggregation-paths\`
    Environment_Variable: \`ENDOR_API_GROUP_AGGREGATION_PATHS\`
    Type: json
    Description: Specify one or more fields to group resources by.

    - Flag: \`group-show-aggregation-uuids\`
    Environment_Variable: \`ENDOR_API_GROUP_SHOW_AGGREGATION_UUIDS\`
    Type: boolean
    Description: Get the UUIDs of the resources in each group as specified by \`--group-aggregation-paths\`.

    - Flag: \`group-unique-count-paths\`
    Environment_Variable: \`ENDOR_API_GROUP_UNIQUE_COUNT_PATHS\`
    Type: json
    Description: Count the number of unique values, for these fields, in the group.

    - Flag: \`group-unique-value-paths\`
    Environment_Variable: \`ENDOR_API_GROUP_UNIQUE_VALUE_PATHS\`
    Type: json
    Description: Get the unique values, for these fields, in the group.

    - Flag: \`list-all\`
    Environment_Variable: \`ENDOR_API_LIST_ALL\`
    Type: boolean
    Description: List all resources (use \`-t\`or \`--timeout\` to increase timeout for big queries).

    - Flag: \`page-id\`
    Environment_Variable: \`ENDOR_API_PAGE_ID\`
    Type: string
    Description: Set the page ID to start from.

    - Flag: \`page-size\`
    Environment_Variable: \`ENDOR_API_PAGE_SIZE\`
    Type: integer
    Description: Set the page size to limit the number of results returned (default is 100).

    - Flag: \`page-token\`
    Environment_Variable: \`ENDOR_API_PAGE_TOKEN\`
    Type: string
    Description: Set the page token to start from.

    - Flag: \`pr-uuid\`
    Environment_Variable: \`ENDOR_API_PR_UUID\`
    Type: string (UUID format)
    Description: Only list resources from a specific PR scan.

    - Flag: \`sort-order\`
    Environment_Variable: \`ENDOR_API_SORT_ORDER\`
    Type: string
    Description: Sort resources in the specified order, ascending or descending (default ascending).

    - Flag: \`sort-path\`
    Environment_Variable: \`ENDOR_API_SORT_PATH\`
    Type: string
    Description: Specify a field to sort resources by.

    - Flag: \`traverse\`
    Environment_Variable: \`ENDOR_API_TRAVERSE\`
    Type: boolean
    Description: Get data from any child namespaces as well.


    `}
</YamlTable>

### endorctl api list examples

Use the `--filter` flag to customize your query and the `--field-mask` flag to limit the fields returned.
For example, run the following command to list the description and the target dependency name for all findings in a given project.

```shell theme={null}
endorctl api list \
  --resource Finding \
  --filter "spec.project_uuid==<uuid>" \
  --field-mask "meta.description,spec.target_dependency_package_name"
```

See [Filters](/developers-api/rest-api/using-the-rest-api/filters) and [Masks](/developers-api/rest-api/using-the-rest-api/masks) for more information on filters and field-masks.

Get a count of the number of projects hosted in your Endor Labs tenant.

```bash theme={null}
endorctl api list \
  --resource Project \
  --count \
  | jq -r '.count_response.count'
```

List all projects in the namespace and only return the name of each project.

```shell theme={null}
endorctl api list \
  --resource Project \
  --list-all \
  --field-mask meta.name \
  | jq '.list.objects[].meta.name'
```

List all package versions at a given source code Git reference.

```bash theme={null}
endorctl api list \
  --resource "PackageVersion" \
  --output-type "yaml" \
  --filter "spec.project_uuid==<uuid> and spec.source_code_reference.version.ref==<git-reference>"
```

List all direct dependencies of a specific package given its UUID.

```bash theme={null}
endorctl api list \
  --resource DependencyMetadata \
  --filter "spec.importer_data.package_version_uuid==<UUID> and spec.dependency_data.direct==true"
```

Return a count of findings associated with the default branch for a given project.

```shell theme={null}
endorctl api list \
  --resource Finding \
  --filter "context.type==CONTEXT_TYPE_MAIN and spec.project_uuid==<project-uuid>" \
  --count
```

Return a count of unique vulnerabilities in non-test dependencies for a given project. Filters to vulnerabilities with an upstream patch available and a reachable function.

```shell theme={null}
endorctl api list \
  --resource Finding \
  --filter "context.type==CONTEXT_TYPE_MAIN and spec.project_uuid==<project-uuid> and spec.finding_categories contains [FINDING_CATEGORY_VULNERABILITY] and spec.finding_tags contains [FINDING_TAGS_NORMAL] and spec.finding_tags contains [FINDING_TAGS_REACHABLE_FUNCTION] and spec.finding_tags contains [FINDING_TAGS_FIX_AVAILABLE]" \
  --group-aggregation-paths "spec.finding_metadata.vulnerability.meta.name"
```

Return the count of the number of scans run on the default branch since a given date.

```shell theme={null}
endorctl api list \
  --resource ScanResult \
  --filter "context.id==default and meta.create_time >= date(2023-11-14)" \
  --count
```

See [Use cases](/developers-api/rest-api/using-the-rest-api/use-cases) for more examples.

## endorctl api update

```shell theme={null}
endorctl api update -r [resource] [flags]
```

### endorctl api update interactive mode

* Use `--interactive` or `-i` to update an object with an interactive code editor.
  * Define your editor using `export EDITOR=<editor>` where the editor is the command you use to edit files. For example, `export EDITOR=vi` allows you to edit in vi and `export EDITOR=code` opens the file with the code command in VS Code.
  * Specify which fields you want to update using the `--field-mask` parameter. If this is not set, endorctl will try to update all fields.

### endorctl api update examples

To interactively update a project with the UUID 6549886f0dd828140b4a477b.

```shell theme={null}
endorctl api update -r Project -i --uuid 6549886f0dd828140b4a477b --field-mask meta.tags
```

To add a tag "CrownJewel" to a project named [https://github.com/endorlabs/github-action](https://github.com/endorlabs/github-action) use the following command.

```shell theme={null}
endorctl api update -r Project \
  --name https://github.com/endorlabs/github-action \
  --data "{ \"meta\": {\"tags\": [ \"CrownJewel\" ] }}" \
  --field-mask 'meta.tags'
```
