Enterprise API

API Documentation

Everything you need to run MyFast AI Answer Engine Optimization reports programmatically for your clients. Don't have a key yet? Create an enterprise account.

Overview

The Enterprise API lets agencies and platforms run AEO reports for any number of clients from their own systems. You send one authenticated request per client; we queue it, run the full analysis across every AI engine, and deliver a PDF report plus a companion transcript file. You can optionally request a developer bundle of ready-to-publish fix files. All endpoints are rooted at:

https://aeo.myfast.ai/api/enterprise/v1

Requests and responses are JSON. Reports never run inline: a request returns immediately with a 202 Accepted and a job you can poll or receive by webhook. Behind the scenes we run up to five reports concurrently, and within your own account your jobs are worked in the order you submit them (per-account FIFO) — so a burst from one client can never starve another account, and your own reports keep their order.

Three ways to generate reports

You do not need to write any code to run reports. Every account has three ways to generate them, and all three tag and organize each report by client in your back office — so you can come back at any time and add a developer pack to a past report, then hand the correct download link to the right client.

1. The API

Best for platforms and agencies with engineering resources. Send one authenticated request per client from your own systems. Everything on this page documents this path.

2. Individual report form

No code required. In your back office, open Generate Reports → Individual, key in the client’s business details, optionally tick “also generate the developer pack,” and submit.

3. Bulk CSV

Run many clients at once. In Generate Reports → Bulk CSV, drag & drop, choose a file, or paste CSV text. We validate every row, then queue and tag one report per row. Format is documented below.

Whichever path you use, finished reports and developer packs collect in the Client Deliveries list in your back office, grouped by yourclientTag. Each delivered report also carries an Add developer pack action so you can purchase and attach the pack later without re-running the report.

Bulk CSV format

The bulk uploader accepts a standard comma-separated file. The first row must be a header row naming the columns (case-insensitive; common aliases are accepted). Each following row is one client report. You can upload up to 500 rows at a time. Onlydomain, businessName and category are required — every other column is optional.

ColumnRequired?Description
domainrequiredClient website domain, e.g. acmeplumbing.com.
businessNamerequiredBusiness name as it should appear in searches. Wrap in "quotes" if it contains a comma.
categoryrequiredBusiness category or type, e.g. Plumber or SaaS CRM.
keywordCountoptional (default 100)Buyer keywords to test, 100–1000, rounded to the nearest 100.
clientTagoptionalYour own label for the client, e.g. client2175. Used to group deliveries in your back office.
wantDevBundleoptional (default false)Put true / yes / y / 1 / x to also generate the developer pack for this row.
deliverEmailoptionalEmail address to send this client’s finished report to.
targetAudienceoptionalIdeal customer, to sharpen keyword generation.
locationoptionalCity / region for local businesses.
radiusMilesoptionalService radius for local businesses.
competitorsoptionalKnown competitors, as free text in a single cell (wrap in "quotes" if it contains commas).
contactNameoptionalClient contact name stored with the report.
contactEmailoptionalClient contact email stored with the report.
contactPhoneoptionalClient contact phone stored with the report.

Example file

Wrap any value that contains a comma in double quotes. A minimal file needs only the three required columns; here is a fuller example that also tags clients and requests developer packs:

domain,businessName,category,keywordCount,clientTag,wantDevBundle,deliverEmail
acmeplumbing.com,Acme Plumbing,Plumber,100,client2175,true,[email protected]
brightsmiledental.com,"Bright Smile Dental, PC",Dentist,200,client2176,,
summitcrm.io,Summit CRM,SaaS CRM,300,client2177,yes,[email protected]

The back office also has a Download template button that gives you this exact header row to fill in. When you submit, we show you how many rows were accepted, how many were skipped, and the reason for each invalid row so you can fix and re-upload just those.

Authentication

Every request must carry your secret API key. Once your card is on file, open your back office and click Generate & reveal my API key — the key is shown exactly once, so copy it into your secret manager right away. Send it in an Authorization header using the Bearer scheme (an x-api-key header is also accepted):

Authorization: Bearer ent_live_your_key_here

Keys are secret. Store them server-side in a secret manager and never expose them in browser code. If a key is lost or compromised, rotate it — the old key is revoked immediately and a new one issued.

Create a report

POST/api/enterprise/v1/reports

