StudioMeyer API: read public website data
The base URL is https://studiomeyer.io/api/v1. The GET requests below need no account or API key. They read published services and fictional demo sites, send no contact details and start no purchase.
Quick start: curl, JavaScript and Python
GET /api/v1/services?lang=en returns the service catalog in English. Set lang=de or lang=es for German or Spanish; English is the default when lang is omitted. GET /api/v1/portfolio reads the demo portfolio.
The JavaScript example uses fetch and runs in a .mjs file with Node.js. The Python example uses only urllib and json from the standard library. These are HTTP examples, not published StudioMeyer SDKs.
Python sends an explicit application identifier, User-Agent: StudioMeyer-API-Example/1.0, instead of the library default.
curl --fail-with-body \
-H "Accept: application/json" \
"https://studiomeyer.io/api/v1/services?lang=en"
curl --fail-with-body \
-H "Accept: application/json" \
"https://studiomeyer.io/api/v1/portfolio?limit=1"const response = await fetch(
"https://studiomeyer.io/api/v1/services?lang=en",
{ headers: { Accept: "application/json" } }
);
const data = await response.json();
if (!response.ok) throw new Error(`${response.status}: ${data.message}`);
console.log(data.language, data.webdesign.packages);import json
from urllib.error import HTTPError
from urllib.request import Request, urlopen
request = Request(
"https://studiomeyer.io/api/v1/services?lang=en",
headers={
"Accept": "application/json",
"User-Agent": "StudioMeyer-API-Example/1.0",
},
)
try:
with urlopen(request, timeout=20) as response:
data = json.load(response)
print(data["language"], data["webdesign"]["packages"])
except HTTPError as error:
problem = {}
if "json" in error.headers.get("Content-Type", "").lower():
try:
problem = json.loads(error.read().decode("utf-8", errors="replace"))
except json.JSONDecodeError:
pass
if not isinstance(problem, dict):
problem = {}
message = (problem.get("message") or problem.get("detail")
or problem.get("title") or problem.get("error") or error.reason)
raise RuntimeError(f"HTTP {error.code}: {message}") from errorProcess responses as data
The services response is a JSON object with agency, website, language and the service areas. webdesign contains packages, payment, scope and care. Each package includes id, name, price, priceType and delivery. Read prices and terms from this response instead of maintaining a separate client-side price list.
The JSON below is an excerpt from the services response. OpenAPI contains the complete schema. The portfolio response includes projects, total, demos, filters and next_cursor. Every portfolio entry has type: "demo"; these examples are not customer references.
{
"agency": "StudioMeyer",
"language": "en"
}Filter and paginate the demo portfolio
limit is an integer from 1 to 100 and defaults to 20. Omit cursor for the first request. Then pass next_cursor unchanged as cursor for the next page until next_cursor is null. Keep the filters and page size unchanged as you paginate.
industry accepts immobilien, gastronomie, hotellerie or alle; style accepts premium, modern or alle. Use the documented values: unknown filter values currently leave results unfiltered. An invalid cursor or a limit outside the allowed range returns HTTP 400.
const url = new URL("https://studiomeyer.io/api/v1/portfolio");
url.searchParams.set("limit", "2");
let cursor = null;
do {
if (cursor === null) url.searchParams.delete("cursor");
else url.searchParams.set("cursor", cursor);
const response = await fetch(url);
const page = await response.json();
if (!response.ok) throw new Error(`${response.status}: ${page.message}`);
console.log(page.projects);
cursor = page.next_cursor;
} while (cursor !== null);Check HTTP status and structured errors
Check the HTTP status first. Error responses contain success: false, code, message, resolution and the existing error field. Additional fields depend on the endpoint. Error messages are currently in English, even when reading services in another language.
GET /api/v1/portfolio?limit=0 returns HTTP 400 with the response below. An unsupported HTTP method returns 405; the Allow header lists supported methods. Correct the request using the contract and resolution rather than repeatedly sending it unchanged.
{
"success": false,
"code": "VALIDATION_ERROR",
"message": "limit must be an integer between 1 and 100",
"error": "Invalid pagination limit",
"resolution": "Check the request parameters and JSON body against the API documentation."
}Request limits and retries
The public website API allows 60 requests per minute per IP address. RateLimit, RateLimit-Policy and the X-RateLimit headers report the current allowance. On HTTP 429, wait at least the number of seconds in Retry-After. A 503 response can also carry Retry-After when the rate-limit check is temporarily unavailable.
Spread requests over time and avoid immediate retry loops. Anonymous website limits are separate from the daily allowance of a Memory product account.
Contact inquiries require approval
POST /api/v1/consultation sends a non-binding contact inquiry. A person arranges the appointment afterwards; the API does not book it. Send the request only when the user asks for contact and approves sharing their contact details. This guide does not make a contact request.
For an approved inquiry, the endpoint supports an optional Idempotency-Key. Use a random UUID for one intended inquiry and reuse the same key and JSON body when retrying. A changed body returns 409 IDEMPOTENCY_CONFLICT. On 409 IDEMPOTENCY_IN_PROGRESS, observe Retry-After and keep the same key and body. If it remains incomplete, contact support rather than automatically switching to a new key.
This idempotency rule belongs to the documented inquiry endpoint, not every API. Account and payment flows have separate contracts and authorization boundaries.
Contracts and further documentation
OpenAPI describes parameters, JSON schemas, status codes and headers. The interactive Swagger documentation uses the same public contract. Before a write request, check its effects and the required user approval.
The Memory API is a separate service with its own OpenAPI contract. The GitHub organization links to available repositories; it does not imply that every StudioMeyer component is public.