Skip to content
API

Earnings & monetization

Earnings, payouts, and monetization, acquisition, and debugging insights.

When other users run your paid public Actors, you earn part of the Actor fee they pay. These endpoints cover creator setup (terms and payout details), your earnings ledger, payout requests and statements, pricing changes, publish checks and reviews, and owner insights (monetization, acquisition, debugging). Paths are relative to https://api.scrape.ly. For the rules and the dashboard flow, see Publish & monetize.

All endpoints require authentication. Earnings, creator, and payout endpoints require your account API key: run tokens, CI tokens, and x402 payments get 403 insufficient-permissions. Terms, payout details, payout requests, and statements also reject OAuth app tokens.

How earnings work:

RuleValue
Your share80% of the Actor fee paid with purchased credits. Scrape.ly keeps 20%
Free credits, your own runsEarn nothing
Platform usage (compute, storage, proxy)Not shared
Availability30 days (14 in good standing) after the run settles. Checked hourly
Refunds and chargebacksReverse the earnings they funded with a negative clawback entry
PayoutsOn request, by crypto or PayPal from $25, or by bank transfer from $500. One pending request at a time
First payoutCapped at $500. Request the rest once it's paid
ProcessingEach request is reviewed and sent by hand. There is no fixed processing time

Earnings are kept separate from your credit balance and are never spent on runs.

Creator status

GET/v2/monetization/status

Everything the dashboard checklist shows: what you can do, what's missing, your balances, and the rules.

.bash
curl "https://api.scrape.ly/v2/monetization/status" \
  -H "Authorization: Bearer $SCRAPELY_TOKEN"
.json
{
  "data": {
    "suspended": false,
    "suspendedReason": null,
    "terms": {
      "currentVersion": "2026-10-01",
      "isDraft": false,
      "acceptedVersion": "2026-10-01",
      "acceptedAt": "2026-10-02T09:00:00.000Z"
    },
    "can": { "setPaidPricing": true, "publishPaid": true, "receivePayouts": true },
    "requirements": [
      { "id": "terms", "label": "Accept the Creator Terms", "state": "complete", "requiredFor": ["paid_pricing", "paid_publish"] },
      { "id": "email_verified", "label": "Verify your email address", "state": "external", "requiredFor": ["payouts"] },
      { "id": "public_profile", "label": "Make your profile public", "state": "complete", "requiredFor": ["paid_publish"] },
      {
        "id": "payout_details", "label": "Add payout details", "state": "complete", "requiredFor": ["payouts"],
        "details": { "method": "crypto", "destination": "USDT on TRON (TRC-20) TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", "minimumUsd": 25, "heldUntil": null }
      }
    ],
    "balances": {
      "pendingNd": 12500000000, "availableNd": 45000000000, "paidOutNd": 0, "reservedNd": 0,
      "pendingUsd": 12.5, "availableUsd": 45.0, "paidOutUsd": 0, "reservedUsd": 0
    },
    "rules": {
      "revenueShare": 0.8,
      "holdDays": 30,
      "payoutMinimumUsd": 25,
      "firstPayoutCapUsd": 500,
      "priceIncreaseNoticeDays": 14,
      "payoutMethod": "crypto",
      "payoutMinimums": { "crypto": 25, "paypal": 25, "bank_transfer": 500 },
      "payoutMethods": [
        { "id": "crypto", "label": "Crypto", "minimumUsd": 25 },
        { "id": "paypal", "label": "PayPal", "minimumUsd": 25 },
        { "id": "bank_transfer", "label": "Bank transfer", "minimumUsd": 500 }
      ],
      "cryptoOptions": [{ "asset": "usdt", "network": "tron", "label": "USDT on TRON (TRC-20)" }],
      "destinationHoldHours": 72,
      "payoutsHeldUntil": null,
      "standardHoldDays": 30,
      "trustedHoldDays": 14,
      "trustedMinAccountAgeDays": 60,
      "trusted": false
    },
    "payoutRequest": {
      "available": true,
      "reason": null,
      "message": null,
      "maxAmountUsd": 45.0,
      "minimumUsd": 25,
      "shortfallUsd": null,
      "heldUntil": null,
      "capped": false,
      "pendingRequest": null
    },
    "timeline": {
      "nextAvailableAt": "2026-11-12T08:03:46.000Z",
      "nextAvailableUsd": 4.1,
      "minimumReachedAt": null,
      "isFirstPayout": true
    },
    "usage30d": { "feeRuns": 120, "earningRuns": 95, "freeCreditRuns": 25, "freeCreditFeeUsd": 1.85 }
  }
}
Requirement stateMeaning
completeDone
incompleteNot started
externalHandled by your account sign-up (email verification)

