_Version: 1.0_

> This document is the LLM-friendly export of the API. It is regenerated on every request from the live OpenAPI spec. Use it as context when asking an AI assistant for help.

# fature.al Partner API

Wolt is a food ordering and delivery platform: the customer orders in the Wolt app and the order reaches the restaurant or store that prepares it. That restaurant or store is called the venue here. This document is for the software running at the venue: the till, kitchen or store program that receives Wolt orders and processes them.

With this API your system follows the Wolt orders of a single venue through fature.al: it reads each order's lifecycle from the event feed, sends acceptance, rejection and readiness back to Wolt, and gets the fiscal invoice that fature.al issues for each order.

It is a separate document because the token here has a narrower meaning: a single venue. Everything else, the bearer token, the `X-Client-Id` and `X-Client-Secret` pair, the response format and the fiscalization glossary, works the same as in the main API and is explained at [`/docs/api`](/docs/api).

## Servers

| Environment | URL |
| --- | --- |
| **Live** | `https://fature.al/api/partner/v1` |
| **Sandbox** | `https://demo.fature.al/api/partner/v1` |

## One token, one venue

The bearer token resolves to a single Wolt venue and every endpoint works only on it. The id of an order that belongs to another venue gets a `404`, not a `403`: a wrong id and someone else's id cannot be told apart.

Call `GET /ping` first: it returns the company, the business unit and the Wolt venue the token is linked to, so it confirms the credentials and tells you what you are working on.

## The event feed is the backbone

Call `GET /events` periodically with the latest `next_cursor` you received. The feed is append-only: no event changes and none is deleted, so nothing is lost while your system is down. Delivery is at-least-once, so treat the `(order_id, type)` pair as idempotent. Each event carries a short snapshot of the order at that moment, which is usually enough without a second call.

## Every write requires an Idempotency-Key

The eight action endpoints require the `Idempotency-Key` header. A request without it is rejected with **400**.

- A retry with the same key returns a replay of the first response instead of sending Wolt a second action, and the replay carries the `Idempotent-Replayed: true` header. Keys are kept for 24 hours.
- A second call with the same key while the first is still in progress is rejected with **409**.
- Only successful results are stored, so a transient failure can be safely retried with the same key.

## Errors

A failed request returns the same format as the rest of the API, plus a stable `code`:

```json
{"status": false, "message": "Porosia nuk u gjet.", "code": "order_not_found"}
```

Decide based on `code`, not `message`: the message is translated and may change.

| Code | Status | Meaning |
| --- | --- | --- |
| `unauthenticated` | 401 | The token is missing or invalid |
| `wolt_not_enabled` | 403 | The company does not have the Wolt module |
| `forbidden` | 403 | The token's user does not have the Wolt right |
| `no_venue` | 403 | The token does not resolve to a single active venue |
| `order_not_found` | 404 | No such order for this venue |
| `invalid_transition` | 409 | The action is not allowed for the order's current status. Nothing was sent to Wolt |
| `idempotency_key_required` | 400 | The `Idempotency-Key` header is missing |
| `idempotency_in_progress` | 409 | A call with the same key is still in progress |
| `invalid_data` | 422 | The request body failed validation |
| `action_failed` | 422 | The action failed on our side and was not carried out |
| `wolt_upstream_error` | 502 | Wolt rejected the action or did not respond. Safe to retry with the same key |

The token is checked by the API's general authentication before the request gets here, so a `401` may also come as `{"message": "Unauthenticated."}`, without a `code`. Send the `Accept: application/json` header on every request, so that an invalid token gets a `401` and not a redirect.

## Rate limits

Reads carry the feed polling loop, so they have the wider limit; writes are sent to Wolt, so they have a narrower one. Both are counted per token.

| | Limit |
| --- | --- |
| Reads (`GET`) | 180 per minute |
| Writes (`POST`) | 60 per minute |

Over the limit the response is **429** with a `Retry-After` header that says how many seconds to wait.

