# GET /v1/github/installation/install-url (/docs/api/reference/github/install-url)



<Endpoint method="GET" path="/v1/github/installation/install-url" auth="Bearer" scope="github:admin" phase="1" />

Returns a one-time URL that, when opened in the browser, walks your user through installing the Layers GitHub App on the org or repos they choose. After install, GitHub redirects back to your `returnUrl` with `installation_id` and `state` query parameters — you then POST the `installation_id` to [`POST /v1/github/installation`](/docs/api/reference/github/register-installation).

`returnUrl` must be on your key's `allowedReturnDomains` list. Calls with an unlisted URL fail with `403 RETURN_URL_NOT_ALLOWED` so a compromised key can't redirect the user somewhere it shouldn't. URLs expire after 15 minutes.

<Parameters
  title="Query"
  rows="[
  { name: 'returnUrl', type: 'string', required: true, description: 'HTTPS URL on your domain that GitHub redirects to after install. Must be on the key\'s allowlist.' },
  { name: 'state', type: 'string', description: 'Opaque value you round-trip for CSRF. Echoed on the redirect. Layers generates one if omitted.' },
]"
/>

## Example request [#example-request]

<Tabs items="['curl', 'TypeScript', 'Python']">
  <Tab value="curl">
    ```bash
    curl "https://api.layers.com/v1/github/installation/install-url?returnUrl=https%3A%2F%2Fapp.gicgrowth.com%2Flayers%2Fcallback" \
      -H "Authorization: Bearer lp_live_01HX9Y6K7EJ4T2_4QZpN..."
    ```
  </Tab>

  <Tab value="TypeScript">
    ```ts
    const { authUrl, state, expiresAt } = await layers.github.installUrl({
      returnUrl: "https://app.gicgrowth.com/layers/callback",
    });
    // Redirect the user to authUrl.
    ```
  </Tab>

  <Tab value="Python">
    ```python
    url = layers.github.install_url(
        return_url="https://app.gicgrowth.com/layers/callback",
    )
    # Redirect the user to url["authUrl"].
    ```
  </Tab>
</Tabs>

## Response [#response]

<Response status="200" description="OK">
  ```json
  {
    "authUrl": "https://github.com/apps/layers-connector/installations/new?state=lUNN5tIRm-K3...&redirect_uri=https%3A%2F%2Fapp.gicgrowth.com%2Flayers%2Fcallback",
    "installUrl": "https://github.com/apps/layers-connector/installations/new?state=lUNN5tIRm-K3...&redirect_uri=https%3A%2F%2Fapp.gicgrowth.com%2Flayers%2Fcallback",
    "state": "lUNN5tIRm-K3a8sBXvBQDxVOCgz2x9YK",
    "expiresAt": "2026-04-18T19:29:09.000Z"
  }
  ```

  `installUrl` is an alias for `authUrl` — both are the same value, kept for clients that prefer the shorter name. Either is safe to redirect to.
</Response>

## Errors [#errors]

| Status | Code                     | When                                                                                                           |
| ------ | ------------------------ | -------------------------------------------------------------------------------------------------------------- |
| 422    | `VALIDATION`             | `returnUrl` missing or not HTTPS.                                                                              |
| 401    | `UNAUTHENTICATED`        | Missing or invalid key.                                                                                        |
| 403    | `FORBIDDEN_SCOPE`        | Key lacks `github:admin`.                                                                                      |
| 403    | `RETURN_URL_NOT_ALLOWED` | `returnUrl` is not on the key's `allowedReturnDomains` list. Update via ladmin or your organization dashboard. |
| 429    | `RATE_LIMITED`           | Write budget exhausted.                                                                                        |

## See also [#see-also]

* [`POST /v1/github/installation`](/docs/api/reference/github/register-installation) — post back the installation\_id
* [Return-URL allowlist](/docs/api/operational/security-and-compliance#return-url-allowlist) — security rationale
