Levrum.NerisSharp 1.5.0

dotnet add package Levrum.NerisSharp --version 1.5.0
                    
NuGet\Install-Package Levrum.NerisSharp -Version 1.5.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Levrum.NerisSharp" Version="1.5.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Levrum.NerisSharp" Version="1.5.0" />
                    
Directory.Packages.props
<PackageReference Include="Levrum.NerisSharp" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Levrum.NerisSharp --version 1.5.0
                    
#r "nuget: Levrum.NerisSharp, 1.5.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Levrum.NerisSharp@1.5.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Levrum.NerisSharp&version=1.5.0
                    
Install as a Cake Addin
#tool nuget:?package=Levrum.NerisSharp&version=1.5.0
                    
Install as a Cake Tool

NerisSharp

A .NET client library for the NERIS API (National Emergency Response Information System), the FSRI-hosted data platform for fire and EMS reporting. Supports NERIS API v1.5.

The library wraps the REST endpoints at api.neris.fsri.org in typed models and async methods, so a consuming application can read and write Entities, Incidents, Stations, and Units without hand-rolling HTTP requests or OAuth token requests.

NerisSharp targets netstandard2.1, so it can be referenced from .NET Framework 4.8, .NET Core 3.x, and modern .NET.

Installation

A Nuget package is available.

Install through your IDE's Nuget package manager by searching for Levrum.NerisSharp or from command line using:

dotnet add package Levrum.NerisSharp
Install-Package Levrum.NerisSharp

To use the source code, clone the repository and add a project reference to NerisSharp/NerisSharp.csproj, or build the DLL and reference it directly.

Quick start

using NerisSharp;
using NerisSharp.Models;

// HttpClient is owned by the caller and should be long-lived, not created per call.
var httpClient = new HttpClient();

//Create a config object with your credentials and pass to NerisBase. See below for different types of credential flows.
var config = Config.CreateClientCredentialConfig(clientId, clientSecret, UrlType.Test);
var neris = new NerisBase(config, httpClient);

var request = new IncidentRequestModel
{
    Neris_Id_Entity = "FD01234567",
    Call_Create_Start = DateTimeOffset.UtcNow.AddDays(-7),
    Call_Create_End = DateTimeOffset.UtcNow,
};

List<IncidentModel> incidents = await neris.GetAllIncidents(request);

Repository layout

Path Purpose
NerisSharp/ The class library that models NERIS data and allows for interaction with the NERIS API
NerisSharpTest/ Xunit Test Suite
TestProject/ Console harness for manual testing against the live or test API.

Inside NerisSharp/:

  • NerisBase.cs - constructor, authentication, route building, shared _call helper, error handling, and logging.
  • QueryMethods/ - EntityMethods.cs, IncidentMethods.cs, StationMethods.cs, UnitMethods.cs. These are all parts of the same partial class NerisBase, split by resource, containing methods for interacting with NERIS API.
  • Models/ElementModels/ - the API's data objects (EntityModel, IncidentModel, StationModel, UnitModel, and the incident modules under Incident/Modules/).
  • Models/RequestModels/ - search/filter models (IncidentRequestModel, EntityRequestModel).
  • Models/Config.cs - connection settings and endpoint selection.
  • Utils/ - serialization, URI composition, enum helpers, and the sync bridge.
  • Exceptions/ - Custom Errors this Library may throw.

Usage

Configuration and authentication

Client Credential and Username/Password Authentication are both supported.

Client Credential Authentication

Client credential authentication is preferred to Username/Password as Username/Password authentication requires completing an MFA challenge. Supply a Client Id and Secret from NERIS. View NERIS documentation to learn how to create client credentials, this process may differ depending on if you are a vendor/integration partner or fire service professional.

// UrlType.Live  -> https://api.neris.fsri.org/v1/
// UrlType.Test  -> https://api-test.neris.fsri.org/v1/
var config = Config.CreateClientCredentialConfig(clientId, clientSecret, UrlType.Live);

After supplying Client credentials, the library will handle all authentication automatically.

Username Password Authentication

Supply your NERIS username and password to the config. You will have to manually login and supply your MFA challenge code.

// UrlType.Live  -> https://api.neris.fsri.org/v1/
// UrlType.Test  -> https://api-test.neris.fsri.org/v1/
var config = Config.CreatePasswordConfig(username, password, UrlType.Live);
NerisBase neris = new NerisBase(config, httpClient);
await neris.Login();
if (neris.RequiresChallengeResponse)
{
    //supply challenge code. Example with Console.
    string code = Console.ReadLine();
    neris.LoginChallenge(code);
}