## Servers

- `https://fature.al/api/partner/v1` - Live
- `https://demo.fature.al/api/partner/v1` - Sandbox

## Endpoints

### GET /wolt/events

**Summary:** Read the event feed

The backbone of the integration. Call this endpoint periodically with the latest `next_cursor` you received, and get the venue's order lifecycle events in order. The feed is append-only, so nothing is lost while your system is down; delivery is at-least-once, so treat the `(order_id, type)` pair as idempotent. Each event carries in `order` a short snapshot of the order at that moment.

**Tags:** Wolt Partner API

**Parameters:**

| Name | In | Required | Description |
|------|----|----------|-------------|
| `since` | query | no | The cursor to continue from; send the previous next_cursor. Default is 0, the start of the stored history. |
| `limit` | query | no | Maximum number of events returned, 1-200. |
| `types` | query | no | Event types to include, comma-separated, e.g. order.received,order.ready. |

**Responses:**

- `200` - The events after `since` in `events`, oldest to newest, with `next_cursor` and `has_more`; `events` is empty when there is nothing new.
- `401`
- `403` - The company does not have the Wolt module, the token's user does not have the Wolt right, or the token does not resolve to a single active venue.
- `429` - Rate limit reached: 180 reads per minute per token. Retry after the number of seconds in the Retry-After header.

---

### GET /wolt/orders

**Summary:** List orders

The venue's orders, newest first.

To go further back, send the `next_cursor` from the previous response as `?cursor=`. Stop when `has_more` is `false`.

This is a snapshot for listing and backfilling history. To stay in sync with the venue in real time, read the event feed: it is append-only and ordered, so nothing is lost.

**Tags:** Wolt Partner API

**Parameters:**

| Name | In | Required | Description |
|------|----|----------|-------------|
| `cursor` | query | no | Returns orders older than this id; send the previous next_cursor. |
| `limit` | query | no | Number of orders per request, 1-100. |
| `status` | query | no | Filters by Wolt status, e.g. received, acknowledged, ready, delivered. |
| `from` | query | no | Only orders received on or after this date (YYYY-MM-DD). |
| `to` | query | no | Only orders received on or before this date (YYYY-MM-DD). |

**Responses:**

- `200` - The venue's orders in `orders`, newest to oldest, with `next_cursor` and `has_more`; `orders` is empty when there are no orders.
- `401`
- `403` - The company does not have the Wolt module, the token's user does not have the Wolt right, or the token does not resolve to a single active venue.
- `429` - Rate limit reached: 180 reads per minute per token. Retry after the number of seconds in the Retry-After header.

---

### GET /wolt/orders/{id}

**Summary:** Get an order

Returns the full state of an order as fature.al holds it: the header, the parties, the lines, the totals and the fiscal link. Use it when the short snapshot from the feed or the list is not enough, for example to show the order in the kitchen with the chosen modifiers, the customer's note and the discounts, or to reread the current state after an event. The `order` object is the same one every action endpoint returns, so a single reader covers both. As long as the order has no invoice, `invoice` is `null` and the lines come from the Wolt payload; once the invoice is issued, the lines come from the fiscal invoice and carry the product they were invoiced with.

**Tags:** Wolt Partner API

**Parameters:**

| Name | In | Required | Description |
|------|----|----------|-------------|
| `id` | path | yes | The order's id in fature.al, from the feed or the order list. |

**Responses:**

- `200` - The full order in `data.order`: header, parties, lines, totals and the invoice reference.
- `401`
- `403` - The company does not have the Wolt module, the token's user does not have the Wolt right, or the token does not resolve to a single active venue.
- `404` - No such order for this venue.
- `429` - Rate limit reached: 180 reads per minute per token. Retry after the number of seconds in the Retry-After header.

---

### POST /wolt/orders/{id}/accept

**Summary:** Accept an order

Passes the acceptance on to Wolt. No fiscal invoice is issued here: it is issued when the order is marked ready.

