Skip to main content
A special closing is a one-off window during which a location is closed, on top of its regular opening hours — think public holidays, private events, renovations, or an unplanned shutdown. Each closing belongs to exactly one location and is bounded by a start and end instant. Special closings live under their parent location. The full path is /v1/locations/{location_id}/special_closings, with individual closings addressed at /v1/locations/{location_id}/special_closings/{special_closing_id}.

The special_closing object

{
  "id": "scl_3b9f2c7a1e8d40f6",
  "object": "special_closing",
  "location_id": "loc_8f2c91d4a7e34b10",
  "starts_at": "2026-12-24T22:00:00Z",
  "ends_at": "2026-12-26T06:00:00Z",
  "reason": "Christmas holidays",
  "created_at": "2026-05-29T10:15:00Z",
  "updated_at": "2026-05-29T10:15:00Z"
}
id
string
Unique opaque identifier, prefixed scl_. Treat it as a case-sensitive string.
object
string
Always "special_closing".
location_id
string
The parent location (loc_…) this closing applies to.
starts_at
string
ISO 8601 UTC instant at which the closure begins.
ends_at
string
ISO 8601 UTC instant at which the closure ends.
reason
string | null
A human-readable explanation for the closure (for example "Public holiday"). May be null.
created_at
string
ISO 8601 UTC creation timestamp.
updated_at
string
ISO 8601 UTC last-update timestamp.

Time zones

starts_at and ends_at are absolute UTC instants — the trailing Z is part of the contract. They are not wall-clock times. To present a closing to a restaurant operator, convert each instant into the location’s timezone (an IANA identifier such as Europe/Zurich, available on the location object).
Always send starts_at and ends_at in UTC. If you collect a local date and time from a user, convert it to UTC before calling the API — accounting for daylight saving time in the location’s zone. A closing meant to run “all of December 25th in Zurich” spans 23:00 UTC Dec 24 → 23:00 UTC Dec 25, not midnight to midnight UTC.
The example below converts a local wall-clock window in Europe/Zurich into the UTC instants the API expects.
// "Closed all day on 25 December 2026" in the location's local zone.
const timezone = "Europe/Zurich";

function toUtcInstant(localDateTime, tz) {
  // localDateTime is "YYYY-MM-DDTHH:mm" in the target zone.
  const target = new Date(`${localDateTime}:00`);
  const asUtc = new Date(target.toLocaleString("en-US", { timeZone: "UTC" }));
  const asTz = new Date(target.toLocaleString("en-US", { timeZone: tz }));
  const offsetMs = asUtc.getTime() - asTz.getTime();
  return new Date(target.getTime() + offsetMs).toISOString();
}

const startsAt = toUtcInstant("2026-12-25T00:00", timezone); // 2026-12-24T23:00:00.000Z
const endsAt = toUtcInstant("2026-12-26T00:00", timezone); // 2026-12-25T23:00:00.000Z

List special closings

Returns a paginated list of the closings for a location, ordered by created_at.
Endpoint
GET /v1/locations/{location_id}/special_closings

Query parameters

limit
integer
default:"10"
Number of results per page, between 1 and 100.
starting_after
string
Cursor for the next page — the id of the last object in the previous page. Mutually exclusive with ending_before.
ending_before
string
Cursor for the previous page — the id of the first object in the current page. Mutually exclusive with starting_after.
created_after
string
Return closings created after this ISO 8601 timestamp.
created_before
string
Return closings created before this ISO 8601 timestamp.
updated_after
string
Return closings updated after this ISO 8601 timestamp.
updated_before
string
Return closings updated before this ISO 8601 timestamp.
curl "https://server.chataigne.ai/v1/locations/loc_8f2c91d4a7e34b10/special_closings?limit=20" \
  -H "x-api-key: ch_org_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Response
{
  "object": "list",
  "data": [
    {
      "id": "scl_3b9f2c7a1e8d40f6",
      "object": "special_closing",
      "location_id": "loc_8f2c91d4a7e34b10",
      "starts_at": "2026-12-24T22:00:00Z",
      "ends_at": "2026-12-26T06:00:00Z",
      "reason": "Christmas holidays",
      "created_at": "2026-05-29T10:15:00Z",
      "updated_at": "2026-05-29T10:15:00Z"
    }
  ],
  "has_more": false,
  "url": "/v1/locations/loc_8f2c91d4a7e34b10/special_closings"
}

Create a special closing

Creates a closing under a location. This is a resource-creating POST, so an Idempotency-Key header is required.
Endpoint
POST /v1/locations/{location_id}/special_closings

Body parameters

