DEV Community

Cover image for How to Use Heroku API: Complete Integration Guide (2026)
Preecha
Preecha

Posted on

How to Use Heroku API: Complete Integration Guide (2026)

TL;DR

The Heroku API lets you automate deployments, manage apps, configure add-ons, and scale infrastructure programmatically. It uses OAuth 2.0 and token-based authentication, RESTful endpoints for apps, dynos, builds, and pipelines, and a rate limit of 10,000 requests per hour per account.

Try Apidog today

This guide shows how to authenticate, call core endpoints, integrate Heroku into CI/CD, and handle production concerns such as retries, rate limits, and rollbacks.

Introduction

Heroku powers over 4 million applications across 170+ countries. If you are building deployment automation, CI/CD pipelines, or multi-app management tools, integrating with the Heroku API is a practical way to replace repetitive CLI and dashboard work.

Teams managing 10+ Heroku apps can spend hours every week on manual deploys and configuration changes. With the API, you can automate deployments, scale dynos based on traffic, and synchronize configuration across environments.

You will implement:

  • Bearer-token authentication
  • App, dyno, and config-var management
  • Build, release, and rollback workflows
  • Pipelines and slug promotion
  • Add-on, domain, and SSL configuration
  • Rate-limit handling and production monitoring

๐Ÿ’ก Apidog can help test Heroku endpoints, validate authentication flows, inspect responses, mock API behavior, and share test scenarios with your team.

What Is the Heroku API?

Heroku provides a RESTful Platform API for managing applications and infrastructure on the Heroku platform.

You can use it to automate:

  • Application creation, configuration, and deletion
  • Dyno scaling and process management
  • Build and release management
  • Add-on provisioning and configuration
  • Pipeline and promotion management
  • Domain and SSL certificate management
  • Log drain and monitoring setup
  • Team and collaborator management

Key Features

Feature Description
RESTful design Standard HTTP methods with JSON responses
Token authentication Bearer token with OAuth 2.0 support
Range requests Pagination for large result sets
Rate limiting 10,000 requests per hour per account
Idempotent creates Safe retry behavior for writes
Gzip compression Response compression for bandwidth savings

API Architecture Overview

Heroku uses a versioned REST API:

https://api.heroku.com/
Enter fullscreen mode Exit fullscreen mode

The API follows the JSON:API specification with consistent resource patterns and relationships.

API Versions Compared

Version Status Authentication Use case
Platform API (v3) Current Bearer token New integrations
GitHub Integration Current OAuth 2.0 GitHub-connected apps
Container Registry Current Docker auth Container deployments

Getting Started: Authentication Setup

Step 1: Create a Heroku Account

Before accessing the API, create a Heroku account.

Image

  1. Visit the Heroku website.
  2. Click Sign Up and create an account.
  3. Verify your email address.
  4. Complete account setup.

Step 2: Install the Heroku CLI

Use the CLI to authenticate, generate tokens, and test commands.

# macOS
brew tap heroku/brew && brew install heroku

# Windows
npm install -g heroku

# Linux
curl https://cli-assets.heroku.com/install.sh | sh
Enter fullscreen mode Exit fullscreen mode

Step 3: Generate an API Token

Log in through the CLI:

heroku login
Enter fullscreen mode Exit fullscreen mode

This opens a browser for authentication and stores your credentials locally.

Create a short-lived authorization token:

heroku authorizations:create --short-lived
Enter fullscreen mode Exit fullscreen mode

Or create a long-lived token for CI/CD:

heroku authorizations:create \
  --description "CI/CD Pipeline" \
  --expires-in "1 year"
Enter fullscreen mode Exit fullscreen mode

Store credentials in environment variables, never in source code:

# .env
HEROKU_API_KEY="your_api_key_here"
HEROKU_APP_NAME="your-app-name"
Enter fullscreen mode Exit fullscreen mode

Step 4: Send Authentication Headers

Heroku uses Bearer token authentication. Include these headers in every request:

