BytewellsDocs

Preview documentation. Bytewells is in private beta. These pages are incomplete and will change often. Do not use them for production integrations.

API reference

REST API under /v2 — Apify-compatible storage and runs, plus marketplace endpoints.

Bytewells Cloud provides a REST API compatible with the Apify API v2, plus marketplace endpoints for the Store, rentals, credits and publishing (see Marketplace).

Base URL

https://bytewells.com/api/v2

Authentication

All requests require a Bearer token in the Authorization header:

curl -H "Authorization: Bearer YOUR_TOKEN" \
  https://bytewells.com/api/v2/datasets

All resource endpoints are user-scoped — authenticated users can only access their own resources.

Three token kinds are accepted:

  • cp_-prefixed API keys (created via the endpoints below, shown in full only once at creation).
  • JWTs returned by /v2/auth/login and /v2/auth/register.
  • Run-scoped tokens (rt_<runId>.<signature>) that the runner injects into each Actor container as APIFY_TOKEN. They act as the run's owner only while the run is active (plus a 10-minute grace period) and only on the storage and run endpoints an Actor needs; every other endpoint returns 403.

As an alternative to the Bearer header, a ?token= query parameter is accepted on any authenticated route — useful for browser download links that can't set custom headers.

MethodEndpointDescription
POST/v2/auth/registerSign up {email, password, name?, username?, referralCode?}, returns user + JWT
POST/v2/auth/loginLog in with email/password, returns a JWT
GET/v2/auth/apify/startBegin Login/Connect with Apify (intent=login|connect, PKCE); see Import from Apify
GET/v2/auth/apify/callbackOAuth redirect from Apify (sets JWT cookie / connection)
GET/v2/auth/meGet the authenticated user
POST/v2/auth/api-keysCreate an API key (raw key returned once)
GET/v2/auth/api-keysList API keys
DELETE/v2/auth/api-keys/:keyIdRevoke an API key

Registration is open when PUBLIC_REGISTRATION=true (the default). Every new user gets a personal organization that holds billing, credits and published listings. The first admin user is created on startup from the ADMIN_EMAIL / ADMIN_PASSWORD environment variables.


Datasets

Store and retrieve scraped data.

MethodEndpointDescription
GET/v2/datasetsList all datasets
POST/v2/datasetsCreate a new dataset
GET/v2/datasets/:idGet dataset details
DELETE/v2/datasets/:idDelete a dataset
POST/v2/datasets/:id/itemsPush items to dataset
GET/v2/datasets/:id/itemsRetrieve items

Push Items

curl -X POST \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '[{"title": "Item 1"}, {"title": "Item 2"}]' \
  https://bytewells.com/api/v2/datasets/{id}/items

Retrieve Items

Supports pagination with offset and limit query parameters (max limit: 1000).

curl -H "Authorization: Bearer $TOKEN" \
  "https://bytewells.com/api/v2/datasets/{id}/items?offset=0&limit=100"

Omitting limit returns the entire dataset (matching real Apify), streamed as plain JSON with Apify-style pagination headers — no in-memory materialization on the server, and offset is still honored. Passing an explicit limit uses the paged path. Before v1.6.0 the no-limit case silently defaulted to 100 items; Apify-compatible clients fetching without a limit were truncated.

Pass ?download=1 to stream the entire dataset as a single JSON array file (attachment disposition) — same zero-materialization path.


Key-Value Stores

Store arbitrary data by key.

MethodEndpointDescription
GET/v2/key-value-storesList all stores
POST/v2/key-value-storesCreate a new store
GET/v2/key-value-stores/:idGet store details
DELETE/v2/key-value-stores/:idDelete a store
GET/v2/key-value-stores/:id/keysList record keys
PUT/v2/key-value-stores/:id/records/:keySet a record
GET/v2/key-value-stores/:id/records/:keyGet a record
DELETE/v2/key-value-stores/:id/records/:keyDelete a record

Common Keys

  • INPUT — Actor input configuration
  • OUTPUT — Actor output/results

Presigned Record URLs

GET .../records/:key?presigned=1 returns a presigned S3 URL valid for 1 hour instead of the record body — useful for large or binary values (screenshots, big JSON) the browser should fetch directly from object storage.


Request Queues

Manage URLs to crawl with automatic deduplication.

