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

# Get one restaurant

GET https://www.lettbestilt.no/api/v1/partner/restaurants/{slug}

**Partner key + restaurant key.** Setup status, SagaPay status (real restaurants only; `null` for sandboxes), verified domains, webhooks (never the secret) and the restaurant's API keys (name, last four characters, environment, scopes, expiry). Also works for an archived restaurant.

No contact details or customer data.

Reference: https://docs.lettbestilt.no/api-reference/partner/get-partner-restaurant

## Authentication

- `Authorization` header (bearer token, required) — The partner key, sent as `Authorization: Bearer lbp_test_…`. Created in the partner portal under **Partner key**. It belongs to the partner, not to a restaurant, and only works against `/api/v1/partner`. Server to server only: a request with an `Origin` header is rejected with `403 FORBIDDEN`. A test key sees and creates only sandboxes; live partner keys are not available yet. A revoked key, a restaurant key (`lbs_…`) here, or a suspended or archived partner returns `401 UNAUTHORIZED`; an expired key returns `401 KEY_EXPIRED`.
- `X-LettBestilt-Restaurant-Key` header (required) — The restaurant's own key (`lbs_test_…` or `lbs_live_…`), sent in `X-LettBestilt-Restaurant-Key` together with the partner key for calls about one restaurant. The key must have full access (scope `*`, otherwise `403 INSUFFICIENT_SCOPE`), belong to a restaurant the partner owns, and be in the same environment as the partner key (otherwise `401 UNAUTHORIZED`). A slug that does not exist, belongs to another partner or does not match the key always gives the same `404 RESTAURANT_NOT_FOUND`. Older keys without an environment in the prefix (`lbs_<random>`) are not accepted here; rotate them in the partner portal.

## Request

### Path parameters

- `slug` (string, required) — The restaurant's slug. Must match the restaurant key in `X-LettBestilt-Restaurant-Key`.

## Response

### 200

The restaurant.

- `data` (PartnerRestaurantDetails, required) — Details, available with both keys. No contact details or customer data.

## Errors

### 401 Unauthorized Error

`UNAUTHORIZED`: a key is missing, invalid or revoked, the two keys are in different environments, or the partner is suspended or archived. `KEY_EXPIRED`: one of the keys is past its expiry date.

- `error` (ErrorBody, required)

### 403 Forbidden Error

`FORBIDDEN`: the request has an `Origin` header. `INSUFFICIENT_SCOPE`: the restaurant key does not have full access (`error.details.requiredScope` is `*`).

- `error` (ErrorBody, required)

### 404 Not Found Error

`RESTAURANT_NOT_FOUND`: the same response whether the slug does not exist, belongs to another partner or does not match the restaurant key.

- `error` (ErrorBody, required)

### 429 Too Many Requests Error

`RATE_LIMITED`: more than 120 calls per minute for this partner key.

- `error` (ErrorBody, required)

## Types

### PartnerRestaurantDetails

Details, available with both keys. No contact details or customer data.

- `slug` (string, required) — The restaurant's identifier everywhere in `/api/v1`.
- `name` (string, required)
- `environment` (enum, required) — `TEST` for a sandbox, `LIVE` for a real restaurant.
  - Allowed values: `TEST`, `LIVE`
- `sandbox` (boolean, required) — `true` for a sandbox.
- `live` (boolean, required) — A real restaurant that has gone live and takes orders. A new real restaurant is not live until its owner has signed and set it live. Always `false` for sandboxes; they accept test orders in `/api/v1` anyway.
- `archived` (boolean, required) — Archived with `DELETE` (real restaurants only). Only LettBestilt can restore it.
- `createdAt` (datetime, required)
- `archivedAt` (datetime, required, nullable) — When the restaurant was archived, or `null`.
- `setup` (PartnerRestaurantDetailsSetup, required)
- `payment` (PartnerRestaurantDetailsPayment, required, nullable) — Online payment with SagaPay. `null` for sandboxes, where payment is simulated.
- `domains` (list of PartnerRestaurantDetailsDomainsItems, required) — The restaurant's verified domains.
- `webhooks` (list of PartnerWebhook, required)
- `apiKeys` (list of PartnerRestaurantApiKey, required)

