Yazam API Apr 2026
📡 API Reference

Yazam API Reference

Two complementary REST APIs for file security filtering. Choose the interface that best fits your integration architecture.

Composite /composite - Stateless · Single request
🔗 Native /native - Stateful · Session-based · Progress streaming
Composite API
Single-request filtering
Stateless · Load-balancer safe · Best for web services & microservices
POST /composite →
🔗 Native API
Session-based filtering
Stateful · Progress streaming · Chunked upload · Embedded stream retrieval
POST → PUT → GET → DELETE →

Overview

Yazam API provides two distinct REST APIs under the same server. Both share the same authentication system and response format - but differ in their state model and workflow.


Authentication

Both APIs share the same four authentication methods. Apply the appropriate method on every request as required by the server configuration.

Bearer Token

Obtain a token via GET /logon (see Endpoints), then supply it in every request.

Authorization: Bearer <TOKEN>
HTTP Basic

Username and password encoded in Base64.

Authorization: Basic <base64(user:pass)>
Windows (NTLM/Kerberos)

Integrated Windows authentication via default network credentials (e.g. UseDefaultCredentials in .NET).

Anonymous

No authentication header required. Must be explicitly enabled on the server.

Client Certificate

Optionally enabled. The client must present a valid certificate whose Subject is pre-configured on the server.

⚠️
Note: Authentication headers are omitted from all code samples below. Add the appropriate method before deploying to production.

Encryption & TLS

HTTP / HTTPS
Both protocols are supported. All code samples assume https://.
HTTPS (Recommended)
Strongly recommended for all production environments to ensure confidentiality and integrity. The server must have a valid TLS/SSL certificate.

GET /logon

ℹ️
This endpoint applies to both the Composite API (/composite) and the Native API (/native). Use it to obtain a Bearer token when token-based authentication is configured on the server.
GET /logon Obtain an auth token

Authenticates the caller and returns a Bearer token for subsequent requests. Credentials are passed in HTTP headers.

Request Headers

HeaderTypeRequiredDescription
UserstringRequiredUsername for authentication.
PasswordstringRequiredPassword for authentication.

Response

Returns a token string to be used as Authorization: Bearer <TOKEN> in all subsequent calls to both APIs.


⚡ Composite API
Composite API
Stateless · Single request · Load-balancer safe
Submit files, apply a policy, and receive filtered output - all in one synchronous HTTP call. All server resources are auto-cleaned after each response.
/composite

Overview

The Composite API handles file filtering in a single multipart/form-data POST request. It is stateless - no session is maintained between calls, making it fully compatible with load balancers and horizontal scaling.

Endpoints

POST /composite Submit files for filtering

The primary endpoint. Submits one or more files for security filtering in a single synchronous request. Body must be multipart/form-data.

Body Parts

Part NameTypeRequiredDescription
filefileRepeatableFile(s) to filter. Both filename and filename* are supported in Content-Disposition. May appear multiple times.
policystringRequiredFiltering policy name recognized by the engine.
clientstringOptionalIdentifier of the requesting entity.
relationstringOptionalSoftware submitting the files. A number 194-255 or a predefined name.
passwordstringRepeatablePassword(s) for decrypting protected streams.
historystringOptionalEnable history and define its content in the summary.
reportstringOptionalDestination for storing the filtering report server-side.
returnstringUp to ×2Which files to return and the summary format. See return parameter.
commentstringOptionalArbitrary text associated with a submitted file. Must use the same filename/filename* parameter in its Content-Disposition header as the corresponding file part.

Response

Returns multipart/form-data with a summary part (the filtering result) and optional file parts (returned files with original filename*).

GET /composite/policies List all policies

Returns a JSON array of all defined filtering policy names.

JSON Response
[ "DefaultPolicy", "StrictPolicy", "EmailPolicy" ]
GET /composite/{resource} Get shared configuration

Retrieves shared server-side configuration.