Queues a new AEO report for one client. Returns immediately with a job you can track. Your account's jobs are worked in submission order, and the response tells you your current queue position and an estimated wait. Pass an Idempotency-Key header to make retries safe (see Idempotency).

Request body

FieldTypeDescription
domainstring (required)The client website domain, e.g. "acmeplumbing.com".
businessNamestring (required)The client business name as it should appear in searches.
categorystring (required)The business category or type, e.g. "Plumber", "SaaS CRM".
keywordCountnumber (optional, default 100)How many buyer keywords to test. 100–1000, rounded to the nearest 100. This is a report-depth control only — it does not change the price. Every report is a flat $49 for your first 5, then $24 each after that.
clientTagstring (optional)Your own label for the client this report belongs to — any value you like, e.g. "acme-plumbing" or "client2175". Echoed back on the job, printed on delivery emails, tagged onto delivered files, and used to group deliveries by client in your back office so you always know whose report is whose.
wantDevBundleboolean (optional, default false)Also generate a developer bundle for this report. The developer pack is $199 for your first 5 packs, then $99 each after that — billed the first time you buy the pack for a given business, and every later report for that same business gets the pack free (no charge).
deliverEmailstring (optional)Email address to send the finished report and companion file to (in addition to the status URL).
webhookUrlstring (optional)Override your account-level completion webhook for this one report. When set, we POST a signed report.completed / report.failed event to this URL. Leave unset to use your saved account webhook (if any).
targetAudiencestring (optional)Describe the ideal customer to sharpen keyword generation.
locationstring (optional)City / region for local businesses.
radiusMilesnumber (optional)Service radius for local businesses.
competitorsstring[] (optional)Known competitors to factor into the analysis.
contactName / contactEmail / contactPhonestring (optional)Client contact details stored with the report.

Example request

curl -X POST https://aeo.myfast.ai/api/enterprise/v1/reports \
  -H "Authorization: Bearer ent_live_your_key_here" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 6f1c2e-acme-2026-01-05" \
  -d '{
    "domain": "acmeplumbing.com",
    "businessName": "Acme Plumbing",
    "category": "Plumber",
    "keywordCount": 100,
    "clientTag": "acme-plumbing",
    "wantDevBundle": false,
    "deliverEmail": "[email protected]"
  }'

Example response (202)

{
  "jobId": "clx...",
  "status": "queued",
  "type": "report",
  "keywordCount": 100,
  "clientTag": "acme-plumbing",
  "wantDevBundle": false,
  "devBundleAlreadyOwned": false,
  "devBundleCharge": "$0",
  "estimatedCharge": "$49",
  "queuePosition": 3,
  "queueDepth": 3,
  "estimatedWait": "6 min",
  "concurrency": 5,
  "webhookUrl": "https://your-app.com/hooks/myfast",
  "statusUrl": "/api/enterprise/v1/reports/clx...",
  "message": "Report queued. It will be processed in request order and delivered by email and via this status URL."
}

queuePosition is your job's 1-based place in the global queue (null once it starts), queueDepth is how many jobs are waiting, and estimatedWait is a human-readable ETA based on recent average run times and the {5} concurrent slots. webhookUrl echoes where we'll POST the completion event, if configured.

When wantDevBundle is true, the response also returns devBundleAlreadyOwned and devBundleCharge. If you already bought the developer pack for this business, devBundleAlreadyOwned is true, devBundleCharge is $0, and estimatedCharge covers only the report — the pack is regenerated and delivered free.

Check job status

GET/api/enterprise/v1/reports/:jobId

Poll this endpoint (or use the statusUrl returned at creation) to track a job. Status moves through queued → processing → completed (or failed). When complete, result holds the delivery links.

Example response (completed)

{
  "jobId": "clx...",
  "type": "report",
  "status": "completed",
  "domain": "acmeplumbing.com",
  "businessName": "Acme Plumbing",
  "clientTag": "acme-plumbing",
  "wantDevBundle": false,
  "reportId": "rep_...",
  "result": {
    "pdfUrl": "https://.../report.pdf",
    "companionUrl": "https://.../what-ai-said.html",
    "bundleUrl": null
  },
  "error": null,
  "attempts": 1,
  "durationMs": 394000,
  "queuePosition": null,
  "queueDepth": 2,
  "estimatedWait": null,
  "createdAt": "2026-01-05T14:00:00.000Z",
  "startedAt": "2026-01-05T14:00:07.000Z",
  "completedAt": "2026-01-05T14:06:41.000Z"
}

