Show your catalogue with the Storefront API
Read your organization's branding, products, locations and currencies without signing in, and take orders from your site.
The Storefront API gives your site what every visitor sees: your branding, your products and their plans, the locations and software a customer can choose, and your status page. Reading it needs no credential. Placing an order, previewing a coupon and paying an invoice need a signed-in customer's token.
Before you begin
Section titled Before you begin- Set up at least one product with an active plan. See Set up products and pricing.
- Fill in your branding on the Settings tab. See Change organization settings.
- To take orders, sign customers in first. See Sign customers in to your storefront.
Show your brand
Section titled Show your brandGET /storefront/branding returns what your pages need on every load: org_name, company_name, logo_url, favicon_url, primary_color, secondary_color, support_email, terms_url, privacy_url and default_currency. Colours you have not set come back as #1FA37A and #12141A, and the currency as USD.
It also carries a block for each optional storefront feature, so your site can show only what is switched on:
| Block | What it tells your site |
|---|---|
turnstile |
Whether to show the Cloudflare Turnstile challenge, and its public site_key. |
maintenance |
Whether to show a maintenance page. Staff signed in to the staff console still see the site. |
coupons |
Whether customers can enter a coupon code. |
free_tier |
Whether free servers can be ordered now, and the ads shown with them. |
community_forum, community_knowledgebase |
Whether the forum and guides are on. |
community_chat |
Whether to show your Discord chat, and the invite link. See Connect a Discord server. |
public_server_list |
Whether the public server list is on, and its categories and tags. |
google_analytics, trustpilot |
Whether to load Google Analytics, and when to ask for a Trustpilot review. |
List products and plans
Section titled List products and plansList what you sell:
Shellcurl "https://api.coritan.com/api/v1/orgs/acme/storefront/products?category=minecraft"The answer holds
productsandorg_name. Filter withcategory(minecraft,games,cloudoraddons) orgame, and page withpageandper_page(up to 200, default 100). A product backed by a server or an instance also says whether it can be ordered right now, inis_orderable_nowandstock_status(in_stockorout_of_stock), with the reason inavailability_reason.Open one product by its slug to get its plans:
Shellcurl "https://api.coritan.com/api/v1/orgs/acme/storefront/products/survival-smp"Each plan in
pricinghas theidyou order with, itsname,billing_cycle,price,setup_feeandcurrency.config_schemadescribes the options the product asks for.
Offer locations and software
Section titled Offer locations and software| Route | What it returns |
|---|---|
GET /storefront/locations |
The data centre locations. Add module=container or module=vps, and optionally hardware_tier_id, to learn which have room: each location then has available, reason and usage_percent. |
GET /storefront/vps-templates |
The operating systems a Cloud Compute order can use, with each one's minimum CPU, memory and disk. |
GET /storefront/specializations |
The games and apps a server can run. product_slug narrows the list to the ones that product features, in its order. |
GET /storefront/specializations/{slug}/compose |
The versions and choices one game or app offers. |
GET /storefront/currencies |
The currencies customers can pay in, with each one's rate against 1 USD. |
GET /storefront/timezones |
The time zones a customer can pick for scheduled tasks. |
For Minecraft, GET /storefront/gameproxy/policy says whether an order gets a join address automatically, on which base domain and port. POST /storefront/gameproxy/name-suggestions suggests free names (count up to 20), and POST /storefront/gameproxy/availability?subdomain=... checks one. See Customise the game proxy messages.
For an external server, GET /storefront/external-servers/regions lists the regions it can be served from. POST /storefront/external-servers/probe checks that the customer's own server answers, from upstream_host, upstream_port and mode. It needs the customer's token and is rate limited.
Take an order
Section titled Take an orderOptionally, check a coupon code for the plan:
Shellcurl "https://api.coritan.com/api/v1/orgs/acme/storefront/coupons/preview?code=SPRING&org_product_id=12&org_pricing_id=31" \ -H "Authorization: Bearer $CUSTOMER_TOKEN"The answer has
valid. When it istrue,amount_beforeandamount_aftershow the first invoice's total. When it isfalse,messagesays why.Place the order as the customer:
Shellcurl -X POST "https://api.coritan.com/api/v1/orgs/acme/storefront/order" \ -H "Authorization: Bearer $CUSTOMER_TOKEN" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: 3f6c2a9e-order-1" \ -d '{"org_product_id": 12, "org_pricing_id": 31, "hostname": "survival-smp", "accepted_terms": true, "config": {}}'| Field | What it holds | | --- | --- | |
org_product_id,org_pricing_id| The product and the plan. Both are required. | |hostname| A name for the service, up to 100 characters. | |config| The options the product'sconfig_schemaasks for, such as a location. | |accepted_terms| Must betruefor a server, an instance or an external server. We record the acceptance with the invoice. | |terms_url| The terms the customer accepted. Defaults to the Terms of service URL in your settings. | |turnstile_token| The Turnstile answer. A free order needs it whenturnstile.enabledistrue. | |coupon_code| A coupon, taken off the first invoice. A code that does not apply refuses the order. |The answer has
service_id,invoice_id,invoice_number,total,currency,due_dateandrequires_payment.statusispending_paymentuntil the invoice is paid, orprovisioningwhen there is nothing to pay. Send the sameIdempotency-Keywhen you retry, and the same order comes back instead of a second one.Send the customer to pay, as the next section shows. We create the resource once the invoice is paid.
Pay an invoice
Section titled Pay an invoicePOST /storefront/checkout/{invoice_id} starts a payment for the customer's unpaid or overdue invoice and returns a checkout_url to send them to.
curl -X POST "https://api.coritan.com/api/v1/orgs/acme/storefront/checkout/5021?currency=EUR" \
-H "Authorization: Bearer $CUSTOMER_TOKEN" \
-H "Origin: https://shop.example.net"
currency defaults to the customer's own, and gateway_name to the gateway we pick for that currency and the customer's country. return_url and cancel_url must be absolute http or https addresses. Leave them out and we build them from the request's Origin: /billing/invoices/{invoice_id}?paid=1 and ?cancelled=1 on your site. The answer also lists the available_gateways for that currency.
Show status, notices and a contact form
Section titled Show status, notices and a contact formGET /storefront/statusreturns the health of each location, the incidents and maintenance your staff post, and the state of the services your storefront relies on. Resolved incidents stay for 24 hours.GET /storefront/noticesreturns the notices for visitors who are not signed in. Signed-in customers get theirs fromGET /portal/notices, which can target paying customers.POST /storefront/contactsends a visitor's message to your Support email, or to your SMTP from address when there is none, and emails the visitor an acknowledgement. With neither address set, nobody is emailed. It takesname,emailandmessage, withkindset togeneralorbare_metal_quoteand optionalcompany,location,cpu,ram,storage,quantityandtimeline. Leave thewebsitefield empty: we treat a filled one as a bot. When the visitor sends their customer token, the message also opens a sales conversation in your support inbox.
Result
Section titled ResultYour site shows your brand and catalogue to every visitor, and a signed-in customer can order and pay. The order appears on the Services tab and in the customer's invoices, and your webhooks receive order.created.
Troubleshooting
Section titled TroubleshootingProduct not foundorPricing plan not found- The product is not available, or the plan is turned off or belongs to another product.
Accept the Terms of Service to place this order- Send
accepted_terms: trueonce the customer has ticked your terms. Order already in progress- The same order with the same
Idempotency-Keyis still being placed. Wait for the first request to finish. 409withfree_limit_reached, or503withfree_tier_paused- The customer holds as many free servers as allowed, or free servers are paused for now. Offer a paid plan.
403 Customer account is not activeor403 Service limit reached (500/500)- The customer is suspended or closed, or your organization holds as many services as it may. Ask support to raise the limit.
422witherrors- The options in
configcannot be ordered, for example because the location has no room, or the coupon does not apply. The messages say why. Invoice not found or not payableorNo balance remaining- The invoice belongs to another customer, or it is already paid.
return_url and cancel_url are required and must be absolute http(s) URLs ...- Send both, or send an
Originheader we can build them from. 429 Too many inquiries. Try again shortly.- One address sent too many contact messages in a short time.
Related
Section titled RelatedAPI operations on this page
| Method | Path | What it does |
|---|---|---|
GET | /api/v1/orgs/{org_slug}/storefront/branding | Public branding + legal links for the org storefront |
POST | /api/v1/orgs/{org_slug}/storefront/checkout/{invoice_id} | Create a payment checkout session for a specific invoice |
POST | /api/v1/orgs/{org_slug}/storefront/contact | Public contact / bare-metal quote intake |
GET | /api/v1/orgs/{org_slug}/storefront/coupons/preview | What a code would take off this plan's first invoice, before ordering |
GET | /api/v1/orgs/{org_slug}/storefront/currencies | Public enabled pay currencies with FX rates (quote per 1 USD) |
POST | /api/v1/orgs/{org_slug}/storefront/external-servers/probe | Customer: check a backend before ordering ("Test connection") |
GET | /api/v1/orgs/{org_slug}/storefront/external-servers/regions | Public: edge regions an external server can be served from, and the default |
POST | /api/v1/orgs/{org_slug}/storefront/gameproxy/availability | Storefront availability |
POST | /api/v1/orgs/{org_slug}/storefront/gameproxy/name-suggestions | Storefront name suggestions |
GET | /api/v1/orgs/{org_slug}/storefront/gameproxy/policy | Public: whether Minecraft orders auto-attach gameproxy + base domain |
GET | /api/v1/orgs/{org_slug}/storefront/locations | Public DC list, optionally with capacity for a module |
GET | /api/v1/orgs/{org_slug}/storefront/notices | Live notices for everyone, for the dashboard bar when nobody is signed in |
POST | /api/v1/orgs/{org_slug}/storefront/order | Authenticated customer places an order for a product |
GET | /api/v1/orgs/{org_slug}/storefront/products | Public endpoint: browse the organization's product catalog |
GET | /api/v1/orgs/{org_slug}/storefront/products/{product_slug} | Public endpoint: view a single product with all pricing tiers |
GET | /api/v1/orgs/{org_slug}/storefront/specializations | Public game/app specialization catalog for order UX |
GET | /api/v1/orgs/{org_slug}/storefront/specializations/{slug}/compose | Storefront compose specialization |
GET | /api/v1/orgs/{org_slug}/storefront/timezones | Zones a schedule may be set to, and the old names for them |
GET | /api/v1/orgs/{org_slug}/storefront/status | Per-location and per-node platform health, for the public status page |
GET | /api/v1/orgs/{org_slug}/storefront/vps-templates | Ready OS templates for Cloud / VPS storefront orders |