PUT /composite/{resource} Set shared configuration

Overwrites shared server-side configuration for the given resource.


The Return Parameter

The return parameter can appear up to twice in a single request - once to specify which files to return, and once to set the summary format.

File Selection

modified
Return only files that were modified during filtering.
passed
Return only files that passed without modification.
submitted
Return all submitted files regardless of filtering outcome.

Summary Format

raw | xml
(Default) Raw XML - suitable for machine parsing.
object | json
JSON object - best for REST consumers and JavaScript.
report | html
Human-readable HTML report.
table | csv
CSV table - suitable for spreadsheet export.
💡
Example: Use return=modified and return=json together to get filtered files and a machine-readable summary in one response.

Response Summary Structure

The summary may include the following fields and elements. Any tag except the root may appear multiple times at the same level.

Root - <Result>

Date
Universal sortable date/time pattern in UTC.
Policy
Filtering policy.
Client
Filtering agent - the caller can set anything or use the default.
ProductVersion
Filtering engine version.
Antivirus
Used antimalware engine(s), separated by a vertical line | if multiple.
<Warning>
Any warning as human-readable text.

<File> - Data Stream (only recursive element - can contain itself)

Name
Logical path within its container if embedded, or given name otherwise.
Size
Data size before filtering.
Path
Physical path in the temporary cache. Only its file extension is significant - it can differ from the logical name and more precisely indicates stream type.
Status
Assigned by the engine: Blocked, Modified, or Intact.
Partial
How many descendant streams were removed from this one.
Duration
Time in milliseconds it took to filter this stream, excluding non-AMSI antiviruses.
Type
Stream type within or in relation to its container.

<Annotation> - Information about the stream (does not alter its status)

Type
String ID.
Count
Encountered overall.
Expression
Mandatory or forbidden regular expression, in .NET format.
Inner text
Human-readable message.
<Match>
An instance of the forbidden regular expression found in the stream.
Position
Index of the instance within the context.
Length
Length of the instance.
Inner text
The context - a short neighbourhood of the instance within the stream.

<Event> - Modification of the stream (not including embedded ones)

Type
String ID.
Count
Encountered overall.
Inner text
Human-readable message.

<Block> - Rejection of the stream

Type
String ID.
Count
Encountered overall.
Error
Error code.
Expression
Mandatory or forbidden regular expression, in .NET format.
Inner text
Human-readable message.
<Match>
An instance of the forbidden regular expression found in the stream.
Position
Index of the instance within the context.
Length
Length of the instance.
Inner text
The context - a short neighbourhood of the instance within the stream.

<File> - Embedded Data Stream

🔄
<File> is the only recursive element - it can contain itself. Embedded streams follow the exact same structure as the parent <File> element described above. See also: ... (see above) in the Word reference.
📌
Note: Any tag except the root <Result> may appear multiple times at the same level.

Response Summary Examples

Generic examples of the filtering summary in both JSON and XML formats.

