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

# Deploy from GitHub

> Deploy your API's Worker from a GitHub repository: a preview deployment for every pull request, production on every merge.

Keep your API's Worker code in a GitHub repository and deploy it with the [`jojapicom/deploy-action`](https://github.com/jojapicom/deploy-action) GitHub Action: every pull request gets a [preview deployment](/studio/deployments) with its own URL, commented on the pull request, and every merge to your default branch goes to production. Each deployment records its commit, branch and pull request, so the **Deployments** tab links straight to the code it runs.

## Set up

1. **Put the Worker in the repository.** `npx @jojapi/cli pull <your-api>` writes the files and a `jojapi.json` that names the API. Commit both. Files under `src/` and npm dependencies are bundled by the CLI.
2. **Create a Management API token** in the Studio (**Management API**) with the `code:read` and `code:write` scopes.
3. **Add it to the repository** as the secret `JOJAPI_TOKEN` (**Settings → Secrets and variables → Actions**) by pasting the value. With `gh secret set JOJAPI_TOKEN`, paste it at the prompt: piping an unset shell variable into it stores an empty secret without an error, and the deploy then fails with "The token input is empty".
4. **Add the workflow** below as `.github/workflows/jojapi.yml`.

```yaml theme={null}
name: Deploy to JoJ API

on:
  push:
    branches: [main]
  pull_request:

jobs:
  deploy:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      pull-requests: write # the preview URL comment
    concurrency: jojapi-${{ github.ref }}
    steps:
      - uses: actions/checkout@v7
      - uses: jojapicom/deploy-action@v1
        with:
          token: ${{ secrets.JOJAPI_TOKEN }}
```

The action installs npm dependencies when the repository has a `package-lock.json`, runs `jojapi deploy` and sets the outputs `status`, `url`, `deployment-id`, `deployment-number`, `preview-url` and `promoted` for later steps. Its README lists every input: `working-directory`, `production`, `message`, `comment` and more.

## What happens

| Event                                  | Result                                                                                                                                           |
| -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| Pull request opened or updated         | A preview deployment with the pull request's head commit and title. One comment on the pull request shows its URL and is updated on every push   |
| Push to `main` (a merge)               | A production deployment with the merge commit. If the files are the ones the pull request already previewed, they are deployed again as they are |
| Nothing changed                        | No deployment; the step ends with a notice                                                                                                       |
| Pull request from a fork or Dependabot | Skipped with a notice: such runs get no secrets                                                                                                  |
| Empty token anywhere else              | The job fails: the secret is not set or empty                                                                                                    |

A failed build or upload fails the job with the error (also shown in the pull request comment), and production stays as it was. Roll back from the **Deployments** tab or with `npx @jojapi/cli rollback`.

An API still in template mode switches to code mode with its first deploy. A pull request's preview leaves production on the template's deployment until the merge; **Back to template** in the Studio restores the template.

## Several APIs in one repository

Give each API its own folder with its `jojapi.json` and one action step per folder, each with its own `working-directory` (for example `apis/search`). Each API keeps its own pull request comment. A folder whose files did not change deploys nothing.

## The CLI in scripts

`jojapi deploy --json` prints one line of JSON for scripts:

```json theme={null}
{"status":"deployed","promoted":false,"deployment":{"id":"k3j9x2ab","number":14,"url":"https://my-api--k3j9x2ab.jojapi.dev"},"preview_url":"https://my-api--preview.jojapi.dev","uploaded":2,"deleted":0}
```

Outside GitHub Actions the CLI reads the commit and branch from the local git checkout and marks deployments made from uncommitted changes. `--message` overrides the description taken from the commit or pull request title.
