# Async Account Creation

The `POST /accounts` endpoint supports **asynchronous account creation** via a callback URL.

> See [Open API Spec](https://api.metacopier.io/rest/api/documentation/swagger-ui/index.html#/Account%20API/createAccount)

## How It Works

1. You send a `POST /accounts` request with a `callbackUrl` field in the body.
2. The API validates the request and returns **202 Accepted** immediately with a `requestId`.
3. The account is created in the background.
4. Once finished (success or failure), the result is **POSTed to your callback URL**.

> **Without** `callbackUrl`, the endpoint behaves exactly as before - synchronous, blocking until the account is created.

***

## Timeouts

| Mode                                              | Recommended Read Timeout     | Why                                                                                                                                             |
| ------------------------------------------------- | ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| **Sync** (`POST /accounts` without `callbackUrl`) | **100 seconds**              | The synchronous endpoint completes within 100 seconds. If it takes longer, the request is likely stuck.                                         |
| **Async** (`POST /accounts` with `callbackUrl`)   | **N/A**                      | The API returns `202 Accepted` instantly. The result arrives via callback - no timeout to worry about.                                          |
| **Polling** (`GET /accounts/async/{requestId}`)   | **300 seconds** (if waiting) | Async account creation includes internal retries and can take up to 300 seconds. Poll periodically until the status is `COMPLETED` or `FAILED`. |

> **Important**: The async flow internally retries broker connections and waits for system capacity, which is why it can take up to 300 seconds. This is handled entirely server-side - your client just needs to wait for the callback or poll.

***

## Quick Start

### 1. Create Account (Async)

```bash
curl -X POST https://api.metacopier.io/rest/api/backend/v1/accounts \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": { "id": 1 },
    "region": { "id": 1 },
    "loginServer": "ICMarketsSC-MT5-4",
    "loginAccountNumber": "12345678",
    "loginAccountPassword": "your_password",
    "callbackUrl": "https://your-server.com/webhook/account-created"
  }'
```

### Response - 202 Accepted

```json
{
  "requestId": "acc_a1b2c3d4e5f67890",
  "message": "Account creation request accepted. The result will be POSTed to the provided callback URL.",
  "callbackUrl": "https://your-server.com/webhook/account-created",
  "status": "QUEUED"
}
```

***

## Callback Payload

When the account creation completes, a **POST** request is sent to your `callbackUrl`.

### On Success

```json
{
  "requestId": "acc_a1b2c3d4e5f67890",
  "success": true,
  "account": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "type": { "id": 1, "name": "MT5" },
    "region": { "id": 1, "name": "New York" },
    "loginServer": "ICMarketsSC-MT5-4",
    "loginAccountNumber": "12345678",
    "accountInformation": {
      "connected": true
    }
  },
  "error": null
}
```

### On Failure

```json
{
  "requestId": "acc_a1b2c3d4e5f67890",
  "success": false,
  "account": null,
  "error": "[WRONG_CREDENTIALS]"
}
```

### Callback Headers

| Header         | Description                     |
| -------------- | ------------------------------- |
| `Content-Type` | `application/json`              |
| `X-Request-Id` | The `requestId` for correlation |

### Retry Policy

If your callback endpoint is unavailable, the request is retried:

* **3 attempts** total
* **Backoff**: 2 seconds after attempt 1, 4 seconds after attempt 2
* Each retry uses a **different IP address** (rotating proxy)

***

## Polling (Optional)

You can also poll for status instead of (or in addition to) using callbacks.

### Get Status of a Single Request

```bash
curl https://api.metacopier.io/rest/api/backend/v1/accounts/async/acc_a1b2c3d4e5f67890 \
  -H "Authorization: Bearer YOUR_API_KEY"
```

**Response:**

```json
{
  "requestId": "acc_a1b2c3d4e5f67890",
  "status": "COMPLETED",
  "account": { ... },
  "error": null
}
```

### Get All Async Requests

```bash
curl https://api.metacopier.io/rest/api/backend/v1/accounts/async \
  -H "Authorization: Bearer YOUR_API_KEY"
```

Returns an array of all tracked async requests for your project.

***

## Status Lifecycle

| Status       | Description                                             |
| ------------ | ------------------------------------------------------- |
| `QUEUED`     | Request accepted, waiting to be processed               |
| `PROCESSING` | Account is currently being created                      |
| `COMPLETED`  | Account created successfully (includes `account` field) |
| `FAILED`     | Account creation failed (includes `error` field)        |

> Statuses are retained for **1 hour** after completion, then automatically removed.

***

## Processing Rules

* **Sequential per project**: Only 1 account creation runs at a time per project. Additional requests are queued and processed in order.

***

## Callback URL Requirements

| Rule         | Details                                             |
| ------------ | --------------------------------------------------- |
| **Protocol** | `https://` or `http://`                             |
| **Format**   | Must be a valid URL                                 |
| **Method**   | Your endpoint must accept `POST` requests           |
| **Response** | Return any `2xx` status code to acknowledge receipt |

If the URL is invalid, the API returns `400 Bad Request` with one of:

* `[CALLBACK_URL_REQUIRED]` - field is present but empty
* `[CALLBACK_URL_INVALID]` - malformed URL
* `[CALLBACK_URL_INVALID_PROTOCOL]` - protocol is not http/https

***

## Error Codes

All standard `POST /accounts` errors apply. These are returned synchronously (before the 202) if validation fails:

| Error                                            | HTTP Status | Description                         |
| ------------------------------------------------ | ----------- | ----------------------------------- |
| `[CALLBACK_URL_INVALID]`                         | 400         | Malformed callback URL              |
| `[CALLBACK_URL_INVALID_PROTOCOL]`                | 400         | Callback URL must use http or https |
| `[REGION_NOT_FOUND]`                             | 404         | Invalid region ID                   |
| `[ACCOUNT_TYPE_NOT_FOUND]`                       | 404         | Invalid account type ID             |
| `[ACCOUNT_LEVEL_API_KEY_CANNOT_CREATE_ACCOUNTS]` | 403         | Must use a project-level API key    |

Errors that occur **during** async processing are delivered via the callback payload and the polling endpoint (status = `FAILED`).

***

## Example: Node.js Callback Server

```javascript
const express = require('express');
const app = express();
app.use(express.json());

app.post('/webhook/account-created', (req, res) => {
  const { requestId, success, account, error } = req.body;

  if (success) {
    console.log(`Account created: ${account.id} (request: ${requestId})`);
    // Store the account, update your database, etc.
  } else {
    console.error(`Account creation failed: ${error} (request: ${requestId})`);
    // Handle the error, notify your user, etc.
  }

  res.status(200).send('OK');
});

app.listen(3000);
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.metacopier.io/rest-api/api/async-account-creation.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
