Overview

You send a repository URL and an issue description. Kodah processes the codebase and returns a unified diff. All processing happens on Kodah's infrastructure.

Base URL

text
https://api.kodah.io

How it works

  1. You submit a job with a repo URL and issue description → receive a job_id
  2. You poll the status of the job until it reaches completed or failed
  3. You retrieve the diff and apply it to your codebase

Job lifecycle

queued running completed | failed

Jobs typically complete in 1–5 minutes.

Quickstart

Three commands to go from zero to a patch.

Step 1 — Create an account

Go to kodah.io/register.html and sign in with GitHub. You will receive an API key prefixed with kdh_. Save it — you will need it for every request.

Step 2 — Submit a job

bash
curl -X POST https://api.kodah.io/jobs \
  -H "Content-Type: application/json" \
  -H "X-API-Key: kdh_your_key_here" \
  -d '{
    "repo_url": "https://github.com/your-org/your-repo",
    "task": "fix",
    "description": "TypeError in calculate_total: unsupported operand type += float and str",
    "ref": "main"
  }'
response
{
  "job_id": "74fc9334-0d1a-48a7-9936-60b9dd84a24a"
}

Step 3 — Poll until complete

bash
curl https://api.kodah.io/jobs/74fc9334-0d1a-48a7-9936-60b9dd84a24a/status \
  -H "X-API-Key: kdh_your_key_here"
response
{
  "job_id": "74fc9334-...",
  "status": "completed",
  "elapsed_s": 87.4
}

Step 4 — Retrieve the diff

bash
curl https://api.kodah.io/jobs/74fc9334-0d1a-48a7-9936-60b9dd84a24a \
  -H "X-API-Key: kdh_your_key_here"
response
{
  "job_id": "74fc9334-...",
  "diff": "diff --git a/src/processor.py b/src/processor.py\n--- a/src/processor.py\n+++ b/src/processor.py\n@@ -8,3 +8,3 @@\n-        total = 0\n+        total = 0.0\n         for item in items:\n-            total += item['price']\n+            total += float(item['price'])"
}

Authentication

All API requests must include your API key in the X-API-Key header.

bash
X-API-Key: kdh_your_key_here

Keep your key private. Do not commit it to version control or expose it in client-side code. If your key is compromised, sign in again at kodah.io/register.html to generate a new one. Your old key will be invalidated immediately.

Requests without a valid API key return 401 Unauthorized. Requests with a valid key but insufficient credits return 402 Payment Required.

Credits & Limits

Kodah uses a simple credit system. Every fix costs exactly $0.50, deducted from your balance before the job starts.

Free tier

Every account receives 10 free fixes per calendar month, valid for public repositories only. Free fixes reset on the first day of each month and do not carry over.

Paid credits

Purchase credits from your dashboard. Paid credits never expire and work on both public and private repositories.

Concurrency limit

If the server is at capacity, your request returns 429 Too Many Requests. Wait a moment and retry — jobs typically finish within minutes.

Credit not charged for system errors. If a job fails due to an error on Kodah's side, the credit is automatically restored to your account.

Submit a Job

POST /jobs

Submit a new fix job. Returns immediately with a job_id. Processing happens asynchronously.

Request body

FieldTypeDescription
repo_urlrequired string Full HTTPS URL of the GitHub repository. Example: https://github.com/owner/repo
taskrequired string Must be "fix". This is the only supported task type.
descriptionrequired string A description of the bug or issue to fix. Include error messages, stack traces, or reproduction steps for best results.
refoptional string Branch name or commit hash to use. Defaults to "main".

Response

json
{
  "job_id": "74fc9334-0d1a-48a7-9936-60b9dd84a24a"
}

Status codes

202Job accepted. Processing has started.
401Missing or invalid API key.
402Insufficient credits.
429Server at capacity. Retry after a few minutes.

Poll Status

GET /jobs/{job_id}/status

Check the current status of a job. Does not consume credits.

Response

json
{
  "job_id": "74fc9334-...",
  "status": "completed",
  "created_at": "2026-04-29T10:00:00Z",
  "completed_at": "2026-04-29T10:02:27Z",
  "elapsed_s": 147.3,
  "error": null
}

Status values

runningJob is being processed. Continue polling.
completedJob finished successfully. Retrieve the diff.
failedJob failed. Check the error field for details.

Get Result

GET /jobs/{job_id}

Retrieve the generated diff once the job is complete. Returns 425 if still running, 422 if failed.

Response

json
{
  "job_id": "74fc9334-...",
  "diff": "diff --git a/src/processor.py ..."
}

The diff field contains a standard unified diff. Apply it with git apply or review it in any diff viewer.

bash — applying the patch
# Save the diff to a file
curl https://api.kodah.io/jobs/JOB_ID \
  -H "X-API-Key: kdh_your_key" \
  | jq -r '.diff' > patch.diff

# Review it
cat patch.diff

# Apply it
git apply patch.diff

Account

