← AdHalo

AdHalo API

Import products, generate image ads and collect the finished files from n8n, Make, a script or your agency tooling. JSON in, JSON out, base URL https://adhalo.app/api/v1.

Connect your AI agent with MCP

New to agent workflows? Read the product-photo image ad guide for the workflow, allowance and limits before connecting.

On Integrations, expand “Connect your agent” and create a scoped key. These are separate from REST keys: ah_agent_… works only at /api/mcp. Choose read-only, optionally allow product imports or image generation, and set expiry from 1–90 days (default 7). Ten active keys per account; revoke any time. Copy the key once and store it in your agent's secret manager, not prompts, URLs, Git, or shared chat history.

Use a Streamable HTTP MCP client supporting custom headers. This is an example configuration, not OAuth or a guarantee that every MCP client uses the same config format:

{
  "mcpServers": {
    "adhalo": {
      "url": "https://adhalo.app/api/mcp",
      "headers": { "Authorization": "Bearer ah_agent_YOUR_KEY" }
    }
  }
}
  • Read: get_allowance, list_products, get_product, list_ads, get_ad.
  • Edit: import_product safely imports a product page and actual photos.
  • Generate: preview_image_generation, generate_image_ads makes normal image batches only—1–3 unique formats, one image allowance debit per format.

Ask your agent to read your product and allowance, preview options, and show you the exact debit. Generation requires approved=true, the returned preview_hash, max_image_debit at least that amount, and a stable 8–128 character idempotency_key. Approval records the agent's intent; it cannot prove a human reviewed the request. Grant generation permission only to an agent you trust. Existing subscription, moderation, Pro-model, and business-spend limits still apply; no extra charges bypass those limits. A preview reserves nothing and is an allowance count, not a dollar-price estimate.

Jobs are asynchronous. Poll get_ad for ready/failed status and a fresh expiring download link. Keep the same retry key and identical inputs: completed submissions replay their original job ids rather than starting another batch. A pending or uncertain submission is intentionally not rerun—inspect list_ads instead of inventing a new key. Product changes or a new subscription cycle require a fresh preview for a new batch.

There is no video generation, angle-pack/grid fanout, social publishing, deletion, billing, admin access, or key creation through MCP. Existing video ads can be read and downloaded. Product page text is untrusted content, never instructions for your agent. Limits: 100 HTTP requests/minute per IP, 60/minute per authenticated key, shared across MCP operations; respect Retry-After and poll sparingly.

Authentication

Create a key on the Integrations page (up to 5 per account). The full key, ah_live_…, is shown once; we store only a hash, so keep it somewhere safe and revoke it if it leaks. Send it on every request:

curl https://adhalo.app/api/v1/me \
  -H "Authorization: Bearer ah_live_YOUR_KEY"

