using System.Collections.Generic;
using System.Net.Http.Headers;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
public class TallyfyProcessLauncher
private static readonly HttpClient client = new HttpClient();
[JsonPropertyName("users")]
public List<int> Users { get; set; }
[JsonPropertyName("guests")]
public List<string> Guests { get; set; }
[JsonPropertyName("groups")]
public List<string> Groups { get; set; }
public class TaskOverride
[JsonPropertyName("owners")]
public TaskOwners Owners { get; set; }
[JsonPropertyName("deadline")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string Deadline { get; set; }
public class LaunchPayload
[JsonPropertyName("checklist_id")]
public string ChecklistId { get; set; }
[JsonPropertyName("name")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string Name { get; set; }
[JsonPropertyName("summary")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string Summary { get; set; }
[JsonPropertyName("prerun")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public Dictionary<string, object> Prerun { get; set; }
[JsonPropertyName("tasks")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public Dictionary<string, TaskOverride> Tasks { get; set; }
public static async Task LaunchProcessAsync(LaunchPayload payload)
var accessToken = Environment.GetEnvironmentVariable("TALLYFY_ACCESS_TOKEN") ?? "YOUR_PERSONAL_ACCESS_TOKEN";
var orgId = Environment.GetEnvironmentVariable("TALLYFY_ORG_ID") ?? "YOUR_ORGANIZATION_ID";
var apiUrl = $"https://go.tallyfy.com/api/organizations/{orgId}/runs";
if (string.IsNullOrWhiteSpace(payload?.ChecklistId)) {
Console.WriteLine("Error: ChecklistId is required.");
using var request = new HttpRequestMessage(HttpMethod.Post, apiUrl);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
request.Headers.Add("X-Tallyfy-Client", "APIClient");
var options = new JsonSerializerOptions { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull };
string jsonPayload = JsonSerializer.Serialize(payload, options);
request.Content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");
HttpResponseMessage response = await client.SendAsync(request);
string responseBody = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
Console.WriteLine($"Launched process. Status: {response.StatusCode}");
using var doc = JsonDocument.Parse(responseBody);
Console.WriteLine(JsonSerializer.Serialize(doc.RootElement, new JsonSerializerOptions { WriteIndented = true }));
Console.WriteLine($"Failed. Status: {response.StatusCode}");
Console.WriteLine($"Response: {responseBody}");
catch (HttpRequestException e)
Console.WriteLine($"Request error: {e.Message}");
Console.WriteLine($"Unexpected error: {ex.Message}");
// static async Task Main(string[] args)
// var payload = new LaunchPayload {
// ChecklistId = "TEMPLATE_ID_HERE",
// Name = "C# Launched Process",
// Prerun = new Dictionary<string, object> {
// {"kickoff_field_id_1", "C# Client"}
// Tasks = new Dictionary<string, TaskOverride> {
// {"step_id_abc", new TaskOverride {
// Owners = new TaskOwners { Users = new List<int>{ 12345 } }
// await LaunchProcessAsync(payload);