json
{
  "Date": "2025-08-26 11:49:24Z",
  "Policy": "POLICY_NAME",
  "Client": "CLIENT",
  "ProductVersion": "VERSION",
  "Antivirus": "ANTIVIRUS_ENGINE",
  "Files": [
    {
      "Name": "FILE1_NAME",
      "Size": "129144",
      "Path": "C:\\Temp\\FILE1",
      "Status": "Modified",
      "Partial": "0",
      "Protected": "0",
      "Duration": "31",
      "History": "251",
      "Results": [
        {
          "Type": "Reencoded",
          "History": "352",
          "Description": "File was regenerated.",
          "Kind": "Modification"
        }
      ]
    },
    {
      "Name": "FILE2_NAME",
      "Size": "108",
      "Path": "C:\\Temp\\FILE2",
      "Status": "Modified",
      "Partial": "1",
      "Protected": "0",
      "Duration": "0",
      "History": "252",
      "Files": [
        {
          "Name": "EMBEDDED_FILE",
          "Size": "43",
          "Path": "C:\\Temp\\EMBEDDED_TMP",
          "Status": "Blocked",
          "Partial": "0",
          "Protected": "0",
          "Duration": "0",
          "Type": "Script",
          "History": "253",
          "Results": [
            {
              "Type": "LinkSetPossible",
              "History": "353",
              "Description": "Navigation can be manipulated.",
              "Kind": "Rejection"
            }
          ]
        }
      ]
    }
  ],
  "Results": [
    { "Description": "ANTIVIRUS_ENGINE", "Kind": "Antivirus" }
  ]
}
xml
<Result Date="2025-08-26 14:11:22Z" Policy="POLICY_NAME" Client="CLIENT"
        ProductVersion="VERSION" Antivirus="ANTIVIRUS_ENGINE">
  <Antivirus>ANTIVIRUS_ENGINE</Antivirus>
  <File Name="FILE1_NAME" Size="129144" Path="C:\Temp\FILE1"
        Status="Modified" Partial="0" Protected="0" Duration="15" History="254">
    <Event Type="Reencoded" History="354">File was regenerated.</Event>
  </File>
  <File Name="FILE2_NAME" Size="108" Path="C:\Temp\FILE2"
        Status="Modified" Partial="1" Protected="0" Duration="0" History="255">
    <File Name="EMBEDDED_FILE" Size="43" Path="C:\Temp\EMBEDDED_TMP"
          Status="Blocked" Partial="0" Protected="0" Duration="0"
          Type="Script" History="256">
      <Block Type="LinkSetPossible" History="355">Navigation can be manipulated.</Block>
    </File>
  </File>
</Result>

C# (.NET)

c#
using (MultipartFormDataContent job = new MultipartFormDataContent
{
    { new StringContent("<POLICY_NAME>"), "policy" },
    { new StringContent("<CLIENT>"),      "client" },
    { new StringContent("modified"),      "return" }
})
{
    job.Add(new StreamContent(File.OpenRead("<PATH_TO_FILE1>")), "file", "<FILE1_NAME>");
    job.Add(new StreamContent(File.OpenRead("<PATH_TO_FILE2>")), "file", "<FILE2_NAME>");

    using (HttpClient hc = new HttpClient(new HttpClientHandler(), true)
    { BaseAddress = new Uri(@"https://<HOST>/composite/"), Timeout = Timeout.InfiniteTimeSpan })

    using (HttpResponseMessage response = await hc.SendAsync(
        new HttpRequestMessage(HttpMethod.Post, "") { Content = job },
        HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false))
    {
        response.EnsureSuccessStatusCode();

        MultipartMemoryStreamProvider result = await response.Content
            .ReadAsMultipartAsync(new MultipartMemoryStreamProvider()).ConfigureAwait(false);
        foreach (HttpContent part in result.Contents)
        {
            if (part.Headers.ContentDisposition.Name == "summary")
                Console.WriteLine("Summary: \n" + part.ReadAsStringAsync().ConfigureAwait(false));
            else if (part.Headers.ContentDisposition.Name == "file")
                using (Stream file = await part.ReadAsStreamAsync().ConfigureAwait(false))
                {
                    Console.WriteLine("Modified file: " + part.Headers.ContentDisposition.FileNameStar + ", size: " + file.Length);
                    // process file ...
                }
        }
    }
}

Python

python
import os, requests
from requests_toolbelt.multipart import decoder
import pyrfc6266

path1 = r"<PATH_TO_FILE1>"
path2 = r"<PATH_TO_FILE2>"
fn1 = os.path.basename(path1)
fn2 = os.path.basename(path2)

with open(path1, "rb") as f1, open(path2, "rb") as f2:
    r = requests.post(
        "https://<HOST>/composite/",
        data=[
            ("policy", "<POLICY_NAME>"),
            ("client", "<CLIENT>"),
            ("return", "modified"),
            ("return", "json"),
        ],
        files=[
            ("file", (fn1, f1, "application/octet-stream")),
            ("file", (fn2, f2, "application/octet-stream")),
        ],
        # Add authentication here if required
    )

