---
title: Schedule a UC4 job
summary: Starts a named UC4/Automic job by posting an empty JSON object ({}), with no job parameters, to the configured route.
status: draft
owner: SAIF Framework Platform Team
last_reviewed: 2026-10-02
library: SAIF.NetCore.Clients.UC4
reference_type: package
operation_id: OP-UC4-02
trigger: A consumer calls await client.ScheduleJob(appname, jobname)
---

# Schedule a UC4 job

This operation starts a named UC4/Automic job. On the first call for a given `UC4Client` instance it also performs lazy, one-time initialization of the injected `IHttpJsonClient` with caller-identity information.

| Field | Value |
| --- | --- |
| **Operation ID** | OP-UC4-02 |
| **Trigger** | Consumer calls `await client.ScheduleJob(appname, jobname)` |
| **Inputs** | `appname` — the calling application's ID, sent as the `Application-ID` header. `jobname` — the UC4 job name, appended to the configured route. |
| **Outputs** | `Task<IHttpRequestResult>`, the raw HTTP result; the caller must inspect `IsSuccessful`, `StatusCode`, and `ErrorMessage`. |
| **Primary components** | `UC4Client.ScheduleJob`, `UC4Client.Init` |
| **Entry point** | `src/SAIF.NetCore.Clients.UC4/SAIF.NetCore.Clients.UC4/SAIF.NetCore.Clients.UC4/Services/UC4Client.cs` |

## Steps