`pickup_minutes` has two meanings, depending on the order type:

| Order type | What `pickup_minutes` promises |
| --- | --- |
| Marketplace | When the food will be ready, so Wolt dispatches the courier for that time |
| Self-delivery | **The full delivery time** promised to the customer |

A wrong value on a marketplace order sends a courier who waits, or leaves the food to go cold.

**Tags:** Wolt Partner API

**Parameters:**

| Name | In | Required | Description |
|------|----|----------|-------------|
| `id` | path | yes | The order's id in fature.al, from the feed or the order list. |
| `Idempotency-Key` | header | yes | Idempotency key: a unique key of your own for this action. A retry with the same key returns a replay of the first response instead of sending Wolt a second action, and the replay carries the header Idempotent-Replayed: true. Kept for 24 hours. |

**Request body content types:** application/json

**Responses:**

- `200` - The refreshed order in `data.order`, with status `acknowledged`; `pickup_at` holds the time promised to Wolt, when one was promised.
- `401`
- `400` - The Idempotency-Key header is missing.
- `403` - The company does not have the Wolt module, the token's user does not have the Wolt right, or the token does not resolve to a single active venue.
- `404` - No such order for this venue.
- `409` - The order's current status does not allow this action, or a call with the same Idempotency-Key is still in progress. Nothing was sent to Wolt.
- `422` - pickup_minutes is outside the 5-180 range, or the action failed on our side and was not performed.
- `502` - Wolt rejected the action or did not respond. Retry safely with the same Idempotency-Key.
- `429` - Rate limit reached: 60 writes per minute per token. Retry after the number of seconds in the Retry-After header.

---

### POST /wolt/orders/{id}/confirm-preorder

**Summary:** Confirm a preorder

Confirms a preorder, one the customer has scheduled for later. It stays pending until Wolt releases it to production close to its scheduled time, and only after that can it be marked ready.

**Tags:** Wolt Partner API

**Parameters:**

| Name | In | Required | Description |
|------|----|----------|-------------|
| `id` | path | yes | The order's id in fature.al, from the feed or the order list. |
| `Idempotency-Key` | header | yes | Idempotency key: a unique key of your own for this action. A retry with the same key returns a replay of the first response instead of sending Wolt a second action, and the replay carries the header Idempotent-Replayed: true. Kept for 24 hours. |

**Responses:**

- `200` - The refreshed order in `data.order`, with status `preorder_confirmed`.
- `401`
- `400` - The Idempotency-Key header is missing.
- `403` - The company does not have the Wolt module, the token's user does not have the Wolt right, or the token does not resolve to a single active venue.
- `404` - No such order for this venue.
- `409` - The order's current status does not allow this action, or a call with the same Idempotency-Key is still in progress. Nothing was sent to Wolt.
- `422` - The action failed on our side and was not performed.
- `502` - Wolt rejected the action or did not respond. Retry safely with the same Idempotency-Key.
- `429` - Rate limit reached: 60 writes per minute per token. Retry after the number of seconds in the Retry-After header.

---

### POST /wolt/orders/{id}/courier-at-customer

**Summary:** Mark the courier at the customer

Second self-delivery step: the courier arrived at the customer. Only for **self-delivery** orders, and only after `pickup-completed`. Wolt notifies the customer that the courier has arrived, so send it when that is true and not in advance.

The order moves to `courier_at_customer`. The delivery itself is confirmed separately with `delivered`.

**Tags:** Wolt Partner API

**Parameters:**

| Name | In | Required | Description |
|------|----|----------|-------------|
| `id` | path | yes | The order's id in fature.al, from the feed or the order list. |
| `Idempotency-Key` | header | yes | Idempotency key: a unique key of your own for this action. A retry with the same key returns a replay of the first response instead of sending Wolt a second action, and the replay carries the header Idempotent-Replayed: true. Kept for 24 hours. |