Authorization: Bearer {api_key}
Accept: application/vnd.heroku+json; version=3
Enter fullscreen mode Exit fullscreen mode

Step 5: Make Your First API Call

Verify that your token works:

curl -n https://api.heroku.com/account \
  -H "Accept: application/vnd.heroku+json; version=3" \
  -H "Authorization: Bearer $HEROKU_API_KEY"
Enter fullscreen mode Exit fullscreen mode

Example response:

{
  "id": "user-id-here",
  "email": "developer@example.com",
  "name": "Developer Name",
  "created_at": "2024-01-15T10:30:00Z",
  "updated_at": "2026-03-20T14:22:00Z"
}
Enter fullscreen mode Exit fullscreen mode

Step 6: Create a Reusable JavaScript Client

Create one request helper so every call includes the required headers and consistent error handling.

const HEROKU_API_KEY = process.env.HEROKU_API_KEY;
const HEROKU_BASE_URL = "https://api.heroku.com";

const herokuRequest = async (endpoint, options = {}) => {
  const response = await fetch(`${HEROKU_BASE_URL}${endpoint}`, {
    ...options,
    headers: {
      Authorization: `Bearer ${HEROKU_API_KEY}`,
      Accept: "application/vnd.heroku+json; version=3",
      "Content-Type": "application/json",
      ...options.headers
    }
  });

  if (!response.ok) {
    const error = await response.json().catch(() => ({}));
    throw new Error(
      `Heroku API Error (${response.status}): ${error.message || response.statusText}`
    );
  }

  if (response.status === 204) {
    return null;
  }

  return response.json();
};

// Usage
const account = await herokuRequest("/account");
console.log(`Logged in as: ${account.email}`);
Enter fullscreen mode Exit fullscreen mode

Application Management

Create an App

Create a Heroku app programmatically:

const createApp = async (appName, region = "us") => {
  return herokuRequest("/apps", {
    method: "POST",
    body: JSON.stringify({
      name: appName,
      region
    })
  });
};

// Usage
const app = await createApp("my-awesome-app-2026");

console.log(`App created: ${app.name}`);
console.log(`Git URL: ${app.git_url}`);
console.log(`Web URL: ${app.web_url}`);
Enter fullscreen mode Exit fullscreen mode

Expected response:

{
  "id": "app-uuid-here",
  "name": "my-awesome-app-2026",
  "region": { "name": "us" },
  "created_at": "2026-03-25T10:00:00Z",
  "updated_at": "2026-03-25T10:00:00Z",
  "git_url": "https://git.heroku.com/my-awesome-app-2026.git",
  "web_url": "https://my-awesome-app-2026.herokuapp.com",
  "owner": { "email": "developer@example.com" },
  "build_stack": { "name": "heroku-24" }
}
Enter fullscreen mode Exit fullscreen mode

List Apps

Fetch apps available to the authenticated account:

const listApps = async (limit = 50) => {
  return herokuRequest(`/apps?limit=${limit}`);
};

const apps = await listApps();

apps.forEach((app) => {
  console.log(`${app.name} - ${app.web_url}`);
});
Enter fullscreen mode Exit fullscreen mode

Get App Details

Retrieve details for a specific app:

const getApp = async (appName) => {
  return herokuRequest(`/apps/${appName}`);
};

const app = await getApp("my-awesome-app-2026");

console.log(`Stack: ${app.build_stack.name}`);
console.log(`Region: ${app.region.name}`);
Enter fullscreen mode Exit fullscreen mode

Update an App

Use PATCH to update app settings:

const updateApp = async (appName, updates) => {
  return herokuRequest(`/apps/${appName}`, {
    method: "PATCH",
    body: JSON.stringify(updates)
  });
};

const updated = await updateApp("old-app-name", {
  name: "new-app-name"
});
Enter fullscreen mode Exit fullscreen mode

Delete an App

Delete an app only after confirming the target app name in your deployment tooling.

