Skip to main content

Create Aggregate

Provision a new sub-tenant (aggregate) under your aggregator store. The new tenant is created with its own domain, admin user, and store configuration.


Endpoint​

POST /api/v3/aggregates

Request Body​

Required Fields​

FieldTypeDescription
namestringStore name (max 255 characters)
langstringStore language. Must be one of the supported codes (e.g., en, es, pt).
timezonestringStore timezone (IANA format, e.g., America/New_York)
support_emailstringSupport email address (max 255 characters)

Optional Fields​

FieldTypeDefaultDescription
final_domainstringAuto-generated from name as slugStore domain (must be unique, max 255 chars)
external_idstringnullYour own opaque identifier for the sub-tenant (max 255 chars)
primary_colorstringnullPrimary brand color (hex, e.g., #336699)
secondary_colorstringnullSecondary brand color (hex, e.g., #FF6600)
reader_accent_colorstringnullReader accent color used in the reader's light and dark themes (hex, e.g., #0066CC)
reader_flashcards_enabledbooleanfalseWhen true, signed-in readers of the store can create flashcards from text selections in PDF and EPUB products. Never offered to anonymous readers or on audiobooks. Off by default; the aggregator's own setting is not inherited.
logo_urlstringnullPublic URL of the store logo, pointing to a JPG, PNG, WEBP, or SVG image (max 2048 chars). The platform downloads and hosts the image; see Logo and Icon Import.
icon_urlstringnullPublic URL of the store icon/favicon, pointing to a JPG, PNG, WEBP, or SVG image (max 2048 chars). The platform downloads and hosts the image; see Logo and Icon Import.
disable_sellingbooleanfalseWhen true, disables all e-commerce functionality on the store (checkout, paid plans, paid content). Selling is enabled by default.
landing_enabledbooleanfalseWhen true, the public landing page is shown. Disabled by default for new aggregates.
External ID

external_id lets you reference sub-tenants using an identifier from your own system (e.g., a CRM ID, an ERP code). It must be unique per aggregator and can be used on the get and update endpoints by passing ?id_type=external on the URL.

Domain Format

final_domain supports two formats:

  • Platform subdomain: mybookstore.publica.la (accessible at https://mybookstore.publica.la)
  • Custom domain: www.mybookstore.com (requires DNS configuration pointing to Publica.la)

If omitted, a domain is auto-generated from the store name (e.g., name "My Bookstore" generates mybookstore.publica.la).

Logo and Icon Import​

When you send logo_url or icon_url, the platform checks the URL during validation, then downloads the image and stores it as the store's own logo or icon:

  • The URL must be reachable when you make the request and must serve a JPG, PNG, WEBP, or SVG image, as reported by the Content-Type header the server returns.
  • The image can be at most 20,000 KB.
  • Responses return the URL of the hosted copy on the platform's asset domain, not the URL you sent. Treat it as an opaque value.
  • The icon sizes derived from icon_url (favicon and app icons) are generated in the background, so they can take a moment to appear on the store.

Auth Token (SSO) Fields​

Configure single sign-on for the sub-tenant by sending an external_auth object. This is the same JWT (HS256) auth token integration that previously required a manual setup through support; you can now provision it programmatically for any of your sub-tenants. See the Auth Token guide for the token format and login flow.

FieldTypeDefaultDescription
external_auth.keystringnullWrite-only. The HMAC secret used to sign your JWTs (minimum 32 characters). Sending a valid key enables SSO. Never returned in any response.
external_auth.issuerstringnullYour platform identifier. Must match the iss claim in your tokens. Required when key is sent.
external_auth.redirect_urlstringnullWhere users are sent on auth errors. Required when key is sent.
external_auth.login_urlstringnullYour platform's login URL.
external_auth.logout_urlstringnullWhere users are sent after logging out.
external_auth.home_urlstringnullYour platform's home URL.
external_auth.account_urlstringnullYour platform's account URL.
Key is write-only

The key is a shared secret and is never returned by any endpoint (create, get, list, or update). Responses include an external_auth object with every field except key, plus an enabled boolean that reflects whether a key is configured.

Storefront Redirect Fields​

Send a storefront_redirect object to send visitors of the sub-tenant's storefront to an external site. Use it for stores that only need to serve reading and leave browsing to another site, such as a discovery portal you run.

FieldTypeDefaultDescription
storefront_redirect.enabledbooleanfalseTurns the redirect on (true) or off (false). Required when storefront_redirect is sent.
storefront_redirect.urlstringnullWhere visitors are sent. Must be an http or https URL (max 2048 chars). Required when enabled is true.
What the redirect covers

While the redirect is on, every storefront page sends visitors to url, on every domain of the store and whether or not they are signed in. The reader and the store dashboard keep working. When a reader signs in through an integration that sends reader_exit_url (see the Auth Token guide), that URL takes precedence over url for that reader.

Inherited from Aggregator​

These values are automatically set from the aggregator and cannot be overridden:

AttributeDescription
FeesTransaction and sales fee structure
CurrenciesMain and secondary currency configuration

What Happens on Create​

When you create an aggregate, the platform automatically:

  1. Creates the tenant with the provided configuration
  2. Provisions store infrastructure (library, default shelves, sales settings)
  3. Inherits fees and currencies from the aggregator
  4. Creates an admin user linked to the email of the authenticated user
  5. Returns an api_key to authenticate requests on behalf of the new store

Request Examples​

Minimal (Auto-Generated Domain)​

curl -X POST "https://yourstore.publica.la/api/v3/aggregates" \
-H "X-User-Token: your-api-token" \
-H "Content-Type: application/json" \
-d '{
"name": "My Bookstore",
"lang": "en",
"timezone": "America/New_York",
"support_email": "[email protected]"
}'

The domain is auto-generated as mybookstore.publica.la.

With Auth Token (SSO)​

curl -X POST "https://yourstore.publica.la/api/v3/aggregates" \
-H "X-User-Token: your-api-token" \
-H "Content-Type: application/json" \
-d '{
"name": "My Bookstore",
"lang": "en",
"timezone": "America/New_York",
"support_email": "[email protected]",
"external_auth": {
"key": "your-32-character-or-longer-secret-key",
"issuer": "my-platform",
"redirect_url": "https://my-platform.com/auth-error",
"logout_url": "https://my-platform.com/logout"
}
}'

With Flashcards and Storefront Redirect​

curl -X POST "https://yourstore.publica.la/api/v3/aggregates" \
-H "X-User-Token: your-api-token" \
-H "Content-Type: application/json" \
-d '{
"name": "University Library",
"lang": "en",
"timezone": "America/New_York",
"support_email": "[email protected]",
"reader_flashcards_enabled": true,
"storefront_redirect": {
"enabled": true,
"url": "https://discovery.example.com"
}
}'