MethodEndpointDescription
GET/v2/request-queuesList all queues
POST/v2/request-queuesCreate a new queue
GET/v2/request-queues/:idGet queue details
DELETE/v2/request-queues/:idDelete a queue
GET/v2/request-queues/:id/headGet next pending requests
POST/v2/request-queues/:id/head/lockLock and fetch requests
POST/v2/request-queues/:id/requestsAdd request to queue
POST/v2/request-queues/:id/requests/batchBatch add requests
GET/v2/request-queues/:id/requests/:requestIdGet request details
PUT/v2/request-queues/:id/requests/:requestIdUpdate request status
PUT/v2/request-queues/:id/requests/:requestId/lockProlong request lock
DELETE/v2/request-queues/:id/requests/:requestId/lockRelease a lock

Deduplication

Requests are deduplicated by uniqueKey. Adding a request with an existing uniqueKey is a no-op.

Locking

The lock endpoint (POST .../head/lock) supports distributed crawling. Parameters:

  • lockSecs — Lock duration in seconds (max 86400)
  • limit — Number of requests to fetch (max 1000)
  • clientKey — Unique identifier for the crawling client

Actors

Manage Actor definitions.

MethodEndpointDescription
GET/v2/actsList all Actors
POST/v2/actsCreate an Actor
GET/v2/acts/:idGet Actor details
PUT/v2/acts/:idUpdate an Actor
DELETE/v2/acts/:idDelete an Actor
POST/v2/acts/:id/runsStart a new run
POST/v2/acts/:id/run-syncRun an Actor and wait for finish

Wherever :id identifies an Actor, you can pass its id, the name of one of your own Actors, or username~actor-name (Apify style) for a Store Actor.

GET /v2/acts/:id also returns inputSchema, readme, username and, when the Actor is listed in the Store, a listing summary. Users entitled to run an Actor they don't own get a read-only view.

Entitlement and billing

Starting a run (POST /v2/acts/:id/runs, run-sync, reruns and schedules) checks, in order:

  1. Entitlement. You own the Actor, or its listing is free, or your organization has a live rental (TRIALING/ACTIVE) or an unexpired time-window pass. On run-start paths only (not run-scoped tokens), if pass auto-purchase is enabled a fare-capped pass may be bought from prepaid credits. Otherwise 402 with error type rental-required, data.listingSlug, and when the Actor sells passes a machine-readable data.passes offer.
  2. Credits. Non-owner runs (and any run by a non-admin) need a positive prepaid credit balance, else 402 insufficient-credits.

Request and response shapes of these endpoints are unchanged from Apify's.

Runs are billed at COMPUTE_PRICE_PER_CU_USD (default $0.15) per compute unit: 1 CU = 1 GB of memory for 1 hour, billed per second with a 60-second minimum.

Deleting Actors