const deleteApp = async (appName) => {
  await herokuRequest(`/apps/${appName}`, {
    method: "DELETE"
  });

  console.log(`App ${appName} deleted successfully`);
};
Enter fullscreen mode Exit fullscreen mode

Dyno Management

Scale Dynos

Scale a process type, such as web or worker:

const scaleDyno = async (appName, processType, quantity) => {
  return herokuRequest(`/apps/${appName}/formation/${processType}`, {
    method: "PATCH",
    body: JSON.stringify({ quantity })
  });
};

// Scale web dynos to 3
const processType = "web";
const formation = await scaleDyno("my-app", processType, 3);

console.log(`Scaled to ${formation.quantity} ${processType} dynos`);
Enter fullscreen mode Exit fullscreen mode

Get Dyno Formation

Inspect the current formation before making scaling changes:

const getFormation = async (appName, processType = null) => {
  const endpoint = processType
    ? `/apps/${appName}/formation/${processType}`
    : `/apps/${appName}/formation`;

  return herokuRequest(endpoint);
};

const formation = await getFormation("my-app");

formation.forEach((proc) => {
  console.log(`${proc.type}: ${proc.quantity} dynos (@ ${proc.size})`);
});
Enter fullscreen mode Exit fullscreen mode

Available Dyno Sizes

Dyno type Use case Cost/month
eco Hobby projects, demos $5
basic Small production apps $7
standard-1x Standard workloads $25
standard-2x High-performance apps $50
performance Production-critical apps $250+
private Enterprise isolation Custom

Restart Dynos

Restart all dynos, or target a specific process type:

const restartDynos = async (appName, processType = null) => {
  const endpoint = processType
    ? `/apps/${appName}/formation/${processType}`
    : `/apps/${appName}/dynos`;

  await herokuRequest(endpoint, {
    method: "DELETE"
  });

  console.log(`Dynos restarted for ${appName}`);
};
Enter fullscreen mode Exit fullscreen mode

Run a One-Off Dyno

Use one-off dynos for tasks such as migrations or maintenance scripts:

const runCommand = async (appName, command) => {
  return herokuRequest(`/apps/${appName}/dynos`, {
    method: "POST",
    body: JSON.stringify({
      command,
      size: "standard-1x"
    })
  });
};

const dyno = await runCommand("my-app", "npm run migrate");
console.log(`Dyno started: ${dyno.id}`);
Enter fullscreen mode Exit fullscreen mode

Configuration Variables

Get Config Vars

Fetch an app's environment variables:

const getConfigVars = async (appName) => {
  return herokuRequest(`/apps/${appName}/config-vars`);
};

const config = await getConfigVars("my-app");

console.log(`DATABASE_URL: ${config.DATABASE_URL}`);
console.log(`NODE_ENV: ${config.NODE_ENV}`);
Enter fullscreen mode Exit fullscreen mode

Set Config Vars

Use PATCH to add or update config vars:

const setConfigVars = async (appName, variables) => {
  return herokuRequest(`/apps/${appName}/config-vars`, {
    method: "PATCH",
    body: JSON.stringify(variables)
  });
};

const updated = await setConfigVars("my-app", {
  NODE_ENV: "production",
  API_SECRET: "your-secret-key",
  LOG_LEVEL: "info"
});
Enter fullscreen mode Exit fullscreen mode

Config Var Practices

  • Never commit secrets: keep sensitive values in environment variables or a secret manager.
  • Separate environments: use distinct values for development, staging, and production.
  • Rotate credentials regularly: update API keys and passwords on a schedule.
  • Prefix related values: for example, STRIPE_SECRET_KEY and STRIPE_WEBHOOK_SECRET.

Build and Release Management

Create a Build

Use the Builds API to deploy code from a source blob URL:

const createBuild = async (appName, sourceBlobUrl) => {
  return herokuRequest(`/apps/${appName}/builds`, {
    method: "POST",
    body: JSON.stringify({
      source_blob: {
        url: sourceBlobUrl
      }
    })
  });
};

const build = await createBuild(
  "my-app",
  "https://storage.example.com/source.tar.gz"
);