With Branding and Custom Domain​

curl -X POST "https://yourstore.publica.la/api/v3/aggregates" \
-H "X-User-Token: your-api-token" \
-H "Content-Type: application/json" \
-d '{
"name": "My Bookstore",
"final_domain": "www.mybookstore.com",
"external_id": "crm-12345",
"lang": "en",
"timezone": "America/New_York",
"support_email": "[email protected]",
"primary_color": "#1A237E",
"secondary_color": "#FF6F00",
"reader_accent_color": "#0066CC",
"logo_url": "https://example.com/assets/logo.png",
"icon_url": "https://example.com/assets/icon.png"
}'

Response​

Success Response (201 Created)​

{
"data": {
"id": "42",
"external_id": null,
"slug": "my-bookstore",
"name": "My Bookstore",
"final_domain": "mybookstore.publica.la",
"lang": "en",
"timezone": "America/New_York",
"api_key": "api-a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"support_email": "[email protected]",
"primary_color": null,
"secondary_color": null,
"reader_accent_color": null,
"reader_flashcards_enabled": false,
"logo_url": null,
"icon_url": null,
"disable_selling": false,
"landing_enabled": false,
"storefront_redirect": {
"enabled": false,
"url": null
},
"external_auth": {
"enabled": false,
"issuer": null,
"redirect_url": null,
"login_url": null,
"logout_url": null,
"home_url": null,
"account_url": null
},
"created_at": "2026-03-24T15:30:00+00:00"
}
}

