Settings

http
GET   /v1/settings
PATCH /v1/settings

One curated resource for the venue's configuration. GET returns the current values; PATCH is a partial update — send only the fields you want to change. Available on every plan with an active subscription.

Publish to go live

Like menu content, settings changes affect the public menu after the next publication snapshot — finish your changes, then call POST /v1/publish.

Fields#

All fields are optional in PATCH. Unknown fields are rejected with a 400 validation error naming the property — secrets and internal fields (payment/delivery-provider credentials, cached data, ids) are not part of this resource in either direction.

GroupFields
Venue corename, address, phone, googleMapsUrl, wifiPassword, additionalInfo, country (ISO 3166-1 alpha-2), defaultCurrency (ISO 4217, see Reference), timezone (IANA)
SEOseoTitle (≤60), seoDescription (≤160), cuisineType, googlePlaceId
Working hoursschedule, orderSchedule — arrays of { day, isOpen, openTime?, closeTime? } (HH:MM)
Social / reviewsinstagramUrl, telegramUrl, tiktokUrl, twitterUrl, tripAdvisorUrl, googleReviewsUrl
Designtheme (LIGHT|DARK), brandColor (hex), menuFontFamily, menuCardStyle (see Reference)
LanguagesdefaultLanguage, enabledLanguages[] (allowed values in Reference)
Order config*deliveryEnabled, pickupEnabled, dineInOrderingEnabled, minimumOrderAmount, deliveryFee, freeDeliveryThreshold, pickupDiscount (0–100), estimatedDeliveryTime, estimatedPickupTime, deliveryEmail
NotificationsnotifyWaiterEnabled, notifyHookahEnabled, notifyBillEnabled, notifyBookingEnabled, notifyOrderEnabled, telegramChatId, orderTelegramChatId

GET additionally returns read-only agent context:

  • logoUrl — set it via the logo ingest;
  • publicMenuUrl — the venue's live menu link (https://<slug>.duck-hub.com/menu) to report back when the build is done;
  • lastPublishedAt — timestamp of the latest POST /v1/publish (null = never published), so you can tell whether draft changes have gone live.

* Order config requires the delivery feature

The whole order-config group is gated by your plan's delivery feature. On plans without it, PATCHing any of those fields fails with 403 and code DELIVERY_NOT_AVAILABLE; all other fields still work. Check planLimits.features.hasDelivery in GET /v1/reference first.

Money fields (minimumOrderAmount, deliveryFee, freeDeliveryThreshold) are integers in minor currency units. defaultLanguage is always kept inside enabledLanguages automatically. Notification chat changes are audit-logged server-side.

Example#

bash
curl -X PATCH https://api.duck-hub.com/v1/settings \
  -H "Authorization: Bearer dk_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Trattoria Roma",
    "cuisineType": "Italian",
    "defaultCurrency": "EUR",
    "timezone": "Europe/Rome",
    "enabledLanguages": ["en", "it", "de"],
    "schedule": [
      { "day": "monday", "isOpen": true, "openTime": "10:00", "closeTime": "22:00" },
      { "day": "sunday", "isOpen": false }
    ]
  }'

PATCH responds 200 with the same curated view GET returns.

Concurrency (ETag / If-Match)#

Settings can also be edited in the DuckHub app — to avoid silently overwriting a concurrent change, use optimistic concurrency:

  1. GET /v1/settings returns an ETag response header.
  2. Send it back on PATCH as If-Match. If the settings changed since your read (e.g. the owner edited them in the app), the PATCH fails with 412 and code STALE_RESOURCE — re-read, re-apply your change, retry.
  3. Omitting If-Match keeps the old unconditional behavior.
bash
ETAG=$(curl -si https://api.duck-hub.com/v1/settings \
  -H "Authorization: Bearer dk_live_your_api_key" \
  | grep -i '^etag:' | cut -d' ' -f2 | tr -d '\r')
 
curl -X PATCH https://api.duck-hub.com/v1/settings \
  -H "Authorization: Bearer dk_live_your_api_key" \
  -H "Content-Type: application/json" \
  -H "If-Match: $ETAG" \
  -d '{"name": "Trattoria Roma"}'

Every PATCH response also carries the fresh ETag, so chained conditional updates don't need an extra GET. (The same pattern will apply to other single-resource endpoints as they gain conditional writes; bulk sync has no single version to match and stays unconditional.)

Errors#

  • 400 Validation failed — invalid value (unsupported currency/locale, bad timezone, malformed schedule) or an unknown/secret field
  • 403 DELIVERY_NOT_AVAILABLE — order-config field on a plan without the delivery feature
  • 412 STALE_RESOURCE — your If-Match no longer matches (settings changed since you read them)
  • 401 / 403 SUBSCRIPTION_INACTIVE — see Errors