console.log(`Build started: ${build.id}`);
console.log(`Status: ${build.status}`);
Enter fullscreen mode Exit fullscreen mode

Poll Build Status

Wait for a build to finish before promoting or releasing it:

const getBuild = async (appName, buildId) => {
  return herokuRequest(`/apps/${appName}/builds/${buildId}`);
};

const checkBuildStatus = async (appName, buildId, maxAttempts = 30) => {
  for (let i = 0; i < maxAttempts; i += 1) {
    const build = await getBuild(appName, buildId);

    if (build.status === "succeeded") {
      console.log("Build succeeded!");
      return build;
    }

    if (build.status === "failed") {
      throw new Error(`Build failed: ${build.output}`);
    }

    console.log(`Build in progress... attempt ${i + 1}`);
    await new Promise((resolve) => setTimeout(resolve, 5000));
  }

  throw new Error("Build timeout");
};
Enter fullscreen mode Exit fullscreen mode

List Releases

Inspect recent release history:

const listReleases = async (appName, limit = 10) => {
  return herokuRequest(`/apps/${appName}/releases?limit=${limit}`);
};

const releases = await listReleases("my-app");

releases.forEach((release) => {
  console.log(
    `v${release.version} - ${release.description} - ${release.created_at}`
  );
});
Enter fullscreen mode Exit fullscreen mode

Roll Back a Release

Create a new release that rolls back to a previous release version:

const rollback = async (appName, releaseId) => {
  return herokuRequest(`/apps/${appName}/releases`, {
    method: "POST",
    body: JSON.stringify({
      rollback: releaseId
    })
  });
};

const rollbackRelease = await rollback("my-app", 42);
console.log(`Rolled back to v${rollbackRelease.version}`);
Enter fullscreen mode Exit fullscreen mode

Pipeline Management

Create a Pipeline

Create a pipeline for your CI/CD workflow:

const createPipeline = async (pipelineName) => {
  return herokuRequest("/pipelines", {
    method: "POST",
    body: JSON.stringify({
      name: pipelineName
    })
  });
};

const pipeline = await createPipeline("my-app-pipeline");
console.log(`Pipeline created: ${pipeline.id}`);
Enter fullscreen mode Exit fullscreen mode

Add Apps to Pipeline Stages

Attach development, staging, and production apps:

const addAppToPipeline = async (pipelineId, appName, stage) => {
  return herokuRequest("/pipeline-couplings", {
    method: "POST",
    body: JSON.stringify({
      pipeline: pipelineId,
      app: appName,
      stage // development, staging, or production
    })
  });
};

await addAppToPipeline(pipeline.id, "my-app-dev", "development");
await addAppToPipeline(pipeline.id, "my-app-staging", "staging");
await addAppToPipeline(pipeline.id, "my-app-prod", "production");
Enter fullscreen mode Exit fullscreen mode

Promote a Slug

Promote a slug from one app to the next stage:

const promoteSlug = async (slugId, fromApp, toApp) => {
  await herokuRequest("/promotions", {
    method: "POST",
    body: JSON.stringify({
      from: fromApp,
      to: toApp,
      slug: slugId
    })
  });

  console.log(`Promoted slug ${slugId} from ${fromApp} to ${toApp}`);
};
Enter fullscreen mode Exit fullscreen mode

Add-On Management

Provision an Add-On

Provision add-ons through the API:

const provisionAddon = async (appName, addonPlan, config = {}) => {
  return herokuRequest("/addon-attachments", {
    method: "POST",
    body: JSON.stringify({
      app: appName,
      plan: addonPlan,
      config
    })
  });
};

const db = await provisionAddon("my-app", "heroku-postgresql:mini");

console.log(`Database provisioned: ${db.addon.name}`);
console.log(`DATABASE_URL: ${db.addon.config_vars.DATABASE_URL}`);
Enter fullscreen mode Exit fullscreen mode

Popular Add-Ons

