Skip to content

Create a brand

The brands.create operation: POST /api/v1/brands in the REST API and the brands_create tool in the MCP server.

POST/api/v1/brands

Creates a brand (a storefront or product line) under one of the organization's legal entities. The brand starts in test mode only (status: test_only); it goes live through the go-live checklist.

  • slug is unique across Ownrecord: it appears in checkout URLs and API keys.
  • invoiceSeries.invoice (and creditNote, default {invoice}-CN) must be unused by every other brand of the same entity: each brand numbers its invoices in its own series within the entity.
  • statementDescriptor defaults to the name in capitals.

The plan limits the number of brands (brands.max). Needs brands:write: organization owners and admins, or an org or entity API key with that scope (a test-mode key creates the brand like any other key: brands aren't mode-separated).

At a glance

  • REST: POST /api/v1/brands
  • MCP tool: brands_create
  • Operation ID: brands.create
  • Scope: Organization, or one of its legal entities or brands
  • Permission: brands:write
  • Risk tier: write
  • Dry run: Supported (send Ownrecord-Dry-Run: true)
  • Idempotency: Idempotency-Key required
  • Modes: Test and live
  • Authentication: API key with the brands:write scope
  • Since: M1

Request

Body

A JSON object (Content-Type: application/json):

FieldTypeRequiredDescription
entityIdent_… IDYes
namestringYes
slugstringYes
invoiceSeriesobjectYes
invoiceSeries.invoicestringYes
invoiceSeries.creditNotestringNo
statementDescriptorstringNo
brandingobjectNo
branding.logoUrlstringNo
branding.iconUrlstringNo
branding.primaryColorstringNo
branding.accentColorstringNo
branding.supportEmailstringNo
branding.supportUrlstringNo
branding.termsUrlstringNo
branding.privacyUrlstringNo

Response

201 Created with a JSON object:

FieldTypeDescription
idbrd_… ID
object"brand"
orgIdorg_… ID
entityIdent_… ID
slugstring
namestring
statusone of draft, test_only, live, suspended
isPlatformBrandboolean
brandingobject
branding.logoUrlstring or null
branding.iconUrlstring or null
branding.primaryColorstring or null
branding.accentColorstring or null
branding.supportEmailstring or null
branding.supportUrlstring or null
branding.termsUrlstring or null
branding.privacyUrlstring or null
statementDescriptorstring
statementDescriptorSuffixstring or null
invoiceSeriesobject
invoiceSeries.invoicestring
invoiceSeries.creditNotestring
billingSettingsobject
billingSettings.dunningobject
billingSettings.dunning.retryOffsetsDaysarray of integer
billingSettings.dunning.finalActionone of unpaid, canceled
billingSettings.entitlementGraceDaysinteger
billingSettings.sendInvoiceobject
billingSettings.sendInvoice.graceDaysinteger
billingSettings.cardExpiryRemindersboolean
billingSettings.pausedEntitlementsboolean
billingSettings.paymentBehaviorone of allow_incomplete, pending_if_incomplete
policiesobject
policies.breakageRecognitionone of at_expiry, manualat_expiry (the default) or manual (held as expired credits until recognised).
policies.supportRefundLimitsarray of objectThe support role's refund limit per currency (M8); a currency not listed has the default of 100 of it.
policies.supportRefundLimits[].amountstringInteger micros as a string.
policies.supportRefundLimits[].currencystring
policies.disputeWalletFreezebooleanFreeze the customer's wallets when a dispute opens (default true; §19.2, M8).
policies.taxIdUnavailableone of charge_as_b2c, blockWhat a sale does when a tax ID couldn't be checked (§9.1 step 1; M13): charge_as_b2c (the default) or block.
portalSettingsobject
portalSettings.allowPlanChangesbooleanCustomers may switch plans along planChangeMatrix (no row: no switch).
portalSettings.planChangeMatrixarray of objectOne row per price: a subscription item on fromPriceId may switch to any of toPriceIds (same mode and currency).
portalSettings.planChangeMatrix[].fromPriceIdprice_… ID
portalSettings.planChangeMatrix[].toPriceIdsarray of price_… ID
portalSettings.allowCancelbooleanCustomers may cancel their subscriptions.
portalSettings.cancelBehaviorone of period_end, immediateA portal cancellation ends the subscription at the period end (default) or at once.
portalSettings.collectCancelReasonbooleanThe portal asks why the customer cancels.
portalSettings.allowQuantityChangesbooleanCustomers may change the quantity (seats) of licensed items.
checkoutSettingsobject
checkoutSettings.localesarray of stringThe brand's languages, its default first. A default, not a restriction: a customer's own language comes first.
checkoutSettings.collectPhoneboolean
checkoutSettings.requireBusinessDetailsone of auto, always, never
createdAtdate-time
updatedAtdate-time

Examples

A brand with its own invoice series

HTTP
POST /api/v1/brands
Authorization: Bearer or_test_…
Idempotency-Key: 3f1c9a52-7d0e-4b8f-9a61-0c2d5e8b7f14
Content-Type: application/json

{
  "entityId": "ent_01m4tx5nj8emwbyf7y9vcf47x2",
  "name": "Acme App",
  "slug": "acme-app",
  "invoiceSeries": {
    "invoice": "ACM"
  }
}

Response (201):

JSON
{
  "id": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
  "object": "brand",
  "orgId": "org_01m4tx5nj7ekd958x53w4bntcg",
  "entityId": "ent_01m4tx5nj8emwbyf7y9vcf47x2",
  "slug": "acme-app",
  "name": "Acme App",
  "status": "test_only",
  "isPlatformBrand": false,
  "branding": {
    "logoUrl": null,
    "iconUrl": null,
    "primaryColor": null,
    "accentColor": null,
    "supportEmail": null,
    "supportUrl": null,
    "termsUrl": null,
    "privacyUrl": null
  },
  "statementDescriptor": "ACME APP",
  "statementDescriptorSuffix": null,
  "invoiceSeries": {
    "invoice": "ACM",
    "creditNote": "ACM-CN"
  },
  "billingSettings": {
    "dunning": {
      "retryOffsetsDays": [1, 3, 5, 7],
      "finalAction": "unpaid"
    },
    "entitlementGraceDays": 7,
    "sendInvoice": {
      "graceDays": 14
    },
    "cardExpiryReminders": true,
    "pausedEntitlements": false,
    "paymentBehavior": "allow_incomplete"
  },
  "policies": {
    "breakageRecognition": "at_expiry",
    "supportRefundLimits": [],
    "disputeWalletFreeze": true,
    "taxIdUnavailable": "charge_as_b2c"
  },
  "portalSettings": {
    "allowPlanChanges": true,
    "planChangeMatrix": [],
    "allowCancel": true,
    "cancelBehavior": "period_end",
    "collectCancelReason": true,
    "allowQuantityChanges": false
  },
  "checkoutSettings": {
    "locales": ["en", "hr"],
    "collectPhone": false,
    "requireBusinessDetails": "auto"
  },
  "createdAt": "2026-10-13T12:00:00.000Z",
  "updatedAt": "2026-10-13T12:00:00.000Z"
}
HTTP
POST /api/v1/brands
Authorization: Bearer or_test_…
Idempotency-Key: 3f1c9a52-7d0e-4b8f-9a61-0c2d5e8b7f14
Content-Type: application/json

{
  "entityId": "ent_01m4tx5nj8emwbyf7y9vcf47x2",
  "name": "Acme App",
  "slug": "acme-app",
  "invoiceSeries": {
    "invoice": "ACM",
    "creditNote": "ACM-CN"
  },
  "statementDescriptor": "ACME APP",
  "branding": {
    "supportEmail": "help@acme.example",
    "termsUrl": "https://acme.example/terms",
    "privacyUrl": "https://acme.example/privacy"
  }
}

Response (201):

JSON
{
  "id": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
  "object": "brand",
  "orgId": "org_01m4tx5nj7ekd958x53w4bntcg",
  "entityId": "ent_01m4tx5nj8emwbyf7y9vcf47x2",
  "slug": "acme-app",
  "name": "Acme App",
  "status": "test_only",
  "isPlatformBrand": false,
  "branding": {
    "logoUrl": null,
    "iconUrl": null,
    "primaryColor": null,
    "accentColor": null,
    "supportEmail": "help@acme.example",
    "supportUrl": null,
    "termsUrl": "https://acme.example/terms",
    "privacyUrl": "https://acme.example/privacy"
  },
  "statementDescriptor": "ACME APP",
  "statementDescriptorSuffix": null,
  "invoiceSeries": {
    "invoice": "ACM",
    "creditNote": "ACM-CN"
  },
  "billingSettings": {
    "dunning": {
      "retryOffsetsDays": [1, 3, 5, 7],
      "finalAction": "unpaid"
    },
    "entitlementGraceDays": 7,
    "sendInvoice": {
      "graceDays": 14
    },
    "cardExpiryReminders": true,
    "pausedEntitlements": false,
    "paymentBehavior": "allow_incomplete"
  },
  "policies": {
    "breakageRecognition": "at_expiry",
    "supportRefundLimits": [],
    "disputeWalletFreeze": true,
    "taxIdUnavailable": "charge_as_b2c"
  },
  "portalSettings": {
    "allowPlanChanges": true,
    "planChangeMatrix": [],
    "allowCancel": true,
    "cancelBehavior": "period_end",
    "collectCancelReason": true,
    "allowQuantityChanges": false
  },
  "checkoutSettings": {
    "locales": ["en", "hr"],
    "collectPhone": false,
    "requireBusinessDetails": "auto"
  },
  "createdAt": "2026-10-13T12:00:00.000Z",
  "updatedAt": "2026-10-13T12:00:00.000Z"
}

Errors

CodeHTTP statusWhenWhat to do
validation_failed400A field is missing or malformed (details.issues).Fix the fields listed in details.issues and send the request again.
slug_invalid400The slug has the wrong format or is a reserved word.Choose a slug such as acme or acme-app. Reserved words such as api, console and docs can't be used.
slug_taken409Another brand already uses this slug (brand slugs are unique on Ownrecord).Choose another slug. Organization and brand slugs are unique across Ownrecord; entity slugs are unique within an organization.
invoice_series_taken409Another brand of the entity already uses the invoice or credit-note series.Choose a different series code. Each brand numbers its invoices and credit notes in its own series within the entity.
resource_not_found404The entity doesn't exist or is outside the request's scope.Check the ID and that your credentials are scoped to the right organization, entity, brand and mode.
scope_mismatch403The request is scoped to one brand; brands are created at an entity.Use credentials scoped to that organization, entity or brand, or leave the scope fields out of the request.
entitlement_required403The plan's brands.max is reached.Upgrade the organization's plan, or remove something to get back under the limit.
permission_denied403You can't create brands here.Ask an organization owner or admin for a role or scope that allows this action.

It can also return these common errors: api_version_unsupported, invalid_json, unsupported_media_type, authentication_required, api_key_invalid, idempotency_key_required, idempotency_key_reused, idempotency_in_progress, approval_required, approval_rejected, approval_expired, stale_approval, approval_policy_denied, rate_limited, internal_error.