If you are an in-house developer at a $5M to $10M GC, or a tech-forward solo contractor who can read a curl command, you can ship a production AI agent on top of Opsite's API in a weekend. The platform exposes 40 tools across 4 scope groups (Sales, Project execution, Money, Operations), bearer-token authentication, idempotency keys, rate-limit headers, and a stable contract surface at /api/v1/*. Based on Opsite's internal data, the first useful agent - one that closes a real business loop - usually ships in 6 to 14 hours of focused work.

Bar Benbenishty is a licensed California GC (CSLB #1103938) and the founder of Opsite. He wrote this guide because contractors with one developer on staff are outshipping VC-funded construction startups by building exactly the agent their business needs and nothing else.

Want to see the platform live first? Book a demo and we will walk you through the full feature set before you write a line of code.

What does the Opsite API give me to build against?

The Opsite API gives you 40 tools, role-scoped per-user API keys, request-id propagation, idempotency, and per-key rate limits - all served from a stable /api/v1/* contract surface. According to data from contractors building custom integrations on Opsite, the most-built first agent is a payments collection agent that wraps list_overdue_invoices and send_payment_reminder.

Here is the load-bearing surface, all shipped in production:

  • Bearer-token auth: Authorization: Bearer opsk_<prefix>_<secret>
  • 40 scopes across Sales, Project execution, Money, Operations
  • Per-user keys (not contractor-wide), so revoking a developer key does not affect production
  • Role-scope enforcement: a Field role cannot mint money scopes; a Viewer is read-only; a PM cannot write subs, POs, or sub-payments
  • X-Request-Id on every response, generated upstream or honored if you send one
  • X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset on every response (success path included, not just 429)
  • Idempotency-Key on unsafe methods, Stripe-shaped: opt-in, hashed body, cached 24 hours, 422 on body mismatch
  • Audit log table api_key_calls records method, path, status, scope_required, scope_granted, ip, duration
  • OpenAPI 3.1 spec at /openapi.yaml, AI plugin manifest at /.well-known/ai-plugin.json, /llms.txt for AI discovery

The MCP server source lives at apps/mcp-server/src/{client,index,tools,schemas}.ts if you want to study the patterns directly.

How do I authenticate and make my first API call?

You authenticate by minting a per-user API key in Settings, then sending it as a bearer token. According to Opsite's internal data, the median time from account creation to a successful list_jobs call from curl is under 10 minutes.

Step 1: Mint a key. Go to app.useopsite.com/settings/api-keys, click "New key," pick a label, check the scopes you actually need, and pick a rate-limit tier (api, ai, auth, or strict). Opsite shows the plaintext token once. Copy it. The format looks like opsk_a1b2c3d4e5f6_<32hex>.

Step 2: Hit the API:

curl -H "Authorization: Bearer opsk_xxx_yyy" \
  -H "Idempotency-Key: $(uuidgen)" \
  https://app.useopsite.com/api/v1/jobs

Step 3: Read the response headers. You should see:

X-Request-Id: 7f3a...
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 99
X-RateLimit-Reset: 1714521600

That is your full handshake. From here, you can wire any LLM (Claude, GPT-4o, Gemini, or a local Llama model) to call these endpoints with structured tool definitions.

What does a real production agent look like in TypeScript?

A real production agent is a thin client that wraps the Opsite API with retries, idempotency, and a typed tool surface. Here is a payments collection agent that lists overdue invoices and sends payment reminders, following the same patterns Opsite's own MCP server uses:

import { randomUUID } from "node:crypto";

const API = process.env.OPSITE_API_URL ?? "https://app.useopsite.com/api/v1";
const KEY = process.env.OPSITE_API_KEY!;

async function call<T>(
  method: string,
  path: string,
  body?: unknown,
  idempotencyKey?: string
): Promise<T> {
  const headers: Record<string, string> = {
    "Authorization": `Bearer ${KEY}`,
    "X-Request-Id": randomUUID(),
    "User-Agent": "yourgc-agent/1.0",
  };
  if (body) headers["Content-Type"] = "application/json";
  if (idempotencyKey) headers["Idempotency-Key"] = idempotencyKey;

  const res = await fetch(`${API}${path}`, {
    method,
    headers,
    body: body ? JSON.stringify(body) : undefined,
  });

  const requestId = res.headers.get("X-Request-Id");
  const remaining = res.headers.get("X-RateLimit-Remaining");

  if (!res.ok) {
    const err = await res.json().catch(() => ({}));
    throw new Error(
      `Opsite ${res.status} on ${method} ${path} (req ${requestId}): ${err.message ?? res.statusText}`
    );
  }
  return res.json() as Promise<T>;
}

// Tool 1: list overdue invoices
async function listOverdueInvoices(minBalance = 0) {
  const result = await call<{ records: Array<{ id: string; fields: Record<string, unknown> }> }>(
    "GET",
    `/airtable/invoices?filter=overdue&min_balance=${minBalance}`
  );
  return result.records;
}

// Tool 2: send a payment reminder (idempotent)
async function sendPaymentReminder(invoiceId: string) {
  return call(
    "POST",
    `/invoices/${invoiceId}/payment-reminder`,
    { channel: "email" },
    `reminder-${invoiceId}-${new Date().toISOString().slice(0, 10)}`
  );
}

// Agent loop
async function main() {
  const overdue = await listOverdueInvoices(10_000);
  console.log(`Found ${overdue.length} overdue invoices over $10k`);
  for (const invoice of overdue) {
    await sendPaymentReminder(invoice.id);
  }
}

main();

Three things worth calling out. First, the Idempotency-Key is deterministic per invoice per day, so a retry on the same day is a no-op instead of a double-send. Second, the X-Request-Id is read on every error so support can trace the call in the Opsite audit log. Third, the rate-limit headers let you pace the loop instead of hitting a 429.

"As a licensed GC who built Opsite after running my own remodels, I will tell you the single highest-ROI agent for a small GC is a payments agent. It is 40 lines of code. It pays for the entire engineering hire in the first quarter." - Bar Benbenishty, founder, Opsite

What scopes should I request for what kind of agent?

The scopes you request should match the smallest set of tools the agent needs. According to Opsite's internal data on API key activity, the most over-scoped keys come from developers who copy-paste the full scope checkbox grid. Mint narrow keys. Rotate them quarterly.

Agent typeScope groupSpecific scopesRisk
Sales follow-up botSalesleads:read, leads:write, proposals:readLow
Daily log triage agentOperationsdaily_logs:read, action_items:read, action_items:writeLow
Project status summarizerProject executionjobs:read, change_orders:read, permits:readLow
Payments collection agentMoneyinvoices:read, invoices:write, draws:readMedium
Sub onboarding agent (GL insurance, workers comp, W-9 verification)Operationssubs:read, subs:write, compliance:readMedium
Cash flow analytics agentMoney + Projectinvoices:read, draws:read, jobs:readLow
Full ops manager agentAll four groupsbroadHigh - gate behind Phase 5 mandates when shipped

The Money group is the one to be conservative on. Phase 3.5 (broader writes including sub-payments and POs) is intentionally on a 4-week observation hold while Opsite watches the audit logs from Phase 3 in production.

How do I handle errors, retries, and idempotency correctly?

Handle errors and retries by reading X-Request-Id on every response, treating 5xx as retryable with backoff, treating 4xx as never-retryable, and setting Idempotency-Key on every unsafe method. According to Opsite's internal data, the most common agent bug is retrying a 422 (validation error) instead of fixing the payload.

HTTP statusMeaningWhat your agent should do
200 / 201SuccessContinue
401Bad or revoked bearer tokenStop. Page a human.
403Scope deniedStop. Re-mint a key with the right scope.
404Resource missingDo not retry. Investigate.
409Idempotency key reused on a concurrent retryWait and re-read the original response
422Body mismatch on idempotency, or validation errorDo not retry. Fix the request.
429Rate limitedBackoff using X-RateLimit-Reset
5xxServer errorRetry with exponential backoff, max 5 attempts

The Idempotency-Key window is 24 hours. After that, the same key is fresh again. Use a deterministic key (resource id plus a timestamp slice) so retries inside that window are safe and retries outside it are intentional.

What is shipped today versus what should I plan for?

What is shipped today is enough to build a real business agent. What is coming next will let you remove polling and add cryptographic mandates for money-moving actions. Plan for both.

Shipped:

  • 40 tools across 4 scope groups
  • Bearer-token auth, scope enforcement, audit log
  • X-Request-Id, X-RateLimit-*, Idempotency-Key
  • OpenAPI 3.1 spec, AI plugin manifest, /llms.txt
  • Hosted MCP at /api/mcp, stdio MCP via @opsite/mcp-server
  • Voyage voyage-3-lite semantic search at 512 dims across daily logs, messages, action items, jobs, proposals, leads
  • Outcome tracking via agent_outputs and a weekly digest
  • Sub compliance tracking: GL insurance expiry, workers comp certificates, W-9 status (readable via compliance:read scope)

Pending:

  • Outbound webhooks (Phase 4): subscribe to invoice.paid, change_order.signed, proposal.viewed instead of polling
  • Cryptographic agent mandates (Phase 5): a contractor signs a mandate authorizing your agent to approve change orders up to a dollar limit, Opsite enforces it server-side
  • Voice plus agent loop (Phase 6)
"Every GC I talk to has the same story. They tried Procore, realized it costs more than their truck payment, and went back to spreadsheets. The API is the middle ground. You build the agent that fits your workflow, you keep the platform on flat-rate pricing, and you do not get nickel-and-dimed on per-user fees." - Bar Benbenishty, founder, Opsite

Ready to start building? Book a demo and we will walk you through the API surface and MCP toolset live.

Frequently Asked Questions

How do I get an Opsite API key for development?

Mint one in Settings at app.useopsite.com/settings/api-keys. Pick the scopes your agent needs, set a 90-day expiry, and choose the api rate-limit tier for development. According to Opsite's internal data, the median first key has 4 to 6 scopes attached, not all 40.

Does Opsite charge per API call?

No. The API is included in Opsite's flat-rate plans ($349 to $999 per month, no per-user fees). Rate limits apply per key with 4 tiers. Compared to Procore ($6,000 to $10,000+ per month for a 15-person team, based on publicly listed pricing as of 2026), Buildertrend (per-seat licensing fees), or CoConstruct (per-project pricing), the difference on a $5M GC is typically $50,000 to $100,000 a year in software costs alone.

What programming languages can I use?

Any language that can make an HTTP request. The Opsite team maintains the TypeScript MCP server (@opsite/mcp-server) as the reference implementation. Contractors have shipped agents in Python, Go, and Rust against the same /api/v1/* surface.

How do I test my agent without hitting production data?

Mint a Viewer-role key (read-only) and start there. Promote to write scopes only after the agent has been observed for at least one full week. Every call appears in the api_key_calls audit table for review.

What happens when Phase 4 webhooks ship?

You stop polling. Register a webhook URL for invoice.paid or change_order.signed, Opsite signs the payload with HMAC-SHA256, and your agent gets a push within 60 seconds of the state transition. Migration is additive - your existing polling code keeps working.