Skip to content

Update a brand

The brands.update operation: PATCH /api/v1/brands/{id} in the REST API and the brands_update tool in the MCP server.

PATCH/api/v1/brands/{id}

Renames a brand or changes its slug, branding (logo, icon, colors, support email and URL, terms and privacy URLs), statement descriptor or billing settings. Send only the fields to change; null clears an optional value (for a billing setting: back to its default).

Billing settings: dunning.retryOffsetsDays (retries after a failed charge, days after the first failure, default 1, 3, 5, 7), dunning.finalAction (unpaid, the default, or canceled after the last retry), entitlementGraceDays (features stay on while past due, default 7), sendInvoice.graceDays (a send_invoice invoice is overdue this many days after its due date, default 14), cardExpiryReminders (default on), pausedEntitlements (paused subscriptions keep their features, default off) and paymentBehavior (default for immediate changes invoiced to a card). They apply from the next step of each subscription.

Policies: breakageRecognition says when expired paid credits become breakage revenue: at_expiry (the default) or manual, which holds them as expired credits until your finance team recognises them with a ledger adjustment. It applies to credits that expire from then on. disputeWalletFreeze (default on) freezes the customer's wallets when a dispute opens; a won dispute unfreezes the wallets it froze. supportRefundLimits sets the most the support role may refund at once, per currency (100 of a currency without one; finance has no limit). taxIdUnavailable says what a sale does when a business customer's tax ID couldn't be checked because the register didn't answer (spec §9.1): charge_as_b2c (the default: tax is charged as for a consumer, and a credit note can refund it once the ID validates) or block (the sale is refused with tax_id_unavailable until the register answers). It applies to quotes from then on.

Customer portal (portalSettings): whether customers may switch plans (allowPlanChanges, along planChangeMatrix: one row per price naming the prices it may switch to, in the same mode and currency; no row means no switch), cancel (allowCancel, cancelBehavior period_end or immediate, collectCancelReason) and change seats (allowQuantityChanges). The matrix is checked against the brand's prices and replaced whole.

Languages (checkoutSettings.locales): the brand's languages for hosted pages and customer emails, its default first. A customer's own language and their browser's come first; the brand's default is the fallback.

A new slug changes the brand's checkout URLs; existing API keys keep working. The invoice series can't change once set. Needs brands:write (organization owners and admins, or an API key with that scope).

At a glance

  • REST: PATCH /api/v1/brands/{id}
  • MCP tool: brands_update
  • Operation ID: brands.update
  • 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 optional
  • Modes: Test and live
  • Authentication: API key with the brands:write scope
  • Since: M1

Request

Path parameters

FieldTypeDescription
idbrd_… ID

Body

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

FieldTypeRequiredDescription
namestringNo
slugstringNo
brandingobjectNo
branding.logoUrlstring or nullNo
branding.iconUrlstring or nullNo
branding.primaryColorstring or nullNo
branding.accentColorstring or nullNo
branding.supportEmailstring or nullNo
branding.supportUrlstring or nullNo
branding.termsUrlstring or nullNo
branding.privacyUrlstring or nullNo
statementDescriptorstringNo
statementDescriptorSuffixstring or nullNo
billingSettingsobjectNoBilling settings; each field: a value sets it, null resets it to the default, absent leaves it.
billingSettings.dunningobjectNo
billingSettings.dunning.retryOffsetsDaysarray of integer (1 to 60) or nullNoRetries after a failed charge, in days after the first failure (strictly increasing).
billingSettings.dunning.finalActionone of unpaid, canceled or nullNoAfter the last retry: unpaid (kept, features off) or canceled.
billingSettings.entitlementGraceDaysinteger (0 to 60) or nullNoWhile past due, features stay on for this many days after the failure.
billingSettings.sendInvoiceobjectNo
billingSettings.sendInvoice.graceDaysinteger (0 to 90) or nullNoA send_invoice invoice is overdue this many days after its due date.
billingSettings.cardExpiryRemindersboolean or nullNo
billingSettings.pausedEntitlementsboolean or nullNo
billingSettings.paymentBehaviorone of allow_incomplete, pending_if_incomplete or nullNo
policiesobjectNoAccounting policies; each field: a value sets it, null resets it to the default, absent leaves it.
policies.breakageRecognitionone of at_expiry, manual or nullNoWhen expired paid credits become breakage revenue: at_expiry (the default) or manual (held as expired credits until finance recognises them with a ledger adjustment). null resets it to the default.
policies.supportRefundLimitsarray of object or nullNoThe most the support role may refund at once, one amount per currency (finance has no limit). A currency without one has the default of 100 of it (100.00 EUR). The list replaces the brand's; null removes them all.
policies.disputeWalletFreezeboolean or nullNoFreeze the customer's wallets when a dispute opens (default true); a won dispute unfreezes them. null resets it to the default.
policies.taxIdUnavailableone of charge_as_b2c, block or nullNoWhat a sale does when the customer's tax ID couldn't be checked because the register (VIES, HMRC, the Swiss UID register) didn't answer: charge_as_b2c (the default: tax is charged as for a consumer; a credit note can refund it once the ID validates) or block (the sale is refused with tax_id_unavailable until the register answers). null resets it to the default.
portalSettingsobjectNoThe customer portal's settings; send only what changes.
portalSettings.allowPlanChangesbooleanNoCustomers may switch plans in the portal, along planChangeMatrix.
portalSettings.planChangeMatrixarray of object or nullNoReplaces the whole matrix; null or an empty list removes it (no plan switch in the portal).
portalSettings.allowCancelbooleanNoCustomers may cancel in the portal.
portalSettings.cancelBehaviorone of period_end, immediateNoperiod_end (default: it runs to the end of the paid period) or immediate.
portalSettings.collectCancelReasonbooleanNoAsk why the customer cancels.
portalSettings.allowQuantityChangesbooleanNoCustomers may change seats of licensed items.
checkoutSettingsobjectNoHosted page settings; send only what changes.
checkoutSettings.localesarray of one of en, de, fr, hr, it, esNoThe brand's languages for hosted pages and customer emails, its default first (en, de, fr, hr, it, es). A default, not a restriction: a customer's own language still comes first.

