Products, Perks & Locations
Read-only reference for the six catalog endpoints — products, perks, product perks, paywall locations, and payment provider configuration.
The catalog endpoints expose your project's purchase configuration as flat, read-only lists. They return exactly what is currently deployed for the project your credential resolves to — no pagination, no filters (except the product-perks lookup), no writes.
The catalog model
Six resources make up the catalog:
- Products are the purchasable items in your app. Every product carries a
type—subscription,one-time, orone-time-consumable. See Products. - Perks are the entitlements a purchase grants — the things you gate features on. See Perks.
- Product perks are the join rows linking a product to the perks it unlocks.
- Paywall locations are the named places in your app where a paywall can be shown
(for example
onboardingorsettings-upsell). - Payment provider configurations are your project's store connections (Apple App Store, Google Play) and whether each is enabled.
- Payment provider products map a catalog product to the actual store SKU via a provider-specific
configurationobject.
The catalog is written elsewhere
These endpoints only read. The catalog itself is defined in your schema and pushed from your
project — there are no POST/PATCH/DELETE routes here. If you want the whole catalog in one
response, already joined and keyed the way the CLI and SDK consume it, use the
Schema endpoint instead of stitching these six lists together.
Authentication
All catalog endpoints accept any project-scoped credential — a project secret key
(x-secret-key) or a user API key (x-api-key). The project is resolved from the credential, so
there is no project ID in the path. See Authentication.
The examples below use the production base URL https://api.voidhash.com.
List products
GET /api/v1/productsReturns every product in the project.
curl https://api.voidhash.com/api/v1/products \
-H "x-secret-key: vh_sk_..."Each row has the shape:
type Product = {
id: string;
name: string;
projectId: string;
slug: string;
type: "subscription" | "one-time" | "one-time-consumable";
};[
{
"id": "prod_01j...",
"name": "Monthly Premium",
"projectId": "proj_01j...",
"slug": "monthly-sub",
"type": "subscription"
}
]The slug is the identifier you defined in your schema; id is Voidhash's internal identifier
and is what the product-perks lookup expects.
List perks
GET /api/v1/perksReturns every perk in the project.
curl https://api.voidhash.com/api/v1/perks \
-H "x-secret-key: vh_sk_..."type Perk = {
id: string;
name: string;
projectId: string;
slug: string;
};List perks for a product
GET /api/v1/product-perks/by-product-id/:productIdReturns the join rows for one product — which perks it unlocks. productId is the internal
product id from the products list, not the slug.
curl https://api.voidhash.com/api/v1/product-perks/by-product-id/prod_01j... \
-H "x-secret-key: vh_sk_..."type ProductPerk = {
id: string;
perkId: string;
productId: string;
};Join perkId back against the perks list to get names and slugs. An invalid productId yields a
400 with Api/ProductPerkValidationError.
List paywall locations
GET /api/v1/paywall-locationsReturns the paywall locations defined for the project. Locations are what the SDK resolves against when it decides which paywall to show at a given point in your app.
curl https://api.voidhash.com/api/v1/paywall-locations \
-H "x-secret-key: vh_sk_..."type PaywallLocation = {
description: string | null;
id: string;
name: string;
projectId: string;
slug: string;
};List payment provider configurations
GET /api/v1/payment-provider-configurationsReturns the project's store connections and whether each is currently enabled.
curl https://api.voidhash.com/api/v1/payment-provider-configurations \
-H "x-secret-key: vh_sk_..."type PaymentProviderConfiguration = {
enabled: boolean;
id: string;
name: string;
projectId: string;
providerId: string;
};List payment provider products
GET /api/v1/payment-provider-productsReturns the mapping between catalog products and store SKUs. Each row ties a productId to a
provider configuration and carries the provider-specific configuration (for example the App
Store product identifier, or the Google Play product ID and base plan ID).
curl https://api.voidhash.com/api/v1/payment-provider-products \
-H "x-secret-key: vh_sk_..."type PaymentProviderProduct = {
configuration: Record<string, unknown>;
id: string;
paymentProviderConfigurationId: string;
productId: string;
providerId: string;
};The configuration object is intentionally untyped at the API surface — its shape depends on the
provider. Set these values in your schema's per-product providers block; see
Products for what each provider expects.
Errors
All six endpoints share the same error surface. Errors are JSON objects tagged with _tag:
| Status | _tag | Meaning |
|---|---|---|
401 | Api/NotAuthenticatedError | Missing or invalid credential. |
403 | Api/ActionForbiddenError | Credential lacks the required project permission. |
400 | Api/ProductPerkValidationError | Invalid productId (product-perks lookup only). |
500 | Api/ProductServiceError, Api/PerkServiceError, Api/ProductPerkServiceError, Api/PaywallLocationServiceError, Api/PaymentProviderConfigurationServiceError, Api/PaymentProviderProductServiceError | Internal error in the owning service. |