durationMs is the wall-clock processing time once a job completes. While a job is still queued, queuePosition and estimatedWait are populated; both become null once it moves to processing.

List jobs

GET/api/enterprise/v1/reports

Returns your 50 most recent jobs (reports and bundles), newest first, each in the same shape as the status response. Useful for reconciling deliveries or building a dashboard.

{ "jobs": [ { "jobId": "clx...", "type": "report", "status": "completed", ... } ] }

Request a developer bundle

POST/api/enterprise/v1/bundle

Generate a developer bundle for an existing completed report. (To get the bundle at the same time as the report, set wantDevBundle: true on the report request instead.) The bundle contains a custom llms.txt, JSON-LD schema, answer & FAQ pages, an updated sitemap and an install guide — tagged to your client. The developer pack is a one-time purchase per business: you are billed $199 for your first 5 packs (then $99 each) the first time you buy it for a given business, and every later bundle for that same business is free. The response includes devBundleAlreadyOwned so you know whether this call will be charged.

Request body

{
  "reportId": "rep_...",        // required — must belong to your account and be completed
  "clientTag": "acme-plumbing", // optional — defaults to the report's tag
  "deliverEmail": "[email protected]" // optional
}

Example response (202)

{
  "jobId": "clx...",
  "status": "queued",
  "type": "dev_bundle",
  "reportId": "rep_...",
  "devBundleAlreadyOwned": false,
  "estimatedCharge": "$199",
  "queuePosition": 2,
  "queueDepth": 2,
  "estimatedWait": "6 min",
  "concurrency": 5,
  "statusUrl": "/api/enterprise/v1/reports/clx..."
}

Queue & throughput

Reports are processed by a pool that runs up to five reports at the same time. Within a single account, jobs start in the order you submitted them (per-account FIFO), so your own reports never jump ahead of each other, and no single account can monopolise the pool at the expense of others.

  • Position & ETA. Creating a report returns queuePosition, queueDepth and a human-readable estimatedWait. The same fields appear when you poll a queued job, so you can show clients an accurate “time remaining”.
  • Automatic retries. A job that hits a transient error is retried automatically with back-off (up to three attempts). The current count is on every job as attempts.
  • Self-healing. A maintenance sweep runs continuously in the background to re-queue any job whose worker was interrupted, so nothing gets stuck. You never have to intervene.
  • Live metrics. Your back office shows live concurrency, queued and processing counts, 24-hour completions, average run time and an estimated queue-drain time.

Idempotency

Network timeouts and retries are a fact of life. To make a create-report or create-bundle call safe to retry, send an Idempotency-Key header with a value that is unique to that logical request (a UUID, or something like client2175-2026-01-05). You may also pass it in the JSON body as idempotencyKey.

  • The first request with a given key creates the job and returns 202 Accepted.
  • Any later request with the same key (per account) returns the same job with 200 OK and "idempotent": true — no duplicate report is ever queued, and you are never double-charged.
  • Keys are scoped to your account. Concurrent retries with the same key are handled safely — exactly one job is created.
# Retrying with the same key returns the original job, not a new one
curl -X POST https://aeo.myfast.ai/api/enterprise/v1/reports \
  -H "Authorization: Bearer ent_live_your_key_here" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: client2175-2026-01-05" \
  -d '{ "domain": "acmeplumbing.com", "businessName": "Acme Plumbing", "category": "Plumber" }'

# -> 200 OK  { "jobId": "clx...", "idempotent": true, ... }

Completion webhooks

Instead of polling, you can have us call you when a job finishes. Set a Webhook URL in your back office (applies to every report), or pass webhookUrl on a single request to override it just for that job. We send an HTTP POST with a JSON body the moment a job reaches completed or failed.

Events

report.completed and report.failed. The event name is also sent in an X-MyFast-Event header.

Payload

POST https://your-app.com/hooks/myfast
X-MyFast-Event: report.completed
X-MyFast-Signature: sha256=<hex hmac of the raw body>
Content-Type: application/json