multipart_data = decoder.MultipartDecoder.from_response(r)
for part in multipart_data.parts:
    cd = part.headers.get(b"Content-Disposition", b"").decode("ascii", "ignore")
    disp, params = pyrfc6266.parse(cd)
    name = next(p for p in params if p.name == "name").value
    if name == "summary":
        print(part.text)
    elif name == "file":
        print(next(p for p in params if p.name == "filename*").value)
🔗 Native API
Native API
Stateful · Session-based · Progress streaming
Multi-step workflow: submit streams, trigger filtering, retrieve results. Supports real-time progress and chunked uploads.
/native

Overview & Sessions

The Native API maintains a server-side session per client interaction. The session corresponds to a running instance of the filtering engine. Unlike the Composite API, files are submitted and retrieved one at a time across multiple HTTP calls.

⚠️
Load Balancer: All requests within a session must hit the same server instance. Configure sticky sessions (session affinity) on any load balancer in front of this API.

Session Identity

On the first POST the server assigns a session ID and returns it in both a Set-Cookie header and a X-Session-ID response header. Include this ID on all subsequent calls.

Cookie (Recommended)
Most HTTP clients handle the session cookie automatically.
X-Session-ID
Pass manually via header. Takes precedence over the cookie when both are present.

Naming Streams

Every stream must be identified by a filename with the correct extension - the engine uses the extension to determine the stream type.

Content-Name header
URL-encoded. E.g. Content-Name: report.docx
?name= query param
E.g. /native?name=report.docx
Content-Path / ?path=
Retrieve any stream (including embedded) directly by its path from the engine's filtering response.
💡
Chunked upload: Submitting a stream with a name already used in the current session appends the data as an additional chunk of the same stream.

Session Workflow

A complete session follows these five steps in order. Always end with DELETE to free server resources immediately.

1
POST First stream - no session ID
Request has succeeded with a new filtering session created and its ID generated. HTTP 201 Created.
2
POST Additional streams (optional)
Repeat with session ID attached. Chunked uploads reuse the same filename. Returns HTTP 200 OK.
3
PUT Trigger filtering
Send policy and optional parameters. The engine filters all submitted streams synchronously. Optionally stream progress via progress=comet. Returns HTTP 200 OK.
4
GET Retrieve filtered streams
Retrieve each filtered stream one at a time by name or path. Returns HTTP 200 OK.
5
DELETE End session
Explicitly frees all server-side resources. Returns HTTP 204 No Content. Do not skip this step.

Endpoints

POST /native Submit a stream

Submits a raw data stream to the current session. The first call (no session ID) creates a new session.

Request Headers / Query Params

ParameterTypeRequiredDescription
Content-Name or ?name=stringRequiredURL-encoded filename with extension. Reusing an existing name appends a chunk to that stream.
X-Session-ID or cookiestring2nd+ callOmit on the very first request to start a new session. Required on all subsequent calls.

Request Body

Raw binary stream content (no multipart wrapping).

Response

201 Created
Request has succeeded with a new filtering session created and its ID generated.
200 OK
Stream accepted into existing session.
PUT /native Trigger filtering

Triggers synchronous filtering of all streams in the current session. Parameters can be sent as JSON, application/x-www-form-urlencoded, or query string properties.

Parameters

ParameterTypeRequiredDescription
policystringRequiredFiltering policy recognized by the engine.
clientstringOptionalEntity originating the process. Defaults to the authenticated user.
relationstringOptionalSoftware submitting the files. A number 194-255 or a predefined name.
passwordstringRepeatableOne or more passwords for decrypting encrypted streams.
historystringOptionalEnable history and define its content. Overrides server defaults.
reportstringOptionalDestination path for storing the filtering report server-side.
returnstringOptionalOutput format: xml, json, html, or csv.
progressstringOptionalSet to comet to stream progress line-by-line in the response body, followed by an empty line then the final result. Requires ResponseHeadersRead in .NET.

