# Call External API

> Call any HTTP API from API Maker with the call external API system API - JSON, forms, file uploads, SOAP and XML, bytes, with basic, bearer, API key and OAuth 2 authentication, redirects, retries, file downloads, and lists of calls in parallel or in sequence.

Source: https://docs.apimaker.dev/v4/docs/apis-all/system-apis/system-generated-call-external-api.html

Makes HTTP calls to any API from the server : REST with JSON, a form, an upload of files, SOAP and other XML, GraphQL, bytes. It says who asks (basic, bearer, API key, OAuth 2), follows redirects, tries again when a call failed, and gives the answer as JSON, as text, as bytes, or as a file it saved. One call, or a list of calls run in parallel or one after the other, with `preProcess` and `postProcess` rules which copy a value of one answer into the request of another.

| | |
|---|---|
| Method | POST |
| URL | `/api/system-api/admin/call-external-api` : `admin` is the user path of your account |
| Body | one call, an array of calls, or `{ type: "parallel" | "sequential", data: [ … ] }` |
| Answer | `data` : the response of the call, `{ statusCode, ok, headers, body, … }`, or an array of them. The file itself, for one call with [`download`](https://docs.apimaker.dev/v4/docs/apis-all/system-apis/system-generated-call-external-api.html#download-a-file) |
| From code | [`g.sys.system.callExternalApi`](https://docs.apimaker.dev/v4/examples/sys/system/callExternalApi.html) |

## One call

**Body**

```json
{
    "url": "https://api.example.com/customers",
    "method": "POST",
    "timeout": 5000,
    "headers": { "authorization": "Bearer …" },
    "queryParams": { "select": "first_name" },
    "body": { "first_name": "James", "last_name": "Bond" }
}
```

**Answer**

```json
{ "success": true, "statusCode": 200, "data": { "statusCode": 201, "ok": true, "headers": { "content-type": "application/json" }, "body": { "id": 42, "first_name": "James" } } }
```

| Key | Meaning |
|---|---|
| `url` | Required. The full URL. |
| `method` | `GET` (default), `HEAD`, `POST`, `PUT`, `DELETE`, `CONNECT`, `OPTIONS`, `TRACE`, `PATCH`. |
| `timeout` | Milliseconds one request may take. 10 minutes when it is not given. |
| `headers` | The headers of the request. A name is the same header whatever its case. |
| `queryParams`, `pathParams`, `queryArrayFormat` | The values of the query and of the path : see [the URL](https://docs.apimaker.dev/v4/docs/apis-all/system-apis/system-generated-call-external-api.html#the-url). |
| `body`, `bodyType` | What to send, and in which form : see [the body](https://docs.apimaker.dev/v4/docs/apis-all/system-apis/system-generated-call-external-api.html#the-body). |
| `auth` | Who asks : see [authentication](https://docs.apimaker.dev/v4/docs/apis-all/system-apis/system-generated-call-external-api.html#authentication). |
| `responseType` | How the body of the answer is given : see [the answer](https://docs.apimaker.dev/v4/docs/apis-all/system-apis/system-generated-call-external-api.html#the-answer). |
| `download` | Saves the body of the answer as a file : see [download a file](https://docs.apimaker.dev/v4/docs/apis-all/system-apis/system-generated-call-external-api.html#download-a-file). |
| `followRedirects`, `retry`, `throwOnError`, `allowFailure`, `maxResponseSize` | See [redirects, retries and failures](https://docs.apimaker.dev/v4/docs/apis-all/system-apis/system-generated-call-external-api.html#redirects-retries-and-failures). |
| `id` | A name for this call, used by `preProcess` and `postProcess` of other calls. |
| `preProcess`, `postProcess` | Rules `{ from, to }` run before and after the call : `from` is a path starting with the `id` of a call (`saveApi.output.body.data.id`), `to` a path in a call (`setApi.body.customerId`). |
| `output` | Filled with the answer of the call, for the rules of the others. |

- A call with only the keys of the first example works as it always did : every other key is optional.

## The URL

**Body : the values of the path and of the query**

```json
{
    "url": "https://{region}.api.example.com/customers/:customerId/orders",
    "pathParams": { "region": "eu", "customerId": 42 },
    "queryParams": { "status": ["paid", "sent"], "page": 2 },
    "queryArrayFormat": "repeat"
}
```

- This calls `https://eu.api.example.com/customers/42/orders?status=paid&status=sent&page=2`.
- `pathParams` fills `{name}` anywhere before the query, and `:name` where a part of the path starts. Each value is written as a part of a path : `a/b` is `a%2Fb`. A name without a value stays as it is written.
- `queryParams` are added after the ones the URL has already. A text, a number and a boolean are sent as they are, an object as the text of its JSON.
- `queryArrayFormat` says how a list is written :

| `queryArrayFormat` | `{ "ids": [1, 2] }` is sent as |
|---|---|
| `json` (default) | `ids=[1,2]` |
| `repeat` | `ids=1&ids=2` |
| `brackets` | `ids[]=1&ids[]=2` |
| `comma` | `ids=1,2` |

## Authentication

`auth` says who asks. It takes the place of an `authorization` header of the call.

| `auth` | What is sent |
|---|---|
| `{ "type": "basic", "username": "…", "password": "…" }` | `Authorization: Basic …` |
| `{ "type": "bearer", "token": "…" }` | `Authorization: Bearer …`. `prefix` replaces the word `Bearer`. |
| `{ "type": "apiKey", "name": "x-api-key", "value": "…" }` | The header `x-api-key`. With `"in": "query"`, the query parameter `x-api-key`. |
| `{ "type": "oauth2", "tokenUrl": "…", "clientId": "…", "clientSecret": "…", "scope": "…" }` | `Authorization: Bearer <token>`, with a token asked of `tokenUrl`. |

**Body : OAuth 2 client credentials**

```json
{
    "url": "https://api.example.com/reports",
    "auth": {
        "type": "oauth2",
        "tokenUrl": "https://login.example.com/oauth/token",
        "clientId": "CLIENT_ID",
        "clientSecret": "CLIENT_SECRET",
        "scope": "reports.read"
    }
}
```

- The token of `oauth2` is asked for with the `client_credentials` grant, kept in memory until 30 seconds before it expires, and used by every call with the same `auth`. When the API answers `401`, a new token is asked for and the call is sent again, once.
- `grantType` names another grant, and `params` what else the token request holds : `{ "grantType": "password", "params": { "username": "…", "password": "…" } }`. `audience` is sent when it is given. `"credentialsIn": "header"` sends the id and the secret of the client as `Authorization: Basic` and not in the form.
- Keep the secrets out of your code : read them with [`g.sys.system.getSecret`](https://docs.apimaker.dev/v4/docs/apis-all/system-apis/system-generated-get-secret-by-name-api.html#from-code), or copy the token of a call into the next one with `postProcess` (`"to": "ordersApi.auth.token"`).

## The body

`bodyType` says in which form the body is sent, and gives the request its `content-type` when the call names none.

| `bodyType` | `body` | `content-type` |
|---|---|---|
| `json` | An object or an array, sent as JSON. A text is sent as it is. | `application/json` |
| `form` | An object : `{ "a": 1, "b": "x y" }` is sent as `a=1&b=x+y`. A list is its key once for each item, an object the text of its JSON. | `application/x-www-form-urlencoded` |
| `multipart` | An object : every key is a part of the form, a field or a [file](https://docs.apimaker.dev/v4/docs/apis-all/system-apis/system-generated-call-external-api.html#files). | `multipart/form-data`, with its boundary |
| `text` | A text. | `text/plain; charset=utf-8` |
| `xml` | A text. | `application/xml; charset=utf-8` |
| `binary` | Bytes : a `Buffer`, their Base64 text, or a [file](https://docs.apimaker.dev/v4/docs/apis-all/system-apis/system-generated-call-external-api.html#files). | `application/octet-stream`, or the one the name of the file says |

- Without `bodyType`, an object is sent as JSON, or as a form when the `content-type` header of the call is `application/x-www-form-urlencoded` or `multipart/form-data`. A text is sent as it is, a `Buffer` as its bytes.
- A `GET` or a `HEAD` without a `body` is sent without one. Every other JSON call without a `body` sends `{}`.

**Body : a form**

```json
{
    "url": "https://api.example.com/oauth/token",
    "method": "POST",
    "bodyType": "form",
    "body": { "grant_type": "refresh_token", "refresh_token": "…" }
}
```

**Body : SOAP**

```json
{
    "url": "https://soap.example.com/service",
    "method": "POST",
    "bodyType": "xml",
    "headers": { "content-type": "text/xml; charset=utf-8", "SOAPAction": "urn:GetRate" },
    "body": "<soap:Envelope xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'><soap:Body><GetRate/></soap:Body></soap:Envelope>",
    "responseType": "text"
}
```

**Body : GraphQL**

```json
{
    "url": "https://api.example.com/graphql",
    "method": "POST",
    "auth": { "type": "bearer", "token": "…" },
    "body": { "query": "query ($id: ID!) { customer(id: $id) { name } }", "variables": { "id": 42 } }
}
```

### Files

A file is a value of a `multipart` body, or the whole `binary` body.

| Value | The file |
|---|---|
| `{ "file": "reports/a.pdf" }` | A file of the uploads folder (`uploads/reports/a.pdf` in a sandbox). `fileName` and `contentType` replace its name and what the end of its name says it is. |
| `{ "content": "…", "fileName": "note.txt" }` | A text sent as a file. With `"encoding": "base64"`, the bytes the Base64 text stands for. Without `fileName` it is a field, with the `contentType` you give it. |
| A file of `g.req.files` | A file a form sent to your custom API, sent on under its own name and content type. |
| A `Buffer` | Bytes made by your code. |

**Body : a form of several parts, with two files**

```json
{
    "url": "https://api.example.com/documents",
    "method": "POST",
    "bodyType": "multipart",
    "body": {
        "title": "Contract",
        "tags": ["signed", "2026"],
        "document": { "file": "contracts/42.pdf" },
        "note": { "content": "Signed on site", "fileName": "note.txt" }
    }
}
```

**Body : the bytes of a file as the whole body**

```json
{
    "url": "https://storage.example.com/bucket/42.pdf",
    "method": "PUT",
    "bodyType": "binary",
    "body": { "file": "contracts/42.pdf" }
}
```

- Only files of the uploads folder are read : a path which leads out of it is refused.
- A list as the value of a key sends one part for each item, under the same name. An object which is no file is sent as a field of JSON.
- The body of a call is read whole before it is sent : 128 MB at most.

## The answer

| Key | Meaning |
|---|---|
| `statusCode` | The HTTP status of the answer. |
| `ok` | `true` when the status is 200 to 299. |
| `headers` | The headers of the answer, their names in small letters. |
| `body` | The body of the answer : see `responseType`. `null` for a `download` which was saved. |
| `url`, `redirected` | When redirects are followed : the URL the answer came from, and whether a redirect was followed. |
| `attempts` | With `retry` : how many times the request was sent. |
| `file` | With `download` : the file which was saved, `{ path, name, size, contentType }`. |
| `error` | With `allowFailure` : why the call failed, `{ message, code }`. |

| `responseType` | `body` |
|---|---|
| `auto` (default) | JSON when the body is JSON, else its text. Bytes when it is no text : a picture, a PDF, an archive. |
| `json` | JSON. A body which is no JSON is an error which shows its start. |
| `text` | The text of the body, whatever it holds. |
| `base64` | The bytes of the body, as Base64 text. |
| `buffer` | The bytes of the body : a `Buffer` in JavaScript and TypeScript, Base64 text in the other languages and over HTTP. |

- A text is read in the character set its `content-type` names (`charset=iso-8859-1`, `windows-1256`, `shift_jis`, `utf-16` …), UTF-8 without one.
- A body which came compressed (`content-encoding: gzip`, `deflate`, `br`) is unpacked.
- A status of 400 or above is an answer as any other, unless the call asks for [`throwOnError`](https://docs.apimaker.dev/v4/docs/apis-all/system-apis/system-generated-call-external-api.html#redirects-retries-and-failures).

## Download a file

`download` saves the body of the answer as a file of the uploads folder, piece by piece as it arrives where the server itself sends the request, and answers with `file`. The body is not kept in memory, and `body` is `null`.

| `download` | Where the file goes |
|---|---|
| `true` | A place of its own in the uploads folder, with the ending of the file : `3f0c…9a.pdf`. |
| `"invoices/42.pdf"` | That place in the uploads folder. A file which is there gives way. |
| `"invoices/"` | That folder, under the name of the file. |
| `{ "path": "invoices/42.pdf", "fileName": "Invoice 42.pdf" }` | The place, and the name the file has for who it is sent on to. |

**Answer of a call with download**

```json
{
    "statusCode": 200, "ok": true, "headers": { "content-type": "application/pdf" }, "body": null,
    "url": "https://cdn.example.com/invoices/42.pdf", "redirected": true,
    "file": { "path": "invoices/42.pdf", "name": "invoice-42.pdf", "size": 48213, "contentType": "application/pdf" }
}
```

- `file.name` is the name the server gives the file (`content-disposition`), else the last part of its URL, else `download`.
- Redirects are followed, 10 at most, unless the call says `"followRedirects": false`.
- An answer whose status is not 200 to 299 is no file : it is given as any other answer, with its `statusCode` and its `body`, and without `file`.
- A file can be 2 GB ; `maxResponseSize` names another limit, in bytes.
- **From code**, the file is in the uploads folder of the sandbox : read it at `uploads/` + `file.path`, or send it to the caller of your custom API by returning [`__am__downloadFilePath`](https://docs.apimaker.dev/v4/docs/apis-all/custom-apis/user-created-custom-api.html#files). A file which is not sent on stays until the uploads are cleaned (`uploadedFileRemoveOlderThanThisTimeInSeconds`, 30 minutes by default).
- **Over HTTP**, the answer of one call with `download` is the file itself, with its `content-type` and `content-disposition: attachment; filename="…"`, and the file is removed from the server once it was sent. A list of calls answers JSON, and leaves its files in the uploads folder.

**Download a file through API Maker**

```bash
curl -X POST 'https://example.com/api/system-api/admin/call-external-api' \
    -H 'x-am-authorization: TOKEN' -H 'content-type: application/json' \
    -d '{ "url": "https://api.example.com/invoices/42/pdf", "download": true }' \
    --output invoice.pdf
```

## Redirects, retries and failures

| Key | Meaning |
|---|---|
| `followRedirects` | `true` follows 10 redirects at most, a number that many. Default : `false`, the redirect is the answer. As a browser does : after a `303`, and after a `301` or a `302` of a `POST`, the request is a `GET` without a body. Another server is not sent the `authorization` and `cookie` headers. |
| `retry` | Sends the request again when it failed : a number of tries after the first one (10 at most), or the object below. |
| `throwOnError` | `true` : a status of 400 or above is thrown as an error with the status as its `code`, and the `statusCode`, `headers` and `body` of the answer. |
| `allowFailure` | `true` : a call which failed is not thrown. Its answer is `{ "statusCode": 0, "ok": false, "error": { "message": "…" } }`, and the calls after it run. |
| `maxResponseSize` | The most bytes of the answer. 64 MB when it is not given, 2 GB for a `download`. |
| `timeout` | Milliseconds one request may take : each try has that long. |

| Key of `retry` | Default | Meaning |
|---|---|---|
| `count` | `3` | How many times the request is sent again. |
| `delay` | `300` | Milliseconds before the second try. |
| `factor` | `2` | What the wait is multiplied by from one try to the next. |
| `maxDelay` | `30000` | The longest wait, in milliseconds. |
| `statusCodes` | `[408, 429, 500, 502, 503, 504]` | The statuses which are tried again. |
| `onNetworkError` | `true` | Whether a request which got no answer is tried again : no connection, a timeout. |

**Body : a call which is tried again, and thrown when it still fails**

```json
{
    "url": "https://api.example.com/payments",
    "method": "POST",
    "body": { "amount": 1200 },
    "retry": { "count": 4, "delay": 500, "statusCodes": [429, 503] },
    "throwOnError": true
}
```

- A `retry-after` header of the answer is waited for, up to `maxDelay`.
- When every try failed, the answer is the last one. `attempts` says how many times the request was sent.
- A `POST` which is sent again can be done twice by the API it calls : name the statuses which are safe to try again, or send a key the API recognises a repeated request by.

## In parallel, in sequence

**Body : a save, then two calls at once with its result**

```json
[
    { "id": "saveApi", "url": "https://api.example.com/customers", "method": "POST", "body": { "first_name": "James" },
      "postProcess": [ { "from": "saveApi.output.body.id", "to": "setApi.body.customerId" } ] },
    { "type": "parallel", "data": [
        { "id": "setApi", "url": "https://api.example.com/preferences", "method": "PUT", "body": {} },
        { "id": "notify", "url": "https://hooks.example.com/new-customer", "method": "POST", "body": { "source": "shop" }, "allowFailure": true }
    ] }
]
```

- The top level array runs in sequence ; `type: "parallel"` runs its `data` at once, `type: "sequential"` one after the other. Groups nest.
- The answer is an array with one entry per call, nested like the body.
- In sequence, a call which fails ends the list, unless it has `allowFailure`. In parallel, the place of a call which failed is empty, or holds its `error` with `allowFailure`.
- A rule can fill any key of a call : `"to": "ordersApi.auth.token"`, `"to": "ordersApi.pathParams.customerId"`.

## From code

**TypeScript**

```typescript
const resp = await g.sys.system.callExternalApi<{ id: number }>({ url: 'https://api.example.com/customers/42' });
if (resp.statusCode === 200) g.logger.log(resp.body.id);
```

**Python**

```python
resp = await g.sys.system.call_external_api('https://api.example.com/customers/42')
if resp.status_code == 200:
    g.logger.log(resp.body.id)
```

**PHP**

```php
$resp = $g->sys->system->callExternalApi('https://api.example.com/customers/42');
if ($resp->statusCode === 200) {
    $g->logger->log($resp->body->id);
}
```

**C#**

```csharp
var resp = await g.Sys.System.CallExternalApi(new CallExternalApi("https://api.example.com/customers/42"));
if (resp.StatusCode == 200) g.Logger.Log(resp.Body?["id"]);
```

**Go**

```go
resp, err := g.Sys.System.CallExternalApi(am.CallExternalApi{Url: "https://api.example.com/customers/42"})
if err != nil {
	return nil, err
}
if resp.StatusCode == 200 {
	g.Logger.Log(am.AsM(resp.Body).Int("id"))
}
```

**Rust**

```rust
let resp = g.sys.system.call_external_api(CallExternalApi::new("https://api.example.com/customers/42"))?;
if resp.status_code == 200 {
    g.logger.log(&resp.body["id"]);
}
```

**Java**

```java
ExternalApiResponse resp = g.sys.system.callExternalApi(new CallExternalApi("https://api.example.com/customers/42"));
if (resp.getStatusCode() == 200) g.logger.log(JsonObject.from(resp.getBody()).getLong("id"));
```

**Kotlin**

```kotlin
val resp = g.sys.system.callExternalApi(CallExternalApi("https://api.example.com/customers/42"))
if (resp.statusCode == 200L) g.logger.log(JsonObject.from(resp.body).getLong("id"))
```

A custom API which downloads an invoice from another server and sends it to its own caller :

**TypeScript**

```typescript
const saved = await g.sys.system.callExternalApi({
    url: 'https://api.example.com/invoices/42/pdf',
    auth: { type: 'bearer', token: 'TOKEN' },
    download: true,
    throwOnError: true,
});
// the file is in the uploads folder now : your code reads it at 'uploads/' + saved.file.path
return { __am__downloadFilePath: saved.file.path, __am__downloadFolderFileName: saved.file.name };
```

**Python**

```python
saved = await g.sys.system.call_external_api(
    'https://api.example.com/invoices/42/pdf',
    auth={'type': 'bearer', 'token': 'TOKEN'},
    download=True,
    throw_on_error=True,
)
# the file is in the uploads folder now : your code reads it at 'uploads/' + saved.file.path
return {'__am__downloadFilePath': saved.file.path, '__am__downloadFolderFileName': saved.file.name}
```

**PHP**

```php
$saved = $g->sys->system->callExternalApi(
    'https://api.example.com/invoices/42/pdf',
    auth: ['type' => 'bearer', 'token' => 'TOKEN'],
    download: true,
    throwOnError: true,
);
// the file is in the uploads folder now : your code reads it at 'uploads/' . $saved->file->path
return ['__am__downloadFilePath' => $saved->file->path, '__am__downloadFolderFileName' => $saved->file->name];
```

**C#**

```csharp
var saved = await g.Sys.System.CallExternalApi(new CallExternalApi("https://api.example.com/invoices/42/pdf")
{
    Auth = new { type = "bearer", token = "TOKEN" },
    Download = true,
    ThrowOnError = true,
});
// the file is in the uploads folder now : your code reads it at "uploads/" + saved.File.GetString("path")
return new JsonObject { ["__am__downloadFilePath"] = saved.File.GetString("path"), ["__am__downloadFolderFileName"] = saved.File.GetString("name") };
```

**Go**

```go
saved, err := g.Sys.System.CallExternalApi(am.CallExternalApi{
	Url:          "https://api.example.com/invoices/42/pdf",
	Auth:         am.M{"type": "bearer", "token": "TOKEN"},
	Download:     true,
	ThrowOnError: true,
})
if err != nil {
	return nil, err
}
// the file is in the uploads folder now : your code reads it at "uploads/" + saved.File.String("path")
return am.M{"__am__downloadFilePath": saved.File.String("path"), "__am__downloadFolderFileName": saved.File.String("name")}, nil
```

**Rust**

```rust
let saved = g.sys.system.call_external_api(
    CallExternalApi::new("https://api.example.com/invoices/42/pdf")
        .auth(json!({ "type": "bearer", "token": "TOKEN" }))
        .download(true)
        .throw_on_error(true),
)?;
// the file is in the uploads folder now : your code reads it at "uploads/" + the path of the file
return Ok(json!({ "__am__downloadFilePath": saved.file["path"], "__am__downloadFolderFileName": saved.file["name"] }));
```

**Java**

```java
ExternalApiResponse saved = g.sys.system.callExternalApi(new CallExternalApi("https://api.example.com/invoices/42/pdf")
    .auth(Map.of("type", "bearer", "token", "TOKEN"))
    .download(true)
    .throwOnError(true));
// the file is in the uploads folder now : your code reads it at "uploads/" + saved.getFile().getString("path")
return Map.of("__am__downloadFilePath", saved.getFile().getString("path"), "__am__downloadFolderFileName", saved.getFile().getString("name"));
```

**Kotlin**

```kotlin
val saved = g.sys.system.callExternalApi(
    CallExternalApi("https://api.example.com/invoices/42/pdf")
        .auth(mapOf("type" to "bearer", "token" to "TOKEN"))
        .download(true)
        .throwOnError(true),
)
// the file is in the uploads folder now : your code reads it at "uploads/" + saved.file.getString("path")
return mapOf("__am__downloadFilePath" to saved.file.getString("path"), "__am__downloadFolderFileName" to saved.file.getString("name"))
```

- More examples in every language : [forms, files, XML, OAuth 2, retries and downloads](https://docs.apimaker.dev/v4/examples/sys/system/callExternalApi.html).
- Custom APIs can also use any HTTP client of npm from the sandbox ; this API adds the forms, the files, the authentication, the retries, the parallel and sequential plans and the data copying without code.

## Where the request leaves from

- Called over HTTP, the request leaves from the server of API Maker.
- Called from your code, it leaves from where the code runs : its sandbox. The names and the addresses the sandbox reaches are the ones the call reaches.
- The files a call sends and saves are the ones of the uploads folder, which the server and the sandboxes share.

## Access and settings

- Over HTTP, a system API answers once its [settings](https://docs.apimaker.dev/v4/docs/settings/systemApiSettings.html) give it `apiAccessType: TOKEN_ACCESS` (the token of an API user whose [group](https://docs.apimaker.dev/v4/docs/apis-security/api-group-permission.html) grants this system API, in `x-am-authorization`) or `IS_PUBLIC`. Without settings it is `NO_ACCESS` : your code calls it through `g.sys`, the admin panel tests it, and an HTTP call is refused.
- The settings can also cache the answer or require person tokens (`authProviders`) ; [pre and post hooks](https://docs.apimaker.dev/v4/docs/apis-all/hooks/preHook-api.html) run around it like around any API : a pre hook which adds the `auth` of the call keeps the secrets of the other server out of the reach of the caller.
- The [request headers](https://docs.apimaker.dev/v4/docs/apis-all/header/requestHeader.html) apply : `x-am-response-case`, `x-am-content-type-response`, `x-am-internationalization`, `x-am-tenant-username`…

## Errors

| Code | When |
|---|---|
| `400` | The body is wrong : the message names the missing or invalid key (`Invalid value for bodyType. Allowed values are [json, form, multipart, text, xml, binary].`), a file which is not in the uploads folder, or a `download` which leads out of it. |
| `401` | No valid API user token, or the API is `NO_ACCESS` : `You are not authorized to access this API.` |
| `403` | No group grants this system API. |
| The status of the other server | With `throwOnError` : `POST https://api.example.com/payments answered with the status 503.` A status API Maker does not answer with itself is answered as `500`, with the status in the `code` of the error. |
| `500` | The request got no answer, or its answer can not be given : `connect ECONNREFUSED 10.0.0.5:443`, `getaddrinfo ENOTFOUND api.example.com`, `timeout of 5000ms exceeded`, `length limit exceeded`, `Too many redirects : 10 were followed, …`, `The answer is no JSON : …`. |

## Related

- [All APIs at a glance](https://docs.apimaker.dev/v4/docs/apis-all/overview.html) · [Response format](https://docs.apimaker.dev/v4/docs/apis-all/response-format.html) · [System API settings](https://docs.apimaker.dev/v4/docs/settings/systemApiSettings.html) · [System APIs from code](https://docs.apimaker.dev/v4/examples/sys/system/system.html) · [Files of custom APIs](https://docs.apimaker.dev/v4/docs/apis-all/custom-apis/user-created-custom-api.html#files)
