Create a bot
Bots are owned by an organization, not a personal account. Org admins
create them under Organization settings → Developer
(/settings/organizations/{org}/developer).
A bot is what users install. Comments and checks show as @your-slug[bot].
Create the listing
Organization settings → Developer → New bot. You will be asked for:
| Field | What to put |
|---|---|
| Name | Product name people already know. Cannot match a verified, published bot. |
| Slug | Permanent handle. Becomes @slug[bot] and /integrations/your-org/slug. 2–39 characters; lowercase letters, numbers, and hyphens. |
| Description | Short pitch on the marketplace card |
| Homepage URL | Your marketing site (optional) |
| Setup URL | Where the browser goes after install (installation_id is set on the query) |
| Redirect URI | OAuth callback after Sign in with open-git. Leave blank to use the Setup URL. |
| Webhook URL | HTTPS endpoint that receives signed events (optional until you are ready) |
| Webhook events | Installation events are always sent. Optionally subscribe to pull-request events. |
| Marketplace visibility | Unlisted (link only) or public (marketplace index, after you are verified) |
| Permissions | What the bot may do on each installed repo |
| One install + Sign in | Off until you opt in. Requires a linked OAuth app (Setup URL, Redirect URI, or an existing client). Combined marketplace consent for bot access and Sign in with open-git. |
On create you get, once:
- An install private key — you sign a short JWT with this to mint API tokens
- A webhook secret — 64 hex characters; you verify
X-Hub-Signature-256with this - An OAuth client id and secret — only if you set a Setup URL or Redirect URI
Save them. Rotate from the bot page if you lose them. Rotating the install key immediately revokes outstanding installation tokens.
The create-bot dump:
# Store these now. They are not shown again.
OPEN_GIT_URL=https://open-git.com
OPEN_GIT_BOT_ID=8f3c…
OPEN_GIT_BOT_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n…\n-----END PRIVATE KEY-----"
OPEN_GIT_BOT_WEBHOOK_SECRET=…
OPEN_GIT_OAUTH_CLIENT_ID=…
OPEN_GIT_OAUTH_CLIENT_SECRET=…
const config = {
openGitUrl: process.env.OPEN_GIT_URL ?? "https://open-git.com",
botId: process.env.OPEN_GIT_BOT_ID!,
privateKey: process.env.OPEN_GIT_BOT_PRIVATE_KEY!.replace(/\\n/g, "\n"),
webhookSecret: process.env.OPEN_GIT_BOT_WEBHOOK_SECRET!,
oauthClientId: process.env.OPEN_GIT_OAUTH_CLIENT_ID!,
oauthClientSecret: process.env.OPEN_GIT_OAUTH_CLIENT_SECRET!,
}
Setup URL, redirect URI, and webhook URL
Setup URL is a browser redirect. After install, if this URL is a valid
absolute URL, the installer is sent there with installation_id set on the
query. Localhost is fine for development (http://localhost:4010/connect).
If you omit it, or it cannot be parsed, they land on Settings → Connections
instead.
Redirect URI is the OAuth callback. After the user consents, we send
them here with code and state. Leave it blank on the bot form to use
the Setup URL. Localhost is fine for development
(http://localhost:4010/connect or a separate /oauth/callback path).
Your app must send this exact URL as redirect_uri.
Webhook URL is server-to-server. It must be public HTTPS — not localhost,
*.localhost, 0.0.0.0, or a private IP literal. We do not follow redirects
(a 3xx response is a failed delivery). It is never used as an OAuth redirect
URI. See Webhooks.
You can add a Setup URL or Redirect URI later. Either one creates a linked OAuth app, unless you attach an OAuth app you already created. The registered callback is the Redirect URI if you set one, otherwise the Setup URL. Changing it adds the new URL to that client’s redirect list without removing other callbacks. Clearing both disables the linked client (Sign in with open-git for that client stops). Saving an unpublished bot does not create or re-enable a linked client.
Register https://your-app.com/connect as the Setup URL. After install we
send the browser to:
https://your-app.com/connect?installation_id=0c1a-…
If the Setup URL already has a query string, installation_id is added to it.
app.get("/connect", async (req, res) => {
const installationId =
typeof req.query.installation_id === "string"
? req.query.installation_id
: null
// beginSignIn is in the Sign in with open-git guide
res.redirect(await beginSignIn({ installationId }))
})
Permissions you can request
Users see this list before they install. You cannot ask for git push.
| Permission | Label | Your bot can |
|---|---|---|
metadata:read |
Read repository metadata | Name, visibility, and default branch. Always included. |
pull_requests:read |
List and read pull requests | Titles, bodies, and head SHAs |
pull_request.comments |
Comment on pull requests | Write comments as @slug[bot] |
pull_request.reviews |
Submit pull request reviews | Approve, comment, or request changes as the bot |
checks:write |
Create and update commit checks | Post merge-gate checks on commits |
A review bot usually wants checks:write and pull_request.comments.
Changing the permission set (add or remove) revokes outstanding installation tokens. Mint again on the next webhook. Rotating the install private key also revokes every token.
Who can find you
| Visibility | Who sees the listing |
|---|---|
| Unlisted | Anyone with the link. On /integrations only for people in the publishing org, so you can test install before going public. |
| Public | On /integrations for everyone when the bot is published and the publisher is verified. Until then, same as unlisted. |
Share /integrations/your-org/your-slug for private betas. That URL works
while the bot is still published, including unverified and unlisted bots. It
404s if the bot is unpublished or the owner/slug do not match.
Slugs are unique across open-git. Names such as coderabbit are reserved
until you verify. You also cannot pick a display name that matches a
verified, published bot.
Verify the publisher
On the bot’s Verification page, request a token and publish a DNS TXT record:
open-git-verify=the-token-we-show-you
Then check the domain. That sets verification to domain. Verified public
listings can appear on /integrations. Staff can also verify from
/admin/bots without DNS — that sets verification to staff, lists the
bot publicly, and marks it featured (sorts those cards first). Featured
is not a publisher control. The bot must already be published. Unverify
clears featured and sets visibility back to unlisted.
Next
- Wire Sign in with open-git on the Setup URL
- Handle webhooks
- Call the API when a pull request opens