> This page is for Spain Public Administration Flow.

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

# Cancel Session

PATCH https://widgets.infonite.tech/api/flows/es-public-administration/v1/manager/{session_id}/cancel

Close an active session from your side: the widget stops accepting interaction and the session ends.

**Key Technical Details:**

* **No Request Body Required**: This operation does not accept a payload; it automatically defaults the cancellation reason to `CLIENT_CANCELLED` with empty feedback metadata.
* **Idempotency (304)**: If the session is already finalized (completed, failed, or cancelled), the endpoint transitions nothing and returns `304 Not Modified`.
* **Concurrency Lock (504)**: Acquires an exclusive database lock on the session. If the lock cannot be acquired within a reasonable time, it returns `504 Gateway Timeout`.

## Cancelling stops the reading. It does not undo what was already read

If anything had already been retrieved when you cancelled, the session ends with `status_code: COMPLETED` and **the records are delivered**: you can read them from [Get Session Results](https://infonite.dev/flows/spain-public-administration/api-reference/spain-public-administration-api/sessions-results/flows-es-public-administration-v-1-session-results) and they travel in the end event like any other finished session.

`CLIENT_CANCELLED` is recorded only when the session had **nothing** — nobody opened the widget, nobody consented, or no source answered before you called.

The reason is what a cancellation means at that point in a session. Records are delivered as each source answers, so by the time some of them are in hand the work that produced them is **done** — the authentication happened, the person consented to it, and the data is ours to hand over. What is still pending is the rest of the session, and cancelling it is a decision to **give up the remaining products**, not a statement that nothing happened.

So the outcome describes what the session achieved:

| When you cancel                      | `status_code`          | What you get                                                                                     |
| :----------------------------------- | :--------------------- | :----------------------------------------------------------------------------------------------- |
| Something had already been retrieved | **`COMPLETED`**        | Everything retrieved up to that moment. Whatever had not answered is absent — and is not coming. |
| Nothing had been retrieved yet       | **`CLIENT_CANCELLED`** | No records. `retrieved_features` is empty and there is no `data`.                                |

Cancelling **stops them**. Any read still in flight is aborted at once, and its features close as aborted rather than as a timeout: nothing keeps running against an institution after you have closed the session, and nothing arrives afterwards.

The session also carries a `warning` message recording that it was cancelled with records already in hand — visible in `messages`, so the outcome is explainable months later without anybody having to reconstruct it.

A session that is still open is not costing you anything, and the sources that have not answered are usually the slow ones by nature (the credit registry report is produced in the background). Subscribe to [On Flow Ended](/flows/spain-public-administration/webhooks) and let it close on its own; cancel when you have decided you do not want what is missing.

> This endpoint needs to be executed with an app secret, so should always be used in server side without exposing the secret to customers.

Reference: https://infonite.dev/flows/spain-public-administration/api-reference/spain-public-administration-api/sessions-management/flows-es-public-administration-v-1-session-cancel

## Authentication

- `X-APP-SECRET` header (required) — Application Secret

## Servers

- `https://widgets.infonite.tech/api/flows` (Legacy, default)
- `https://widgets.infonite.io/api/flows` (Production)

## Request

### Path parameters

- `session_id` (string, required) — Session ID to fetch

## Response

### 204

**204 No Content**Cancelled Successfully

## Errors

### 404 Not Found Error

**404 Not Found**Session not found

- `detail` (string, required) — Error message

### 422 Unprocessable Entity Error

Validation Error

- `detail` (list of ValidationError, optional)

### 429 Too Many Requests Error

**429 Too Many Requests**Too many requests. Rate limit exceeded.

- `detail` (string, required) — Error message

### 504 Gateway Timeout Error

**504 Gateway Timeout**Lock timeout, retry again

- `detail` (string, required) — Error message

## Types

### ValidationError

- `loc` (list of ValidationErrorLocItems, required)
- `msg` (string, required)
- `type` (string, required)
- `input` (any, optional)
- `ctx` (ValidationErrorCtx, optional)

### ValidationErrorLocItems

- string
- integer

### ValidationErrorCtx

## Examples

**SDK Code**

```python
import requests

url = "https://widgets.infonite.tech/api/flows/es-public-administration/v1/manager/644599da47847b79c03cc94f/cancel"

headers = {"X-APP-SECRET": "<apiKey>"}

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

print(response.json())
```

```javascript
const url = 'https://widgets.infonite.tech/api/flows/es-public-administration/v1/manager/644599da47847b79c03cc94f/cancel';
const options = {method: 'PATCH', headers: {'X-APP-SECRET': '<apiKey>'}};

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://widgets.infonite.tech/api/flows/es-public-administration/v1/manager/644599da47847b79c03cc94f/cancel"

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

	req.Header.Add("X-APP-SECRET", "<apiKey>")

	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://widgets.infonite.tech/api/flows/es-public-administration/v1/manager/644599da47847b79c03cc94f/cancel")

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

request = Net::HTTP::Patch.new(url)
request["X-APP-SECRET"] = '<apiKey>'

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.patch("https://widgets.infonite.tech/api/flows/es-public-administration/v1/manager/644599da47847b79c03cc94f/cancel")
  .header("X-APP-SECRET", "<apiKey>")
  .asString();
```

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

$client = new \GuzzleHttp\Client();

$response = $client->request('PATCH', 'https://widgets.infonite.tech/api/flows/es-public-administration/v1/manager/644599da47847b79c03cc94f/cancel', [
  'headers' => [
    'X-APP-SECRET' => '<apiKey>',
  ],
]);

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

```csharp
using RestSharp;

var client = new RestClient("https://widgets.infonite.tech/api/flows/es-public-administration/v1/manager/644599da47847b79c03cc94f/cancel");
var request = new RestRequest(Method.PATCH);
request.AddHeader("X-APP-SECRET", "<apiKey>");
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = ["X-APP-SECRET": "<apiKey>"]

let request = NSMutableURLRequest(url: NSURL(string: "https://widgets.infonite.tech/api/flows/es-public-administration/v1/manager/644599da47847b79c03cc94f/cancel")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "PATCH"
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()
```