### ErrorBody

- `code` (enum, required) — A machine-readable error code.
  - Allowed values: `MISSING_SLUG`, `MISSING_TOKEN`, `INVALID_JSON`, `INVALID_SUCCESS_URL`, `INVALID_CANCEL_URL`, `VALIDATION_FAILED`, `RESTAURANT_NOT_FOUND`, `ORDER_NOT_FOUND`, `RATE_LIMITED`, `BAD_REQUEST`, `UNAUTHORIZED`, `FORBIDDEN`, `INSUFFICIENT_SCOPE`, `KEY_EXPIRED`, `POPUP_NOT_AVAILABLE`, `PRICE_CHANGED`, `PAYMENT_INCOMPLETE`, `PAYMENT_PENDING`, `PAYMENT_PROVIDER_INVALID`, `FULFILLMENT_NOT_ALLOWED`, `IDEMPOTENCY_CONFLICT`, `DINE_IN_DISABLED`, `PARTY_TOO_LARGE`, `TOO_EARLY`, `INTERNAL_ERROR`, `PARTNER_AGREEMENT_REQUIRED`, `IDEMPOTENCY_KEY_REQUIRED`, `SLUG_TAKEN`, `SANDBOX_LIMIT`, `RETENTION`, `RESTAURANT_ARCHIVED`, `KEY_NOT_FOUND`, `KEY_IN_USE`, `WEBHOOK_NOT_FOUND`, `WEBHOOK_LIMIT`, `CHANGED`
- `message` (string, required) — A human-readable explanation. Often in Norwegian, and for business rules usually suitable to show the customer.
- `requestId` (string, required) — The same value as the `X-Request-Id` response header. Search for it in the API log in the partner portal, and include it when you contact LettBestilt.
- `details` (any, optional) — Extra data for some codes, for example `issues` for `VALIDATION_FAILED`, the totals for `PRICE_CHANGED` or `requiredScope` for `INSUFFICIENT_SCOPE`.

### PartnerRestaurantDetailsSetup

- `confirmedSteps` (integer, required) — Setup steps the restaurant has confirmed in its getting-started flow.
- `totalSteps` (integer, required) — The number of setup steps.
- `launched` (boolean, required) — The owner has set the restaurant live at least once.

### PartnerRestaurantDetailsPayment

Online payment with SagaPay. `null` for sandboxes, where payment is simulated.

- `state` (enum, required)
  - Allowed values: `NOT_STARTED`, `IN_PROGRESS`, `ACTIVE`, `FAILED`
- `label` (string, required)
- `description` (string, required)

### PartnerRestaurantDetailsDomainsItems

- `domain` (string, required)
- `primary` (boolean, required)
- `verifiedAt` (datetime, required, nullable)

### PartnerWebhook

A webhook subscription. The signing secret is only shown when it is created.

- `id` (string, required)
- `url` (string, required)
- `events` (list of enum, required)
  - Allowed values: `ORDER_CREATED`, `ORDER_PAID`, `ORDER_STATUS_CHANGED`, `ORDER_CANCELLED`, `RESERVATION_REQUESTED`, `RESERVATION_APPROVED`, `RESERVATION_REJECTED`
- `active` (boolean, required) — `false` when the webhook is paused. Events that happen while it is paused are not stored or sent.
- `createdAt` (datetime, required)
- `lastDeliveryAt` (datetime, required, nullable)
- `lastDeliveryStatus` (integer, required, nullable) — The HTTP status your endpoint returned on the last delivery.
- `lastFailureAt` (datetime, required, nullable)
- `lastFailureReason` (string, required, nullable) — A fixed category, for example `HTTP 500` or `request timeout`.

### PartnerRestaurantApiKey

A restaurant key (`lbs_…`) as the partner sees it. Never the key itself or its hash.

- `id` (string, required) — Used to rotate and revoke the key.
- `name` (string, required) — The name you gave the key.
- `last4` (string, required) — The last four characters of the key.
- `environment` (enum, required)
  - Allowed values: `TEST`, `LIVE`