{
  "event": "report.completed",
  "createdAt": "2026-01-05T14:06:41.500Z",
  "data": {
    "jobId": "clx...",
    "type": "report",
    "status": "completed",
    "domain": "acmeplumbing.com",
    "businessName": "Acme Plumbing",
    "clientTag": "acme-plumbing",
    "reportId": "rep_...",
    "result": { "pdfUrl": "https://...", "companionUrl": "https://...", "bundleUrl": null },
    "error": null,
    "attempts": 1,
    "durationMs": 394000,
    "completedAt": "2026-01-05T14:06:41.000Z"
  }
}

Verifying the signature

Each delivery is signed so you can trust it came from us. Compute an HMAC-SHA256 of the raw request body using your webhook signing secret (shown in your back office, prefixed whsec_), hex-encode it, and compare it to the X-MyFast-Signature header (which is prefixed sha256=). Use a constant-time comparison.

// Node.js (Express raw body)
import crypto from 'crypto';

const signature = req.headers['x-myfast-signature'];      // "sha256=abc123..."
const expected = 'sha256=' + crypto
  .createHmac('sha256', process.env.MYFAST_WEBHOOK_SECRET) // whsec_...
  .update(req.rawBody)                                      // the exact bytes we sent
  .digest('hex');

const ok = crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
if (!ok) return res.status(400).send('bad signature');

Respond with any 2xx status to acknowledge. Webhooks are best-effort notifications — the job status URL is always the source of truth, so if you miss a delivery you can still poll or use the deliveries list in your back office.

Delivery & billing

  • Deliverables. Every report is delivered as a PDF plus a separate companion file with the verbatim “what AI said, word for word” transcript. Files are delivered as secure links (by email if you set deliverEmail, and always on the job's status URL).
  • Who we email. You control this from your back office under Delivery Preferences. Choose “We handle delivery” and we email each client their links directly under your brand; choose “I fulfill my clients” and we never contact your clients — every link is sent to you instead and listed in your back office, grouped by clientTag, so you deliver them yourself. You can also email yourself a single digest of all client links, or the links for one client, at any time.
  • Developer pack entitlement. The developer pack is a one-time purchase per business. Once you buy it for a business, every future report for that same business can include the pack free. A different business requires its own one-time purchase.
  • Pricing (preferred-client tiers). Reports are a flat $49 each for your first 5, then $24 each after that. Developer packs are $199 for your first5, then $99 each — charged once per business, free on every later report for that same business. There is no setup fee and the tier is worked out per account.
  • Pay-as-you-go. There is no weekly run-up and no batch invoice. Each report or developer pack is charged to your saved card at the moment you use it, so your balance is always current.
  • Failed payments. If a charge cannot be collected, your API key is paused (requests return 402 api_key_paused) and we email you a link to update your card. As soon as payment succeeds the key unlocks instantly and queued work resumes — nothing is lost.

Error codes

Errors return a JSON body with a human-readable error and a stable code you can branch on.

HTTPcodeMeaning
401missing_api_keyNo key supplied. Send it as an Authorization: Bearer header.
401invalid_api_keyThe key does not match any active key, or it was revoked.
403account_suspendedThe enterprise account has been suspended. Contact support.
402billing_inactiveNo active payment method on file. Add a card in your back office to activate billing — there is no setup fee.
402api_key_pausedThe key is paused because a pay-as-you-go charge could not be collected. Update your card in your back office to unlock instantly.
429daily_cap_reachedYour account's daily report cap has been reached. Try again after the UTC day rolls over, or raise the cap in your back office.
400invalid_requestRequired fields are missing or malformed.
404not_foundThe requested job or report does not belong to this account.
409report_not_readyA bundle was requested for a report that has not finished yet.

How to implement it into your system

  1. 1. Store your key securely. Put it in your server-side secret manager or environment variables. Never ship it to a browser or mobile client.
  2. 2. Trigger a report from your workflow. Whenever you onboard a client or want a fresh audit, POST to /v1/reports with that client's details and your own clientTag. Persist the returned jobId against the client in your database.
  3. 3. Track completion. Either poll the statusUrl every minute or so until status is completed, or set deliverEmail and let us email the finished links. Both the PDF and companion file URLs arrive in result.
  4. 4. Offer the bundle when you're ready. If a client wants the done-for-you fixes, POST the report's reportId to /v1/bundle and hand them the resulting link.
  5. 5. Handle the paused state. Treat a 402 api_key_paused or billing_inactive as “action needed on billing” in your UI, and retry once the invoice is settled.