Requirements may carry details, for example currentVersion for the terms. For payout details: method, your destination in full, the method's minimumUsd, and heldUntil while a changed destination is on hold.

rules.payoutMinimumUsd is the minimum for your current method ($25 before you choose one). rules.cryptoOptions lists every supported currency and network (the example shows one). rules.payoutsHeldUntil is set while a destination changed in the last destinationHoldHours is on hold (a first destination saved while your available balance is below the minimum isn't held). rules.holdDays is the hold for your new earnings: trustedHoldDays while trusted is true (at least one paid payout, account at least trustedMinAccountAgeDays old, not suspended, no takedown or rejected review), otherwise standardHoldDays.

timeline is computed from money you've already earned: nextAvailableAt and nextAvailableUsd are the next pending amount to become available, and minimumReachedAt is when your available balance reaches your method's minimum (null if it already has, or if it needs more earnings). isFirstPayout is true until a payout has been paid, while the first-payout cap applies.

usage30d counts runs of your Actors in the last 30 days that charged an Actor fee (feeRuns), the ones that earned you something (earningRuns), and the ones paid entirely with free or promotional credits (freeCreditRuns, with their fees in freeCreditFeeUsd), which earn nothing.

balances.reservedUsd is the amount held by your pending payout request. It's no longer in availableUsd and not yet in paidOutUsd, which counts sent payouts only.

payoutRequest tells you whether you can request a payout now:

FieldMeaning
availabletrue when a request would be accepted
maxAmountUsdThe default and largest amount you can request now: your available balance, or $500 for your first payout (capped: true). null while available is false
minimumUsdThe minimum for your method
reason, messageWhy you can't request one, and a sentence to show. See below
shortfallUsdWith below_minimum, how much more available balance you need
heldUntilWhen a new destination becomes active
pendingRequestYour pending request, in the payout request shape, or null
reasonExample message
below_minimum$12.40 more needed for the PayPal minimum ($25).
destination_on_holdNew payout details become active on 2026-10-16 09:00 UTC.
request_pendingYou have a pending payout request. Cancel it or wait until it is processed before requesting another.
payout_details_missingAdd your legal details and a payout destination under Billing → Payouts to request a payout.
suspendedMonetization is suspended on your account, so payouts are on hold.
GET/v2/monetization/status

Creator Terms

GET/v2/monetization/terms
POST/v2/monetization/terms/accept

GET returns the current terms: version, title, effectiveDate, isDraft, format (markdown), and text, plus your accepted, acceptedVersion, and acceptedAt.

POST accepts a version. Send the version you showed the user:

.bash
curl -X POST "https://api.scrape.ly/v2/monetization/terms/accept" \
  -H "Authorization: Bearer $SCRAPELY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "version": "2026-10-17" }'
StatusMeaning
201Accepted. Returns version, acceptedAt, and alreadyAccepted: false
200You had already accepted this version (alreadyAccepted: true)
409 terms-version-outdatedA newer version exists. data.currentVersion has it

Payout details

GET/v2/monetization/payout-profile
PUT/v2/monetization/payout-profile

PUT replaces your payout details: the payout method, its destination, and the statement details printed on your statements.

FieldRequiredLimits
methodYescrypto, paypal, or bank_transfer
destinationWhen adding or changing the destinationAn object with the fields for the method, below. Leave it out to keep the saved destination of the same method
legalNameYes2–200 characters
countryYesTwo-letter ISO 3166 code
addressLine1YesUp to 200 characters
addressLine2NoUp to 200 characters
cityYesUp to 100 characters
postalCodeNoUp to 32 characters
regionNoUp to 100 characters
vatIdNoUp to 32 characters: letters, digits, spaces, dots, and dashes

destination fields per method:

MethodFieldRequiredLimits
paypalemailYesA valid email, up to 254 characters
cryptoassetYesusdt, usdc, or btc
cryptonetworkYesusdt: tron, ethereum, polygon, solana. usdc: ethereum, polygon, base, solana. btc: bitcoin
cryptoaddressYesA valid address for the network, checksum included
bank_transferaccountHolderNameYes2–140 characters
bank_transferibanOne of iban or accountNumberA valid IBAN: country length and check digits. Spaces are ignored
bank_transferaccountNumberOne of iban or accountNumber4–34 letters and digits
bank_transferroutingCodeNoABA routing number, sort code, IFSC, BSB. 3–34 letters and digits
bank_transferswiftBicUnless iban is from a SEPA country8 or 11 characters
bank_transferbankNameYes2–140 characters
bank_transferbankCountryYesTwo-letter ISO 3166 code
bank_transferholderAddressYes5–300 characters
.bash
curl -X PUT "https://api.scrape.ly/v2/monetization/payout-profile" \
  -H "Authorization: Bearer $SCRAPELY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "method": "crypto",
    "destination": { "asset": "usdt", "network": "tron", "address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t" },
    "legalName": "Jane Doe", "country": "DE", "addressLine1": "Example Str. 1", "city": "Berlin"
  }'

