# docs
- - [overview](#overview)
- - [quickstart](#quickstart)
- - [cloning](#cloning)
- - [webhooks](#webhooks)
- - [GitHub sync](#github-sync)
- - [v1 api](#v1-api)
## overview
Corigin gives agents a Git remote for generated code.
## quickstart
### install the CLI
npm install -g @corigin/cli### sign in from the terminal
corigin login### create a repo
corigin init hello-corigin### push with Git
echo "hello from corigin" > README.md
git add README.md
git commit -m "initial commit"
git push -u origin main## cloning
Use cloning when the Corigin repo already exists.
### clone from the dashboard
Open Repos, copy the Clone URL, or open Connect for the full clone command.
git clone <clone-url> <repo-name>### let an agent use the repo
git remote -vGive the agent the working directory and the existing origin remote. Agents should use the existing Git remote. They should not create a second source-control surface or ask for workspace API keys.
## webhooks
Repo webhooks deliver accepted Corigin pushes to a public HTTPS endpoint.
### configure a webhook
Open a repo in the dashboard, then create a webhook from the Webhook section.
The URL must be a public HTTPS URL with a domain name. IP literals, localhost, and .localhost hosts are rejected.
Corigin returns the signing secret only when the webhook is created or replaced. Store it when it is shown.
### delivery
Corigin sends one push request after an accepted push creates a repo push event.
{
"id": "77777777-7777-4777-8777-777777777777",
"type": "push",
"created_at": "2026-06-27T00:00:00.000Z",
"repo_id": "33333333-3333-4333-8333-333333333333",
"refs": [
{
"name": "refs/heads/main",
"before": null,
"after": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"force": false
}
]
}Requests include Corigin-Event-Id, Corigin-Event-Type, Corigin-Webhook-Timestamp, and Corigin-Webhook-Signature.
### verify the signature
The signature is HMAC SHA-256 over the timestamp, a period, and the raw request body.
import { createHmac, timingSafeEqual } from "node:crypto";
export function verifyCoriginWebhook(input: {
body: Buffer;
secret: string;
signatureHeader: string;
timestampHeader: string;
}) {
const expected = createHmac("sha256", input.secret)
.update(`${input.timestampHeader}.`)
.update(input.body)
.digest("hex");
const received = input.signatureHeader.replace(/^v1=/, "");
if (!/^[a-f0-9]{64}$/u.test(received)) return false;
return timingSafeEqual(Buffer.from(expected, "hex"), Buffer.from(received, "hex"));
}## GitHub sync
GitHub sync imports a GitHub repository into Corigin and keeps branch updates flowing into the Corigin remote.
### import from GitHub
Use Add GitHub sync in the dashboard. The setup flow installs or reuses the Corigin GitHub App, authorizes repository access, and returns to the dashboard with an import picker.
Choose one authorized repository. Corigin creates a repo, names it from the GitHub repository name, and stores the GitHub connection on the new Corigin repo.
### sync behavior
GitHub push webhooks for branch create and update events queue sync runs. Each connection syncs serially; independent connections can sync in parallel.
Branch deletes are ignored. If the GitHub App installation is removed, suspended, or loses access to a repository, Corigin disables the affected sync connection.
### disconnect
Open the Corigin repo, then use Disconnect in the GitHub section. Disconnecting removes the active sync connection for that Corigin repo; it does not delete the Corigin repo.
## [v1 api](https://api.corigin.dev)
### examples
npm install @corigin/sdkThe SDK provides typed V1 API calls for repo lifecycle, repo webhook configuration, and repo-scoped Git tokens.
import { createCorigin } from "@corigin/sdk";
const corigin = createCorigin({ apiKey: "<workspace-api-key>" });
const repo = await corigin.repos.create({ name: "hello-corigin" });
console.log(repo.remote_url);
await corigin.repos.webhooks.put(repo.id, {
url: "https://example.com/corigin/webhook",
});
const token = await corigin.repos.tokens.create({
repo_id: repo.id,
access: "write",
ttl_seconds: 3600,
});### OpenAPI spec
openapi: 3.1.0
info:
title: Corigin API
version: 0.1.0
summary: >-
API for agent-ready Git repos.
description: >-
Create Corigin repos, read repo metadata,
configure push webhooks, and issue short-lived Git tokens
for clone, fetch, and push.
servers:
- url: https://api.corigin.dev
paths:
/healthz:
get:
operationId: apiHealthz
summary: Check API health
security: []
responses:
"200":
description: API is healthy.
content:
text/plain:
schema:
type: string
const: ok
/v1/repos:
get:
operationId: listRepos
summary: List repos
security:
- WorkspaceApiKey: []
parameters:
- name: limit
in: query
required: false
schema:
type: integer
minimum: 1
maximum: 100
default: 100
- name: cursor
in: query
required: false
schema:
$ref: "#/components/schemas/RepoId"
responses:
"200":
description: Repos accessible with the API key.
content:
application/json:
schema:
$ref: "#/components/schemas/ListReposResponse"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
post:
operationId: createRepo
summary: Create a Git repo
description: >-
Create an empty Corigin repo and return its Git remote
URL. Repo names are metadata and may repeat.
security:
- WorkspaceApiKey: []
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreateRepoRequest"
responses:
"201":
description: Repo created.
content:
application/json:
schema:
$ref: "#/components/schemas/Repo"
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"409":
$ref: "#/components/responses/Conflict"
/v1/repos/{id}:
get:
operationId: getRepo
summary: Get repo metadata
security:
- WorkspaceApiKey: []
parameters:
- $ref: "#/components/parameters/RepoId"
responses:
"200":
description: Repo accessible with the API key.
content:
application/json:
schema:
$ref: "#/components/schemas/Repo"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
delete:
operationId: deleteRepo
summary: Delete a repo
description: >-
Delete the repo from future list results and prevent new
repo-scoped Git tokens from being issued. Existing repo
tokens remain valid until expiry.
security:
- WorkspaceApiKey: []
parameters:
- $ref: "#/components/parameters/RepoId"
responses:
"204":
description: Repo deleted.
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
/v1/repos/{id}/webhook:
get:
operationId: getRepoWebhook
summary: Get repo webhook
security:
- WorkspaceApiKey: []
parameters:
- $ref: "#/components/parameters/RepoId"
responses:
"200":
description: Repo webhook configuration.
content:
application/json:
schema:
$ref: "#/components/schemas/RepoWebhook"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
put:
operationId: putRepoWebhook
summary: Create or replace a repo webhook
security:
- WorkspaceApiKey: []
parameters:
- $ref: "#/components/parameters/RepoId"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PutRepoWebhookRequest"
responses:
"200":
description: >-
Repo webhook configuration with generated signing
secret.
content:
application/json:
schema:
$ref: "#/components/schemas/RepoWebhookWithSecret"
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
delete:
operationId: deleteRepoWebhook
summary: Delete a repo webhook
security:
- WorkspaceApiKey: []
parameters:
- $ref: "#/components/parameters/RepoId"
responses:
"204":
description: Repo webhook configuration deleted.
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
/v1/repos/token:
post:
operationId: createRepoToken
summary: Issue a repo-scoped Git token
description: >-
Issue a short-lived token for Git clone, fetch,
or push access to one repo. Deleted repos, revoked
API keys, and removed account access prevent new
tokens from being issued.
security:
- WorkspaceApiKey: []
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreateRepoTokenRequest"
responses:
"201":
description: Repo token created.
content:
application/json:
schema:
$ref: "#/components/schemas/CreateRepoTokenResponse"
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
components:
securitySchemes:
WorkspaceApiKey:
type: http
scheme: bearer
description: Corigin API key created in the dashboard.
parameters:
RepoId:
name: id
in: path
required: true
schema:
$ref: "#/components/schemas/RepoId"
responses:
BadRequest:
description: Invalid request.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
Unauthorized:
description: Missing or invalid credential.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
Forbidden:
description: Credential is valid but not authorized.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
NotFound:
description: Resource not found.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
Conflict:
description: Request conflicts with current account state.
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
schemas:
RepoId:
type: string
format: uuid
Timestamp:
type: string
format: date-time
RepoName:
type: string
minLength: 1
maxLength: 128
RemoteUrl:
type: string
description: Git remote URL returned by Corigin.
pattern: "^corigin://[0-9a-f-]{36}$"
example: "corigin://018f2f76-9a7b-7c2d-8a7e-0e36f7c8d002"
Repo:
type: object
additionalProperties: false
required:
- id
- name
- remote_url
- created_at
properties:
id:
$ref: "#/components/schemas/RepoId"
name:
$ref: "#/components/schemas/RepoName"
remote_url:
$ref: "#/components/schemas/RemoteUrl"
created_at:
$ref: "#/components/schemas/Timestamp"
ListReposResponse:
type: object
additionalProperties: false
required:
- next_cursor
- repos
properties:
next_cursor:
anyOf:
- $ref: "#/components/schemas/RepoId"
- type: "null"
repos:
type: array
items:
$ref: "#/components/schemas/Repo"
CreateRepoRequest:
type: object
additionalProperties: false
required:
- name
properties:
name:
$ref: "#/components/schemas/RepoName"
RepoWebhook:
type: object
additionalProperties: false
required:
- created_at
- updated_at
- url
properties:
created_at:
$ref: "#/components/schemas/Timestamp"
updated_at:
$ref: "#/components/schemas/Timestamp"
url:
type: string
format: uri
PutRepoWebhookRequest:
type: object
additionalProperties: false
required:
- url
properties:
url:
type: string
format: uri
RepoWebhookWithSecret:
type: object
additionalProperties: false
required:
- created_at
- updated_at
- url
- signing_secret
properties:
created_at:
$ref: "#/components/schemas/Timestamp"
updated_at:
$ref: "#/components/schemas/Timestamp"
url:
type: string
format: uri
signing_secret:
type: string
description: >-
Webhook HMAC signing secret returned only when the
webhook is created or replaced.
RepoTokenAccess:
type: string
enum:
- read
- write
CreateRepoTokenRequest:
type: object
additionalProperties: false
required:
- repo_id
- access
properties:
repo_id:
$ref: "#/components/schemas/RepoId"
access:
$ref: "#/components/schemas/RepoTokenAccess"
ttl_seconds:
type: integer
minimum: 60
maximum: 43200
default: 60
description: Token lifetime in seconds.
CreateRepoTokenResponse:
type: object
additionalProperties: false
required:
- token
- expires_at
properties:
token:
type: string
expires_at:
$ref: "#/components/schemas/Timestamp"
Error:
type: object
additionalProperties: false
required:
- code
- message
properties:
code:
type: string
enum:
- BadRequest
- missing_authorization
- invalid_api_key
- repo_not_found
- repo_deleted
- active_repo_limit_exceeded
- workspace_suspended
- upstream_failure
message:
type: string