Add-on Plan Starting price Use case
heroku-postgresql mini $5/mo Production database
heroku-redis mini $5/mo Caching, sessions
papertrail choklad $7/mo Log aggregation
sentry developer Free Error tracking
mailgun sandbox Free Email delivery
newrelic lite Free Application monitoring

List Installed Add-Ons

const listAddons = async (appName) => {
  return herokuRequest(`/apps/${appName}/addons`);
};

const addons = await listAddons("my-app");

addons.forEach((addon) => {
  console.log(
    `${addon.plan.name} - $${addon.pricing.plan.price} - ${addon.state}`
  );
});
Enter fullscreen mode Exit fullscreen mode

Remove an Add-On

const removeAddon = async (appName, addonId) => {
  await herokuRequest(`/apps/${appName}/addons/${addonId}`, {
    method: "DELETE"
  });

  console.log(`Addon ${addonId} removed from ${appName}`);
};
Enter fullscreen mode Exit fullscreen mode

Domain and SSL Management

Add a Custom Domain

const addDomain = async (appName, domainName) => {
  return herokuRequest(`/apps/${appName}/domains`, {
    method: "POST",
    body: JSON.stringify({
      hostname: domainName
    })
  });
};

const domain = await addDomain("my-app", "api.example.com");
console.log(`CNAME target: ${domain.cname}`);
Enter fullscreen mode Exit fullscreen mode

Configure an SSL Certificate

const addSslCertificate = async (
  appName,
  domainId,
  certificateChain,
  privateKey
) => {
  return herokuRequest(
    `/apps/${appName}/domains/${domainId}/ssl_endpoint`,
    {
      method: "PATCH",
      body: JSON.stringify({
        ssl_cert: {
          cert_chain: certificateChain,
          private_key: privateKey
        }
      })
    }
  );
};
Enter fullscreen mode Exit fullscreen mode

Enable Automatic Certificate Management

const enableACM = async (appName, domainName) => {
  return herokuRequest(
    `/apps/${appName}/domains/${domainName}/sni_endpoint`,
    {
      method: "POST",
      body: JSON.stringify({
        kind: "acm"
      })
    }
  );
};
Enter fullscreen mode Exit fullscreen mode

Rate Limiting and Quotas

Understand the Limits

Heroku enforces API limits to protect platform stability:

  • Standard limit: 10,000 requests per hour per account
  • Window: rolling 60-minute window
  • Reset: automatic after the window passes
  • Exceeded limit: HTTP 429 Too Many Requests

Read Rate-Limit Headers

Heroku includes rate-limit information in responses:

Header Description
RateLimit-Limit Maximum requests per hour
RateLimit-Remaining Remaining requests in the current window
RateLimit-Reset Unix timestamp when the window resets

To inspect headers, return both parsed data and the original response from your request helper:

const herokuRequestWithMeta = async (endpoint, options = {}) => {
  const response = await fetch(`${HEROKU_BASE_URL}${endpoint}`, {
    ...options,
    headers: {
      Authorization: `Bearer ${HEROKU_API_KEY}`,
      Accept: "application/vnd.heroku+json; version=3",
      "Content-Type": "application/json",
      ...options.headers
    }
  });

  const data = response.status === 204 ? null : await response.json();

  if (!response.ok) {
    throw new Error(
      `Heroku API Error (${response.status}): ${data?.message || response.statusText}`
    );
  }

  return { data, headers: response.headers };
};
Enter fullscreen mode Exit fullscreen mode

Implement Exponential Backoff

Retry rate-limited calls with exponential backoff:

const makeRateLimitedRequest = async (
  endpoint,
  options = {},
  maxRetries = 3
) => {
  for (let attempt = 1; attempt <= maxRetries; attempt += 1) {
    try {
      const { data, headers } = await herokuRequestWithMeta(endpoint, options);

      const remaining = Number(headers.get("RateLimit-Remaining"));
      const resetTime = headers.get("RateLimit-Reset");

      if (remaining < 100) {
        console.warn(
          `Low quota remaining: ${remaining}, resets at ${resetTime}`
        );
      }

      return data;
    } catch (error) {
      const isRateLimited = error.message.includes("(429)");

      if (isRateLimited && attempt < maxRetries) {
        const delay = 2 ** attempt * 1000;

        console.log(`Rate limited. Retrying in ${delay}ms...`);
        await new Promise((resolve) => setTimeout(resolve, delay));
        continue;
      }

      throw error;
    }
  }
};
Enter fullscreen mode Exit fullscreen mode