Invalid fields return 400 invalid-input with a per-field data.errors object, keyed destination.<field> for destination fields. method and destination are required.

GET and PUT return:

FieldMeaning
methodThe payout method, or null before you choose one
destinationYour destination in full, including the routing code and holder address for bank transfers. Includes a summary such as Bank transfer DE89370400440532013000
detailsYour statement details
minimumPayoutUsdThe minimum for your method
destinationChangedAtWhen the destination was last added or changed
payoutsHeldUntilWhile a changed destination is on hold, when payouts to it start. Otherwise null
destinationHoldHours72
methods, cryptoOptionsThe methods with their minimums, and the supported crypto currencies and networks
updatedAtWhen the payout details were last saved

Statements, emails and the change log show the destination masked. Adding or changing a destination emails your account address. After a change you can't request a payout to it for 72 hours; a first destination saved while your available balance is below the minimum isn't held. A request you made before the change still goes to the destination it was made with. Saving the same destination again doesn't restart the hold. See Changed destinations wait 72 hours.

Ledger

GET/v2/monetization/ledger

Every entry that changes your balance, newest first. Supports limit (default 20, max 100), offset, and type (comma-separated).

typeAmountBecomes available
earningPositive30 days after the run settled (14 in good standing)
clawbackNegative, after a refund or chargebackSame date as the earning it reverses
adjustmentEither, a correction with a reasonImmediately
payoutNegative, the amount of a payout request, reserved when you make itImmediately
payout_reversalPositive, a cancelled or rejected request returnedImmediately

Each item has id, type, amountNd, amountUsd, availableAt, createdAt, actorId, actorName, runId, relatedEntryId (the earning a clawback reverses), payoutId, funding, source, and reason. An unknown type returns 400.

Payout requests

POST/v2/monetization/payout-requests
GET/v2/monetization/payout-requests
GET/v2/monetization/payout-requests/{requestId}
POST/v2/monetization/payout-requests/{requestId}/cancel

You request a payout once your available balance reaches your method's minimum and your destination is out of its 72-hour hold. The request reserves the amount right away: it leaves your available balance as a payout ledger entry, so it can't be paid twice. You can have one pending request at a time. Scrape.ly reviews each request and sends it by hand to the method and destination saved on the request. There is no fixed processing time.