The api_key is always included in the create response. To retrieve it later, use ?include=api_key on the get or list endpoints.

API Key Usage

Use the api_key in the X-User-Token header to make API requests directly to the sub-tenant's endpoints (content, orders, etc.).


Error Handling​

Validation Errors (422)​

{
"message": "The given data was invalid.",
"errors": {
"name": ["The name field is required."],
"final_domain": ["The final domain has already been taken."],
"support_email": ["The support email must be a valid email address."]
}
}

Invalid Domain Format (422)​

{
"message": "The given data was invalid.",
"errors": {
"final_domain": ["The final_domain format is invalid."]
}
}

Invalid Color Format (422)​

{
"message": "The given data was invalid.",
"errors": {
"primary_color": ["The primary color format is invalid."]
}
}

Invalid Logo or Icon (422)​

Returned when the image cannot be fetched, is not a supported format, or is larger than 20,000 KB:

{
"message": "The given data was invalid.",
"errors": {
"logo_url": ["The logo url could not be downloaded."],
"icon_url": ["The icon url must point to a JPG, PNG, WEBP or SVG image."]
}
}

Authorization Errors (403)​

Returned when the authenticated tenant is not allowed to provision sub-tenants. Two messages are possible:

{
"message": "Tenant does not have aggregation capabilities."
}
{
"message": "Aggregated tenants cannot provision tenants."
}

Authentication Errors (401)​

{
"message": "Unauthenticated."
}

Validation Rules​

FieldRules
nameRequired, string, max 255 characters
final_domainOptional, string, max 255 characters, unique, valid domain format
external_idOptional, nullable, string, max 255 characters, unique per aggregator
langRequired, string, one of the supported language codes
timezoneRequired, valid IANA timezone
support_emailRequired, valid email, max 255 characters
primary_colorOptional, nullable, hex color format (#RRGGBB)
secondary_colorOptional, nullable, hex color format (#RRGGBB)
reader_accent_colorOptional, nullable, hex color format (#RRGGBB)
reader_flashcards_enabledOptional, boolean
logo_urlOptional, nullable, http or https URL, max 2048 characters. Must be reachable and serve a JPG, PNG, WEBP, or SVG image of at most 20,000 KB
icon_urlOptional, nullable, http or https URL, max 2048 characters. Must be reachable and serve a JPG, PNG, WEBP, or SVG image of at most 20,000 KB
disable_sellingOptional, boolean
landing_enabledOptional, boolean
storefront_redirectOptional, object
storefront_redirect.enabledRequired when storefront_redirect is sent, boolean
storefront_redirect.urlRequired when storefront_redirect.enabled is true, nullable, http or https URL, max 2048 characters
external_auth.keyRequired when external_auth is sent, string, minimum 32 characters
external_auth.issuerRequired when external_auth is sent, string, max 255 characters
external_auth.redirect_urlRequired when external_auth is sent, valid URL, max 2048 characters
external_auth.login_urlOptional, nullable, valid URL, max 2048 characters
external_auth.logout_urlOptional, nullable, valid URL, max 2048 characters
external_auth.home_urlOptional, nullable, valid URL, max 2048 characters
external_auth.account_urlOptional, nullable, valid URL, max 2048 characters

Validation Error (422)​

{
"message": "The given data was invalid.",
"errors": {
"external_auth.key": [
"The external authentication key must be at least 256 bits (32 bytes)."
]
}
}

See Also​