starts_at
string
required
ISO 8601 UTC instant at which the closure begins.
ends_at
string
required
ISO 8601 UTC instant at which the closure ends.
reason
string
Optional human-readable explanation for the closure. Omit or send null to leave it unset.
curl https://server.chataigne.ai/v1/locations/loc_8f2c91d4a7e34b10/special_closings \
  -H "x-api-key: ch_org_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Idempotency-Key: 6f1d3b8a-2c47-4e90-9a1b-0d2f7c5e1234" \
  -H "Content-Type: application/json" \
  -d '{
    "starts_at": "2026-12-24T22:00:00Z",
    "ends_at": "2026-12-26T06:00:00Z",
    "reason": "Christmas holidays"
  }'
Response
{
  "id": "scl_3b9f2c7a1e8d40f6",
  "object": "special_closing",
  "location_id": "loc_8f2c91d4a7e34b10",
  "starts_at": "2026-12-24T22:00:00Z",
  "ends_at": "2026-12-26T06:00:00Z",
  "reason": "Christmas holidays",
  "created_at": "2026-05-29T10:15:00Z",
  "updated_at": "2026-05-29T10:15:00Z"
}
Replaying the same Idempotency-Key with the same body returns the original closing, with the header Idempotent-Replayed: true. Reusing the key with a different body returns 409 idempotency_error, and a concurrent in-flight duplicate returns 409 conflict_error. Keys are retained for 24 hours. See Idempotency.

Retrieve a special closing

Fetches a single closing by id.
Endpoint
GET /v1/locations/{location_id}/special_closings/{special_closing_id}
curl https://server.chataigne.ai/v1/locations/loc_8f2c91d4a7e34b10/special_closings/scl_3b9f2c7a1e8d40f6 \
  -H "x-api-key: ch_org_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Response
{
  "id": "scl_3b9f2c7a1e8d40f6",
  "object": "special_closing",
  "location_id": "loc_8f2c91d4a7e34b10",
  "starts_at": "2026-12-24T22:00:00Z",
  "ends_at": "2026-12-26T06:00:00Z",
  "reason": "Christmas holidays",
  "created_at": "2026-05-29T10:15:00Z",
  "updated_at": "2026-05-29T10:15:00Z"
}
A request for an id that does not exist under the location returns 404 not_found_error.

Update a special closing

Updates one or more fields on a closing. Only the fields you send are changed; omitted fields keep their current value.
Endpoint
PATCH /v1/locations/{location_id}/special_closings/{special_closing_id}

Body parameters

starts_at
string
New start instant, ISO 8601 UTC.
ends_at
string
New end instant, ISO 8601 UTC.
reason
string | null
New reason. Send null to clear an existing reason.
curl -X PATCH https://server.chataigne.ai/v1/locations/loc_8f2c91d4a7e34b10/special_closings/scl_3b9f2c7a1e8d40f6 \
  -H "x-api-key: ch_org_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "ends_at": "2026-12-27T06:00:00Z",
    "reason": "Christmas & Boxing Day"
  }'
Response
{
  "id": "scl_3b9f2c7a1e8d40f6",
  "object": "special_closing",
  "location_id": "loc_8f2c91d4a7e34b10",
  "starts_at": "2026-12-24T22:00:00Z",
  "ends_at": "2026-12-27T06:00:00Z",
  "reason": "Christmas & Boxing Day",
  "created_at": "2026-05-29T10:15:00Z",
  "updated_at": "2026-05-29T11:42:08Z"
}

Delete a special closing

Permanently removes a closing. The location reverts to its regular opening hours for that window.
Endpoint
DELETE /v1/locations/{location_id}/special_closings/{special_closing_id}
curl -X DELETE https://server.chataigne.ai/v1/locations/loc_8f2c91d4a7e34b10/special_closings/scl_3b9f2c7a1e8d40f6 \
  -H "x-api-key: ch_org_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Deleting a closing that does not exist returns 404 not_found_error.

Errors

Special closing endpoints use the standard error model. The most common cases:
HTTP statuserror.typeWhen
400invalid_request_errorA timestamp is missing or not valid ISO 8601, or a parameter is malformed.
401authentication_errorNo API key was provided.
403authorization_errorAn admin key (ch_admin_…) was used on /v1, or a dashboard session was used.
404not_found_errorThe location or closing id does not exist or is not accessible to your key.
409idempotency_errorThe Idempotency-Key was reused with a different body.
409conflict_errorA concurrent in-flight request used the same Idempotency-Key.
429rate_limit_errorThe per-key rate limit was exceeded; retry after Retry-After.
Example error
{
  "error": {
    "type": "invalid_request_error",
    "code": "parameter_invalid",
    "message": "ends_at must be a valid ISO 8601 UTC timestamp.",
    "param": "ends_at",
    "request_id": "req_2y8Fk1Zx0Qm7"
  }
}

Next steps

Opening hours

Special closings sit on top of a location’s regular weekly delivery and pickup schedule.

Locations

Read a location’s timezone to render starts_at and ends_at in local wall-clock time.

Idempotency

Creating a closing requires an Idempotency-Key. Learn how safe retries work.