# Git Sync

When using the [Detection Rules as Code](/scanner/using-scanner-complete-feature-reference/detections-and-alerting/detection-rules/detection-rules-as-code.md) feature, you can use the API to drive detection rule syncs from your own tooling — either to trigger a GitHub-polled sync immediately (e.g. on commit) or to push a repository / individual rule to a user-pushed sync source.

## Trigger a GitHub-polled sync

<mark style="color:green;">**`POST`**</mark> `/v1/sync_github_repositories`

Trigger an immediate sync for the tenant's GitHub-polled sync sources. Syncs run automatically every 5 minutes; use this endpoint to sync sooner (e.g. immediately after a commit lands).

**Body**

<table><thead><tr><th>Name</th><th width="192.8828125">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>tenant_id</code> <mark style="color:red;">required</mark></td><td>string</td><td>Unique identifier for the tenant</td></tr></tbody></table>

**Example**

```bash
curl $API_BASE/v1/sync_github_repositories \
-H "Authorization: Bearer $SCANNER_API_KEY" \
-H "Content-Type: application/json" \
-X POST \
-d '{ "tenant_id": "00000000-0000-0000-0000-000000000000" }'
```

**Response**

Returns the `tenant_id`.

```bash
{ "tenant_id": "00000000-0000-0000-0000-000000000000" }
```

## Upload a repository zipball

<mark style="color:green;">**`POST`**</mark> `/v1/upload_git_repo_zipball`

Upload a zip archive of a repository to a [user-pushed sync source](/scanner/using-scanner-complete-feature-reference/detections-and-alerting/detection-rules/detection-rules-as-code/getting-started.md#set-up-user-pushed-sync). The server runs the same validate / test / materialize pipeline as a GitHub-polled sync, so a successful upload fully reconciles the sync source against the contents of the zip (including deleting rules whose YAML has been removed).

{% hint style="warning" %}
This is the endpoint [`scanner-cli sync-git-repo`](/scanner/using-scanner-complete-feature-reference/detections-and-alerting/detection-rules/detection-rules-as-code/cli.md#sync-an-entire-repository-sync-git-repo) calls. Most users should use the CLI (or the [`scanner-inc/sync-detection-rules`](https://github.com/scanner-inc/sync-detection-rules) GitHub Action that wraps it) rather than hitting the endpoint directly — the CLI handles zipping the working tree, deriving the branch / commit SHA / commit message, and surfacing per-file failures for you.
{% endhint %}

**Body**

`multipart/form-data` with the following fields:

<table><thead><tr><th width="220">Name</th><th width="120">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>push_key</code> <mark style="color:red;">required</mark></td><td>string</td><td>Per-tenant identifier of the push sync source. Set by you when you add a push sync source under <strong>Detections > Synced Repositories</strong>.</td></tr><tr><td><code>branch</code> <mark style="color:red;">required</mark></td><td>string</td><td>Branch the uploaded zip corresponds to. <code>(push_key, branch)</code> picks exactly one sync source row.</td></tr><tr><td><code>commit_sha</code> <mark style="color:red;">required</mark></td><td>string</td><td>Arbitrary revision identifier (typically <code>git rev-parse HEAD</code>, optionally with a <code>+dirty</code> suffix). Stored verbatim on the resulting sync attempt.</td></tr><tr><td><code>commit_message</code></td><td>string</td><td>Optional commit message to store alongside the SHA, e.g. the first line of <code>git log -1 --pretty=%B</code>. Absent or empty falls back to a synthetic <code>pushed at &#x3C;ts></code> placeholder.</td></tr><tr><td><code>zip</code> <mark style="color:red;">required</mark></td><td>file (binary)</td><td>Raw zip archive of the repository at the specified revision, in the same layout that GitHub's <a href="https://docs.github.com/en/rest/repos/contents#download-a-repository-archive-zip">zipball archive endpoint</a> produces.</td></tr></tbody></table>

**Example**

```bash
curl "$API_BASE/v1/upload_git_repo_zipball" \
-H "Authorization: Bearer $SCANNER_API_KEY" \
-X POST \
-F "push_key=my-rules-repo" \
-F "branch=main" \
-F "commit_sha=$(git rev-parse HEAD)" \
-F "commit_message=$(git log -1 --pretty=%B)" \
-F "zip=@repo.zip;type=application/zip"
```

**Response**

Returns counts of rules synced, failures, and warnings. If `failures` is non-empty, no rules from the upload were synced (`detection_rules_synced` and `detection_rules_deleted` are both `0`).

```json
{
  "detection_rules_synced": 12,
  "detection_rules_deleted": 1,
  "failures": [],
  "warnings": []
}
```

## Upsert a single rule by push key

<mark style="color:green;">**`POST`**</mark> `/v1/detection_rule_yaml/upsert_by_push_key`

Create or update a single detection rule on a [user-pushed sync source](/scanner/using-scanner-complete-feature-reference/detections-and-alerting/detection-rules/detection-rules-as-code/getting-started.md#set-up-user-pushed-sync), keyed by the `push_key` (or legacy `sync_key`) declared in the rule's YAML.

{% hint style="warning" %}
This is the endpoint [`scanner-cli sync`](/scanner/using-scanner-complete-feature-reference/detections-and-alerting/detection-rules/detection-rules-as-code/cli.md#sync-individual-rules-sync) calls per file. Most users should use the CLI rather than hitting the endpoint directly.

For normal flows, prefer `/v1/upload_git_repo_zipball` (or [GitHub-polled sync](/scanner/using-scanner-complete-feature-reference/detections-and-alerting/detection-rules/detection-rules-as-code/getting-started.md#set-up-github-polled-sync)): both reconcile the whole set of rules in a sync source on every run. This endpoint only creates and updates rules — it has no way to delete a rule that's been removed from the repo — and shouldn't be mixed with the repo-level flows on the same rules.
{% endhint %}

**Body**

<table><thead><tr><th width="220">Name</th><th width="120">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>rule_yaml</code> <mark style="color:red;">required</mark></td><td>string</td><td>Single detection rule YAML. Must declare a <code>push_key</code> (or legacy <code>sync_key</code>) at the top level; that key identifies the rule within its tenant for upsert lookup. See the <a href="https://scanner.dev/schema/scanner-detection-rule.v1.json">detection rule schema</a>.</td></tr><tr><td><code>sync_config_yaml</code> <mark style="color:red;">required</mark></td><td>string</td><td>Per-repo sync config YAML providing the <code>event_sink_keys → event_sink_ids</code> map used to resolve the rule's <code>event_sink_keys</code>. Pass an empty string (<code>""</code>) or a YAML doc with no <code>event_sink_keys</code> field if the rule has no event sinks.</td></tr></tbody></table>

**Example**

```bash
curl $API_BASE/v1/detection_rule_yaml/upsert_by_push_key \
-H "Authorization: Bearer $SCANNER_API_KEY" \
-H "Content-Type: application/json" \
-X POST \
-d '{
    "rule_yaml": "# schema: https://scanner.dev/schema/scanner-detection-rule.v1.json\nname: ...\npush_key: my-rule\n...",
    "sync_config_yaml": "event_sink_keys:\n  low_severity_alerts:\n    - sink_id: \"00000000-0000-0000-0000-000000000000\"\n"
}'
```

**Response**

Returns the upserted detection rule and whether it was newly created.

```json
{
  "detection_rule": {
    "id": "d87284f8-b0f3-4464-9ba9-258c0e585d09",
    "...": "..."
  },
  "created": true
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.scanner.dev/scanner/using-scanner-complete-feature-reference/developer-tools/api/git-sync.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