POST takes an optional amountUsd with up to two decimals. Leave it out to request payoutRequest.maxAmountUsd from the status: your whole available balance, or $500 for your first payout.

.bash
curl -X POST "https://api.scrape.ly/v2/monetization/payout-requests" \
  -H "Authorization: Bearer $SCRAPELY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "amountUsd": 45.00 }'

It returns 201 with the request:

.json
{
  "data": {
    "id": "pr_3f9c2a7e1b4d4c0e9a8f6b5d4c3b2a10",
    "amountNd": 45000000000,
    "amountUsd": 45.0,
    "capped": false,
    "status": "pending",
    "method": "crypto",
    "destination": "TR7NHq…Lj6t",
    "destinationLabel": "USDT on TRON (TRC-20) TR7NHq…Lj6t",
    "statementId": null,
    "createdAt": "2026-10-13T09:00:00.000Z",
    "requestedAt": "2026-10-13T09:00:00.000Z",
    "paidAt": null,
    "paymentReference": null,
    "amountSentUsd": null,
    "feeUsd": null,
    "rejectedReason": null,
    "processedAt": null,
    "cancellable": true
  }
}
FieldMeaning
amountUsdThe amount reserved and to be paid
cappedThe amount was limited by the $500 first-payout cap
method, destination, destinationLabelWhere the payout goes, masked. Saved when you made the request
requestedAtWhen you made the request. createdAt is the same
paidAt, paymentReferenceWhen it was sent, and the transaction ID or payment reference
amountSentUsd, feeUsdWhat arrived and the transfer fee, when Scrape.ly records them
rejectedReasonWhy a request was rejected
processedAtWhen it was paid, rejected, or cancelled
statementIdThe statement issued when it was paid
cancellableYou can still cancel it
statusMeaning
pendingReserved and waiting to be sent
paidSent. A statement is issued
rejectedNot sent, with a rejectedReason. The amount is back in your available balance
cancelledYou cancelled it. The amount is back in your available balance

GET lists your requests, newest first, with items, total, offset, and limit (default 20, max 100). GET /v2/monetization/payouts returns the same list.

POST .../cancel cancels a pending request and returns it with status: "cancelled". Cancelling it again returns the same result. Scrape.ly emails you when a request is paid or rejected.

ErrorWhen
409 payout-below-minimumYour available balance is below the minimum. data has availableUsd, minimumUsd, and shortfallUsd
409 payout-destination-on-holdYour destination is in its 72-hour hold. data.heldUntil says until when
409 payout-request-pendingYou already have a pending request. data.requestId has it
409 payout-details-missingYour legal details or payout destination are missing
403 monetization-suspendedMonetization is suspended on your account
400 invalid-inputamountUsd isn't a positive number with up to two decimals, or is outside the minimum and maxAmountUsd. data has both
404 payout-request-not-foundUnknown request ID
409 payout-request-stateCancelling a request that is already paid or rejected. data.status has its status
409 payout-request-processingCancelling a request that is already being sent
GET/v2/monetization/payout-requests

Statements

GET/v2/monetization/statements
GET/v2/monetization/statements/{statementId}

Statements are self-billing documents, one per paid request: id, number (SCR-<year>-<sequence>), period (YYYY-MM, the month it was paid), payoutId, amountNd, amountUsd, currency, issuer, recipient (your details when it was issued), summary (including requestedAt, paidAt, and paymentReference), issuedAt, and voidedAt. An unknown statement returns 404 statement-not-found. The list supports limit and offset.

GET/v2/monetization/statements

Pricing changes and reviews

GET/v2/actors/{actorId}/pricing-changes
DELETE/v2/actors/{actorId}/pricing-changes/{changeId}
GET/v2/actors/{actorId}/publish-checks
DELETE/v2/actors/{actorId}/publication-review

