OTO offers
OTO offers endpoints of the Zanfia Workspace API, with schemas and code samples.
Reusable post-purchase one-time offers (OTO), shown once full-screen between payment success and the thank-you step: priceId references an existing price on the upsold product (creators typically add a dedicated discounted price for the OTO) and timerMinutes sets an optional countdown, anchored at first impression. These routes manage the reusable offer documents only — attach one to a checkout's chain via PATCH /checkouts/{checkoutId} (oto field). Deleting an offer is permanent; checkout chains still referencing it are left with a dangling step, same as order bumps. All routes require a Authorization: Bearer header — see Authentication.
List OTO offers
/oto-offersAuthorization
bearerAuth API key from Dashboard → Integrations → API, MCP and CLI.
In: header
Response Body
application/json
application/json
curl -X GET "https://example.com/oto-offers"{ "otoOffers": [ { "id": "string", "name": "string", "productId": "string", "productName": "string", "priceId": "string", "headline": "string", "description": "string", "acceptCtaText": "string", "declineText": "string", "timerMinutes": 0, "media": [ { "type": "image", "url": "string", "mediaId": "string", "thumbnailUrl": "string" } ], "createdAt": "2019-08-24T14:15:22Z", "updatedAt": "2019-08-24T14:15:22Z" } ]}{ "error": "string"}Create an OTO offer
/oto-offersAuthorization
bearerAuth API key from Dashboard → Integrations → API, MCP and CLI.
In: header
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Reusable post-purchase one-time offer (workspaces/{wid}/oto-offers). Field set mirrors exactly what the checkout builder's OTO panel writes — see OtoOfferDocument. checkout.oto (the chain attachment) keeps going through UpdateCheckoutRequestDTO, untouched by this DTO group.
Response Body
application/json
application/json
curl -X POST "https://example.com/oto-offers" \ -H "Content-Type: application/json" \ -d '{ "name": "string", "productId": "string", "productName": "string", "priceId": "string", "headline": "string", "description": "string", "acceptCtaText": "string", "declineText": "string" }'{ "otoOfferId": "string"}{ "error": "string"}Get an OTO offer
/oto-offers/{otoOfferId}Authorization
bearerAuth API key from Dashboard → Integrations → API, MCP and CLI.
In: header
Path Parameters
OTO offer id
Response Body
application/json
application/json
curl -X GET "https://example.com/oto-offers/string"{ "otoOffer": { "id": "string", "name": "string", "productId": "string", "productName": "string", "priceId": "string", "headline": "string", "description": "string", "acceptCtaText": "string", "declineText": "string", "timerMinutes": 0, "media": [ { "type": "image", "url": "string", "mediaId": "string", "thumbnailUrl": "string" } ], "createdAt": "2019-08-24T14:15:22Z", "updatedAt": "2019-08-24T14:15:22Z" }}{ "error": "string"}Update an OTO offer
/oto-offers/{otoOfferId}Authorization
bearerAuth API key from Dashboard → Integrations → API, MCP and CLI.
In: header
Path Parameters
OTO offer id
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Partial OTO-offer update — every content field is patchable.
Response Body
application/json
application/json
curl -X PATCH "https://example.com/oto-offers/string" \ -H "Content-Type: application/json" \ -d '{}'{ "updated": true}{ "error": "string"}Delete an OTO offer
/oto-offers/{otoOfferId}Authorization
bearerAuth API key from Dashboard → Integrations → API, MCP and CLI.
In: header
Path Parameters
OTO offer id
Response Body
application/json
application/json
curl -X DELETE "https://example.com/oto-offers/string"{ "deleted": true}{ "error": "string"}Was this article helpful?

