Skip to content
looot docs
Esc
↑↓navigate↵open⌘Jpreview
On this page

Integrate looot into your app

Call any looot job or tool from your own backend with one HTTP request. API key, first call, reading the answer, retries, long runs, files and costs.

Your app can use every looot job and tool directly, without an AI agent: a CRM that finds work emails for new leads, an internal dashboard that enriches companies, a pipeline that pulls SEO rankings every night. It is one REST API with one key and one prepaid balance.

1. Get an API key

In the dashboard, open Settings, API keys and create a key for your app. Give it a monthly spending limit so a bug in your code can never spend your whole balance. Keep the key on your server, never in a browser or mobile app.

export LOOOT_TOKEN="your key"

2. Pick a job or a tool

  • A job is a task, like people.email.find. looot picks a provider for you, and with fallback on it tries the next one if the first finds nothing. Start here.
  • A tool is one provider’s endpoint, like hunter-email-finder. Use it when you need that exact provider.

Browse them all in Jobs and Tools. Each page lists the inputs, the providers and their prices, and ready code.

3. Make the call

One request starts the run and, with wait, returns the answer in the same response.

curl -X POST "https://api.looot.ai/v1/runs" \
  -H "Authorization: Bearer $LOOOT_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: lead-4821-email" \
  -d '{"endpointId":"job:people.email.find","input":{"first_name":"Jane","last_name":"Doe","domain":"example.com"},"fallback":true,"wait":30}'
const response = await fetch("https://api.looot.ai/v1/runs", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.LOOOT_TOKEN}`,
    "Content-Type": "application/json",
    "Idempotency-Key": `lead-${lead.id}-email`,
  },
  body: JSON.stringify({
    endpointId: "job:people.email.find",
    input: { first_name: lead.firstName, last_name: lead.lastName, domain: lead.domain },
    fallback: true,
    wait: 30,
  }),
});
const run = await response.json();
import os, requests

run = requests.post(
    "https://api.looot.ai/v1/runs",
    headers={
        "Authorization": f"Bearer {os.environ['LOOOT_TOKEN']}",
        "Idempotency-Key": f"lead-{lead_id}-email",
    },
    json={
        "endpointId": "job:people.email.find",
        "input": {"first_name": "Jane", "last_name": "Doe", "domain": "example.com"},
        "fallback": True,
        "wait": 30,
    },
    timeout=70,
).json()

4. Read the answer

Field What it holds
status completed, failed, or queued and running while it works
outcome hit (found it), weak, miss (nothing found), error, rejected (bad input)
normalized The answer in looot’s own field names, the same whichever provider answered (for example normalized.email)
result The provider’s raw answer, as it sent it
pricing.finalChargeMicros What this run cost, in millionths of a dollar
route With fallback: every provider tried, in order, and which one answered

Read normalized first. It doesn’t change when looot switches provider.

5. Retries never pay twice

Send the same Idempotency-Key again and you get the same run back, never a second charge. Build the key from your own record (lead-4821-email), so a crashed worker can safely retry.

6. Long runs

wait holds the request for up to 60 seconds. If the run takes longer, you get it back with status: "queued" or "running". Poll it:

curl "https://api.looot.ai/v1/runs/RUN_ID" -H "Authorization: Bearer $LOOOT_TOKEN"

7. Files and text answers

Some tools answer with a file (speech, an image, a video, a PDF) or with CSV or plain text.

  • Small text and CSV answers come back in result.text, with result.format (csv, text, html, xml, markdown).
  • Files and large answers come back as result.media, with a downloadPath. Download it with your key: GET https://api.looot.ai + downloadPath.

8. What it costs

  • Every run reserves its maximum price first, then charges what the provider really billed. The rest goes back to your balance.
  • A run that fails at the provider costs $0. A job run that finds nothing usually costs $0.
  • Check your balance with GET /v1/balance and top up in the dashboard.

9. Errors to handle

HTTP Code What to do
402 insufficient_balance Top up, then retry with a new idempotency key
402 key_spend_limit_reached This key hit its monthly limit. Raise it in Settings, API keys
400 validation_error The input doesn’t match the tool. error.details names the field
429 too_many_inflight_runs Slow down, then retry

Every error has error.code, error.message and error.retryable.

Write actions

Some tools change data in an account you connected (send an email, create a CRM contact, delete a file). Their pages say Write action at the top, and GET /v1/operations/{id} returns effectClassification: "effectful". Call those only on purpose.

Was this page helpful?