GET /me

Returns account information including credit balance.

json
{
  "email": "you@example.com",
  "free_credits": 8,
  "paid_balance": 10.00,
  "fix_price_usd": 0.50
}

Private Repos

Private repository access is granted automatically when you sign in with GitHub and authorize repository access. No tokens or additional configuration required.

When you create your account at kodah.io/register.html, GitHub asks you to grant Kodah access to your repositories. Once granted, you can submit private repos the same way as public ones — just use the full HTTPS URL.

Private repos require paid credits. Free monthly fixes are valid for public repositories only. Submitting a private repo with no paid balance returns 402 Payment Required.

bash — private repo example
curl -X POST https://api.kodah.io/jobs \
  -H "Content-Type: application/json" \
  -H "X-API-Key: kdh_your_key_here" \
  -d '{
    "repo_url": "https://github.com/your-org/private-repo",
    "task": "fix",
    "description": "KeyError in config parser when config file is missing optional section",
    "ref": "main"
  }'

Polling Pattern

Since jobs are asynchronous, you need to poll the status endpoint until the job finishes. Here is a recommended shell script for that.

bash — full polling script
#!/bin/bash
# Usage: ./fix.sh "https://github.com/owner/repo" "your bug description"

API_KEY="kdh_your_key_here"
REPO_URL="$1"
DESCRIPTION="$2"
BASE="https://api.kodah.io"

# Submit job
JOB_ID=$(curl -s -X POST "$BASE/jobs" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: $API_KEY" \
  -d "{\"repo_url\": \"$REPO_URL\", \"task\": \"fix\", \"description\": \"$DESCRIPTION\"}" \
  | jq -r '.job_id')

echo "Job submitted: $JOB_ID"

# Poll until done
while true; do
  STATUS=$(curl -s "$BASE/jobs/$JOB_ID/status" \
    -H "X-API-Key: $API_KEY" \
    | jq -r '.status')

  echo "Status: $STATUS"

  if [ "$STATUS" = "completed" ]; then
    # Retrieve and apply diff
    curl -s "$BASE/jobs/$JOB_ID" \
      -H "X-API-Key: $API_KEY" \
      | jq -r '.diff' > patch.diff
    echo "Patch saved to patch.diff"
    break
  elif [ "$STATUS" = "failed" ]; then
    echo "Job failed."
    break
  fi

  sleep 15
done

CI/CD Integration

Kodah's API is designed to be embedded in automated pipelines. A common pattern is to trigger a fix job when a bug is detected in staging or when a test suite fails.

The following example shows a GitHub Actions workflow that calls Kodah when tests fail on a pull request.

yaml — .github/workflows/auto-fix.yml
name: Auto Fix on Failure

on:
  workflow_run:
    workflows: ["Test Suite"]
    types: [completed]

jobs:
  fix:
    if: ${{ github.event.workflow_run.conclusion == 'failure' }}
    runs-on: ubuntu-latest
    steps:
      - name: Submit fix job
        run: |
          JOB_ID=$(curl -s -X POST https://api.kodah.io/jobs \
            -H "Content-Type: application/json" \
            -H "X-API-Key: ${{ secrets.KODAH_API_KEY }}" \
            -d "{
              \"repo_url\": \"https://github.com/${{ github.repository }}\",
              \"task\": \"fix\",
              \"description\": \"Tests failed on branch ${{ github.ref_name }}. Please investigate and fix.\",
              \"ref\": \"${{ github.ref_name }}\"
            }" | jq -r '.job_id')
          echo "JOB_ID=$JOB_ID" >> $GITHUB_ENV

      - name: Wait for result
        run: |
          for i in {1..20}; do
            STATUS=$(curl -s "https://api.kodah.io/jobs/$JOB_ID/status" \
              -H "X-API-Key: ${{ secrets.KODAH_API_KEY }}" \
              | jq -r '.status')
            [ "$STATUS" = "completed" ] && break
            [ "$STATUS" = "failed" ] && exit 1
            sleep 30
          done
          curl -s "https://api.kodah.io/jobs/$JOB_ID" \
            -H "X-API-Key: ${{ secrets.KODAH_API_KEY }}" \
            | jq -r '.diff' > patch.diff
          cat patch.diff

Store your API key as a GitHub Actions secret named KODAH_API_KEY. Never hardcode it in your workflow files.

Error Reference

All errors follow the same format: a JSON object with a detail field describing the issue.

json
{ "detail": "Invalid API key" }
CodeMeaningResolution
401 Missing or invalid API key Check your X-API-Key header
402 No credits remaining Add credits at kodah.io/dashboard.html
402 Private repos require paid credits Purchase credits or use a public repository
404 Repository not found Check the repo URL and make sure it is accessible
404 Job not found Check the job_id
422 Job failed Check the error field in the status response
425 Job still running Continue polling the status endpoint
429 Job already in progress Wait for your current job to finish before submitting another
429 Server at capacity Wait a few minutes and retry