1. If `IsConfigured` is `false`, run `Init(appname)`; otherwise skip to step 3 ([BR-UC4-06](../business-rules.md#br-uc4-06-client-identity-is-fixed-on-first-use), [BR-UC4-07](../business-rules.md#br-uc4-07-isconfigured-has-a-public-setter-that-bypasses-initialization)).
   - Not thread-safe (no lock); concurrent first calls may both run `Init`*.
2. `Init`: call `_httpJsonClient.SetClientInfo(ServiceUrl, ClientName, Environment.MachineName, appName)`, then set `IsConfigured = true` ([BR-UC4-03](../business-rules.md#br-uc4-03-job-scheduling-url-is-built-by-direct-string-concatenation), [BR-UC4-04](../business-rules.md#br-uc4-04-caller-identity-is-sent-via-fixed-and-caller-supplied-headers), [BR-UC4-05](../business-rules.md#br-uc4-05-application-id-cannot-be-null)).
   - Delegates to `SAIF.NetCore.HttpClients`'s `HttpJsonClient.SetClientInfo(baseUrl, userName, machineName, applicationId)`: constructs `ClientInfo(machineName, applicationId, userName)` (throws `ArgumentNullException` if any argument is null) and sets `_baseUri = new Uri(baseUrl)`.
   - On failure: a null `appname` throws `ArgumentNullException` from `ClientInfo`; an empty or malformed `ServiceUrl` throws `UriFormatException`. In both cases `IsConfigured` stays `false`, so the next call retries `Init`.

   > **Origin**: Step 2 is implemented in [`Initialize client`](../../saif-netcore-httpclients/operations/initialize-client.md) (`SAIF.NetCore.HttpClients`) and executed on behalf of this operation.
3. POST to `$"{ScheduleJobEndpoint}{jobname}"` with an empty JSON object (`{}`), with no job parameters ([BR-UC4-03](../business-rules.md#br-uc4-03-job-scheduling-url-is-built-by-direct-string-concatenation), [BR-UC4-08](../business-rules.md#br-uc4-08-scheduling-requests-retry-automatically-on-specific-transient-status-codes), [BR-UC4-09](../business-rules.md#br-uc4-09-scheduling-failures-are-returned%2C-not-thrown)).
   - Delegates to `HttpJsonClient.PostAsync(urlPart, body)` → `ExecuteAsync(urlPart, Method.POST, body, retries: 3)`:
     - `ValidateInitialization`, which throws `ClientNotInitializedException` if `_clientInfo` or `_baseUri` is null.
     - `CreateClient`, which sets the base URI and assigns `client.Authenticator = _authenticator` — the authenticator already held by the injected `IHttpJsonClient` instance, not a value UC4 itself sets or clears — plus the serializer and the timeout override (none for UC4). UC4 never calls `SetNtlmAuthentication`/`SetBasicAuthentication` or sets `BearerToken`, so the authenticator is whatever the host configured on the injected client: `null` if the host configured none, or a working authenticator (demonstrably capable of carrying credentials) if it did.
     - `CreateRequest`, which adds the JSON body and the headers `Client-Name` = machine name, `Application-ID` = appname, and `Client-User` = `"SAIF.NetCore.Clients.UC4"`, plus `Authorization` only if `BearerToken` is set (never set by UC4), plus any custom `Headers`, which are then cleared.
     - Runs the request synchronously inside `Task.Run`; if the status is in `RetryOnStatusCodes` (default 401, 502, 503), sleeps `RetryDelayInMs` (default 1000 ms) and retries, up to 3 retries. These are standard `HttpJsonClient` defaults, changeable by a host that calls `SetOptions`, even though UC4 itself never calls `SetOptions` and never overrides them.
     - Builds `HttpRequestResult` (populates headers, and on failure populates `ErrorMessage` from `errormessage`/`exceptionmessage`/`message` JSON tokens or the raw content), stores it in `RequestResult`, and returns it.

   > **Origin**: The sub-steps above are implemented in `HttpJsonClient` (`SAIF.NetCore.HttpClients`) — see [Execute request](../../saif-netcore-httpclients/operations/execute-request.md) — and executed on behalf of this operation.
   - On failure: non-success HTTP status codes are **not** thrown; they are returned in `IHttpRequestResult` (`IsSuccessful = false`). Network failures surface as `ErrorException` or `ErrorMessage` on the result*.
4. Return the `IHttpRequestResult` to the caller unchanged ([BR-UC4-09](../business-rules.md#br-uc4-09-scheduling-failures-are-returned%2C-not-thrown)).
   - No interpretation of the response body; the UC4 run ID or any response payload is left for the caller to read with `GetResult<T>()` or `Content`.

## Process flow

```mermaid
flowchart TD
	Start([Caller invokes ScheduleJob]) --> D1{IsConfigured?}
	D1 -->|No| Init["Init: SetClientInfo"]
	D1 -->|Yes| Post
	Init --> InitOk{Init succeeded?}
	InitOk -->|No| ErrInit([ArgumentNullException / UriFormatException])
	InitOk -->|Yes| Post["POST empty JSON object {} to route+jobname"]
	Post --> Retry{Status in 401/502/503<br>and retries remaining?}
	Retry -->|Yes| Post
	Retry -->|No| Result([Return IHttpRequestResult to caller])
```

## Failure and edge-case behavior
- A null `appname` on the first call: `ArgumentNullException` from `ClientInfo`; `IsConfigured` remains `false`, so the next call retries `Init`.
- An externally-set `IsConfigured = true` before the first call: `Init` is skipped and the POST fails with `ClientNotInitializedException` unless the injected client was configured elsewhere.
- A 502/503 response after the UC4 API has already accepted the job: the automatic retry can submit a duplicate job if the UC4 Core API's schedule endpoint is not idempotent, which is unknown**.
- Any non-success response: returned as `IHttpRequestResult.IsSuccessful = false`, never thrown.

## Related documentation
- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)

> **Note:** Statements marked with * were inferred from code structure, naming conventions, or
> contextual evidence where direct confirmation was not available in source artifacts. Statements
> marked with ** could not be confirmed; treat as unknown until verified.

## Sources
- `src/SAIF.NetCore.Clients.UC4/SAIF.NetCore.Clients.UC4/SAIF.NetCore.Clients.UC4/Services/UC4Client.cs`
- `src/SAIF.NetCore.HttpClients/SAIF.NetCore.HttpClients/SAIF.NetCore.HttpClients/HttpJsonClient/HttpJsonClient.cs` — declares `SetClientInfo`, `PostAsync`/`ExecuteAsync`, `ValidateInitialization`, `CreateClient`, and `CreateRequest`, the delegated behavior described in steps 2–3.
- `src/SAIF.NetCore.HttpClients/SAIF.NetCore.HttpClients/SAIF.NetCore.HttpClients/ClientInfo.cs` — declares the constructor that throws `ArgumentNullException` for a null `appname`.
- `src/SAIF.NetCore.ServiceContracts/SAIF.NetCore.ServiceContracts/SAIF.NetCore.ServiceContracts/HttpClientOptions.cs` — declares the `RetryOnStatusCodes`/`RetryDelayInMs` defaults applied in step 3.
