Purchase a buy-up from custom code, safely
Two things make the buy-up purchase endpoint different from a plain authenticated POST, and both are easy to get wrong from outside Benecaster’s own UI.
You have to state the amount. confirm_amount_cents is required — the price, in integer minor units, that the subscriber agreed to pay. The server compares it against the live price and returns 409 amount_mismatch when they disagree, with the current amount_cents and currency in the error data so you can re-render and ask again. That is what stops a price change between render and click from being charged silently.
Send cents, not dollars. "5.00" is a whole number, so it passes the format check and is read as five cents — it comes back as amount_mismatch, not as a validation error. If you are seeing a mismatch on a price nobody changed, this is almost always why.
Send an idempotency key if you intend to retry. Idempotency-Key is optional, but it is the difference between a retry returning the original 201 with the same grant_id and returning a confusing 409 already_subscribed. Mint one per user action and reuse it only for retries of that action — then retire it once the server has answered with an error, because at that point nothing was created and the next attempt is a genuinely new purchase.
Buy-ups belong to one show. A {buyup_id} from a different show returns 404, not 403 — the endpoint will not confirm that an ID exists elsewhere. Resolve buy-ups for the show you are working on rather than assuming an install-wide list.
Full endpoint reference: Buy-ups Subscriber REST API.
Code
<?php
/**
* Purchase a buy-up on behalf of the logged-in subscriber.
*
* @param int $show_id Show the subscriber holds a native subscription on.
* @param int $buyup_id Buy-up belonging to that show.
* @param int $amount_cents The price shown to the subscriber, in minor units.
* @param string $action_key Stable per user action; reuse only when retrying it.
*/
function my_addon_purchase_buyup( int $show_id, int $buyup_id, int $amount_cents, string $action_key ) {
$request = new WP_REST_Request(
'POST',
"/benecaster/v1/shows/{$show_id}/buyups/{$buyup_id}/subscribe"
);
$request->set_header( 'Idempotency-Key', $action_key );
$request->set_body_params( [ 'confirm_amount_cents' => $amount_cents ] );
$response = rest_do_request( $request );
if ( $response->is_error() ) {
$error = $response->as_error();
// The price moved between render and click. Re-render at the new
// amount and ask again — do not silently resubmit with the new
// figure, because the subscriber never agreed to it.
if ( 'amount_mismatch' === $error->get_error_code() ) {
$data = $error->get_error_data();
return new WP_Error(
'price_changed',
sprintf(
/* translators: %s: formatted current price */
__( 'The price is now %s. Please confirm the new amount.', 'my-addon' ),
number_format_i18n( $data['amount_cents'] / 100, 2 )
),
$data
);
}
return $error;
}
return $response->get_data(); // grant_id, stripe_subscription_item_id, buyup_id
}
Need this built rather than just documented? See our services →