**Responses:**

- `200` - The refreshed order in `data.order`, with status `courier_at_customer`.
- `401`
- `400` - The Idempotency-Key header is missing.
- `403` - The company does not have the Wolt module, the token's user does not have the Wolt right, or the token does not resolve to a single active venue.
- `404` - No such order for this venue.
- `409` - The order's current status does not allow this action, or a call with the same Idempotency-Key is still in progress. Nothing was sent to Wolt.
- `422` - The action failed on our side and was not performed.
- `502` - Wolt rejected the action or did not respond. Retry safely with the same Idempotency-Key.
- `429` - Rate limit reached: 60 writes per minute per token. Retry after the number of seconds in the Retry-After header.

---

### POST /wolt/orders/{id}/delivered

**Summary:** Mark the order delivered

The final step, used in two cases:

- **Takeaway**: the customer has picked up the order after it was marked ready.
- **Self-delivery**: your courier has delivered it, after `courier-at-customer`.

Marketplace orders do not need it: a Wolt courier picks them up and Wolt closes them.

The order moves to `delivered` and leaves the active orders board.

**Tags:** Wolt Partner API

**Parameters:**

| Name | In | Required | Description |
|------|----|----------|-------------|
| `id` | path | yes | The order's id in fature.al, from the feed or the order list. |
| `Idempotency-Key` | header | yes | Idempotency key: a unique key of your own for this action. A retry with the same key returns a replay of the first response instead of sending Wolt a second action, and the replay carries the header Idempotent-Replayed: true. Kept for 24 hours. |

**Responses:**

- `200` - The refreshed order in `data.order`, with status `delivered`.
- `401`
- `400` - The Idempotency-Key header is missing.
- `403` - The company does not have the Wolt module, the token's user does not have the Wolt right, or the token does not resolve to a single active venue.
- `404` - No such order for this venue.
- `409` - The order's current status does not allow this action, or a call with the same Idempotency-Key is still in progress. Nothing was sent to Wolt.
- `422` - The action failed on our side and was not performed.
- `502` - Wolt rejected the action or did not respond. Retry safely with the same Idempotency-Key.
- `429` - Rate limit reached: 60 writes per minute per token. Retry after the number of seconds in the Retry-After header.

---

### GET /wolt/orders/{id}/invoice

**Summary:** Get the order's fiscal invoice

Returns the fiscal invoice issued for the order: the `IIC`, `FIC` and `EIC` identifiers, verification through `pdf_url`, the client, the amounts and the lines.

The invoice object is the same as that of `GET /api/v1/invoice/{id}/details`, so everything already written for that endpoint applies here unchanged.

## While it is still null

`invoice` is `null` as long as the order has no invoice. Follow `fiscal_state` instead of polling blindly:

| `fiscal_state` | Meaning |
| --- | --- |
| `pending` | No invoice yet. Mark the order ready so that one is issued |
| `deferred` | Issued, waiting for the CIS; `invoice` comes with `fic: null`. Completes on its own |
| `fiscalised` | Done. `invoice` is filled in |
| `failed` | Needs a retry |

Better still, follow the `order.fiscalized` event in the feed instead of polling.

**Tags:** Wolt Partner API

**Parameters:**

| Name | In | Required | Description |
|------|----|----------|-------------|
| `id` | path | yes | The order's id in fature.al, from the feed or the order list. |

**Responses:**

- `200` - The fiscal state in `fiscal_state` and the full invoice in `invoice`; `invoice` is `null` as long as the order has no invoice.
- `401`
- `403` - The company does not have the Wolt module, the token's user does not have the Wolt right, or the token does not resolve to a single active venue.
- `404` - No such order for this venue.
- `429` - Rate limit reached: 180 reads per minute per token. Retry after the number of seconds in the Retry-After header.

---

### POST /wolt/orders/{id}/pickup-completed

**Summary:** Mark the courier pickup

