> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://developer.jelliu.co/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://developer.jelliu.co/_mcp/server.

# Update workspace settings

PATCH https://api.jelliu.co/api/settings
Content-Type: application/json

Changes the timezone, the business country, or both. Send only the fields you are changing; at least one
is required. The response carries both fields as stored.

**`businessCountry`** is where the business is, as an ISO 3166-1 alpha-2 code (`CO`, `MX`, `US`…; any case
is accepted and stored upper case). `null` or an empty string clears it. When set, it decides the language
of agent prompts **generated from then on** (the dashboard's prompt assistant): a Spanish request from a
workspace in an English- or Portuguese-speaking country is written in that country's language, and inside
the right language family the requested variant is kept. When it is not set, the language keeps being
inferred as before (billing address, then the country chosen for the phone number at onboarding).
Existing agents are **not** changed: their language and prompt stay as saved.

**`timezone`** is an IANA zone id (`America/Bogota`, `Europe/Madrid`). Saving it pushes the new clock to
every agent in the workspace in the background.

**Side effects.** A change of `businessCountry` writes a `BUSINESS_COUNTRY_UPDATED` audit entry with the
previous and new value; saving the same value writes none.

**Idempotency.** Idempotent: repeating the same body leaves the same state.

**Access**
- **Required scope:** `full`. Signed-in users need the `admin` or `owner` role.
- **Rate limit:** General API — 120 (Starter), 200 (Growth), 300 (Business) or 600 (Enterprise) requests/min per workspace. See [Rate limits](/rate-limits).
- **Plan:** Available on every plan.


Reference: https://developer.jelliu.co/api-reference/settings/patch-settings

## Authentication

- `Authorization` header (bearer token, required) — Workspace API key: `jl_` followed by 64 lowercase hex characters, created by the workspace owner in the dashboard (**Settings → API Keys**) and sent as `Authorization: Bearer jl_...`. The plaintext is shown once, at creation; Jelliu stores only a SHA-256 hash. A workspace can hold up to 25 active keys. | Scope | GET / HEAD | POST / PUT / PATCH / DELETE | Admin-only routes | | --- | --- | --- | --- | | `read` | Yes | No | No | | `write` | Yes | Yes | No | | `full` | Yes | Yes | Yes | Operations restricted to admins or owners reject keys without the `full` scope with `403`, and say so in their description. No key, whatever its scope, can mint or revoke API keys or rotate a webhook secret — that requires a signed-in owner session. A revoked key stops authenticating within about 10 seconds. See [Authentication](/authentication).

## Request

### Body (application/json)

This endpoint expects an object.

- `timezone` (string, optional) — IANA timezone id.
- `businessCountry` (string, optional, nullable) — ISO 3166-1 alpha-2 country code of the business; `null` or `""` clears it.

## Response

### 200

Saved. Both fields as stored.

- `data` (WorkspaceSettings, required)

## Errors

### 400 Bad Request Error

A field failed validation, or the body named neither field (`VALIDATION_FAILED`).

- `error` (ErrorResponseError, required) — The error object. Always has `code` and `message`.

### 401 Unauthorized Error

No usable credential. Either the `Authorization` header is missing or is not a well-formed `Bearer jl_…` key, or the key is unknown, revoked or expired. Do not retry with the same key. See [Authentication](/authentication#401-unauthorized).

- `error` (ErrorResponseError, required) — The error object. Always has `code` and `message`.

### 403 Forbidden Error

Authenticated, but not allowed: the key's scope does not cover the method, the route is restricted to workspace admins/owners and the key is not `full`, or the workspace is suspended (`TENANT_SUSPENDED`). See [Authentication](/authentication#scopes).

- `error` (ErrorResponseError, required) — The error object. Always has `code` and `message`.

### 429 Too Many Requests Error

Rate limit exceeded for the current 60-second window (`RATE_LIMIT_EXCEEDED`). Wait `Retry-After` seconds, then retry. The `message` differs per limiter; the code does not. See [Rate limits](/rate-limits).

- `error` (ErrorResponseError, required) — The error object. Always has `code` and `message`.

## Types

### WorkspaceSettings

- `timezone` (string, required) — IANA zone the workspace's agents read their clock in. Never null; the platform default when unset.
- `businessCountry` (string, required, nullable) — ISO 3166-1 alpha-2 code of the country the business declared, or null when not declared. When set, it decides the language of newly generated agent prompts.

### ErrorResponseError

The error object. Always has `code` and `message`.

- `code` (string, required) — Stable machine-readable error code (for example `VALIDATION_FAILED`, `PAYLOAD_TOO_LARGE`, `UNAUTHORIZED`, `FORBIDDEN`, `NOT_FOUND`, `BILLING_ERROR`, `COMPLIANCE_BLOCKED`, `RATE_LIMIT_EXCEEDED`, `INTERNAL_ERROR`). Switch on this, not on `message`. See [Errors](/errors).
- `message` (string, required) — Human-readable explanation. English or Spanish depending on the route; may change without notice.
- `details` (ErrorResponseErrorDetails, optional) — Present on `VALIDATION_FAILED` only. Its shape depends on how the route validates: * a field map, either Zod's `flatten()` output (`{ "formErrors": [], "fieldErrors": { "name": ["..."] } }`) or just its `fieldErrors` part (`{ "name": ["..."] }`); * an issue list, where each issue has at least `path`, `message` and `code`. `path` is a dot-separated string on routes that let the schema throw, and an array of keys on routes that forward Zod's raw issues (those also carry Zod's extra issue fields); * for a rejected multipart upload (file in an unexpected field, too many files), a list with the upload error `code` (for example `LIMIT_UNEXPECTED_FILE`) and the `field` name. Absent when the value was rejected outside the route's own validation: a malformed id, number or date the database could not read, or a JSON body that does not parse.
- `metadata` (map from string to any, optional) — Structured detail exposed for a small allowlist of codes only — for example `BILLING_ERROR` carries `limit`, `current` and `tier` (resource caps), `tier` alone (feature gates), or `tier` = `none` with `kind` = `subscription_required` when the workspace has no active subscription. See [Errors](/errors).

### ErrorResponseErrorDetails

Present on `VALIDATION_FAILED` only. Its shape depends on how the route validates: * a field map, either Zod's `flatten()` output (`{ "formErrors": [], "fieldErrors": { "name": ["..."] } }`) or just its `fieldErrors` part (`{ "name": ["..."] }`); * an issue list, where each issue has at least `path`, `message` and `code`. `path` is a dot-separated string on routes that let the schema throw, and an array of keys on routes that forward Zod's raw issues (those also carry Zod's extra issue fields); * for a rejected multipart upload (file in an unexpected field, too many files), a list with the upload error `code` (for example `LIMIT_UNEXPECTED_FILE`) and the `field` name. Absent when the value was rejected outside the route's own validation: a malformed id, number or date the database could not read, or a JSON body that does not parse.

- Field map: Field map
- Issue list: list of ErrorResponseErrorDetailsOneOf1Items

### Field map

- `formErrors` (list of string, optional)
- `fieldErrors` (map from string to list of string, optional)

### ErrorResponseErrorDetailsOneOf1Items

- `path` (ErrorResponseErrorDetailsOneOf1ItemsPath, optional) — Dot-separated string, or an array of keys.
- `message` (string, optional)
- `code` (string, optional) — Zod issue code, for example `invalid_type`.

### ErrorResponseErrorDetailsOneOf1ItemsPath

Dot-separated string, or an array of keys.

- string
- list of ErrorResponseErrorDetailsOneOf1ItemsPathOneOf1Items

### ErrorResponseErrorDetailsOneOf1ItemsPathOneOf1Items

- string
- integer

## Examples

**Request**

```json
{
  "businessCountry": "CO"
}
```

**Response**

```json
{
  "data": {
    "timezone": "America/Bogota",
    "businessCountry": "CO"
  }
}
```

**SDK Code**

```python Settings_patchSettings_example
import requests

url = "https://api.jelliu.co/api/settings"

payload = { "businessCountry": "CO" }
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.patch(url, json=payload, headers=headers)

print(response.json())
```

```javascript Settings_patchSettings_example
const url = 'https://api.jelliu.co/api/settings';
const options = {
  method: 'PATCH',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{"businessCountry":"CO"}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go Settings_patchSettings_example
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api.jelliu.co/api/settings"

	payload := strings.NewReader("{\n  \"businessCountry\": \"CO\"\n}")

	req, _ := http.NewRequest("PATCH", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby Settings_patchSettings_example
require 'uri'
require 'net/http'

url = URI("https://api.jelliu.co/api/settings")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Patch.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"businessCountry\": \"CO\"\n}"

response = http.request(request)
puts response.read_body
```

```java Settings_patchSettings_example
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.patch("https://api.jelliu.co/api/settings")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"businessCountry\": \"CO\"\n}")
  .asString();
```

```php Settings_patchSettings_example
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('PATCH', 'https://api.jelliu.co/api/settings', [
  'body' => '{
  "businessCountry": "CO"
}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp Settings_patchSettings_example
using RestSharp;

var client = new RestClient("https://api.jelliu.co/api/settings");
var request = new RestRequest(Method.PATCH);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"businessCountry\": \"CO\"\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift Settings_patchSettings_example
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = ["businessCountry": "CO"] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api.jelliu.co/api/settings")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "PATCH"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```