Troubleshooting Common Issues

Authentication Fails With 401

Symptoms: You receive Invalid credentials errors.

Checks:

  • Verify the API key with heroku authorizations.
  • Confirm the token has not expired. Long-lived tokens can last up to one year.
  • Check for extra whitespace in HEROKU_API_KEY.
  • Regenerate the token if necessary:
heroku authorizations:create
Enter fullscreen mode Exit fullscreen mode

App Name Already Taken

Symptoms: You receive a โ€œname is already takenโ€ error.

Fixes:

  • Use globally unique names.
  • Add a team, environment, or random suffix.
  • Generate names from a timestamp and random value.
const generateUniqueAppName = (baseName) => {
  const timestamp = Date.now().toString(36);
  const random = Math.random().toString(36).substring(2, 6);

  return `${baseName}-${timestamp}-${random}`;
};
Enter fullscreen mode Exit fullscreen mode

Dyno Formation Fails

Symptoms: Scaling operations return errors.

Checks:

  • Verify the process type exists in the app's Procfile.
  • Confirm the account has available dyno quota.
  • Ensure the app is not suspended.
  • Review dyno usage:
heroku ps --app=my-app
Enter fullscreen mode Exit fullscreen mode

Build Times Out

Symptoms: Builds hang or time out after 30 minutes.

Possible fixes:

  • Optimize buildpack selection for your language.
  • Cache dependencies correctly.
  • Split large builds into smaller deployments.
  • Use pre-built slugs for faster deployment.

Rate Limit Exceeded

Symptoms: You receive HTTP 429 responses.

Fixes:

  • Queue requests.
  • Use exponential backoff.
  • Batch requests where possible.
  • Monitor rate-limit headers before reaching the limit.

A simple queue-based limiter:

class HerokuRateLimiter {
  constructor(requestsPerMinute = 150) {
    this.queue = [];
    this.interval = 60000 / requestsPerMinute;
    this.processing = false;
  }

  async add(requestFn) {
    return new Promise((resolve, reject) => {
      this.queue.push({ requestFn, resolve, reject });
      this.process();
    });
  }

  async process() {
    if (this.processing || this.queue.length === 0) {
      return;
    }

    this.processing = true;

    while (this.queue.length > 0) {
      const { requestFn, resolve, reject } = this.queue.shift();

      try {
        const result = await requestFn();
        resolve(result);
      } catch (error) {
        reject(error);
      }

      if (this.queue.length > 0) {
        await new Promise((resolve) => setTimeout(resolve, this.interval));
      }
    }

    this.processing = false;
  }
}
Enter fullscreen mode Exit fullscreen mode

Production Deployment Checklist

Before going live:

  • [ ] Use long-lived API tokens for CI/CD.
  • [ ] Store tokens in secure secret management, such as Vault or AWS Secrets Manager.
  • [ ] Implement rate limiting and request queuing.
  • [ ] Add comprehensive error handling.
  • [ ] Log API calls and failures.
  • [ ] Monitor dyno-hour usage.
  • [ ] Configure log drains for external logging.
  • [ ] Set up pipeline promotions for CI/CD.
  • [ ] Enable Automatic Certificate Management.
  • [ ] Configure a database backup strategy.

Monitoring and Alerting

Track API, deployment, and dyno usage metrics:

const metrics = {
  apiCalls: {
    total: 0,
    successful: 0,
    failed: 0,
    rateLimited: 0
  },
  dynoHours: {
    used: 0,
    quota: 1000
  },
  deployments: {
    successful: 0,
    failed: 0,
    avg_duration: 0
  }
};