You change pricing with PUT /v2/actors/{actorId} and pricingInfos. Increases on an Actor with paying users are scheduled 14 days out, and some changes go to review. See When pricing changes take effect and Manual review.

  • pricing-changes lists the Actor's changes: id, status (scheduled, in_review, applied, cancelled, rejected), changeKind, noticeRequired, details, newPricingInfos, and the effective date.
  • DELETE .../pricing-changes/{changeId} cancels a scheduled or in_review change.
  • publish-checks runs the publish checks without publishing.
  • DELETE .../publication-review withdraws a pending review and returns 204.

For Actors you don't own, these return 404 actor-not-found.

Earnings overview

These endpoints read from the same ledger as the creator endpoints.

Summary

GET/v2/earnings

Without type, returns a summary plus the first 5 items of each category (incoming, available, withdrawn).

.bash
curl "https://api.scrape.ly/v2/earnings" \
  -H "Authorization: Bearer $SCRAPELY_TOKEN"
Query paramTypeDefaultDescription
typestring—incoming, available, or withdrawn. Invalid values return 400 invalid-request.
limitnumber20Page size (max 100), used with type.
offsetnumber0Pagination offset, used with type.
.json
{
  "data": {
    "summary": {
      "incoming": { "totalNd": 12500000000, "totalUsd": 12.5, "count": 3 },
      "available": { "totalNd": 45000000000, "totalUsd": 45.0, "count": 5 },
      "paidOut": { "totalNd": 30000000000, "totalUsd": 30.0 }
    },
    "incoming": { "items": [], "total": 3, "hasMore": false },
    "available": { "items": [], "total": 5, "hasMore": false },
    "withdrawn": { "items": [], "total": 2, "hasMore": false },
    "minWithdrawalUsd": 25
  }
}

With type, the response is summary plus a fully paginated items array, total, offset, limit, and minWithdrawalUsd. Each earning item includes id, userId, actorId, actorName, runId, amountNd, amountUsd, createdAt, availableAt, status (pending, available, or withdrawn), withdrawnAt, and withdrawalId.

  • summary.incoming and summary.available are your pending and available balances, after clawbacks and adjustments.
  • withdrawn items are the payout ledger entries of requests that have been paid. Pending, cancelled, and rejected requests aren't listed; see Payout requests. summary.paidOut is the total actually paid out: it leaves out pending requests, and a cancelled or rejected request nets to zero with its payout_reversal.
  • minWithdrawalUsd is the payout minimum for your method.
GET/v2/earnings

Incoming earnings

GET/v2/earnings/incoming

Pending credits still in the 30-day holding period. Supports limit / offset (max 100). Includes summary plus paginated items.

.bash
curl "https://api.scrape.ly/v2/earnings/incoming?limit=20&offset=0" \
  -H "Authorization: Bearer $SCRAPELY_TOKEN"
GET/v2/earnings/incoming?limit=5

Available earnings

GET/v2/earnings/available

Earnings past their hold, which you can request as a payout. Same pagination. Includes summary, items, and minWithdrawalUsd.

.bash
curl "https://api.scrape.ly/v2/earnings/available" \
  -H "Authorization: Bearer $SCRAPELY_TOKEN"
GET/v2/earnings/available?limit=5

Get a single earning

GET/v2/earnings/{earningId}

Returns one earning you own. Unknown IDs return 404 not-found.

.bash
curl "https://api.scrape.ly/v2/earnings/{earningId}" \
  -H "Authorization: Bearer $SCRAPELY_TOKEN"

Monetization insights

Owner-only stats for how much you earned from other users running your Actors. Amounts are USD. month is YYYY-MM (or a name like August 2026); it defaults to the current month, and an unrecognized value also falls back to the current month.

All insight endpoints (monetization, acquisition, debugging) are cached for 5 minutes.

Per-Actor monetization