- `scopes` (list of string, required) — `["*"]` is full access. Otherwise the scopes the key is limited to.
- `status` (enum, required) — `expiring`: the key expires within 14 days and has not been rotated out. `expired` and `revoked` keys no longer work. A key scheduled for revocation by a rotation stays `active` until then; see `revokedAt`.
  - Allowed values: `active`, `expiring`, `expired`, `revoked`
- `expiresAt` (datetime, required, nullable) — The expiry date, or `null` for no expiry.
- `revokedAt` (datetime, required, nullable) — When the key was revoked. A time in the future means it still works until then (rotation with a grace period).
- `createdAt` (datetime, required)
- `lastUsedAt` (datetime, required, nullable) — Last use, with a resolution of about 5 minutes.

## Examples

**Response**

```json
{
  "data": {
    "slug": "string",
    "name": "string",
    "environment": "TEST",
    "sandbox": true,
    "live": true,
    "archived": true,
    "createdAt": "2024-01-15T09:30:00Z",
    "archivedAt": "2024-01-15T09:30:00Z",
    "setup": {
      "confirmedSteps": 1,
      "totalSteps": 1,
      "launched": true
    },
    "payment": {
      "state": "NOT_STARTED",
      "label": "string",
      "description": "string"
    },
    "domains": [
      {
        "domain": "string",
        "primary": true,
        "verifiedAt": "2024-01-15T09:30:00Z"
      }
    ],
    "webhooks": [
      {
        "id": "string",
        "url": "string",
        "events": [
          "ORDER_CREATED"
        ],
        "active": true,
        "createdAt": "2024-01-15T09:30:00Z",
        "lastDeliveryAt": "2024-01-15T09:30:00Z",
        "lastDeliveryStatus": 1,
        "lastFailureAt": "2024-01-15T09:30:00Z",
        "lastFailureReason": "string"
      }
    ],
    "apiKeys": [
      {
        "id": "string",
        "name": "string",
        "last4": "string",
        "environment": "TEST",
        "scopes": [
          "string"
        ],
        "status": "active",
        "expiresAt": "2024-01-15T09:30:00Z",
        "revokedAt": "2024-01-15T09:30:00Z",
        "createdAt": "2024-01-15T09:30:00Z",
        "lastUsedAt": "2024-01-15T09:30:00Z"
      }
    ]
  }
}
```

**SDK Code**

```python
import requests

url = "https://www.lettbestilt.no/api/v1/partner/restaurants/slug"

headers = {"Authorization": "Bearer <token>"}

response = requests.get(url, headers=headers)

print(response.json())
```

```javascript
const url = 'https://www.lettbestilt.no/api/v1/partner/restaurants/slug';
const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};

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

```go
package main

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

func main() {

	url := "https://www.lettbestilt.no/api/v1/partner/restaurants/slug"

	req, _ := http.NewRequest("GET", url, nil)

	req.Header.Add("Authorization", "Bearer <token>")

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

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

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

}
```

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

url = URI("https://www.lettbestilt.no/api/v1/partner/restaurants/slug")

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

request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'

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

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

HttpResponse<String> response = Unirest.get("https://www.lettbestilt.no/api/v1/partner/restaurants/slug")
  .header("Authorization", "Bearer <token>")
  .asString();
```

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

$client = new \GuzzleHttp\Client();

$response = $client->request('GET', 'https://www.lettbestilt.no/api/v1/partner/restaurants/slug', [
  'headers' => [
    'Authorization' => 'Bearer <token>',
  ],
]);

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

```csharp
using RestSharp;

var client = new RestClient("https://www.lettbestilt.no/api/v1/partner/restaurants/slug");
var request = new RestRequest(Method.GET);
request.AddHeader("Authorization", "Bearer <token>");
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = ["Authorization": "Bearer <token>"]

let request = NSMutableURLRequest(url: NSURL(string: "https://www.lettbestilt.no/api/v1/partner/restaurants/slug")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers

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()
```