First self-delivery step: the venue's own courier picked up the order. Only for **self-delivery** orders, where the venue delivers with its own courier rather than a Wolt courier. Marketplace and takeaway orders never call it.

This is **not** the delivery. The order moves to `picked_up` and stays open through `courier-at-customer` and `delivered`, so it remains on the orders board until the delivery is confirmed.

**Tags:** Wolt Partner API

**Parameters:**

| Name | In | Required | Description |
|------|----|----------|-------------|
| `id` | path | yes | The order's id in fature.al, from the feed or the order list. |
| `Idempotency-Key` | header | yes | Idempotency key: a unique key of your own for this action. A retry with the same key returns a replay of the first response instead of sending Wolt a second action, and the replay carries the header Idempotent-Replayed: true. Kept for 24 hours. |

**Responses:**

- `200` - The refreshed order in `data.order`, with status `picked_up`.
- `401`
- `400` - The Idempotency-Key header is missing.
- `403` - The company does not have the Wolt module, the token's user does not have the Wolt right, or the token does not resolve to a single active venue.
- `404` - No such order for this venue.
- `409` - The order's current status does not allow this action, or a call with the same Idempotency-Key is still in progress. Nothing was sent to Wolt.
- `422` - The action failed on our side and was not performed.
- `502` - Wolt rejected the action or did not respond. Retry safely with the same Idempotency-Key.
- `429` - Rate limit reached: 60 writes per minute per token. Retry after the number of seconds in the Retry-After header.

---

### POST /wolt/orders/{id}/ready

**Summary:** Mark the order ready

**This is the step that issues the fiscal invoice.** If the order has no invoice yet, one is issued and fiscalized here, so marking ready is the moment the sale becomes a legal document. A second call on an order that already has its invoice does not issue a second one.

What comes next depends on the delivery type:

| Delivery type | After marking ready |
| --- | --- |
| Marketplace | A Wolt courier picks up the order |
| Takeaway | The customer picks it up; then call `delivered` |
| Self-delivery | Call `pickup-completed`, then `courier-at-customer`, then `delivered` |

The order moves to status `ready`.

**Tags:** Wolt Partner API

**Parameters:**

| Name | In | Required | Description |
|------|----|----------|-------------|
| `id` | path | yes | The order's id in fature.al, from the feed or the order list. |
| `Idempotency-Key` | header | yes | Idempotency key: a unique key of your own for this action. A retry with the same key returns a replay of the first response instead of sending Wolt a second action, and the replay carries the header Idempotent-Replayed: true. Kept for 24 hours. |

**Responses:**

- `200` - The refreshed order in `data.order`, with status `ready` and the invoice reference in `invoice`; `fiscal_state` is `fiscalised`, or `deferred` when the CIS could not be reached.
- `401`
- `400` - The Idempotency-Key header is missing.
- `403` - The company does not have the Wolt module, the token's user does not have the Wolt right, or the token does not resolve to a single active venue.
- `404` - No such order for this venue.
- `409` - The order's current status does not allow this action, or a call with the same Idempotency-Key is still in progress. Nothing was sent to Wolt.
- `422` - The action failed on our side and was not performed.
- `502` - Wolt rejected the action or did not respond. Retry safely with the same Idempotency-Key.
- `429` - Rate limit reached: 60 writes per minute per token. Retry after the number of seconds in the Retry-After header.

---

### POST /wolt/orders/{id}/reject

**Summary:** Reject an order

Rejects the order and passes the rejection on to Wolt. This is final: a rejected order cannot be accepted afterwards, and no fiscal invoice is issued for it.

| Field | Notes |
| --- | --- |
| `reason` | Free text, up to 255 characters. **Wolt may show it to the customer**, so keep it appropriate |
| `code` | `GENERIC`, `ITEMS_UNAVAILABLE` or `VENUE_CLOSING_SOON`. Default is `GENERIC` |

Both are optional, but an accurate `code` helps Wolt offer the customer a reasonable alternative instead of a generic apology.