const failureRate = metrics.apiCalls.failed / metrics.apiCalls.total;

if (failureRate > 0.05) {
  sendAlert("Heroku API failure rate above 5%");
}

if (metrics.dynoHours.used > metrics.dynoHours.quota * 0.8) {
  sendAlert("Dyno hour usage above 80%");
}
Enter fullscreen mode Exit fullscreen mode

Real-World Use Cases

Automated CI/CD Pipeline

A SaaS team automates deployments from GitHub.

  • Challenge: Manual deployments caused errors and delays.
  • Solution: GitHub Actions with a Heroku API integration.
  • Result: Zero-downtime deployments and 90% faster releases.

Implementation flow:

  1. A GitHub push triggers a workflow.
  2. Tests run in CI.
  3. The Heroku API creates a build from a source blob.
  4. The slug is promoted from staging to production.
  5. The team receives a success or failure notification.

Multi-Environment Management

A consulting firm manages 50+ client apps.

  • Challenge: Manually synchronizing configuration across environments.
  • Solution: Central config management using the Heroku API.
  • Result: Consistent configuration and 8 hours per week saved.

Key integration points:

  • Sync config vars across development, staging, and production.
  • Provision add-ons automatically.
  • Run bulk operations during client onboarding.

Auto-Scaling Based on Traffic

An e-commerce platform handles traffic spikes.

  • Challenge: Manual scaling during sales events.
  • Solution: Load-based auto-scaling through the Heroku API.
  • Result: Zero downtime during 10x traffic spikes.

Auto-scaling logic:

  1. Monitor response times through a metrics API.
  2. Scale up when p95 latency exceeds 500 ms.
  3. Scale down during low-traffic periods.
  4. Alert on sustained high utilization.

Conclusion

The Heroku API provides programmatic access to core platform functionality. For a production integration:

  • Store and rotate Bearer tokens securely.
  • Monitor the 10,000-requests-per-hour limit.
  • Use pipelines to build reliable CI/CD flows.
  • Handle failures, retries, and rollbacks explicitly.
  • Test authentication, request payloads, and error responses before deploying automation.

FAQ

What is the Heroku API used for?

The Heroku API enables programmatic management of applications, dynos, add-ons, and infrastructure. Common use cases include CI/CD automation, multi-app management tools, auto-scaling systems, and infrastructure monitoring dashboards.

How do I get a Heroku API key?

Install the Heroku CLI, run heroku login, then create an authorization:

heroku authorizations:create
Enter fullscreen mode Exit fullscreen mode

Store the returned token securely in environment variables.

Is the Heroku API free to use?

Yes, the Heroku API is free. You pay for provisioned resources such as dynos and add-ons. API rate limits are 10,000 requests per hour per account.

What authentication does the Heroku API use?

Heroku uses Bearer token authentication. Include this header in every request:

Authorization: Bearer {api_key}
Enter fullscreen mode Exit fullscreen mode

Tokens can be short-lived for one hour or long-lived for up to one year.

How do I handle Heroku API rate limits?

Monitor the RateLimit-Remaining header, queue requests, and use exponential backoff after HTTP 429 responses. Staying under 150 requests per minute is a safe operating target.

Can I deploy without Git?

Yes. Use the Builds API to deploy from a source blob URL. Upload code to cloud storage such as S3 or GCS, then reference that URL in the build request.

How do I automate deployments?

Use the Pipeline API to build CI/CD workflows. Create builds, promote slugs through stages, and integrate the flow with GitHub or a custom CI system.

What is the difference between a release and a build?

A build compiles source code into a slug. A release combines a slug with configuration variables to create a deployable version of an app.

How do I roll back a failed deployment?

List recent releases, then send a POST request to /releases with rollback: <release_id>. Heroku creates a new release using the previous version.

Can I manage multiple Heroku accounts?

Yes. Use separate API tokens for each account and switch accounts by changing the HEROKU_API_KEY environment variable.

Top comments (0)