HTTP Activities
Version: 1.0.5 · ID: zoan-packages-http · Author: Zoan Software
The HTTP package lets your automation consume APIs and web services (REST): query data from a system, send information, connect two applications that talk over an API. When a system offers an API, this is the most robust and fastest way to integrate with it — more reliable than automating its interface with the browser.
The response: ZoanHttpResponse
Section titled “The response: ZoanHttpResponse”Every activity returns a ZoanHttpResponse object with:
| Property | Type | Description |
|---|---|---|
.StatusCode | int | Final HTTP status code (200, 201, 204…). After redirects, it is the code of the last response. |
.Ok | bool | true when the code is 2xx. Since any other code makes the activity fail (see below), it is always true in an output you actually receive. |
.Body | object | The response body. JSON is converted automatically into a dictionary/list you can read with ["key"] and [index]. Anything else is the raw text. |
.Headers | Dictionary | The response headers (name → value, both text). |
HTTP GET url = "https://api.example.com/customers/42" → output: respLog message = "Name: " + resp.Body["name"]How the body (.Body) is read
Section titled “How the body (.Body) is read”- If the response
Content-Typeheader containsapplication/jsonand the body is not empty, it is parsed as JSON: an object becomes a dictionary, an array a list, and values becomestring,bool, integer (long) or decimal (double). You can navigate deeply:resp.Body["data"]["items"][0]["id"]. - Navigation is safe: a missing key or an out-of-range index returns an empty value instead of failing. Check it with
resp.Body["field"].IsNull, or use.ContainsKey("field"),.Count,.Keys,.IsObject/.IsArray. - If the server does not declare JSON (for example
text/plain,text/xml,text/html), or the JSON is malformed,.Bodyis the full response text: use it withstr(resp.Body)or pass it to XML, Write File, etc. An empty body (for example on a204) is the text"". - The body is always read as text: these activities are meant for APIs that return data (JSON, XML, text), not for downloading binary files.
Response headers (.Headers)
Section titled “Response headers (.Headers)”Includes both the general and the content headers. When a header has several values, they are joined with ", ". Keys are case-sensitive: use the usual spelling, for example resp.Headers["Content-Type"].
What makes the activity fail
Section titled “What makes the activity fail”| Server response | Result |
|---|---|
| 2xx (200, 201, 202, 204…) | The activity succeeds and returns the ZoanHttpResponse. The log shows GET request completed: HTTP 200. |
| 3xx redirects (301, 302, 307, 308) | Followed automatically; you receive the final response. A redirect from HTTPS to HTTP is not followed. |
| Any other code (304, 4xx, 5xx) | The activity fails with The server answered HTTP 404 (Not Found) to the GET request. The message carries the code, its description and the method; it does not include the body of the error response. |
| No response (DNS, connection refused, invalid TLS certificate) | The activity fails with the system error (type HttpRequestException), for example No such host is known. |
When an error response is expected (and you want to handle it rather than stop), wrap the request in a Try / Catch. In the error variable, .Message holds the text above and .Type tells a network failure ("HttpRequestException") apart from an error status code:
Try / Catch errorVariable = error ├─ try: │ HTTP GET url = "https://api.example.com/customers/" + id → output: resp │ ... use resp.Body ... └─ catch: If condition = error.Message.Contains("HTTP 404") ├─ then: │ Log level = warning message = "Customer " + id + " does not exist" └─ else: Throw message = "The API failed: " + error.MessageFor transient failures (unstable network, 429, 503) put a Retry around the request; for a 400 or 404, retrying will not change the result.
Timeouts
Section titled “Timeouts”| Limit | Value | Configurable |
|---|---|---|
| Connecting to the server | 30 s | No |
| Whole request (connect, send and receive the response) | 300 s (5 min) | Yes, with the timeout parameter (seconds, up to 3600) |
Since version 1.0.5, when either limit runs out the activity fails with a normal error of type TimeoutException, with a message that says what happened:
The GET request to api.example.com did not finish within 300 s (timeout). Raise 'timeout' if the service takes longer.Could not connect to api.example.com within 30 s for the GET request (connection timeout). Check the address and that the server is reachable.
Try / Catch (error.Type is "TimeoutException") and Retry catch that error, just like a network failure:
Try / Catch errorVariable = error ├─ try: │ Retry attempts = 3 delay = 5000 │ └─ body: │ HTTP GET url = "https://api.example.com/reports/" + id timeout = 60 → output: resp └─ catch: If condition = error.Type == "TimeoutException" ├─ then: │ Log level = warning message = "The API did not answer: " + error.Message └─ else: Throw message = error.MessageTerminating the execution from Zoan Cloud or the Designer still cuts the request in progress right away, and Try / Catch does not catch that: the execution ends as cancelled.
Other request details:
- Requests leave from the machine where the robot runs and use the Windows proxy settings.
- The
User-Agent: Zoan-Automation/1.0header is sent. - Connections are reused across requests, so calling the same API many times is efficient.
Authentication
Section titled “Authentication”Most APIs require authentication. The authorization parameter sets it up — it is a JSON field where you give the type and its data. Three types are supported (type is case-insensitive):
| Type | What goes in the authorization field | What is sent |
|---|---|---|
| Bearer (token) | { "type": "bearer", "token": "..." } | Authorization: Bearer <token> |
| Basic (user/password) | { "type": "basic", "username": "...", "password": "..." } | Authorization: Basic <base64(user:password)> (UTF-8) |
| API Key | { "type": "apikey", "header": "X-API-Key", "value": "..." } | The header header with the value value. If you omit header, X-API-Key is used. |
If the main field is missing (token for bearer, value for apikey) or type is not one of the three, no authentication is sent: the API will answer 401 and the activity will fail with that code. If the API expects the key in the URL (?api_key=...), put it directly in url.
OAuth 2.0 token (client credentials)
Section titled “OAuth 2.0 token (client credentials)”Many APIs issue a temporary token in exchange for a client_id and a client_secret. Request it with a POST and use it as a bearer token in the following requests:
HTTP POST url = "https://auth.example.com/oauth/token" contentType = "application/x-www-form-urlencoded" body = "grant_type=client_credentials&client_id=" + clientId + "&client_secret=" + credential("erp-api")["value"] → output: tokenResp
HTTP GET url = "https://api.example.com/invoices?status=pending" authorization = { "type": "bearer", "token": tokenResp.Body["access_token"] } → output: respHeaders
Section titled “Headers”The headers parameter is another JSON field: a dictionary of extra headers to send (name → value). Non-text values are converted to text.
headers = { "Accept": "application/json", "X-Source": "zoan-bot" }Content headers (Content-Type, Content-Length, Content-Encoding…) cannot be set here: they are silently ignored. Set the content type with the contentType parameter of POST, PUT and PATCH. If you put Authorization in headers and also use authorization with bearer or basic, authorization wins.
Body and Content-Type
Section titled “Body and Content-Type”POST, PUT and PATCH send a body (body). The default contentType is application/json, and the body is always UTF-8 encoded (charset=utf-8 is added for you).
contentType | What is sent |
|---|---|
Contains application/json (default) | The body converted to JSON: a dictionary → object, a list → array, a number/boolean/text → that JSON value. |
Anything else (text/plain, text/xml, application/x-www-form-urlencoded…) | The body as text, as is. You build the format (XML, encoded form…). |
body = new Dictionary<string, object> { ["name"] = customerName, ["taxId"] = taxId }contentType must be the media type only (application/json, text/xml): adding parameters such as ; charset=utf-8 makes the activity fail.
Activities
Section titled “Activities”Read and delete (no body)
Section titled “Read and delete (no body)”| Activity | Type | Output | What it does |
|---|---|---|---|
| HTTP GET | http-get | ZoanHttpResponse | Reads/queries data from a URL |
| HTTP DELETE | http-delete | ZoanHttpResponse | Deletes a resource |
Create and update (with body)
Section titled “Create and update (with body)”| Activity | Type | Output | What it does |
|---|---|---|---|
| HTTP POST | http-post | ZoanHttpResponse | Creates a resource or sends data |
| HTTP PUT | http-put | ZoanHttpResponse | Replaces a whole resource |
| HTTP PATCH | http-patch | ZoanHttpResponse | Partially updates a resource |
Next steps
Section titled “Next steps”- HTTP GET — the most common request.
- Data types › ZoanHttpResponse — reading the response.
- Using credentials — authenticate securely.