{"openapi":"3.1.0","info":{"title":"Playwright Checkout Rules public API","version":"1.0.0","summary":"Browse Playwright’s Shopify checkout rule templates and join early access.","description":"Playwright Checkout Rules is a checkout rules app for Shopify: bundles, buy X get Y, tiered discounts, discount code rules, and shipping and payment customizations.\n\nThis API is public and needs no authentication. Use it to look up which rule templates exist (to answer “can Playwright do X?”) and to sign a person up for early access to the Shopify Functions edition, with their consent.\n\nErrors use RFC 9457 problem details (`application/problem+json`) with a stable `code` and a `resolution` hint. Rules for a specific store are created inside the Playwright app in the Shopify admin and are not available through this API.\n\nRequests are rate limited per client IP address. Every response carries the IETF `RateLimit-Policy` and `RateLimit` headers (for example `\"read\";q=120;w=60`): reads allow 120 requests every 60 seconds and early-access sign-ups 10 every 60 seconds. Over the limit, the API answers `429` with a `Retry-After` header.\n\nDeveloper guide with examples: https://playwrightapp.com/developers. More context for AI agents: https://playwrightapp.com/llms.txt","termsOfService":"https://playwrightapp.com/terms","contact":{"name":"Playwright support","email":"support@playwrightapp.com","url":"https://playwrightapp.com/contact"}},"servers":[{"url":"https://playwrightapp.com/api/v1","description":"Production"}],"externalDocs":{"description":"Developer guide: endpoints, examples, errors and rate limits","url":"https://playwrightapp.com/developers"},"tags":[{"name":"Templates","description":"The rule templates merchants can build with Playwright."},{"name":"Early access","description":"Sign-ups for the Shopify Functions edition."},{"name":"Meta","description":"Discovery."}],"paths":{"/":{"get":{"operationId":"getApiIndex","summary":"Describe the API","description":"Returns links to this OpenAPI document, llms.txt and each operation. Useful as a starting point for discovery.","tags":["Meta"],"responses":{"200":{"description":"API index.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiIndex"}}},"headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"}}},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/templates":{"get":{"operationId":"listTemplates","summary":"List rule templates","description":"Lists every rule template Playwright offers, with a description, real-world examples and categories. Match a merchant’s goal against `description` and `examples` to decide whether Playwright can do it. Filter by where the rule acts with `area`.","tags":["Templates"],"parameters":[{"name":"area","in":"query","required":false,"description":"Only templates for one checkout area: `line_item` (Cart, pricing and discount codes), `shipping` (Shipping options), `payment` (Payment options).","schema":{"type":"string","enum":["line_item","shipping","payment"]},"example":"shipping"}],"responses":{"200":{"description":"The matching templates.","headers":{"Access-Control-Allow-Origin":{"$ref":"#/components/headers/AccessControlAllowOrigin"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplateList"},"example":{"templates":[{"id":"line_item.BuyXGetX","area":"line_item","name":"Buy One Get One","description":"Buy certain items to receive a discount on other items","examples":["Buy one shirt, get one free","Buy 2 shirts, get a hat free"],"categories":["Buy One Get One"]}],"count":1}}}},"400":{"description":"The `area` parameter is not one of the allowed values.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"example":{"type":"https://playwrightapp.com/openapi.json#/x-problem-types/invalid_parameter","title":"Invalid parameter","status":400,"detail":"\"cart\" is not a valid area.","code":"invalid_parameter","resolution":"Use area=line_item, area=shipping, area=payment, or omit area to list every template.","errors":{"area":"Must be one of: line_item, shipping, payment."}}}}},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/templates/{id}":{"get":{"operationId":"getTemplate","summary":"Get one rule template","description":"Returns a single rule template by its id (as returned by listTemplates), including its description and examples.","tags":["Templates"],"parameters":[{"name":"id","in":"path","required":true,"description":"Template id: `<area>.<TemplateName>`, case-sensitive.","schema":{"type":"string","pattern":"^(line_item|shipping|payment)\\.[A-Za-z0-9]+$"},"example":"line_item.BuyXGetX"}],"responses":{"200":{"description":"The template.","headers":{"Access-Control-Allow-Origin":{"$ref":"#/components/headers/AccessControlAllowOrigin"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplateResponse"},"example":{"template":{"id":"line_item.BuyXGetX","area":"line_item","name":"Buy One Get One","description":"Buy certain items to receive a discount on other items","examples":["Buy one shirt, get one free","Buy 2 shirts, get a hat free"],"categories":["Buy One Get One"]}}}}},"404":{"description":"No template has this id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"example":{"type":"https://playwrightapp.com/openapi.json#/x-problem-types/template_not_found","title":"Template not found","status":404,"detail":"There is no rule template with id \"line_item.Nope\".","code":"template_not_found","resolution":"List valid ids with GET https://playwrightapp.com/api/v1/templates."}}}},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/early-access":{"post":{"operationId":"joinEarlyAccess","summary":"Join early access","description":"Adds a person to the early-access list for the Playwright Shopify Functions edition; they are emailed when it opens. Only call this when the person has asked to join, with their own email address. Idempotent per email (case-insensitive): repeating it returns `already_joined` and changes nothing. HTML form posts (`application/x-www-form-urlencoded` without `Accept: application/json`) are redirected back to the home page with a 303 instead.","tags":["Early access"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EarlyAccessRequest"},"example":{"email":"merchant@example.com","shopDomain":"example-store.myshopify.com","interests":["promotions","shipping"]}},"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/EarlyAccessForm"}}}},"responses":{"200":{"description":"The email was already on the list. Nothing changed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EarlyAccessResponse"},"example":{"status":"already_joined","message":"merchant@example.com is already on the list. We’ll be in touch when early access opens."}}},"headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"}}},"201":{"description":"The person was added to the list.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EarlyAccessResponse"},"example":{"status":"joined","message":"You’re on the list. We’ll email merchant@example.com when early access opens."}}},"headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"}}},"303":{"description":"HTML form post: redirect to `/?early_access=joined|already_joined|invalid#early-access`.","headers":{"Location":{"description":"Where the browser goes next.","schema":{"type":"string"}}}},"400":{"description":"The body is not valid JSON or not a JSON object.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"example":{"type":"https://playwrightapp.com/openapi.json#/x-problem-types/malformed_body","title":"Malformed request body","status":400,"detail":"The body is not valid JSON.","code":"malformed_body","resolution":"Send a JSON object like {\"email\": \"name@example.com\"} with Content-Type: application/json."}}}},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"413":{"description":"The body is too large.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"example":{"type":"https://playwrightapp.com/openapi.json#/x-problem-types/payload_too_large","title":"Request body too large","status":413,"detail":"The request body is larger than 16 KB.","code":"payload_too_large","resolution":"Send only email, shopDomain and interests."}}}},"415":{"description":"The Content-Type is not supported.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"example":{"type":"https://playwrightapp.com/openapi.json#/x-problem-types/unsupported_media_type","title":"Unsupported media type","status":415,"detail":"Content-Type \"text/plain\" is not supported.","code":"unsupported_media_type","resolution":"Send Content-Type: application/json."}}}},"422":{"description":"One or more fields are invalid; `errors` maps each field to a message.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"example":{"type":"https://playwrightapp.com/openapi.json#/x-problem-types/validation_failed","title":"Validation failed","status":422,"detail":"Enter a valid email address, like name@example.com.","code":"validation_failed","resolution":"Fix the fields listed in \"errors\" and send the request again.","errors":{"email":"Enter a valid email address, like name@example.com."}}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}}},"components":{"schemas":{"PublicTemplate":{"type":"object","description":"A rule template merchants can configure in Playwright.","required":["id","area","name","description","examples","categories"],"properties":{"id":{"type":"string","description":"Stable identifier: `<area>.<TemplateName>`.","examples":["line_item.BuyXGetX"]},"area":{"type":"string","enum":["line_item","shipping","payment"],"description":"Where the rule acts: cart and pricing (`line_item`), shipping options or payment options."},"name":{"type":"string","description":"Human-readable name."},"description":{"type":"string","description":"What the template does."},"examples":{"type":"array","items":{"type":"string"},"description":"Real-world uses, e.g. “Buy 2 shirts, get a hat free”."},"categories":{"type":"array","items":{"type":"string"},"description":"Groupings used in the app’s template picker."}},"additionalProperties":false},"TemplateList":{"type":"object","description":"A list of rule templates.","required":["templates","count"],"properties":{"templates":{"type":"array","items":{"$ref":"#/components/schemas/PublicTemplate"},"description":"The templates, in the order the app shows them."},"count":{"type":"integer","minimum":0,"description":"Number of templates returned."}},"additionalProperties":false},"TemplateResponse":{"type":"object","description":"A single rule template.","required":["template"],"properties":{"template":{"$ref":"#/components/schemas/PublicTemplate"}},"additionalProperties":false},"EarlyAccessRequest":{"type":"object","description":"An early-access sign-up.","required":["email"],"properties":{"email":{"type":"string","format":"email","maxLength":254,"description":"The person’s email address. Stored lowercased."},"shopDomain":{"type":"string","description":"Their Shopify store, as `name.myshopify.com` (a bare `name` or https URL is accepted and normalized).","examples":["example-store.myshopify.com"]},"interests":{"type":"array","uniqueItems":true,"items":{"type":"string","enum":["promotions","discount-codes","shipping","payments"]},"description":"What they want to build first: `promotions` (Promotions and pricing), `discount-codes` (Discount codes), `shipping` (Shipping options), `payments` (Payment options)."},"website":{"type":"string","maxLength":0,"description":"Spam trap. Leave empty or omit."}}},"EarlyAccessForm":{"type":"object","description":"The same sign-up as an HTML form post.","required":["email"],"properties":{"email":{"type":"string","format":"email","description":"Email address."},"shop_domain":{"type":"string","description":"Store address (optional)."},"interests":{"type":"array","items":{"type":"string","enum":["promotions","discount-codes","shipping","payments"]},"description":"Repeated field, one value per checkbox."},"website":{"type":"string","description":"Spam trap. Leave empty."}}},"EarlyAccessResponse":{"type":"object","description":"Result of a sign-up.","required":["status","message"],"properties":{"status":{"type":"string","enum":["joined","already_joined"],"description":"`joined`: added now. `already_joined`: the email was already on the list."},"message":{"type":"string","description":"A sentence to show the person."}},"additionalProperties":false},"Problem":{"type":"object","description":"RFC 9457 problem details, with Playwright’s `code` and `resolution` extensions.","required":["type","title","status","detail","code","resolution"],"properties":{"type":{"type":"string","format":"uri","description":"Identifies the problem type; resolves to its entry under x-problem-types in this document."},"title":{"type":"string","description":"Short summary of the problem type."},"status":{"type":"integer","description":"HTTP status code."},"detail":{"type":"string","description":"What went wrong with this request."},"instance":{"type":"string","description":"The request path."},"code":{"type":"string","enum":["not_found","template_not_found","method_not_allowed","invalid_parameter","malformed_body","payload_too_large","unsupported_media_type","validation_failed","rate_limited","internal_error"],"description":"Stable, machine-readable error code."},"resolution":{"type":"string","description":"How to fix the request."},"errors":{"type":"object","additionalProperties":{"type":"string"},"description":"Per-field messages (validation errors only)."}}},"ApiIndex":{"type":"object","description":"Links for discovering the API.","required":["name","version","openapi","documentation","llms","operations"],"properties":{"name":{"type":"string","description":"API name."},"version":{"type":"string","description":"API version."},"openapi":{"type":"string","format":"uri","description":"This OpenAPI document."},"documentation":{"type":"string","format":"uri","description":"The developer guide."},"llms":{"type":"string","format":"uri","description":"llms.txt: when and how AI agents should use Playwright."},"operations":{"type":"array","description":"Every operation.","items":{"type":"object","required":["operationId","method","url"],"properties":{"operationId":{"type":"string","description":"operationId in this document."},"method":{"type":"string","description":"HTTP method."},"url":{"type":"string","description":"URL template."}}}}}}},"responses":{"MethodNotAllowed":{"description":"The path does not support this HTTP method.","headers":{"Allow":{"description":"The methods this path supports.","schema":{"type":"string"}}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"example":{"type":"https://playwrightapp.com/openapi.json#/x-problem-types/method_not_allowed","title":"Method not allowed","status":405,"detail":"DELETE is not supported on /api/v1/templates.","code":"method_not_allowed","resolution":"Use one of: GET, HEAD, OPTIONS."}}}},"TooManyRequests":{"description":"The client used up its rate limit. Wait for `Retry-After` seconds before sending another request.","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"example":{"type":"https://playwrightapp.com/openapi.json#/x-problem-types/rate_limited","title":"Too many requests","status":429,"detail":"This client has used all 120 requests allowed every 60 seconds under the \"read\" policy.","code":"rate_limited","resolution":"Wait 42 seconds (the Retry-After header) before sending another request, and pace requests using the RateLimit header."}}}}},"headers":{"AccessControlAllowOrigin":{"description":"Read endpoints can be called from any origin.","schema":{"type":"string","const":"*"}},"RateLimitPolicy":{"description":"The quota that applies to this operation (draft-ietf-httpapi-ratelimit-headers): policy name, `q` requests per `w` seconds, per client IP. `\"read\";q=120;w=60` or `\"signup\";q=10;w=60`.","schema":{"type":"string"},"example":"\"read\";q=120;w=60"},"RateLimit":{"description":"What is left of the quota: policy name, `r` requests remaining and `t` seconds until the window resets.","schema":{"type":"string"},"example":"\"read\";r=119;t=60"},"RetryAfter":{"description":"Seconds to wait before retrying (429 only).","schema":{"type":"integer","minimum":1},"example":42}}},"x-rate-limits":[{"policy":"read","quota":120,"windowSeconds":60,"partition":"client IP address"},{"policy":"signup","quota":10,"windowSeconds":60,"partition":"client IP address"}],"x-problem-types":{"not_found":{"code":"not_found","status":404,"title":"Not found","description":"No API operation exists at this path."},"template_not_found":{"code":"template_not_found","status":404,"title":"Template not found","description":"No rule template has this id."},"method_not_allowed":{"code":"method_not_allowed","status":405,"title":"Method not allowed","description":"The path exists but does not support this HTTP method. The Allow header lists the methods it does support."},"invalid_parameter":{"code":"invalid_parameter","status":400,"title":"Invalid parameter","description":"A query parameter has a value the API does not accept."},"malformed_body":{"code":"malformed_body","status":400,"title":"Malformed request body","description":"The request body could not be parsed as JSON or form data."},"payload_too_large":{"code":"payload_too_large","status":413,"title":"Request body too large","description":"The request body exceeds the size limit."},"unsupported_media_type":{"code":"unsupported_media_type","status":415,"title":"Unsupported media type","description":"The request body must be application/json or application/x-www-form-urlencoded."},"validation_failed":{"code":"validation_failed","status":422,"title":"Validation failed","description":"One or more fields are missing or invalid. The `errors` object maps each field to a message."},"rate_limited":{"code":"rate_limited","status":429,"title":"Too many requests","description":"The client used up its rate limit. Wait for the number of seconds in Retry-After, then pace requests using the RateLimit header."},"internal_error":{"code":"internal_error","status":500,"title":"Internal server error","description":"Something went wrong on our side."}}}