If you attempt to access the API while an MFA challenge is required, the library will throw an MFARequiredException to inform you.

General Config

NerisBase takes the Config object, an HttpClient, and optionally an ILogger<NerisBase>. Without a logger, messages go to the console.

var neris = new NerisBase(config, httpClient, logger);

Write protection

Pass denyWriteActions: true to build a read-only client. Every POST/PUT/PATCH/DELETE method then throws NoAccessException before issuing a request. The incident Validate endpoint is exempt, since it does not modify data.

var readOnly = new NerisBase(config, httpClient, logger, denyWriteActions: true);

Model Paths:

All methods that interact with the API for a piece of data require you to supply the Id for the parent data. For instance, all Incident methods require you to submit the Id of the parent Entity that owns the incident. For query methods, the id is placed into the RequestModel object. This is also true for stations and units, where for a given unit you must supply the station that owns the unit, and the entity that owns the station. Most methods have two overloads: one taking a full model (from which the Neris_Id is extracted) and one taking the raw id string.

Queries

Search endpoints take a request model. Validate() runs before the request and throws ValidationException on bad input. Individual searches take a specific Id.

var entities = await neris.GetEntities(new EntityRequestModel { State = "OR", Name = "Portland " });
var entity   = await neris.GetEntity("FD01234567");

Pagination

Incident search endpoints return a IncidentPageSet carrying Next_Cursor and Prev_Cursor. Either walk the cursor yourself with GetIncidentsPage, or let GetAllIncidents do it. The IncidentRequestModel class contains a field for the current cursor.

IncidentPageSet page = await neris.GetIncidentsPage(request);    // one page
request.Cursor = page.Next_Cursor;
IncidentPageSet pageTwo = await neris.GetIncidentsPage(request); // next page
List<IncidentModel> all = await neris.GetAllIncidents(request);  // every page

Entity Requests are slightly different, the EntityPageSet contains info on the Page_Size, Page_Count, and current Page_Number. Increment the Page_Number on the EntityRequestModel to walk pages of Entities.

Writes

Incidents are submitted as an IncidentModelPayload. A payload can be constructed from a retrieved IncidentModel. Incident Post and Put methods are supported, Patch methods are not currently supported for Incidents.

var payload = new IncidentModelPayload(existingIncident);
payload.Base.People_Present = true; //modify the incident

if (await neris.ValidateIncident(entityId, payload))
{
    string nerisId = await neris.PutIncident(entityId, payload);
}

Entities, stations and units do not have their own Payload object and work off their base Model object.

string stationId = await neris.PostStation(entityId, newStation);
string unitId    = await neris.PostUnit(entityId, stationId, newUnit);

For PUT and PATCH, server-managed fields (ex. neris_id, and on incidents submitter_account_type and incident_status) are stripped before sending. PATCH methods accept an optional fieldsToNull set: snake_cased field names to explicitly null out on the server, since omitted fields are left unchanged.

await neris.PatchStation(entityId, stationUpdate, new HashSet<string> { "address_line_2" });

Synchronous callers

The library is async-first. Where a synchronous consumer needs it, a wrapper is provided over Utils/SyncRunner:

List<IncidentModel> incidents = SyncRunner.RunSync(() => GetAllIncidents(requestModel));

Prefer the async methods where you have the choice. The SyncRunner has not been extensively validated and tested.

Errors

  • ValidationException — a request model failed Validate().
  • NoAccessException — a write was attempted on a client constructed with denyWriteActions: true.
  • AuthorizationException — authentication failed.
  • HttpRequestException — the API returned a non-2xx status. The response body is included in the message.
  • ArgumentNullException / ArgumentException — null or whitespace ids, checked before the request is built.
  • MFARequiredException - the API was accessed while an MFA challenge is still hanging. Use the LoginChallenge() method to complete the challenge before attempting to access the API.

Building

dotnet build NerisSharp.sln
dotnet test NerisSharpTest/NerisSharpTest.csproj
dotnet run --project TestProject        # manual harness; needs credentials

TestProject is a scratch harness rather than a test suite — it exercises methods against the live or test API and expects credentials to be supplied in Program.cs.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.1 is compatible. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.5.0 90 10/1/2026
1.0.5 89 9/28/2026
1.0.4 126 8/26/2026
1.0.3 117 8/13/2026
1.0.2 122 8/5/2026
1.0.1 108 8/5/2026
1.0.0 104 8/5/2026