Buy an offer the decision engine offered
const url = 'https://your-tenant-host/edgekit/v1/checkout';const options = { method: 'POST', headers: {'x-edgekit-site-id': 'site_example', 'Content-Type': 'application/json'}, body: '{"offerToken":"example","recurlyTokenId":"example","email":"buyer@example.com","firstName":"Ada","lastName":"Lovelace","threeDSecureActionResultTokenId":"example"}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://your-tenant-host/edgekit/v1/checkout \ --header 'Content-Type: application/json' \ --header 'x-edgekit-site-id: site_example' \ --data '{ "offerToken": "example", "recurlyTokenId": "example", "email": "buyer@example.com", "firstName": "Ada", "lastName": "Lovelace", "threeDSecureActionResultTokenId": "example" }'Redeems the offer_token an outcome field minted, charges the Recurly card token the organization’s own Recurly.js took, and writes the grant. The body is an allowlist: offerToken, recurlyTokenId and email, plus the optional firstName, lastName and threeDSecureActionResultTokenId, and every other key is a 400 naming the key. A body carrying number or cvv means the card form failed to tokenize and raw card data reached EdgeKit. 200 is charged and granted. 202 is data, not a failure: charged (grant still being written; render a completed purchase) or pending (the card’s fate is not yet known; render still processing). 409 is a failed precondition, each with its own code: an expired or unknown offer token, a closed offer, a dead card token, or no active billing provider. 422 is a card decline, carrying Recurly’s own code. Retry-safe with the same offerToken: a settled purchase answers its original result and charges nothing again.
Parameters
Section titled “Parameters”Header Parameters
Section titled “Header Parameters”The site this request is for, within this tenant. Every official EdgeKit SDK sets it from the client you configured; set it yourself only when calling this API directly.
Example
site_exampleThe site this request is for, within this tenant. Every official EdgeKit SDK sets it from the client you configured; set it yourself only when calling this API directly.
Request Bodyrequired
Section titled “Request Bodyrequired”object
The stored handle an offer_token outcome field minted. It names one offer on one site, and its site must be the one this request selected. Opaque: it authorises nothing on its own.
Recurly.js’ card token id, from the organization’s own page: the only card-shaped value EdgeKit ever accepts. It lives about 20 minutes and is reusable inside that window.
The buyer’s address, unverified. It resolves the user the grant belongs to: an existing user on an email match, a new one otherwise. Nothing on this path ever sets email_verified.
Example
buyer@example.comThe buyer’s given name, as typed on the card form. Written only when this purchase creates the user, never onto a user resolved by email match, so an unauthenticated caller cannot rename a stranger.
Example
AdaThe buyer’s family name. Same rule as firstName: written on a new user only, never as an update.
Example
LovelaceRecurly.js’ 3-D Secure result token id, sent only on the request that finalizes a three_d_secure_required refusal. It proves the buyer cleared their bank’s challenge. Never send the threeDSecureActionTokenId the refusal carried: that is the challenge itself. Send the same offerToken and recurlyTokenId alongside it: the offer token is replayable within its TTL and the card token is reusable within its 20 minutes.
Responses
Section titled “Responses”Charged, and the grant is written.
object
granted (200): charged, and the grant is written. charged (202): charged, and the grant is still being written. EdgeKit finishes it, and the buyer has paid either way. Open: treat an unknown member as pending.
The checkout attempt’s id (UUIDv7). Every response carries it; quote it to support.
Example
{ "status": "granted", "attemptId": "01999b1e-6f3a-7c2d-9e51-2a4c8d0f6b31"}charged: the buyer has paid, and EdgeKit finishes writing the grant. pending: the purchase went asynchronous and the card’s fate is not yet known. Branch on status.
object
granted (200): charged, and the grant is written. charged (202): charged, and the grant is still being written. EdgeKit finishes it, and the buyer has paid either way. Open: treat an unknown member as pending.
The checkout attempt’s id (UUIDv7). Every response carries it; quote it to support.
object
The card’s fate is not known yet. Render still processing: never a failure, never an invitation to buy again.
The checkout attempt’s id (UUIDv7). Every response carries it; quote it to support.
The id of the background run finishing the purchase. Diagnostic only: quote it to support; a page cannot resolve it.
Example
{ "status": "granted", "attemptId": "01999b1e-6f3a-7c2d-9e51-2a4c8d0f6b31"}Invalid request.
object
object
Example
{ "error": { "code": "unauthorized", "message": "Invalid or missing API key." }}Not allowed.
object
object
Example
{ "error": { "code": "unauthorized", "message": "Invalid or missing API key." }}Resource not found.
object
object
Example
{ "error": { "code": "unauthorized", "message": "Invalid or missing API key." }}Conflicts with an existing record.
object
object
Example
{ "error": { "code": "unauthorized", "message": "Invalid or missing API key." }}The card was declined. code is Recurly’s own.
object
object
Example
{ "error": { "code": "unauthorized", "message": "Invalid or missing API key." }}Unexpected error.
object
object
Example
{ "error": { "code": "unauthorized", "message": "Invalid or missing API key." }}