Keys work only on /api/v1/*. A revoked key, or a key for a deactivated account, gets 401. Every ad you make through the API uses your plan's monthly quota exactly like the web app, and Pro-only options stay Pro-only.

Rate limits and errors

Limits are per key: 60 requests a minute for reads, 10 a minute for POST /products, and 10 a minute for POST /products/{id}/ads. Over the limit you get 429 with a Retry-After header in seconds.

Errors are JSON with a human-readable message:

{ "error": "monthly quota of 100 ads reached" }
  • 400 invalid body, unknown field, bad parameter
  • 401 missing, invalid or revoked key
  • 402 the option or ad count needs a higher plan
  • 404 not found, or not yours
  • 422 a product page we couldn't use
  • 429 rate limit, or your paid monthly quota is used up

Endpoints

GET/me

Your plan and what is left this billing period. resets_at is your renewal date (paid plans).

curl https://adhalo.app/api/v1/me -H "Authorization: Bearer $ADHALO_KEY"

{ "plan": "pro", "is_paid": true, "quota": 200, "remaining": 162,
  "video_quota": 30, "video_remaining": 27, "max_video_seconds": 12,
  "period_start": "2026-09-01T00:00:00Z", "resets_at": "2026-10-01T00:00:00Z",
  "ends_at_period_end": false }

GET/products

Your 50 most recent products, each with its photos (short-lived image URLs).

curl https://adhalo.app/api/v1/products -H "Authorization: Bearer $ADHALO_KEY"

POST/products

Import a product from its page on your store (Shopify, WooCommerce and most stores with product markup). We read the name, description, price and up to 5 photos, and remember the URL so ad links point back to it. Optional language and currency set the ad copy's language and the price currency (defaults: en, USD).

curl -X POST https://adhalo.app/api/v1/products \
  -H "Authorization: Bearer $ADHALO_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://yourstore.com/products/aurora-headphones"}'

201 Created
{ "id": 42, "name": "Aurora Wireless Headphones", "description": "…",
  "price_cents": 12900, "currency": "USD", "language": "en", "image_count": 3,
  "product_url": "https://yourstore.com/products/aurora-headphones" }

POST/products/{id}/ads

Start image ads for a product. Takes the same options as the generator on the site; all are optional. The response is immediate (202) with the ads in pending; each one becomes ready or failed within a minute or two.

  • formats: up to 3 of 1x1, 4x5, 9x16, 191x100 (default ["1x1"]), one ad per format. 191x100 is the 1.91:1 landscape Google Display, Performance Max and Demand Gen need (1200×628); ["191x100", "1x1", "4x5"] is a full Google Ads set
  • template: a scene style; real-person scenes need Pro
  • headline (≤ 80 chars) and cta (≤ 30): your own copy instead of AI-written
  • explore: true renders a 4-look sheet to pick from on the site (not listed as an ad)
  • variance: 0 balanced, 1 subtle, 2 bold
curl -X POST https://adhalo.app/api/v1/products/42/ads \
  -H "Authorization: Bearer $ADHALO_KEY" \
  -H "Content-Type: application/json" \
  -d '{"formats": ["1x1", "9x16"], "headline": "Silence, on demand", "cta": "Shop now"}'

202 Accepted
[ { "id": "image_981", "kind": "image", "status": "pending", "product_id": 42,
    "format": "1x1", "created_at": "2026-09-23T14:02:11Z", … }, … ]

GET/ads

Image and video ads, newest first. Filters: status (ready, pending, failed), since (RFC 3339, e.g. 2026-09-01T00:00:00Z) and limit (1-500, default 100). Poll with status=ready&since= your last run. Ready ads carry a download_url valid for one hour; fetch the list again for a fresh one.

curl "https://adhalo.app/api/v1/ads?status=ready&since=2026-09-23T00:00:00Z" \
  -H "Authorization: Bearer $ADHALO_KEY"

[ { "id": "image_981", "kind": "image", "status": "ready", "product_id": 42,
    "product_name": "Aurora Wireless Headphones", "format": "1x1",
    "headline": "Silence, on demand", "hook": "40 hours of battery", "cta": "Shop now",
    "download_url": "https://…/adhalo-aurora-wireless-headphones-1x1.jpg?…",
    "link": "https://yourstore.com/products/aurora-headphones?utm_campaign=adhalo&utm_content=adhalo-image-981&utm_medium=paid_social&utm_source=meta",
    "created_at": "2026-09-23T14:02:11Z" } ]

GET/ads/{id}

One ad by its id from the list (image_981, video_17).

curl https://adhalo.app/api/v1/ads/image_981 -H "Authorization: Bearer $ADHALO_KEY"

Product links with UTM tags

When we know a product's store URL (it was imported from a link or a store), every ad carries a link: that URL with your utm_source, utm_medium and utm_campaign (set them on Integrations; defaults meta / paid_social / adhalo) and utm_content=adhalo-<kind>-<id>, so your analytics show which ad sold. Existing query parameters on your URL are kept.

Push instead of poll

Rather than polling /ads, add an ad-ready webhook on Integrations. We POST each finished ad (with its download_url and link) to your URL, signed with an X-AdHalo-Signature header, as soon as it is ready. It works with Zapier, Make and n8n catch hooks.