**Tags:** Wolt Partner API

**Parameters:**

| Name | In | Required | Description |
|------|----|----------|-------------|
| `id` | path | yes | The order's id in fature.al, from the feed or the order list. |
| `Idempotency-Key` | header | yes | Idempotency key: a unique key of your own for this action. A retry with the same key returns a replay of the first response instead of sending Wolt a second action, and the replay carries the header Idempotent-Replayed: true. Kept for 24 hours. |

**Request body content types:** application/json

**Responses:**

- `200` - The refreshed order in `data.order`, with status `rejected`; no invoice is issued.
- `401`
- `422` - The rejection code is not one of GENERIC, ITEMS_UNAVAILABLE or VENUE_CLOSING_SOON, or the action failed on our side. A validation failure adds the errors object to the response.
- `400` - The Idempotency-Key header is missing.
- `403` - The company does not have the Wolt module, the token's user does not have the Wolt right, or the token does not resolve to a single active venue.
- `404` - No such order for this venue.
- `409` - The order's current status does not allow this action, or a call with the same Idempotency-Key is still in progress. Nothing was sent to Wolt.
- `502` - Wolt rejected the action or did not respond. Retry safely with the same Idempotency-Key.
- `429` - Rate limit reached: 60 writes per minute per token. Retry after the number of seconds in the Retry-After header.

---

### POST /wolt/orders/{id}/retry-fiscalize

**Summary:** Retry fiscalization

Use it when `fiscal_state` is `deferred` or `failed`, which happens when the CIS could not be reached at the moment the invoice was issued. The retry does what the case calls for:

- the order already has an unfiscalized invoice, so that invoice is fiscalized;
- the order has no invoice at all, so one is issued and fiscalized now.

**A rejected, canceled or refunded order cannot be fiscalized** and the call is rejected. Retrying on an order that is already fiscalized is harmless and changes nothing.

**Tags:** Wolt Partner API

**Parameters:**

| Name | In | Required | Description |
|------|----|----------|-------------|
| `id` | path | yes | The order's id in fature.al, from the feed or the order list. |
| `Idempotency-Key` | header | yes | Idempotency key: a unique key of your own for this action. A retry with the same key returns a replay of the first response instead of sending Wolt a second action, and the replay carries the header Idempotent-Replayed: true. Kept for 24 hours. |

**Responses:**

- `200` - The refreshed order in `data.order`; `fiscal_state` is `fiscalised` when fiscalization succeeded, or `deferred` when the invoice was issued but the CIS could not be reached.
- `401`
- `400` - The Idempotency-Key header is missing.
- `403` - The company does not have the Wolt module, the token's user does not have the Wolt right, or the token does not resolve to a single active venue.
- `404` - No such order for this venue.
- `409` - The order's current status does not allow this action, or a call with the same Idempotency-Key is still in progress. Nothing was sent to Wolt.
- `422` - The action failed on our side and was not performed.
- `502` - Wolt rejected the action or did not respond. Retry safely with the same Idempotency-Key.
- `429` - Rate limit reached: 60 writes per minute per token. Retry after the number of seconds in the Retry-After header.

---

### GET /wolt/ping

**Summary:** Check the connection

Verifies the token and returns the single Wolt venue it is linked to. Call it first, to confirm the credentials and see which company, business unit and Wolt venue the token works on.

**Tags:** Wolt Partner API

**Responses:**

- `200` - The venue the token works on: the company, the business unit, the venue's Wolt id, the connection status and the server time.
- `401`
- `403` - The company does not have the Wolt module, the token's user does not have the Wolt right, or the token does not resolve to a single active venue.
- `429` - Rate limit reached: 180 reads per minute per token. Retry after the number of seconds in the Retry-After header.

---

## Full OpenAPI specification

For complete schemas, examples and request/response bodies, fetch the JSON spec:

```
https://fature.al/docs/api/partner/en.json
```
