{"openapi":"3.1.0","info":{"title":"Joinery API","version":"1.0.0","summary":"Catalogue, checkout links, licence activation and plugin updates for Joinery WordPress plugins.","description":"The public API of Joinery (https://www.joinerywp.com), which sells WordPress plugins on yearly licences.\n\nUse the catalogue to see plugins, plans and prices, and its checkout links to send someone to buy.\n\nThe licence endpoints are what the plugins call from a WordPress site; they need a licence key and are rate-limited per IP.\n\nErrors are always JSON: `{ \"error\": \"<what happened and what to do next>\", \"code\": \"<stable code>\" }`.\n\nRate limits are per IP. Every response from a limited endpoint carries `RateLimit-Policy` and `RateLimit` (IETF draft-ietf-httpapi-ratelimit-headers) plus `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a `429` adds `Retry-After`.\n\nVersioning: endpoints under /api/v1 keep working as documented. New endpoints, fields and error codes can be added at any time, so ignore what you don't recognise. A breaking change gets a new version (/api/v2). Before anything in /api/v1 is removed, its responses carry `Deprecation` (RFC 9745) and `Sunset` (RFC 8594) headers and a `Link` to the policy for at least six months. Policy: https://www.joinerywp.com/developers#versioning\n\nFor the WordPress REST API that the plugins add to each store (rules, price previews), see https://docs.joinerywp.com.","contact":{"name":"Joinery support","email":"hello@joinerywp.com","url":"https://www.joinerywp.com/contact"},"license":{"name":"Proprietary","url":"https://www.joinerywp.com/terms"}},"externalDocs":{"description":"Developer documentation","url":"https://docs.joinerywp.com"},"servers":[{"url":"https://www.joinerywp.com","description":"Production"}],"tags":[{"name":"Catalogue","description":"What Joinery sells, and how to buy it."},{"name":"Licences","description":"Activate a licence on a WordPress site or free it again."},{"name":"Updates","description":"Plugin updates for a WordPress site."}],"paths":{"/api/v1/catalog":{"get":{"operationId":"getCatalog","tags":["Catalogue"],"summary":"List plugins, plans and prices","description":"Every plugin and bundle Joinery sells, with yearly prices in EUR, USD and GBP (before tax) and a checkout link for each plan. Prices for other currencies are converted at checkout. No authentication.","security":[],"responses":{"200":{"description":"The catalogue.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Catalog"}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}}},"429":{"description":"Too many requests from this IP. Wait for the number of seconds in `Retry-After`. `code`: `rate_limited`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"value":{"error":"Too many requests. Try again in 42 seconds.","code":"rate_limited"}}}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}},"500":{"description":"Something failed on our side. Retry after a short wait. `code`: `server_error`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"server_error":{"value":{"error":"Something went wrong on our side. Try again in a minute; if it keeps happening, contact support.","code":"server_error"}}}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}}}}}},"/api/checkout":{"get":{"operationId":"startCheckout","tags":["Catalogue"],"summary":"Start checkout for a plan","description":"Redirects a person to Stripe Checkout for one plan. Open it in a browser; it is not meant to be called from code. Unknown plans redirect back to the pricing page with `?checkout=unknown-plan`.","security":[],"parameters":[{"name":"plan","in":"query","required":true,"description":"Plan key from the catalogue, e.g. dynamic-pricing-5 or all-access.","schema":{"type":"string","examples":["dynamic-pricing-1"]}},{"name":"currency","in":"query","required":false,"description":"Price list to charge in. Defaults to the visitor’s currency.","schema":{"type":"string","enum":["eur","usd","gbp"]}},{"name":"locale","in":"query","required":false,"description":"Language for checkout and emails.","schema":{"type":"string","enum":["en"],"default":"en"}}],"responses":{"303":{"description":"Redirect to Stripe Checkout, or back to the pricing page with a reason.","headers":{"Location":{"schema":{"type":"string","format":"uri"}}}}}}},"/api/v1/licences/activate":{"post":{"operationId":"activateLicence","tags":["Licences"],"summary":"Activate a licence on a site","description":"Registers a WordPress site against a licence. Activating the same site again is safe. Production sites count toward the licence’s site limit; staging, development and local sites are free. 20 requests per minute per IP.","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivateRequest"}}}},"responses":{"200":{"description":"The site is active.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivateResponse"}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}}},"400":{"description":"The body is missing a key or site, or a field is invalid. `code`: `invalid_request`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_request":{"value":{"error":"Send a licence key and site address.","code":"invalid_request"}}}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}}},"403":{"description":"The licence was refunded or has expired. `code`: `licence_refunded`, `licence_expired`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"licence_refunded":{"value":{"error":"This licence was refunded, so it can’t be activated. Buy a new licence to use it again.","code":"licence_refunded"}},"licence_expired":{"value":{"error":"This licence has expired. Renew it in your Joinery account to get updates.","code":"licence_expired"}}}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}}},"404":{"description":"No licence has that key. `code`: `licence_not_found`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"licence_not_found":{"value":{"error":"We couldn't find that licence key. Check it in your Joinery account.","code":"licence_not_found"}}}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}}},"409":{"description":"Every site on the licence is in use. Deactivate one or buy more sites. `code`: `site_limit_reached`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"site_limit_reached":{"value":{"error":"All 5 sites on this licence are in use. Deactivate a site in your Joinery account, or add more sites.","code":"site_limit_reached"}}}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}}},"429":{"description":"Too many requests from this IP. Wait for the number of seconds in `Retry-After`. `code`: `rate_limited`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"value":{"error":"Too many requests. Try again in 42 seconds.","code":"rate_limited"}}}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}},"500":{"description":"Something failed on our side. Retry after a short wait. `code`: `server_error`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"server_error":{"value":{"error":"Something went wrong on our side. Try again in a minute; if it keeps happening, contact support.","code":"server_error"}}}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}}}}}},"/api/v1/licences/deactivate":{"post":{"operationId":"deactivateLicence","tags":["Licences"],"summary":"Free a site from a licence","description":"Removes a site from a licence so the site can be used elsewhere. Succeeds even if the site wasn’t active. 20 requests per minute per IP.","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeactivateRequest"}}}},"responses":{"200":{"description":"The site is no longer active.","content":{"application/json":{"schema":{"type":"object","required":["ok"],"properties":{"ok":{"const":true}}}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}}},"400":{"description":"The body is missing a key or site, or a field is invalid. `code`: `invalid_request`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_request":{"value":{"error":"Send a licence key and site address.","code":"invalid_request"}}}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}}},"404":{"description":"No licence has that key. `code`: `licence_not_found`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"licence_not_found":{"value":{"error":"We couldn't find that licence key. Check it in your Joinery account.","code":"licence_not_found"}}}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}}},"429":{"description":"Too many requests from this IP. Wait for the number of seconds in `Retry-After`. `code`: `rate_limited`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"value":{"error":"Too many requests. Try again in 42 seconds.","code":"rate_limited"}}}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}},"500":{"description":"Something failed on our side. Retry after a short wait. `code`: `server_error`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"server_error":{"value":{"error":"Something went wrong on our side. Try again in a minute; if it keeps happening, contact support.","code":"server_error"}}}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}}}}}},"/api/v1/updates":{"post":{"operationId":"checkForUpdates","tags":["Updates"],"summary":"Check installed plugins for updates","description":"Returns the newest version of each installed Joinery plugin that is newer than the installed one. Sites with a valid licence covering the plugin get a signed download link; others get `reason` explaining why not. Plugins that are up to date are left out. 60 requests per minute per IP.","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatesRequest"}}}},"responses":{"200":{"description":"Available updates, keyed by plugin slug.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatesResponse"}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}}},"400":{"description":"The body is missing the site or product list, or a field is invalid. `code`: `invalid_request`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_request":{"value":{"error":"Send a licence key and site address.","code":"invalid_request"}}}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}}},"429":{"description":"Too many requests from this IP. Wait for the number of seconds in `Retry-After`. `code`: `rate_limited`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"value":{"error":"Too many requests. Try again in 42 seconds.","code":"rate_limited"}}}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}},"500":{"description":"Something failed on our side. Retry after a short wait. `code`: `server_error`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"server_error":{"value":{"error":"Something went wrong on our side. Try again in a minute; if it keeps happening, contact support.","code":"server_error"}}}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}}}}}},"/api/v1/download/{releaseId}":{"get":{"operationId":"downloadRelease","tags":["Updates"],"summary":"Download a plugin release","description":"Follows a signed download link from `checkForUpdates` (or the Joinery account) and redirects to a 60-second file URL. Links are signed for one licence and release and expire after 7 days. 30 requests per minute per IP.","security":[],"parameters":[{"name":"releaseId","in":"path","required":true,"description":"Release ID from the download link.","schema":{"type":"string","format":"uuid"}},{"name":"licence","in":"query","required":true,"description":"Licence ID from the download link.","schema":{"type":"string","format":"uuid"}},{"name":"expires","in":"query","required":true,"description":"Unix time the link expires.","schema":{"type":"integer"}},{"name":"signature","in":"query","required":true,"description":"HMAC signature from the download link.","schema":{"type":"string","pattern":"^[0-9a-f]{64}$"}}],"responses":{"302":{"description":"Redirect to the plugin zip.","headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Location":{"schema":{"type":"string","format":"uri"}}}},"403":{"description":"The link expired or was changed, or the licence is no longer valid. `code`: `link_expired`, `licence_expired`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"link_expired":{"value":{"error":"This download link has expired. Check for updates again in WordPress, or download from your Joinery account.","code":"link_expired"}},"licence_expired":{"value":{"error":"This licence has expired. Renew it in your Joinery account to get updates.","code":"licence_expired"}}}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}}},"404":{"description":"The release no longer exists. `code`: `release_not_found`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"release_not_found":{"value":{"error":"That release no longer exists. Check for updates again in WordPress.","code":"release_not_found"}}}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}}},"429":{"description":"Too many requests from this IP. Wait for the number of seconds in `Retry-After`. `code`: `rate_limited`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"value":{"error":"Too many requests. Try again in 42 seconds.","code":"rate_limited"}}}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}},"500":{"description":"The file couldn’t be fetched, or something else failed on our side. Try again in a minute. `code`: `download_unavailable`, `server_error`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"download_unavailable":{"value":{"error":"The download is temporarily unavailable. Try again in a minute.","code":"download_unavailable"}},"server_error":{"value":{"error":"Something went wrong on our side. Try again in a minute; if it keeps happening, contact support.","code":"server_error"}}}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}}}}}}},"components":{"headers":{"RateLimit-Policy":{"description":"The limit for this endpoint, e.g. `\"activate\";q=20;w=60` (20 requests per 60 seconds per IP).","schema":{"type":"string"}},"RateLimit":{"description":"Where you stand, e.g. `\"activate\";r=17;t=42` (17 requests left, window resets in 42 seconds).","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in this window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before trying again.","schema":{"type":"integer"}}},"schemas":{"Error":{"type":"object","required":["error","code"],"description":"Every error response.","properties":{"error":{"type":"string","description":"What went wrong and what to do next, in plain English."},"code":{"type":"string","description":"Stable machine-readable code.","enum":["invalid_request","licence_not_found","licence_refunded","licence_expired","site_limit_reached","link_expired","release_not_found","download_unavailable","rate_limited","unauthorised","server_error","forbidden","not_found"]}}},"Money":{"type":"object","required":["eur","usd","gbp"],"description":"A yearly price in whole units of each currency, before tax.","properties":{"eur":{"type":"integer"},"usd":{"type":"integer"},"gbp":{"type":"integer"}}},"Plan":{"type":"object","required":["key","sites","price","checkoutUrl"],"properties":{"key":{"type":"string","description":"Plan key, used by startCheckout."},"sites":{"type":"integer","description":"Production sites included. Staging sites are free."},"price":{"$ref":"#/components/schemas/Money"},"checkoutUrl":{"type":"string","format":"uri","description":"Link that starts checkout in euros."}}},"Catalog":{"type":"object","required":["currencies","pricesInclude","billing","plugins","bundles"],"properties":{"currencies":{"type":"array","items":{"type":"string","enum":["eur","usd","gbp"]}},"pricesInclude":{"const":"none","description":"Prices are before VAT or sales tax."},"billing":{"const":"yearly","description":"Licences renew yearly at the same price."},"plugins":{"type":"array","items":{"type":"object","required":["slug","name","summary","requiresWooCommerce","url","plans"],"properties":{"slug":{"type":"string","description":"WordPress plugin slug."},"name":{"type":"string"},"summary":{"type":"string"},"requiresWooCommerce":{"type":"boolean"},"url":{"type":"string","format":"uri","description":"The plugin’s page."},"plans":{"type":"array","items":{"$ref":"#/components/schemas/Plan"}}}}},"bundles":{"type":"array","items":{"type":"object","required":["key","name","description","sites","price","checkoutUrl"],"properties":{"key":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"sites":{"type":"integer"},"price":{"$ref":"#/components/schemas/Money"},"checkoutUrl":{"type":"string","format":"uri"}}}}}},"ActivateRequest":{"type":"object","required":["key","site"],"properties":{"key":{"type":"string","minLength":10,"maxLength":64,"description":"Licence key from the Joinery account, e.g. JNR-7F3K-Q2M9-HX4D-P8WA.","examples":["JNR-7F3K-Q2M9-HX4D-P8WA"]},"site":{"type":"string","minLength":3,"maxLength":255,"description":"The WordPress site address (home_url()), e.g. https://shop.example.com.","examples":["https://shop.example.com"]},"environment":{"type":"string","enum":["production","staging","development","local"],"default":"production","description":"wp_get_environment_type(). Staging, development and local sites are free and never use up a site."},"wp":{"type":"string","maxLength":32,"description":"WordPress version."},"php":{"type":"string","maxLength":32,"description":"PHP version."}}},"ActivateResponse":{"type":"object","required":["status","plan","expiresAt","sitesUsed","sitesLimit"],"properties":{"status":{"const":"active"},"plan":{"type":"string","description":"Plan name, e.g. \"Dynamic Pricing · 5 sites\"."},"expiresAt":{"type":"string","format":"date-time","description":"When updates and support end unless renewed."},"sitesUsed":{"type":"integer","description":"Production sites using the licence."},"sitesLimit":{"type":"integer"}}},"DeactivateRequest":{"type":"object","required":["key","site"],"properties":{"key":{"type":"string","minLength":10,"maxLength":64,"description":"Licence key from the Joinery account, e.g. JNR-7F3K-Q2M9-HX4D-P8WA.","examples":["JNR-7F3K-Q2M9-HX4D-P8WA"]},"site":{"type":"string","minLength":3,"maxLength":255,"description":"The WordPress site address (home_url()), e.g. https://shop.example.com.","examples":["https://shop.example.com"]},"environment":{"type":"string","enum":["production","staging","development","local"],"default":"production","description":"wp_get_environment_type(). Staging, development and local sites are free and never use up a site."},"wp":{"type":"string","maxLength":32,"description":"WordPress version."},"php":{"type":"string","maxLength":32,"description":"PHP version."}}},"UpdatesRequest":{"type":"object","required":["site","products"],"properties":{"key":{"type":"string","minLength":0,"maxLength":64,"description":"Licence key, or empty if none has been entered yet.","examples":["JNR-7F3K-Q2M9-HX4D-P8WA"],"default":""},"site":{"type":"string","minLength":3,"maxLength":255,"description":"The WordPress site address (home_url()), e.g. https://shop.example.com.","examples":["https://shop.example.com"]},"environment":{"type":"string","enum":["production","staging","development","local"],"default":"production","description":"wp_get_environment_type(). Staging, development and local sites are free and never use up a site."},"wp":{"type":"string","maxLength":32,"description":"WordPress version."},"php":{"type":"string","maxLength":32,"description":"PHP version."},"products":{"type":"array","maxItems":50,"description":"Installed Joinery plugins.","items":{"type":"object","required":["slug","version"],"properties":{"slug":{"type":"string","pattern":"^[a-z0-9-]{1,64}$","examples":["joinery-dynamic-pricing"]},"version":{"type":"string","maxLength":32,"examples":["1.4.0"]}}}}}},"UpdatesResponse":{"type":"object","required":["updates"],"properties":{"updates":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/UpdateInfo"},"description":"Keyed by plugin slug."}}},"UpdateInfo":{"type":"object","required":["version","package","url"],"properties":{"version":{"type":"string"},"package":{"type":"string","description":"Signed download link (downloadRelease), or empty when `reason` is set."},"reason":{"type":"string","enum":["no_licence","expired","inactive","not_covered"],"description":"Why there is no download: no licence key, licence expired, licence refunded, or the licence doesn’t include this plugin."},"url":{"type":"string","format":"uri"},"tested":{"type":"string","description":"Highest WordPress version tested."},"requires":{"type":"string","description":"Minimum WordPress version."},"requires_php":{"type":"string","description":"Minimum PHP version."},"changelog":{"type":"array","maxItems":5,"items":{"type":"object","required":["version","date","notes"],"properties":{"version":{"type":"string"},"date":{"type":"string","format":"date-time"},"notes":{"type":"string"}}}}}}}}}