PPE charging API
Hi. I've developed an integration Actor, im trying now to get PPE charging working. Even though ive configured monetization with a single "pay per event" active, when my actor is triggered, i notice the 1) the run input's pricingInfo.pricingModel is "PRICE_PER_DATASET_ITEM". I was expecting "PAY_PER_EVENT". And 2) im getting "operation is not allowed" error from the charging call. Suggestions?
Solution:Jump to solution
I updated my actor to take the RunID from the ACTOR_RUN_ID environment variable (which is correct). Now the 'charge' API call is returning success 👍 . Next, where else can I get the pricing info, so I can get the configured "max charge per run" 🤔
18 Replies
cc @patrikbraborec
Hi @hmcguirk , thanks for the question. Can you share with me how you configured monetization, please? Also, for the charging call, can you share with me where exactly do you call it?
For monetization, I simply completed the monetization section under the 'Publication' tab in the Console. It is currently marked as 'Active' (green). I have a single event there:
Pricing model: Pay per event
Start date: August 3, 2025
A block of up to 1000 successfully processed dataset rows: $0.50
For the charging call, Im using the API directly as Im not building with python or js (I may revisit this, but that is not today's project). Im using the same event name configured in the Console. I do notice a couple of issues around docs for the API call ( https://docs.apify.com/api/v2/post-charge-run ) 1) it says pay-per-event actors are alpha. I believe this is no longer true? The Monetization step in the Console pushes towards PPE anyway, do not in any way describe as not ready for full use. 2) the docs (above) mention a property called 'eventCount' but if i use this property it complains about a missing 'count' property. So i switched to using 'count' instead of 'eventCount' and when i do so, i get a 'operation is not allowed' error.
Charge events in run | Apify Documentation
<span class='openapi-clients-box'><span class='openapi-clients-box-heading'>Clients</span><a href='https://docs.apify.com/api/client/python/reference/class/RunClientAsync#charge' target='_blank'><img src='https://raw.githubusercontent.com/apify/openapi/b1206ac2adf8f39b05e5a09bf32c2802af58d851/assets/python.svg' class='openapi-clients-box-icon' a...
Ive looked up the 'charge' function in both the python (run.py) and js (run.ts) clients. They both do the same thing and dont do anything complicated. It looks like Im doing the same thing as them. Any updates on this? Thanks
As I am currently completely blocked by my other issue: https://discordapp.com/channels/801163717915574323/1401892779973677230/1401892779973677230 , I have not done any more digging on this one. But is there any other info I can share here on what I'm doing, to help resolve or understand what is or isnt happening here? Im not using the SDKs (using a different language), but instead calling the API directly. Ive looked at what the SDKs are doing, and it looks like Im doing the same thing. I am taking the API token from the container
APIFY_TOKEN
environment variable, and specifying it as a URL parameter e.g. https://api.apify.com/v2/actor-runs/{runId}/charge?token={ApifyApiToken}
This has worked fine for every API call I'm making from a container (I'll change to a header once I get stuff working). I am specifying the idempotency-key
header too. The API does seem to be accepting the payload Im sending - so I believe that is correct (as missing payload properties were returning a different error). I dont understand why the run input's pricingInfo.pricingModel
is not PAY_PER_EVENT
when the Console does show PPE configured (green & active). I cant see the exact event name configured through the Console (since the Console does not show it once it has been accepted), but it should be SUCCESSFUL_PROCESSED_1000
The testing ive done that shows the run input's unexpected pricingModel
has been both from my organisation and from my personal account. I understand that at least the latter (if not both) should really be seeing the correct input pricingInfo
.@hmcguirk just advanced to level 2! Thanks for your contributions! 🎉
Also, this is an Integration actor. Is it possible the
pricingModel
of the parent run that is triggering this actor's run is what Im seeing in the integration's input? Both do have different pricing models. I would think it is reasonable to expect that parent runs and their Intergations might support different & independent pricing models...Can you share with me your actor id, or your user id?
We throw
operationNotAllowed
when actorRunId
is different from runId
in the API endpoint. Can you double-check that when you call https://api.apify.com/v2/actor-runs/:runId/charge you use the correct runId
in the API endpoint?The run Id I'm using is coming from the
input.payload.eventData.actorRunId
Taking a closer look now, I can see that perhaps all properties inside that input.payload
are from the parent actor run that triggered this integration run. I can see my Integration Actor's Run ID in the Console UI, and that appears nowhere in the input.payload
for my integration actor's input. But I do repeatedly see the parent actor's actorId and runId in various properties there...
Should I be getting the RunId from elsewhere? Even if I did get the RunId from somewhere else (environment variable?), I'm also expecting the pricing info from that input.payload
too, which also seems to be for the parent actor run, not for this integration run (i.e. pricing model is not for my integration actor)Have you tried to call the API with your Integration Actor's Run ID instead of parent's Actor ID? Just to try it whatever it works for you
You mean manually? I have not. Ill take a look
Solution
I updated my actor to take the RunID from the ACTOR_RUN_ID environment variable (which is correct). Now the 'charge' API call is returning success 👍 . Next, where else can I get the pricing info, so I can get the configured "max charge per run" 🤔
Perfect. 👍
Do you mean pricingInfo in your code?
I mean that in my code, I need to ensure that the total charge for the run respects the maximum value set by the user. That data is in the pricingInfo
options.maxTotalChargeUsd
for the run.The environment variable contains the value that was specified when the Actor run was started, either through the API's maxTotalChargeUsd parameter or through the Apify Console interface.
The spend limit enforcement is handled by the platform. The platform is designed to automatically stop the Actor when the user runs out of credit.
The documentation for the charge endpoint says the following: "Note that you still have to make sure in your Actor that the total charge for the run respects the maximum value set by the user, as the API does not check this. Above the limit, the charges reported as successful in API will not be added to your payouts, but you will still bear the associated costs.". And I dont want my actors to be abruptly killed when credit reaches 0, I would prefer to log a warning at the start saying something like "Your credit limits this actor to processing X rows. The remaining Y rows will not be processed." and then my actor run do that and end normally.
@hmcguirk just advanced to level 3! Thanks for your contributions! 🎉
Im working on using MaxTotalChargeUsd, MinimalMaxTotalChargeUsd and EventPriceUsd to do exactly that