GET/v2/actors/{actorId}/monetization?month=YYYY-MM
.bash
curl "https://api.scrape.ly/v2/actors/{actorId}/monetization?month=2026-08" \
  -H "Authorization: Bearer $SCRAPELY_TOKEN"

Only the Actor owner can access this (403 forbidden otherwise; 404 actor-not-found if the Actor does not exist).

.json
{
  "data": {
    "totalRevenue": 12.5,
    "totalActorFee": 18.0,
    "totalUsage": 18.0,
    "costPerResult": { "average": 0.01, "minimum": 0, "maximum": 0.04 },
    "dailyResults": { "average": 100, "minimum": 0, "maximum": 400 },
    "dailyRuns": { "average": 8, "minimum": 0, "maximum": 20 },
    "totalUsers": 14,
    "payingUsers": 14,
    "dailyBreakdown": [
      { "date": "2026-08-01", "runs": 4, "results": 80, "revenue": 0.4 }
    ]
  }
}
FieldMeaning
totalRevenueYour share (80%) of Actor fees for the month.
totalActorFeeGross Actor fees users paid. totalUsage currently equals this.
totalUsersDistinct users other than you who ran the Actor that month. payingUsers currently equals this.
dailyBreakdown[].revenueYour share for that day.

Aggregated monetization

GET/v2/monetization?month=YYYY-MM

Same payload, aggregated across all Actors you own.

.bash
curl "https://api.scrape.ly/v2/monetization?month=2026-08" \
  -H "Authorization: Bearer $SCRAPELY_TOKEN"
GET/v2/monetization

Acquisition insights

Page-view funnel for the last 30 days (unique sessions): detail, input, and run views, plus top referrer domains. Owner-only.

Per-Actor acquisition

GET/v2/actors/{actorId}/acquisition
curl "https://api.scrape.ly/v2/actors/{actorId}/acquisition" \
  -H "Authorization: Bearer $SCRAPELY_TOKEN"

Aggregated acquisition

GET/v2/acquisition

Same payload across all Actors you own.

.bash
curl "https://api.scrape.ly/v2/acquisition" \
  -H "Authorization: Bearer $SCRAPELY_TOKEN"
GET/v2/acquisition

Debugging insights

Owner-only run-quality stats for other users' runs of your Actors (your own runs are excluded). Failed includes FAILED and TIMED-OUT.

month is YYYY-MM. If omitted, debugging uses a rolling last 30 days (unlike monetization, which defaults to the calendar month).

Per-Actor debugging

GET/v2/actors/{actorId}/debugging?month=YYYY-MM
curl "https://api.scrape.ly/v2/actors/{actorId}/debugging?month=2026-08" \
  -H "Authorization: Bearer $SCRAPELY_TOKEN"

avgDuration is seconds. successRate and daily value are percentages (0–100).

Aggregated debugging

GET/v2/debugging?month=YYYY-MM

Same payload across all Actors you own.

.bash
curl "https://api.scrape.ly/v2/debugging" \
  -H "Authorization: Bearer $SCRAPELY_TOKEN"
GET/v2/debugging

Errors

StatusTypeMeaning
400invalid-requesttype is not incoming, available, or withdrawn
400invalid-inputInvalid payout details (see data.errors), an invalid payout amountUsd, unknown ledger type, or missing terms version
403forbiddenInsights for an Actor you do not own
403insufficient-permissionsA run, CI, x402, or OAuth token where the account API key is required
403monetization-suspendedRequesting a payout while monetization is suspended
404actor-not-found / not-foundUnknown Actor or earning ID
404statement-not-found / payout-request-not-found / review-not-found / pricing-change-not-foundUnknown statement or payout request, no pending review, or unknown pricing change
409payout-below-minimum / payout-destination-on-hold / payout-request-pending / payout-details-missingA payout can't be requested yet. See Payout requests
409payout-request-state / payout-request-processingThe payout request can't be cancelled anymore
409terms-version-outdatedThe terms version you accepted isn't the current one
409pricing-change-not-cancellableThe pricing change is already applied, cancelled, or rejected