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:
| Rule | Value |
|---|---|
| Your share | 80% of the Actor fee paid with purchased credits. Scrape.ly keeps 20% |
| Free credits, your own runs | Earn nothing |
| Platform usage (compute, storage, proxy) | Not shared |
| Availability | 30 days (14 in good standing) after the run settles. Checked hourly |
| Refunds and chargebacks | Reverse the earnings they funded with a negative clawback entry |
| Payouts | On request, by crypto or PayPal from $25, or by bank transfer from $500. One pending request at a time |
| First payout | Capped at $500. Request the rest once it's paid |
| Processing | Each 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
/v2/monetization/statusEverything the dashboard checklist shows: what you can do, what's missing, your balances, and the rules.
curl "https://api.scrape.ly/v2/monetization/status" \
-H "Authorization: Bearer $SCRAPELY_TOKEN"{
"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 state | Meaning |
|---|---|
complete | Done |
incomplete | Not started |
external | Handled 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:
| Field | Meaning |
|---|---|
available | true when a request would be accepted |
maxAmountUsd | The default and largest amount you can request now: your available balance, or $500 for your first payout (capped: true). null while available is false |
minimumUsd | The minimum for your method |
reason, message | Why you can't request one, and a sentence to show. See below |
shortfallUsd | With below_minimum, how much more available balance you need |
heldUntil | When a new destination becomes active |
pendingRequest | Your pending request, in the payout request shape, or null |
reason | Example message |
|---|---|
below_minimum | $12.40 more needed for the PayPal minimum ($25). |
destination_on_hold | New payout details become active on 2026-10-16 09:00 UTC. |
request_pending | You have a pending payout request. Cancel it or wait until it is processed before requesting another. |
payout_details_missing | Add your legal details and a payout destination under Billing → Payouts to request a payout. |
suspended | Monetization is suspended on your account, so payouts are on hold. |
/v2/monetization/statusCreator Terms
/v2/monetization/terms/v2/monetization/terms/acceptGET 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:
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" }'| Status | Meaning |
|---|---|
201 | Accepted. Returns version, acceptedAt, and alreadyAccepted: false |
200 | You had already accepted this version (alreadyAccepted: true) |
409 terms-version-outdated | A newer version exists. data.currentVersion has it |
Payout details
/v2/monetization/payout-profile/v2/monetization/payout-profilePUT replaces your payout details: the payout method, its destination, and the statement details printed on your statements.
| Field | Required | Limits |
|---|---|---|
method | Yes | crypto, paypal, or bank_transfer |
destination | When adding or changing the destination | An object with the fields for the method, below. Leave it out to keep the saved destination of the same method |
legalName | Yes | 2–200 characters |
country | Yes | Two-letter ISO 3166 code |
addressLine1 | Yes | Up to 200 characters |
addressLine2 | No | Up to 200 characters |
city | Yes | Up to 100 characters |
postalCode | No | Up to 32 characters |
region | No | Up to 100 characters |
vatId | No | Up to 32 characters: letters, digits, spaces, dots, and dashes |
destination fields per method:
| Method | Field | Required | Limits |
|---|---|---|---|
paypal | email | Yes | A valid email, up to 254 characters |
crypto | asset | Yes | usdt, usdc, or btc |
crypto | network | Yes | usdt: tron, ethereum, polygon, solana. usdc: ethereum, polygon, base, solana. btc: bitcoin |
crypto | address | Yes | A valid address for the network, checksum included |
bank_transfer | accountHolderName | Yes | 2–140 characters |
bank_transfer | iban | One of iban or accountNumber | A valid IBAN: country length and check digits. Spaces are ignored |
bank_transfer | accountNumber | One of iban or accountNumber | 4–34 letters and digits |
bank_transfer | routingCode | No | ABA routing number, sort code, IFSC, BSB. 3–34 letters and digits |
bank_transfer | swiftBic | Unless iban is from a SEPA country | 8 or 11 characters |
bank_transfer | bankName | Yes | 2–140 characters |
bank_transfer | bankCountry | Yes | Two-letter ISO 3166 code |
bank_transfer | holderAddress | Yes | 5–300 characters |
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:
| Field | Meaning |
|---|---|
method | The payout method, or null before you choose one |
destination | Your destination in full, including the routing code and holder address for bank transfers. Includes a summary such as Bank transfer DE89370400440532013000 |
details | Your statement details |
minimumPayoutUsd | The minimum for your method |
destinationChangedAt | When the destination was last added or changed |
payoutsHeldUntil | While a changed destination is on hold, when payouts to it start. Otherwise null |
destinationHoldHours | 72 |
methods, cryptoOptions | The methods with their minimums, and the supported crypto currencies and networks |
updatedAt | When 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
/v2/monetization/ledgerEvery entry that changes your balance, newest first. Supports limit (default 20, max 100), offset, and type (comma-separated).
type | Amount | Becomes available |
|---|---|---|
earning | Positive | 30 days after the run settled (14 in good standing) |
clawback | Negative, after a refund or chargeback | Same date as the earning it reverses |
adjustment | Either, a correction with a reason | Immediately |
payout | Negative, the amount of a payout request, reserved when you make it | Immediately |
payout_reversal | Positive, a cancelled or rejected request returned | Immediately |
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
/v2/monetization/payout-requests/v2/monetization/payout-requests/v2/monetization/payout-requests/{requestId}/v2/monetization/payout-requests/{requestId}/cancelYou 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.
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:
{
"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
}
}| Field | Meaning |
|---|---|
amountUsd | The amount reserved and to be paid |
capped | The amount was limited by the $500 first-payout cap |
method, destination, destinationLabel | Where the payout goes, masked. Saved when you made the request |
requestedAt | When you made the request. createdAt is the same |
paidAt, paymentReference | When it was sent, and the transaction ID or payment reference |
amountSentUsd, feeUsd | What arrived and the transfer fee, when Scrape.ly records them |
rejectedReason | Why a request was rejected |
processedAt | When it was paid, rejected, or cancelled |
statementId | The statement issued when it was paid |
cancellable | You can still cancel it |
status | Meaning |
|---|---|
pending | Reserved and waiting to be sent |
paid | Sent. A statement is issued |
rejected | Not sent, with a rejectedReason. The amount is back in your available balance |
cancelled | You 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.
| Error | When |
|---|---|
409 payout-below-minimum | Your available balance is below the minimum. data has availableUsd, minimumUsd, and shortfallUsd |
409 payout-destination-on-hold | Your destination is in its 72-hour hold. data.heldUntil says until when |
409 payout-request-pending | You already have a pending request. data.requestId has it |
409 payout-details-missing | Your legal details or payout destination are missing |
403 monetization-suspended | Monetization is suspended on your account |
400 invalid-input | amountUsd isn't a positive number with up to two decimals, or is outside the minimum and maxAmountUsd. data has both |
404 payout-request-not-found | Unknown request ID |
409 payout-request-state | Cancelling a request that is already paid or rejected. data.status has its status |
409 payout-request-processing | Cancelling a request that is already being sent |
/v2/monetization/payout-requestsStatements
/v2/monetization/statements/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.
/v2/monetization/statementsPricing changes and reviews
/v2/actors/{actorId}/pricing-changes/v2/actors/{actorId}/pricing-changes/{changeId}/v2/actors/{actorId}/publish-checks/v2/actors/{actorId}/publication-reviewYou 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-changeslists 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 ascheduledorin_reviewchange.publish-checksruns the publish checks without publishing.DELETE .../publication-reviewwithdraws a pending review and returns204.
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
/v2/earningsWithout type, returns a summary plus the first 5 items of each category (incoming, available, withdrawn).
curl "https://api.scrape.ly/v2/earnings" \
-H "Authorization: Bearer $SCRAPELY_TOKEN"| Query param | Type | Default | Description |
|---|---|---|---|
type | string | — | incoming, available, or withdrawn. Invalid values return 400 invalid-request. |
limit | number | 20 | Page size (max 100), used with type. |
offset | number | 0 | Pagination offset, used with type. |
{
"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.incomingandsummary.availableare your pending and available balances, after clawbacks and adjustments.withdrawnitems are thepayoutledger entries of requests that have been paid. Pending, cancelled, and rejected requests aren't listed; see Payout requests.summary.paidOutis the total actually paid out: it leaves out pending requests, and a cancelled or rejected request nets to zero with itspayout_reversal.minWithdrawalUsdis the payout minimum for your method.
/v2/earningsIncoming earnings
/v2/earnings/incomingPending credits still in the 30-day holding period. Supports limit / offset (max 100). Includes summary plus paginated items.
curl "https://api.scrape.ly/v2/earnings/incoming?limit=20&offset=0" \
-H "Authorization: Bearer $SCRAPELY_TOKEN"/v2/earnings/incoming?limit=5Available earnings
/v2/earnings/availableEarnings past their hold, which you can request as a payout. Same pagination. Includes summary, items, and minWithdrawalUsd.
curl "https://api.scrape.ly/v2/earnings/available" \
-H "Authorization: Bearer $SCRAPELY_TOKEN"/v2/earnings/available?limit=5Get a single earning
/v2/earnings/{earningId}Returns one earning you own. Unknown IDs return 404 not-found.
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
/v2/actors/{actorId}/monetization?month=YYYY-MMcurl "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).
{
"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 }
]
}
}| Field | Meaning |
|---|---|
totalRevenue | Your share (80%) of Actor fees for the month. |
totalActorFee | Gross Actor fees users paid. totalUsage currently equals this. |
totalUsers | Distinct users other than you who ran the Actor that month. payingUsers currently equals this. |
dailyBreakdown[].revenue | Your share for that day. |
Aggregated monetization
/v2/monetization?month=YYYY-MMSame payload, aggregated across all Actors you own.
curl "https://api.scrape.ly/v2/monetization?month=2026-08" \
-H "Authorization: Bearer $SCRAPELY_TOKEN"/v2/monetizationAcquisition 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
/v2/actors/{actorId}/acquisitioncurl "https://api.scrape.ly/v2/actors/{actorId}/acquisition" \
-H "Authorization: Bearer $SCRAPELY_TOKEN"Aggregated acquisition
/v2/acquisitionSame payload across all Actors you own.
curl "https://api.scrape.ly/v2/acquisition" \
-H "Authorization: Bearer $SCRAPELY_TOKEN"/v2/acquisitionDebugging 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
/v2/actors/{actorId}/debugging?month=YYYY-MMcurl "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
/v2/debugging?month=YYYY-MMSame payload across all Actors you own.
curl "https://api.scrape.ly/v2/debugging" \
-H "Authorization: Bearer $SCRAPELY_TOKEN"/v2/debuggingErrors
| Status | Type | Meaning |
|---|---|---|
| 400 | invalid-request | type is not incoming, available, or withdrawn |
| 400 | invalid-input | Invalid payout details (see data.errors), an invalid payout amountUsd, unknown ledger type, or missing terms version |
| 403 | forbidden | Insights for an Actor you do not own |
| 403 | insufficient-permissions | A run, CI, x402, or OAuth token where the account API key is required |
| 403 | monetization-suspended | Requesting a payout while monetization is suspended |
| 404 | actor-not-found / not-found | Unknown Actor or earning ID |
| 404 | statement-not-found / payout-request-not-found / review-not-found / pricing-change-not-found | Unknown statement or payout request, no pending review, or unknown pricing change |
| 409 | payout-below-minimum / payout-destination-on-hold / payout-request-pending / payout-details-missing | A payout can't be requested yet. See Payout requests |
| 409 | payout-request-state / payout-request-processing | The payout request can't be cancelled anymore |
| 409 | terms-version-outdated | The terms version you accepted isn't the current one |
| 409 | pricing-change-not-cancellable | The pricing change is already applied, cancelled, or rejected |