Response

Filtering summary in the requested format. With progress=comet: progress lines → empty line → final result.

💡
Parameters can be sent as JSON, form-encoded body, or query string - e.g. /native?policy=MyPolicy&return=json.
GET /native Retrieve a filtered stream

Retrieves a single filtered stream from the session. Call once per stream after the PUT filtering step.

Request Headers / Query Params

ParameterTypeRequiredDescription
Content-Name or ?name=stringName or PathFilename used during submission.
Content-Path or ?path=stringName or PathPhysical path from the filtering response. Allows direct retrieval of any stream including embedded ones.

Response

Raw binary content of the filtered stream. 200 OK.

DELETE /native End session & free resources

Terminates the session and immediately frees all server-side resources. Always call DELETE when done.

Response

204 No Content - session deleted, no body.

Sessions auto-expire after a configurable idle timeout, but explicit DELETE is strongly recommended to release server resources immediately.
GET /native/policies List all policies

Returns a JSON array of all defined policy names. Equivalent to GET /composite/policies.

⚠️
This call starts a new session. Remember to DELETE the session afterwards.
GET POST /native/{resource} Shared configuration

GET retrieves, POST sets shared server-side configuration.

⚠️
Both calls start a new session - remember to DELETE when finished. Note: the Native API uses POST to set configuration, unlike the Composite API which uses PUT.

Status Codes

200 OKRequest succeeded. Body contains the requested data.
201 CreatedRequest has succeeded with a new filtering session created and its ID generated.
204 No ContentRequest succeeded with no body (e.g. DELETE).
400 Bad RequestRequired parameter missing or invalid - missing session ID, stream name, policy, unknown output format, or invalid URL path.
404 Not FoundSession is busy (serving another concurrent request) or expired (timed out or deleted).
405 Method Not AllowedHTTP method not permitted on this endpoint.
500 Server ErrorFiltering engine failed. Consult the response headers for details.

C# (.NET)

Complete single-file session including optional real-time progress streaming via comet mode.

c# · with progress (comet)
using (HttpClient hc = new HttpClient(
    new HttpClientHandler { Credentials = new NetworkCredential("<user>", "<pass>") }, true)
    { BaseAddress = new Uri(@"https://<host>:<port>/native/") })
{
    // 1. Submit the file
    hc.DefaultRequestHeaders.Add("Content-Name", WebUtility.UrlEncode("<file name>"));
    (await hc.PostAsync("", new StreamContent(File.OpenRead("<file path>")))).EnsureSuccessStatusCode();

    // 2. Filter with progress streaming
    HttpResponseMessage result = await hc.SendAsync(
        new HttpRequestMessage(HttpMethod.Put, "") {
            Content = new FormUrlEncodedContent(new[] {
                new KeyValuePair<string,string>("policy", "<policy>"),
                new KeyValuePair<string,string>("client", "<client>"),
                new KeyValuePair<string,string>("progress", "comet") })
        }, HttpCompletionOption.ResponseHeadersRead);
    result.EnsureSuccessStatusCode();

    using (TextReader rdr = new StreamReader(await result.Content.ReadAsStreamAsync())) {
        while (true) { string p = await rdr.ReadLineAsync(); if (string.IsNullOrEmpty(p)) break; Console.WriteLine(p); }
        Console.WriteLine(await rdr.ReadToEndAsync()); // filtering result
    }

    // 3. Retrieve filtered file
    using (var resp = await hc.GetStreamAsync(""), out_ = File.Create("<output>"))
        await resp.CopyToAsync(out_);

    // 4. Clean up session
    await hc.DeleteAsync("");
}
c# · without progress
using (HttpClient hc = new HttpClient(
    new HttpClientHandler { Credentials = new NetworkCredential("<user>", "<pass>") }, true)
    { BaseAddress = new Uri(@"https://<host>:<port>/native/") })
{
    // 1. Submit the file
    hc.DefaultRequestHeaders.Add("Content-Name", WebUtility.UrlEncode("<file name>"));
    (await hc.PostAsync("", new StreamContent(File.OpenRead("<file path>")))).EnsureSuccessStatusCode();

    // 2. Filter
    var result = await hc.PutAsync("", new FormUrlEncodedContent(new[] {
        new KeyValuePair<string,string>("policy", "<policy>"),
        new KeyValuePair<string,string>("client", "<client>") }));
    result.EnsureSuccessStatusCode();
    Console.WriteLine(await result.Content.ReadAsStringAsync());

    // 3. Retrieve filtered file
    using (var resp = await hc.GetStreamAsync(""), out_ = File.Create("<output>"))
        await resp.CopyToAsync(out_);

    // 4. Clean up session
    await hc.DeleteAsync("");
}

