# Tip: How Does the REST Entrypoint Work in Solace Agent Mesh?

**URL:** <https://community.solace.com/t/tip-how-does-the-rest-entrypoint-work-in-solace-agent-mesh/4807>\
**Category:** Solace Agent Mesh\
**Created:** [April 17, 2026, 2:30am UTC](https://community.solace.com/t/tip-how-does-the-rest-entrypoint-work-in-solace-agent-mesh/4807 "2026-04-17T02:30:04Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![giri](https://yyz1.discourse-cdn.com/solace/user_avatar/community.solace.com/giri/32/877_2.png) [@giri](https://community.solace.com/u/giri)\
**Post date:** [April 17, 2026, 2:30am UTC](https://community.solace.com/t/tip-how-does-the-rest-entrypoint-work-in-solace-agent-mesh/4807/1 "2026-04-17T02:30:04Z")

</div>

# Tip: How Does the REST Entrypoint Work in Solace Agent Mesh?

Solace Agent Mesh is an event-driven framework for building distributed ecosystems of collaborative AI agents, powered by the Solace Event Mesh for enterprise-grade agent orchestration. Agents do the thinking. But to reach them programmatically from your applications, scripts, or CI/CD pipelines, you need an API. That’s what the **REST Entrypoint** provides.

The REST Entrypoint is a plugin that extends the [base gateway framework](https://github.com/SolaceLabs/solace-agent-mesh-core-plugins) to expose your agent mesh over HTTP. It gives you a clean async API: submit a task, get a task ID, poll for results, and download any files the agents produce. It is built on FastAPI and includes Swagger documentation out of the box.

In this post, we’ll walk through how the REST Entrypoint works, how to install and configure it, the API it exposes, and the key concepts you need to know when integrating with it.

* * *

## How It Works

The REST Entrypoint runs an HTTP server (FastAPI + Uvicorn) that accepts task submissions and translates them into A2A protocol messages for the agent mesh. The flow is:

1. Your application sends a `POST` request with a prompt and an optional file
2. The Entrypoint translates the request into an A2A task and publishes it to the Solace event broker
3. Agents process the task and publish results back
4. Your application polls for the result using the task ID
5. Once complete, you retrieve the response and any artifacts the agents created

The Entrypoint itself makes no LLM calls. It is a transport layer between your HTTP client and the agent mesh.

* * *

## Installation

Install the REST Entrypoint plugin with a single command:

```bash
sam plugin add my-http-rest --plugin sam-rest-gateway

```

This creates a configuration file at `configs/gateways/my-http-rest.yaml`. Before starting, edit the config for your environment.

> **Important** : Authentication is disabled by default in the scaffolded configuration. This is convenient for local development, but make sure you enable authentication before deploying to production (see the Authentication section below).

If you are running the gateway against a **local Solace broker** , also change the REST API port. The default port (8080) conflicts with the local broker, and the gateway will fail to start with `address already in use`. Set the port in your `.env` file:

```auto
REST_API_PORT=5050

```

If you are connecting to a **cloud broker** , the default port 8080 is fine since there is no local port conflict.

Then start it:

```bash
sam run configs/gateways/my-http-rest.yaml

```

* * *

## API Reference

The REST Entrypoint exposes two API versions. The v2 API is the recommended path. The v1 API is deprecated and blocks until the task completes or times out.

### v2 Endpoints (Recommended)

| Method | Path | Purpose |
| --- | --- | --- |
| `POST` | `/api/v2/tasks` | Submit a task |
| `GET` | `/api/v2/tasks/{taskId}` | Poll for result |
| `GET` | `/api/v2/artifacts/` | List session artifacts |
| `GET` | `/api/v2/artifacts/{filename}` | Download latest artifact version |
| `GET` | `/api/v2/artifacts/{filename}/versions` | List artifact version numbers |
| `GET` | `/api/v2/artifacts/{filename}/versions/{version}` | Download specific version |

### Other Endpoints

| Method | Path | Purpose |
| --- | --- | --- |
| `GET` | `/health` | Health check (no auth required) |
| `GET` | `/api/v2/docs` | Swagger UI for v2 API |
| `GET` | `/api/v1/docs` | Swagger UI for v1 API (legacy) |
| `POST` | `/api/v1/invoke` | Synchronous task submission (deprecated) |

* * *

## Submitting a Task

Submit a task using `multipart/form-data` with two required fields: `agent_name` and `prompt`. You can optionally attach files.

The examples below assume `enforce_authentication: false` (dev mode), so no token is needed. If you have authentication enabled, add `-H "Authorization: Bearer ${SAM_TOKEN}"` to each request (see the Authentication section for how to obtain a token).

**Basic request:**

```bash
curl -s -X POST "http://localhost:5050/api/v2/tasks" \
    -F "agent_name=OrchestratorAgent" \
    -F "prompt=What is event-driven architecture?"

```

**Response (202 Accepted):**

```json
{
  "taskId": "abc123-def456"
}

```

**With a file attachment:**

```bash
curl -s -X POST "http://localhost:5050/api/v2/tasks" \
    -F "agent_name=OrchestratorAgent" \
    -F "prompt=Summarize the attached document" \
    -F "files=@/path/to/document.pdf"

```

The Entrypoint saves uploaded files to the artifact service and enriches the prompt with file metadata before forwarding to agents.

* * *

## Polling for Results

After submitting a task, poll the task endpoint until the result is ready:

```bash
curl -s -X GET "http://localhost:5050/api/v2/tasks/${TASK_ID}"

```

- **202 Accepted** : The task is still processing. Poll again.
- **200 OK** : The task is complete. The response contains the agent’s output.

**Completed response example:**

```json
{
  "id": "task-9f7d5f465f5a4f1ca799e8e5ecb35a43",
  "sessionId": "rest-session-36b36eeb69b04da7b67708f90e5512dc",
  "contextId": "rest-session-36b36eeb69b04da7b67708f90e5512dc",
  "status": {
    "state": "completed",
    "message": {
      "role": "agent",
      "parts": [
        { "type": "text", "text": "The agent's response..." }
      ]
    },
    "timestamp": "2025-07-03T16:59:37.486480"
  },
  "artifacts": [],
  "metadata": { "agent_name": "OrchestratorAgent" }
}

```

> **Important** : Results are consume-once. After the first successful `200` response, the result is deleted from the cache. Polling again returns `202`. Design your client to store the response on first retrieval. If your client does not poll within 10 minutes, the result expires and is evicted.

* * *

## Working with Artifacts

When agents create files (CSV reports, images, documents), they are stored as artifacts scoped to the session. Use the `contextId` from the poll response to retrieve them.

**List artifacts in a session:**

```bash
curl -s -X GET "http://localhost:5050/api/v2/artifacts/?session_id=${CONTEXT_ID}"

```

**Download an artifact:**

```bash
curl -s -X GET "http://localhost:5050/api/v2/artifacts/report.csv?session_id=${CONTEXT_ID}" \
    -o "report.csv"

```

Artifacts are versioned. If an agent overwrites a file, previous versions remain accessible via the `/versions` endpoints.

* * *

## Full Workflow Example

Here is a complete workflow: submit a task, poll for the result, and download any artifacts the agent creates. This example assumes dev mode (`enforce_authentication: false`). If authentication is enabled, add `-H "Authorization: Bearer ${SAM_TOKEN}"` to each curl command (see the Authentication section for how to obtain a token).

> **Tip** : Save this as a script file (e.g., `test-rest.sh`) and run it with `bash test-rest.sh`. Pasting multi-line scripts directly into the terminal can cause parsing errors.

```bash
export SAM_REST_ENTRY="http://localhost:5050"

# 1. Submit task
RESPONSE=$(curl -s -X POST "${SAM_REST_ENTRY}/api/v2/tasks" -F "agent_name=OrchestratorAgent" -F "prompt=Create a CSV with 5 sample products")
TASK_ID=$(echo $RESPONSE | jq -r '.taskId')
echo "Task ID: ${TASK_ID}"

# 2. Poll until complete
while true; do
    HTTP_CODE=$(curl -s -o /tmp/poll_result.json -w "%{http_code}" -X GET "${SAM_REST_ENTRY}/api/v2/tasks/${TASK_ID}")
    if ["$HTTP_CODE" = "200"]; then
        echo "Task complete!"
        break
    fi
    echo "Still processing... polling again in 2 seconds"
    sleep 2
done

# 3. Show the task result
echo "Result:"
cat /tmp/poll_result.json | jq .

# 4. Get context ID and list artifacts
CONTEXT_ID=$(cat /tmp/poll_result.json | jq -r '.contextId')
echo "Context ID: ${CONTEXT_ID}"
echo "Artifacts:"
curl -s -X GET "${SAM_REST_ENTRY}/api/v2/artifacts/?session_id=${CONTEXT_ID}" | jq .

# 5. Download first artifact (filename is determined by the agent)
FILENAME=$(curl -s -X GET "${SAM_REST_ENTRY}/api/v2/artifacts/?session_id=${CONTEXT_ID}" | jq -r '.[0].filename')
if ["$FILENAME" != "null"] && [-n "$FILENAME"]; then
    curl -s -X GET "${SAM_REST_ENTRY}/api/v2/artifacts/${FILENAME}?session_id=${CONTEXT_ID}" -o "${FILENAME}"
    echo "Downloaded ${FILENAME}"
else
    echo "No artifacts to download"
fi

```

* * *

## Configuration

Here is a typical configuration with the key options:

```yaml
shared_config:
  - broker_connection: &broker_connection
      broker_url: ${SOLACE_BROKER_URL, ws://localhost:8008}
      broker_username: ${SOLACE_BROKER_USERNAME, default}
      broker_password: ${SOLACE_BROKER_PASSWORD, default}
      broker_vpn: ${SOLACE_BROKER_VPN, default}

  - services:
      artifact_service: &default_artifact_service
        type: "filesystem"
        base_path: "/tmp/samv2"
        artifact_scope: namespace

apps:
  - name: my_rest_gateway_app
    app_module: sam_rest_gateway.app
    broker:
      <<: *broker_connection

    app_config:
      namespace: "${NAMESPACE}"
      gateway_id: my-rest-gw-01
      artifact_service: *default_artifact_service

      rest_api_server_host: ${REST_API_HOST, 0.0.0.0}
      rest_api_server_port: ${REST_API_PORT, 5050}

      enforce_authentication: false
      default_user_identity: "sam_dev_user"

      default_agent_name: "OrchestratorAgent"
      system_purpose: >
        The system is an AI assistant with agentic capabilities.
      response_format: >
        Responses should be clear and concise.

```

### Configuration Options

| Option | Default | Description |
| --- | --- | --- |
| `rest_api_server_host` | `127.0.0.1` | Host address for the HTTP server |
| `rest_api_server_port` | `8080` | HTTP port (change to avoid conflicts, e.g., 5050) |
| `rest_api_https_port` | `1943` | HTTPS port (when SSL certs are provided) |
| `ssl_keyfile` / `ssl_certfile` | - | Paths to SSL certificate files for HTTPS |
| `enforce_authentication` | `true` | Require bearer token authentication |
| `external_auth_service_url` | - | URL of external auth service (required when auth is enforced) |
| `default_user_identity` | - | Fallback user ID when auth is disabled |
| `sync_mode_timeout_seconds` | `60` | Timeout for v1 synchronous calls |
| `gateway_id` | auto-generated | Unique identifier for this Entrypoint instance |
| `system_purpose` | - | System prompt context sent to agents |
| `response_format` | - | Instructions for formatting agent responses |

> **Important** : The `gateway_id` must be unique across all Entrypoint instances connected to the same broker. If two instances share a `gateway_id`, responses will be routed unpredictably.

* * *

## Authentication

The REST Entrypoint has three configuration options that control authentication: `enforce_authentication`, `default_user_identity`, and `force_user_identity`.

### `enforce_authentication`

This is the main switch. It determines whether the gateway requires a bearer token on every request.

**When `true` (production):**

- Every request must include an `Authorization: Bearer <token>` header
- The gateway calls your external auth service to validate the token and retrieve the user’s identity (email)
- Requests without a valid token are rejected with `401 Unauthorized`

**When `false` (development):**

- No token is required on any request
- The gateway uses `default_user_identity` to determine who the user is
- A security warning is logged at startup

### `default_user_identity`

This is the fallback user ID used when authentication is disabled. It tells the gateway “treat all requests as if they came from this user.”

- If `enforce_authentication: false` and `default_user_identity: "sam_dev_user"`, every request is treated as coming from `sam_dev_user`
- If `enforce_authentication: false` and `default_user_identity` is **missing or empty** , the gateway has no user identity to assign, so it rejects the request with `401 Unauthorized`

> **Tip** : Setting `default_user_identity` to `sam_dev_user` specifically is useful because that matches the WebUI’s default user. This means you can see your REST tasks in the WebUI’s Activities tab without any extra configuration. Note that the WebUI is available in the Enterprise edition only.

### `force_user_identity`

This overrides everything, including authenticated users:

- If set, all requests are treated as this user regardless of token or `default_user_identity`
- Purely a dev/debug tool for testing permission scopes or impersonating a specific user

* * *

## Authentication: Development Setup

The scaffolded configuration already has authentication disabled with a default user set:

```yaml
app_config:
  enforce_authentication: false
  default_user_identity: "sam_dev_user"

```

No token is needed. Submit requests directly:

```bash
# Submit a task (no auth header required)
curl -s -X POST "http://localhost:5050/api/v2/tasks" \
    -F "agent_name=OrchestratorAgent" \
    -F "prompt=Hello"

# Poll for result
curl -s -X GET "http://localhost:5050/api/v2/tasks/${TASK_ID}"

# List artifacts
curl -s -X GET "http://localhost:5050/api/v2/artifacts/?session_id=${CONTEXT_ID}"

```

> **Important** : If you see `401 Unauthorized` with `enforce_authentication: false`, check that `default_user_identity` is set in your config. A missing or empty value causes the gateway to reject all requests.

> **Note** : When `enforce_authentication` is `false`, the gateway ignores `Authorization` headers entirely. Even if you pass a bearer token, it is not validated. The gateway always uses `default_user_identity` regardless. To test actual token validation, you need `enforce_authentication: true` with a running external auth service.

* * *

## Authentication: Production Setup

For production, enable authentication and configure an external auth service:

```yaml
app_config:
  enforce_authentication: true
  external_auth_service_url: ${EXTERNAL_AUTH_SERVICE_URL, https://your-auth-service.com}
  external_auth_service_provider: "azure" # or your identity provider

```

### How It Works

1. Your client sends an `Authorization: Bearer <token>` header with each request
2. The gateway validates the token by calling `POST {external_auth_service_url}/is_token_valid` with the bearer token
3. If valid, it retrieves the user’s identity by calling `GET {external_auth_service_url}/user_info?provider=<provider>`
4. The user’s email is extracted and forwarded to agents as part of the task context

### Where Does the Token Come From?

The REST Entrypoint does not issue tokens. The token comes from your identity provider (Azure AD, Okta, Auth0, etc.) through your standard OAuth/OIDC flow.

If you are running the Agent Mesh WebUI alongside the REST Entrypoint with the same auth service, you can grab a valid token from the WebUI’s browser console:

```javascript
// Open browser dev tools on the WebUI and run:
console.log(window.localStorage.access_token)

```

You can also obtain a token programmatically using your identity provider’s token endpoint. For example, with Azure AD:

```bash
# Azure AD client credentials flow (example)
curl -s -X POST "https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/token" \
    -F "client_id={your-client-id}" \
    -F "client_secret={your-client-secret}" \
    -F "scope={your-scope}" \
    -F "grant_type=client_credentials"

```

The response includes an `access_token` you can use as your bearer token.

### Refreshing Tokens

If your token expires, the REST Entrypoint supports token refresh via the auth service:

```bash
curl -s -X POST "${EXTERNAL_AUTH_SERVICE_URL}/refresh_token" \
    -H "Content-Type: application/json" \
    -d '{"provider": "azure", "refresh_token": "${REFRESH_TOKEN}"}'

```

The response includes new `access_token` and `refresh_token` values.

### Prerequisites for Testing with Authentication

To test authentication, you need:

1. `enforce_authentication: true` in your gateway config
2. A running external auth service at the configured `external_auth_service_url`
3. A valid bearer token from your identity provider

Without a running auth service, the gateway will return `503 Authentication service is unavailable` on every request. If you are doing local development without an auth service, use the development setup (`enforce_authentication: false`) instead.

### Testing with Authentication Enabled

```bash
# 1. Get your token (from WebUI console or your identity provider)
export SAM_TOKEN="<your-bearer-token>"

# 2. Submit a task
RESPONSE=$(curl -s -X POST "http://localhost:5050/api/v2/tasks" \
    -H "Authorization: Bearer ${SAM_TOKEN}" \
    -F "agent_name=OrchestratorAgent" \
    -F "prompt=What agents are available?")
TASK_ID=$(echo $RESPONSE | jq -r '.taskId')
echo "Task ID: ${TASK_ID}"

# 3. Poll for result
curl -s -X GET "http://localhost:5050/api/v2/tasks/${TASK_ID}" \
    -H "Authorization: Bearer ${SAM_TOKEN}"

# 4. List artifacts
CONTEXT_ID="<contextId from poll response>"
curl -s -X GET "http://localhost:5050/api/v2/artifacts/?session_id=${CONTEXT_ID}" \
    -H "Authorization: Bearer ${SAM_TOKEN}"

```

### Error Responses (only when `enforce_authentication: true`)

These errors only occur when authentication is enforced. With `enforce_authentication: false`, the gateway accepts all requests regardless of the token.

| Scenario | HTTP Status | Message |
| --- | --- | --- |
| No `Authorization` header | `401` | `"Bearer token not provided."` |
| Invalid or expired token | `401` | `"Invalid or expired token."` |
| Auth service unreachable | `503` | `"Authentication service is unavailable."` |
| User email not in auth response | `401` | `"User email not provided by auth provider"` |
| User not found in identity service | `403` | `"User not authorized for this application"` |

* * *

## Session Management

Each REST API request creates a fresh session with a unique ID (`rest-session-{uuid}`). There is no persistent conversation state between requests.

This means:

- Every request starts a new conversation with the agent
- Artifacts are scoped to the session they were created in
- The `contextId` in the poll response is the session ID you need for artifact retrieval

If you need multi-turn conversations, consider using the WebUI Entrypoint (which supports persistent sessions) or building a client that manages session continuity at the application level.

* * *

## REST vs. Webhook: Which One to Use?

Both are HTTP-based Entrypoints, but they serve different purposes:

| | REST | Webhook |
| --- | --- | --- |
| **Direction** | Bidirectional: submit tasks and retrieve results | Unidirectional: ingest events, no result return |
| **Endpoints** | Fixed API paths (`/api/v2/tasks`, `/api/v2/artifacts`) | Dynamic, user-defined paths (`/hooks/data-feed`) |
| **Payload** | Multipart form data (agent\_name, prompt, files) | Flexible: JSON, YAML, text, binary per endpoint |
| **Auth** | Centralized bearer token for all endpoints | Per-endpoint: token, basic, or none |
| **Use case** | Apps, scripts, CI/CD needing agent responses | Incoming webhooks from GitHub, Stripe, IoT |

Use the REST Entrypoint when your application needs to send a request and get a response. Use the Webhook Entrypoint when external systems push events that should trigger agent processing without waiting for a result.

* * *

## Last Words of Wisdom

1. **Handle consume-once results.** The poll endpoint returns the result exactly once, then deletes it. Your client should store the response on first retrieval.

2. **Poll with backoff.** Start with a short interval (1-2 seconds) and increase if the task takes longer. Results expire after 10 minutes if not retrieved, so make sure your client polls within that window.

3. **Retrieve artifacts before the session expires.** Artifacts are scoped to the session. If you need the files, download them as part of your workflow.

4. **Use Swagger for exploration.** Visit `/api/v2/docs` to explore the API interactively. No authentication required for the docs endpoint.

5. **Scope your `gateway_id`.** Every Entrypoint instance needs a unique ID. Use environment variables (`gateway_id: ${MY_REST_GW_ID, rest-gw-01}`) so you can run multiple instances safely.

6. **Watch your ports.** The REST Entrypoint defaults to port 8080, which conflicts with the local Solace broker. Use a free port like 5050 in your config.

7. **Use consistent identity across gateways.** Set `default_user_identity: "sam_dev_user"` in your REST gateway config to match the WebUI’s default. This ensures consistent user identity when running multiple gateways against the same broker.

* * *

_For more information about Solace Agent Mesh, visit the repository:_

> **[GitHub - SolaceLabs/solace-agent-mesh: An event-driven framework designed to build and...](https://github.com/SolaceLabs/solace-agent-mesh)**
>
> An event-driven framework designed to build and orchestrate multi-agent AI systems. It enables seamless integration of AI agents with real-world data sources and systems, facilitating complex, multi-step workflows.

An event-driven framework designed to build and orchestrate multi-agent AI systems. It enables seamless integration of AI agents with real-world data sources and systems, facilitating complex, multi-step workflows.

* * *