DELETE /v2/acts/:id refuses to delete an Actor that has runs, returning 409 with error type actor-has-runs. Pass ?force=true to cascade-delete the Actor together with its run history (and the runs' webhook deliveries). Force delete still returns 409 (actor-has-active-runs) while any run is READY, RUNNING, or ABORTING — abort those first.

Input Validation

Actor create/update bodies are validated with the following constraints:

  • name — 1-100 chars, alphanumeric with dots, dashes, underscores
  • title — Max 200 chars
  • description — Max 5000 chars
  • defaultRunOptions.timeoutSecs — Max 86400 seconds (24h)
  • defaultRunOptions.memoryMbytes — Max 16384 MB (16 GB)
  • maxRetries — 0-10
  • retryDelaySecs — 1-3600 seconds
  • version — 1-64 chars, alphanumeric with . _ + -

The run-dispatch body (POST /v2/acts/:id/runs) uses bare timeout and memory fields instead, with the same 86400-second and 16384-MB caps.


Actor Versions & Builds

Manage source versions and Docker image builds for an Actor.

MethodEndpointDescription
GET/v2/acts/:id/versionsList versions
POST/v2/acts/:id/versionsCreate a version
GET/v2/acts/:id/versions/:versionIdGet version details
DELETE/v2/acts/:id/versions/:versionIdDelete a version
GET/v2/acts/:id/buildsList builds
POST/v2/acts/:id/buildsStart a build
GET/v2/acts/:id/builds/:buildIdGet build details
POST/v2/acts/:id/builds/:buildId/abortAbort a build
GET/v2/acts/:id/builds/:buildId/logsGet build logs

Hosted builds from source

POST /v2/acts/:id/builds/source?version=0.0&tag=latest with body application/gzip (a tar.gz of the Actor directory) uploads the source and queues a build on the builder. It returns { data: Build }; poll the build or read its logs until it finishes. Builds fill the Actor's inputSchema, readme and actor.json from .actor/input_schema.json, README.md and .actor/actor.json. bw push uses this endpoint.

Images are named bytewells/<username>/<actor-name> with tags latest and b-<buildId>, prefixed by the image registry in production.


Runs

Monitor Actor executions.

MethodEndpointDescription
GET/v2/actor-runsList all runs
GET/v2/actor-runs/:idGet run status
PUT/v2/actor-runs/:idUpdate run status
POST/v2/actor-runs/:id/abortAbort a running Actor
POST/v2/actor-runs/:id/resurrectResurrect a failed run
GET/v2/actor-runs/:id/logsGet run logs
POST/v2/actor-runs/:id/logsAppend log entry
GET/v2/actor-runs/:id/logs/rawDownload raw log text
GET/v2/actor-runs/:id/logApify-compatible alias for /logs/raw
POST/v2/actor-runs/:id/ingest-crawler-statsIngest the run's Crawlee statistics blob into stats
GET/v2/actor-runs/:id/dataset/itemsGet run's dataset items
GET/v2/actor-runs/:id/key-value-store/records/:keyGet run's KV store record

Platform extensions (not part of the Apify v2 surface)

These endpoints power the dashboard and are safe to use from custom tooling, but don't expect them from apify-client or the Apify platform:

MethodEndpointDescription
POST/v2/actor-runs/:id/rerunRerun a terminal (FAILED/ABORTED/TIMED-OUT) run as a new run (since 1.7.0): fresh id and storages, the origin's INPUT bytes, timeout/memory, per-run webhooks, and (within their 24h TTL) envVars are copied; originRunId links back to the first run in the chain. The origin row is untouched. 409 input-not-found when retention already reaped the origin's INPUT; 409 rerun-already-active when a rerun (or runner auto-retry) of the same chain is already queued or running — one active clone per chain, enforced transactionally via a per-chain advisory lock that the runner's auto-retry path takes too, so a manual rerun and an infra retry can't both win. Prefer this over resurrect whenever a webhook consumer keys on the run id.
GET/v2/actor-runs/statsAggregate status counters (total, running, succeeded, failed) plus failures in the last 24h, in one indexed query.
GET/v2/actor-runs/histogramHour-bucketed run counts (?hours=24) for the dashboard throughput chart; server-side aggregation, bounded response.
GET/v2/actor-runs/:id/costCost analysis for one finished run (since 1.3.0): your cost via actual-overlap droplet attribution, an Apify compute-unit estimate, savings %, and the inputs behind the numbers. 400 run-not-finished before terminal status. Computed on read, never persisted.
GET/v2/actor-runs/costs?ids=a,bBatch your-cost for up to 50 runs (since 1.4.0), answered in two set-based queries. Returns { data: { costs: { [runId]: { yourCostUsd } } } } where yourCostUsd is 0 when there is no billable compute and null when attribution was never recorded. Unknown, other-user, and non-terminal ids are silently omitted; >50 ids is a 400.

Run Status Values

StatusDescription
READYQueued, waiting to start
RUNNINGCurrently executing
SUCCEEDEDCompleted successfully
FAILEDExecution failed
ABORTEDManually stopped
ABORTINGAbort requested, not yet terminal (read/filter-only — accepted by the list-runs status filter, not by run update)
TIMED-OUTExceeded time limit

Run response shape (v1.0-committed)

Every endpoint that returns a run (LIST, GET-by-id, PUT, abort, resurrect, rerun) emits the same shape. Notable fields:

FieldTypeNotes
idstringApify-style 21-char nanoid.
actIdstringOwning actor id.
statusenumSee "Run Status Values" above.
defaultDatasetIdstring | nullDataset created at run start; null if the run failed before SDK init.
defaultDatasetItemCountnumber | nullLive count from datasets.item_count, joined per-request. Null when there is no default dataset. Always present on the response — sourced via the centralized RUN_SELECT_WITH_DATASET_COUNT join in the API. Use this when integrating from the dashboard or custom tooling.
defaultKeyValueStoreIdstring | nullDefault KV store for the run.
defaultRequestQueueIdstring | nullDefault request queue for the run.
options.timeoutSecsnumberEffective timeout for this run.
options.memoryMbytesnumberEffective memory limit for this run.
statsobjectCrawlee SDK statistics ingested at run completion, plus the live dataset item count below for Apify-client compatibility.
stats.datasetItemCountnumberSame value as defaultDatasetItemCount, defaulted to 0 when there is no dataset. Mirrors Apify's nested location so apify-client consumers reading run.stats.datasetItemCount work unchanged.
exitCodenumber | nullProcess exit code from the runner; null while the run is still in flight.
startedAt / finishedAtISO stringWall-clock timestamps; finishedAt is null until terminal.
createdAt / modifiedAtISO stringRow lifecycle timestamps.
originRunIdstring | nullFirst run in the chain when this run was produced by the runner's infra auto-retry or by rerun; chains collapse to the original (never a multi-hop walk). Null for first-hand runs.
retryCountnumberHow many infra auto-retries the runner has performed for this run row. Always 0 for runs created via rerun (a rerun is a new run, not a retry).

Note on webhooks: the webhook payload's resource.stats is built by the runner from the ingested Crawlee statistics blob and does NOT currently mirror stats.datasetItemCount — webhook receivers that need the dataset count should query /v2/actor-runs/:id from the resource.id they receive. This is tracked for parity in v1.0.1.


Webhooks

Receive HTTP callbacks when runs reach a terminal state. Webhooks can be standalone (catalog) or attached to a single run via the webhooks field on run dispatch.

MethodEndpointDescription
POST/v2/webhooksCreate a webhook
GET/v2/webhooksList webhooks (supports scope, runId, runActorId filters)
GET/v2/webhooks/:webhookIdGet webhook details
PUT/v2/webhooks/:webhookIdUpdate a webhook
DELETE/v2/webhooks/:webhookIdDelete a webhook
GET/v2/webhooks/:webhookId/deliveriesList delivery attempts
POST/v2/webhooks/:webhookId/testSend a test delivery

Supported event types are the four terminal run events:

  • ACTOR.RUN.SUCCEEDED
  • ACTOR.RUN.FAILED
  • ACTOR.RUN.TIMED_OUT
  • ACTOR.RUN.ABORTED

Subscriptions to other Apify event types (e.g. ACTOR.RUN.CREATED) are rejected with a 400.


Schedules

Run Actors automatically on a cron schedule.

MethodEndpointDescription
POST/v2/schedulesCreate a schedule
GET/v2/schedulesList schedules
GET/v2/schedules/:scheduleIdGet schedule details
PUT/v2/schedules/:scheduleIdUpdate a schedule
DELETE/v2/schedules/:scheduleIdDelete a schedule

Users

MethodEndpointDescription
GET/v2/users/meGet current user (Apify-compatible)
GET/v2/users/me/limitsGet account limits
PUT/v2/users/meUpdate current user (e.g. proxy password)

GET /v2/users/me uses optional authentication: unauthenticated callers receive an anonymous stub instead of a 401. The Apify SDK calls this endpoint to resolve the proxy password (data.proxy.password) when APIFY_PROXY_PASSWORD is not set in the container environment.


System & Operations

MethodEndpointDescription
GET/v2/system/infoVersion, storage health, execution defaults, scaler config
GET/v2/system/retention/statusRetention reaper state (admin-only)
GET/v2/scaler/statusAuto-scaler status (admin-only)
GET/healthLegacy health check
GET/health/liveLiveness probe
GET/health/readyReadiness probe — returns 503 when any storage backend (PostgreSQL, Redis, S3) is degraded
GET/metricsPrometheus metrics (admin-only unless METRICS_PUBLIC=true)

The /health* and /metrics endpoints are served at the root, outside the /v2 prefix.


Marketplace

Bytewells extensions for the Store, rentals, credits and publishing. They are not part of the Apify API.

Money model: compute is prepaid credits kept by Bytewells; passes are one-off debit of those credits with earnings paid to the developer monthly; rentals are Stripe subscription Checkout (programmatic Product+Price) charged on the platform account, with earnings paid to the developer monthly. See Billing and Passes.

Store (public, no auth)

MethodEndpointDescription
GET/v2/storeSearch listings. Query: search, category, sortBy (popularity | newest | price), limit, offset
GET/v2/store/categoriesList categories
GET/v2/store/:username/:actorNameListing detail: README, input schema, pricing, publisher, stats

Renting

Paid rentals use Stripe Checkout mode=subscription with the listing's Product/Price. Trials use the listing's trialDays (0–30). Body must include consentToShareContact: true.

MethodEndpointDescription
POST/v2/store/:username/:actorName/rentStart or resume rental Checkout. 200 {checkoutUrl, rentalId} for paid; free listings activate immediately. 409 rental-exists if live.
GET/v2/me/rentalsYour organization's rentals
POST/v2/me/rentals/:id/cancelCancel at period end (Stripe) or end free/trial immediately

One trial per (listing, renter org), ever. Publisher must be payable (409 publisher-not-payable).

Passes

Passes debit prepaid credits (not Checkout). No card confirmation.

MethodEndpointDescription
GET/v2/store/:username/:actorName/passesTiers, active pass, fare-capped quotes, autoPurchaseEnabled
POST/v2/store/:username/:actorName/passesBody {consentToShareContact: true, tier?}. Buys Flash/Burst/Sprint (or MONTHLY) from credits
GET/v2/me/passesPasses your org holds
GET, PUT/v2/me/pass-settingsOpt in/out of auto-purchase on run start ({autoPurchase, consentToShareContact?})

402 insufficient-credits if the balance cannot cover the charge; 409 publisher-not-payable if the developer has been unable to receive payouts for over 90 days (or is in an unsupported payout country).

Organization and credits

MethodEndpointDescription
GET/v2/me/orgYour personal organization, referral code and link
PUT/v2/me/orgRename the organization
GET/v2/me/creditsAvailable compute credit and ledger
POST/v2/billing/credits/checkoutBody :amountUsd (5–1000). Returns Stripe Checkout URL to top up credits
POST/v2/billing/portalStripe Customer Portal URL (payment methods / invoices for top-ups)

Credits pay for compute and for pass purchases. The sign-up credit expires after 90 days.

Publishing

MethodEndpointDescription
GET, POST/v2/me/listingsList or create listings (pricingModel: FREE or FLAT_PRICE_PER_MONTH, price, trial, passes)
GET, PUT/v2/me/listings/:idRead or update a listing
POST/v2/me/listings/:id/publishPublish. Paid listings need a payable Connect account
POST/v2/me/listings/:id/unpublishUnpublish
GET/v2/me/apifyApify OAuth connection status (configured, connected, username) — see Import from Apify
DELETE/v2/me/apifyDisconnect Apify
GET/v2/me/apify/actorsList Actors on the connected Apify account
POST/v2/me/apify/importBody { actorIds, update?, discountPct? } — import selected Actors as drafts
PUT/v2/me/payout-countryBody {country} (ISO alpha-2, supported payout countries only). Locked once a Connect account exists
POST/v2/billing/connect/onboardOptional body {country} (must match the payout country). Returns Connect onboarding URL
GET/v2/billing/connect/statusConnect account status and payable
GET/v2/me/publisher/customersRenters and pass buyers (name and email, with consent)
GET/v2/me/publisher/statsListing and rental stats
GET/v2/me/publisher/earningsEarnings totals, per-listing figures, balance and payoutHistory

Commission on a new rental or pass: 0% if the renter signed up with your referral link, otherwise 10%. Stripe’s card processing and billing fees are deducted from the developer’s earning at cost; Bytewells pays the fixed Connect fees. Earnings are held 14 days, then paid in one monthly transfer once the payable balance reaches $50 (converted to the platform settlement currency, e.g. EUR, at a rate locked on the payout).

Stripe webhook and admin

MethodEndpointDescription
POST/v2/billing/stripe/webhookSnapshot events (raw body, STRIPE_WEBHOOK_SECRET). Not for API clients
POST/v2/billing/stripe/webhook/thinThin / Connect v2 events (STRIPE_THIN_WEBHOOK_SECRET when configured)
GET/v2/admin/marketplace/metricsAdmin only: GMV, MRR, take rate, listings, paid rentals, sign-ups

On this page