Response

200 OK 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

HTTP
PATCH /api/v1/brands/brd_01m4tx5nj8emwbyf7y9vcf47x4
Authorization: Bearer or_test_…
Content-Type: application/json

{
  "branding": {
    "supportEmail": "help@acme.example",
    "termsUrl": "https://acme.example/terms",
    "privacyUrl": "https://acme.example/privacy"
  }
}

Response (200):

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-14T09:30:00.000Z"
}

Cancel after the last of three retries

HTTP
PATCH /api/v1/brands/brd_01m4tx5nj8emwbyf7y9vcf47x4
Authorization: Bearer or_test_…
Content-Type: application/json

{
  "billingSettings": {
    "dunning": {
      "retryOffsetsDays": [
        2,
        4,
        7
      ],
      "finalAction": "canceled"
    }
  }
}

Response (200):

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": [2, 4, 7],
      "finalAction": "canceled"
    },
    "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-14T09:30:00.000Z"
}

Hold expired credits until finance recognises the breakage

HTTP
PATCH /api/v1/brands/brd_01m4tx5nj8emwbyf7y9vcf47x4
Authorization: Bearer or_test_…
Content-Type: application/json

{
  "policies": {
    "breakageRecognition": "manual"
  }
}

Response (200):

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": "manual",
    "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-14T09:30:00.000Z"
}

Refuse sales while a business customer's tax ID can't be checked

HTTP
PATCH /api/v1/brands/brd_01m4tx5nj8emwbyf7y9vcf47x4
Authorization: Bearer or_test_…
Content-Type: application/json

{
  "policies": {
    "taxIdUnavailable": "block"
  }
}

Response (200):

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": "block"
  },
  "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-14T09:30:00.000Z"
}

Let support refund up to €250 at once

HTTP
PATCH /api/v1/brands/brd_01m4tx5nj8emwbyf7y9vcf47x4
Authorization: Bearer or_test_…
Content-Type: application/json

{
  "policies": {
    "supportRefundLimits": [
      {
        "amount": "250000000",
        "currency": "EUR"
      }
    ]
  }
}

Response (200):

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": [
      {
        "amount": "250000000",
        "currency": "EUR"
      }
    ],
    "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-14T09:30:00.000Z"
}

Let customers switch between Basic and Pro in the portal

HTTP
PATCH /api/v1/brands/brd_01m4tx5nj8emwbyf7y9vcf47x4
Authorization: Bearer or_test_…
Content-Type: application/json

{
  "portalSettings": {
    "allowPlanChanges": true,
    "planChangeMatrix": [
      {
        "fromPriceId": "price_01m4tx5nj8emwbyf7y9vcf47xc",
        "toPriceIds": [
          "price_01m4tx5nj8emwbyf7y9vcf47xd"
        ]
      },
      {
        "fromPriceId": "price_01m4tx5nj8emwbyf7y9vcf47xd",
        "toPriceIds": [
          "price_01m4tx5nj8emwbyf7y9vcf47xc"
        ]
      }
    ],
    "collectCancelReason": true
  },
  "checkoutSettings": {
    "locales": [
      "de",
      "en"
    ]
  }
}

Response (200):

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": [
      {
        "fromPriceId": "price_01m4tx5nj8emwbyf7y9vcf47xc",
        "toPriceIds": ["price_01m4tx5nj8emwbyf7y9vcf47xd"]
      },
      {
        "fromPriceId": "price_01m4tx5nj8emwbyf7y9vcf47xd",
        "toPriceIds": ["price_01m4tx5nj8emwbyf7y9vcf47xc"]
      }
    ],
    "allowCancel": true,
    "cancelBehavior": "period_end",
    "collectCancelReason": true,
    "allowQuantityChanges": false
  },
  "checkoutSettings": {
    "locales": ["de", "en"],
    "collectPhone": false,
    "requireBusinessDetails": "auto"
  },
  "createdAt": "2026-10-13T12:00:00.000Z",
  "updatedAt": "2026-10-14T09:30:00.000Z"
}

Errors

CodeHTTP statusWhenWhat to do
validation_failed400No field to change was sent, or one is malformed; or a plan-change matrix row names a price that isn't the brand's recurring licensed price, an archived target, or a target in another mode or currency (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.Choose another slug. Organization and brand slugs are unique across Ownrecord; entity slugs are unique within an organization.
resource_not_found404No brand with this ID is visible to the request.Check the ID and that your credentials are scoped to the right organization, entity, brand and mode.
version_conflict409The brand changed at the same time; retry.Fetch the object again and retry the change.
permission_denied403You can't change 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_reused, idempotency_in_progress, approval_required, approval_rejected, approval_expired, stale_approval, approval_policy_denied, rate_limited, internal_error.