Skip to main content
Peel has two phases:
  • Build time creates or updates an API under /v1/apis.
  • Runtime executes one of that API’s published endpoints.
Build time is allowed to be investigative. Peel can inspect pages, capture network and selector evidence, evaluate official public surfaces, draft endpoint candidates, run them, repair them, and reject weak outputs. Runtime does none of that. It only executes the contract that passed publication gates.

Build time

You start with POST /v1/apis:
curl -X POST "$PEEL_API_BASE/v1/apis" \
  -H "X-API-Key: $PEEL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://news.ycombinator.com",
    "instructions": "Get top stories with title, score, and author",
    "wait_for_completion": true,
    "timeout_ms": 120000
  }'
Omit wait_for_completion if you prefer a non-blocking create and want to poll. See the polling pattern in the quickstart. That request can do one of two things:
  • Return matched: true when Peel reuses an existing compatible API.
  • Return matched: false when Peel starts a new build.
The API record then moves through the public lifecycle states (queuedrunning → optionally needs_inputcompleted or failed). See Core concepts for what each state means. When a build reaches completed, Peel publishes the current contract at GET /v1/apis/{api_id}. REST :call, MCP call_endpoint, CLI peel call, and the OpenAPI and MCP exports all project that same stored contract. Failed builds are part of the contract too. A failed API should explain why no endpoint was published through failure_reason_code, failure.non_publishable_reason, and failure.artifact instead of returning a pretend API that happened to work once.

What gets published

The detail record is the runtime contract. It includes:
  • id: the stable handle you use everywhere.
  • status: current lifecycle state.
  • source_url: the URL the API was built from.
  • failure_reason_code and failure: present when status is failed. failure.non_publishable_reason gives the stable reason no API was published when one is available; failure.artifact includes the failure class, retryability, billing disposition, suggested user action, and a support_debug_id.
  • auth_mode: public, mixed_public_and_managed_session, or managed_session_only.
  • requires_session: true if any endpoint needs a target-site session.
  • endpoints: the array of callable operations.
  • links: relative API paths for self, health, revise, rebuild, respond, openapi_export, mcp_export, and endpoint_call_template. Resolve them against https://api.peel.sh or your configured PEEL_API_BASE.
Each entry in endpoints includes the fields that matter at runtime:
  • endpoint_name
  • method: the compiled target transport method. Hosted callers still execute endpoints with POST /v1/apis/{api_id}/endpoints/{endpoint_name}:call.
  • description
  • auth_requirement: public or session_required.
  • input_schema
  • output_schema
  • endpoint_type: usually data; login appears for compiled target-site session flows. guided_action is reserved for deterministic action flows and remains gated until Peel has concrete request-sequence evidence and policy approval.
  • runtime_policy: compact policy metadata for compiled custom artifacts, including network, filesystem, environment, import, and timeout constraints when present.
  • runtime_verification: compact build-time verification metadata, including status, field coverage, item count, observed fields, missing fields, and reason when Peel verified the endpoint before publishing it.
  • optional credit_cost: see Credits and limits for tier defaults.
Runtime callers should rely on the published contract instead of guessing names or payloads.

Endpoint kinds

Peel classifies each published endpoint by the work it does:
  • data + auth_requirement: "public": a deterministic read against the public surface. Usually compiled from captured network traffic. It can also fall back to HTML when the site exposes no stable JSON.
  • data + auth_requirement: "session_required": the same shape, but behind a login. Call the API’s login endpoint first, then pass the returned session_id and encryption_key into later calls.
  • login: initiates a session. Returns session_id and encryption_key in the runtime response.
  • guided_action: a deterministic multi-step flow such as a form submission or mutation. Peel keeps this gated unless the build produced replayable request-sequence evidence, narrow classification, and policy checks. For most public docs workflows, expect read-only data endpoints.
If a data endpoint returns changing field names or breaks when the site changes markup, it was likely an HTML or compiled-artifact path that needs fresh evidence. Call POST /v1/apis/{api_id}/rebuild to regenerate from the current site. See API updates.

Runtime

Runtime calls always go through a published endpoint route:
curl -X POST "$PEEL_API_BASE/v1/apis/$API_ID/endpoints/get_top_stories:call" \
  -H "X-API-Key: $PEEL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "limit": 10
  }'
The call response is normalized to a top-level envelope with these fields:
  • status
  • status_code
  • data
  • error
  • error_code
  • execution_time
Some calls also include session-related fields such as initiates_session, session_id, or encryption_key. Runtime error_code values and build-time failure records are documented in Errors. Runtime failures use the same envelope and may return non-2xx HTTP statuses that mirror status_code in the body. Setup errors such as invalid auth, an unknown API, an unknown endpoint, or an API that is still building are host errors and may return a smaller { "error": "..." } shape instead.

When a build pauses

needs_input means the build is waiting for more input. In that state:
  • GET /v1/apis/{api_id} includes user_input_prompt.
  • POST /v1/apis/{api_id}/respond sends the response payload back to the same API.
Example:
curl -X POST "$PEEL_API_BASE/v1/apis/$API_ID/respond" \
  -H "X-API-Key: $PEEL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "response": {
      "your_field": "your_value"
    },
    "wait_for_completion": true,
    "timeout_ms": 120000
  }'
respond only works while the API is in needs_input. Otherwise the server returns 409.

Build completion: no webhooks

Peel does not currently fire webhooks when a build reaches a terminal state. To wait for a build, use one of: If webhook-based build notifications are important to your workflow, email kaan@peel.sh. The surface is not available yet.

Working with an existing API

Every API keeps the same public handle (api.id) across its lifetime. Once it exists, these are the operations you can perform against it:
OperationRouteUse it to
Execute an endpointPOST /v1/apis/{api_id}/endpoints/{endpoint_name}:callRun a compiled endpoint. See the quickstart.
Inspect the contractGET /v1/apis/{api_id}Fetch the current endpoint list, schemas, auth mode, and lifecycle status.
Revise the APIPOST /v1/apis/{api_id}/reviseKeep the same source URL and change the build instructions. Use when the site is right but the intent needs to change.
Rebuild the APIPOST /v1/apis/{api_id}/rebuildKeep the same instructions and refresh the compiled evidence. Use when the site changed.
Respond to a paused buildPOST /v1/apis/{api_id}/respondUnblock a build stuck in needs_input.
Check healthGET /v1/apis/{api_id}/healthBuild-stage diagnostics until a binding is published, then per-binding counters, quality score, and recommended_action.
Export as OpenAPIGET /v1/apis/{api_id}/exports/openapiDownload an OpenAPI 3.1 spec of every published endpoint. See Exporting an API.
Export as MCPGET /v1/apis/{api_id}/exports/mcpDownload an MCP tool manifest for self-hosted agent runtimes. See Exporting an API.
The full decision tree for revise vs rebuild vs respond, including when to inspect health first, is in API updates.