Python

python
import os
from urllib.parse import quote
import requests

base_url = "http://127.0.0.1:8008/native"

def filter_file(session, file_path, policy, client="", return_format="JSON"):
    file_name = os.path.basename(file_path)
    encoded_name = quote(file_name)

    # Submit the file
    with open(file_path, "rb") as file:
        response = session.post(
            base_url,
            data=file,
            headers={"Content-Name": encoded_name}
        )
        response.raise_for_status()

    # Filter the file
    data = {
        "policy": policy,
        "client": client,
        "return": return_format
    }

    response = session.put(base_url, json=data)
    response.raise_for_status()
    print(response.text)

    # Retrieve filtered file
    altered_file_path = f"altered_{file_name}"
    response = session.get(f"{base_url}?name={encoded_name}")
    response.raise_for_status()

    with open(altered_file_path, "wb") as file:
        file.write(response.content)

    return altered_file_path

file_paths = [
    r"C:\path\to\file1.jpg",
    r"C:\path\to\file2.xml"
]

session = requests.Session()
# Optional: add authentication to the session if required
# (for example Basic auth, Bearer token, or client certificate).

try:
    for file_path in file_paths:
        altered_file_path = filter_file(session, file_path, "full")
        print(f"Altered file saved as: {altered_file_path}")
finally:
    response = session.delete(base_url)
    response.raise_for_status()
🧪 Guides

Postman Guide

Recommended steps for setting up Postman to test both APIs.

1 - Create an Environment

Environment Variables
base_urlhttps://<YOUR_HOST>
policy<POLICY_NAME>
clientpostman-test
bearer_token(auto-populated by logon request)

2 - Obtain a Bearer Token

Method: GET  ·  URL: {{base_url}}/logon  ·  Headers: User + Password

Tests Tab (auto-save token)
const token = pm.response.text();
if (token) pm.environment.set("bearer_token", token.trim());

3 - Composite POST Request

Method: POST  ·  URL: {{base_url}}/composite  ·  Auth: Bearer {{bearer_token}}  ·  Body: form-data

KeyTypeValue
policyText{{policy}}
clientText{{client}}
returnTextmodified
returnTextjson
fileFileSelect file → repeat row for each file
⚠️
Duplicate keys: Postman supports duplicate form-data keys. Add a second return row and enter the format value - both will be sent in the same request.

4 - Native API Session

For the Native API, create a Postman Collection with 4 requests in sequence:

POST /native
Body: raw binary, Header: Content-Name: filename.ext. Save the returned X-Session-ID to environment.
PUT /native
Body: form-encoded with policy, client, optionally progress=comet. Header: X-Session-ID: {{session_id}}.
GET /native
Query: ?name=filename.ext. Header: X-Session-ID: {{session_id}}. Save response as binary.
DELETE /native
Header: X-Session-ID: {{session_id}}. Always run this - add it as a Collection-level post-request script.