# API Integration

## Cost Units Public API <a href="#cost-units-public-api" id="cost-units-public-api"></a>

North's Cost Units feature enables you to track and manage custom cost metrics within your cloud financial operations. With the Public API, you can programmatically upload and retrieve cost unit data from outside the North UI, using secure API keys for authentication.

#### When to Use the Public API <a href="#when-to-use-the-public-api" id="when-to-use-the-public-api"></a>

Use the Public API when you want to:

* Automate recurring metric uploads from an internal data pipeline or warehouse
* Sync business metrics from a third-party system on a schedule
* Retrieve Cost Unit data programmatically for custom dashboards or reports
* Integrate metric uploads into CI/CD or ETL workflows

### Creating API Keys <a href="#creating-api-keys" id="creating-api-keys"></a>

Before you can use the Public API, you need to create an API key within the North application. API keys provide secure, programmatic access to your cost unit data without requiring interactive authentication.

#### Key Management in the North UI <a href="#key-management-in-the-north-ui" id="key-management-in-the-north-ui"></a>

To create an API key within the North application:

1. Navigate to the **Streams** tab in [app.north.cloud](http://app.north.cloud/)
2. Open the **API Keys** management section
3. Provide a **name** for the key (for example, "Production Pipeline" or "Weekly Sync")
4. Optionally set an **expiration date** (maximum 365 days from creation)
5. Click **Create**
6. **Copy and save the API key immediately.** The full key is only shown once at creation time and cannot be retrieved later.

API keys use the format `north_api_{secret_hash}`.

#### Viewing API Keys <a href="#viewing-api-keys" id="viewing-api-keys"></a>

The API Keys section displays all active keys for your organization, including:

* Key name
* Date created
* Expiration date (if set)
* Last used timestamp

#### Revoking API Keys <a href="#revoking-api-keys" id="revoking-api-keys"></a>

To revoke a key, click the delete action next to the key you want to remove. Revoked keys are immediately deactivated and can no longer be used to authenticate API requests.

**Important:** When you create a new API key, it will be displayed only once. Make sure to save it securely, as it cannot be retrieved later. If you lose an API key, you'll need to create a new one and revoke the old key.

Each API key is scoped to your organization and provides access to all cost units within your account. The key is validated on every API request to ensure secure access to your data.

### Public API Endpoints <a href="#public-api-endpoints" id="public-api-endpoints"></a>

The Public API provides two endpoints for interacting with your cost units:

* **GET /public/cost-units** - Retrieve existing cost unit data
* **POST /public/cost-units** - Update cost unit data with new metrics

**Note:** The Public API supports updating existing cost units only. To create new cost units, use the North UI or internal API endpoints.

### Authentication <a href="#authentication" id="authentication"></a>

All Public API requests require authentication using an API key. Include your API key in the `Authorization` header of each request:

`Authorization: ApiKey north_api_{your_key}`

The API key is validated on every request. Requests with missing, invalid, expired, or revoked keys will receive a `403` response.

Additionally, you must include your `account_number` as a query parameter in all requests. The API validates that the account number matches the organization associated with your API key.

#### Base URL <a href="#base-url" id="base-url"></a>

`https://api.north.cloud`

### GET /public/cost-units <a href="#get-public-cost-units" id="get-public-cost-units"></a>

Retrieve data from an existing cost unit.

`GET /public/cost-units`

#### Headers <a href="#headers" id="headers"></a>

| Header          | Required | Description                                                   |
| --------------- | -------- | ------------------------------------------------------------- |
| `Authorization` | Yes      | Your API key in the following format: `ApiKey <your-api-key>` |
| `Content-Type`  | No       | Content type (not required for GET requests)                  |

#### Query Parameters <a href="#query-parameters" id="query-parameters"></a>

| Parameter        | Required | Type   | Description                                                            |
| ---------------- | -------- | ------ | ---------------------------------------------------------------------- |
| `account_number` | Yes      | string | Your AWS account number (validated against the API key's organization) |
| `costUnitId`     | Yes      | string | <p>Cost unit identifier</p><p>(e.g., <code>bu-123:cu-456</code>)</p>   |

* &#x20;

#### Example Request <a href="#example-request" id="example-request"></a>

`GET /public/cost-units?account_number=123456789&costUnitId=bu-123:cu-456 Authorization: north_api_AbCdEfGhIjKlMnOpQrStUvWx`

#### Response <a href="#response" id="response"></a>

**Success (200 OK):**

{% code overflow="wrap" %}

```json
{ "status": "success", "message": "Cost unit retrieved successfully", "data": { "businessUnitId": "bu-123", "costUnitId": "cu-456", "status": "processed", "data": { "2024-01-01": { "metric": "100.50" }, "2024-01-02": { "metric": "150.75" } }, "errors": [], "warnings": [], "metadata": { "name": "Impressions", "type": "numerator", "granularity": "daily", "description": "Ad impressions" }, "createdAt": "2024-01-10T12:00:00", "updatedAt": "2024-01-15T08:30:00" }, "meta": { "count": 1, "scannedCount": 1 }, "error": null }
```

{% endcode %}

**Error Responses:**

* **400 Bad Request:** Missing required parameters, invalid format, or business unit ownership validation failed
* **401 Unauthorized:** Invalid or missing API key
* **403 Forbidden:** API key does not have access to the requested resource
* **500 Internal Server Error:** An internal error occurred while processing your request

### POST /public/cost-units <a href="#post-public-cost-units" id="post-public-cost-units"></a>

Update an existing cost unit with new data points. This endpoint supports both merging new data with existing data and completely replacing existing data.

`POST /public/cost-units`

#### Headers <a href="#headers.1" id="headers.1"></a>

| Header          | Required | Description                       |
| --------------- | -------- | --------------------------------- |
| `Authorization` | Yes      | Your API key: `ApiKey {your_key}` |
| `Content-Type`  | Yes      | Must be `application/json`        |

#### Query Parameters <a href="#query-parameters.1" id="query-parameters.1"></a>

| Parameter        | Required | Type    | Description                                                                         |
| ---------------- | -------- | ------- | ----------------------------------------------------------------------------------- |
| `account_number` | Yes      | string  | Your AWS account number (validated against the API key's organization)              |
| `replace`        | No       | boolean | When `true`, completely replaces existing data instead of merging. Default: `false` |

#### Request Body <a href="#request-body" id="request-body"></a>

| Field        | Required | Type   | Description                                                                 |
| ------------ | -------- | ------ | --------------------------------------------------------------------------- |
| `costUnitId` | Yes      | string | Cost unit identifier (required - updates only, no creation via public API). |
| `data`       | Yes      | array  | List of data points with date and metric values                             |

#### Data Point Structure <a href="#data-point-structure" id="data-point-structure"></a>

Each item in the `data` array must contain:

| Field    | Required | Type          | Description                                                  |
| -------- | -------- | ------------- | ------------------------------------------------------------ |
| `date`   | Yes      | string (date) | Date in YYYY-MM-DD format (e.g., "2024-01-15")               |
| `metric` | Yes      | string        | Metric value as string (will be validated as decimal number) |

#### Example Request <a href="#example-request.1" id="example-request.1"></a>

`POST /public/cost-units?account_number=123456789 Authorization: north_api_AbCdEfGhIjKlMnOpQrStUvWx Content-Type: application/json { "costUnitId": "bu-123:cu-456", "data": [ { "date": "2024-01-15", "metric": "100.50" } ] }`

#### Response <a href="#response.1" id="response.1"></a>

**Success (200 OK):**

{% code overflow="wrap" %}

```json
{ "status": "success", "message": "Cost unit processed successfully", "data": { "businessUnitId": "bu-123", "costUnitId": "cu-456", "dataPoints": 2, "errorsCount": 0, "warningsCount": 0, "errors": [], "warnings": [], "processedData": { "2024-01-15": { "metric": "100.50" }, "2024-01-16": { "metric": "150.75" } } } }
```

{% endcode %}

**Error Responses:**

* **400 Bad Request:** Missing required fields, invalid date format, invalid metric value, or business unit ownership validation failed
* **401 Unauthorized:** Invalid or missing API key
* **403 Forbidden:** API key does not have access to the requested resource
* **500 Internal Server Error:** An internal error occurred while processing your request

### Data Merging vs. Replacement <a href="#data-merging-vs.-replacement" id="data-merging-vs.-replacement"></a>

The POST endpoint supports two modes of operation:

* **Merge (default):** When `replace=false` or omitted, new data points are merged with existing data. If a date already exists, the new metric value will update the existing value.
* **Replace:** When `replace=true`, all existing data in the cost unit is completely replaced with the new data array. This is useful for removing dates from a cost unit by sending an array that excludes those dates.

**Tip:** Use `replace=true` when you want to ensure your cost unit contains exactly the data points you send, removing any dates that aren't included in your request.

### Data Validation Notes <a href="#data-validation-notes" id="data-validation-notes"></a>

When uploading data via the POST endpoint, keep in mind:

* `metadata` and `viewId` fields are ignored if provided. Existing metadata is preserved.
* Future dates are rejected. For daily granularity, the current date is also rejected.
* Duplicate dates within a single request are rejected.
* Metric values are rounded to 2 decimal places.

### Examples <a href="#examples" id="examples"></a>

#### Retrieve a Cost Unit <a href="#retrieve-a-cost-unit" id="retrieve-a-cost-unit"></a>

`curl -X GET \ "https://api.north.cloud/public/cost-units?account_number=123456789&costUnitId=bu-123:cu-456" \ -H "Authorization: ApiKey north_api_AbCdEfGhIjKlMnOpQrStUvWx"`

#### Upload Data to a Cost Unit <a href="#upload-data-to-a-cost-unit" id="upload-data-to-a-cost-unit"></a>

`curl -X POST \ "https://api.north.cloud/public/cost-units?account_number=123456789" \ -H "Authorization: ApiKey north_api_AbCdEfGhIjKlMnOpQrStUvWx" \ -H "Content-Type: application/json" \ -d '{ "costUnitId": "bu123:cu-456", "data": [ {"date": "2024-01-01", "metric": "1500.00"}, {"date": "2024-01-02", "metric": "1620.50"} ] }'`

### Best Practices <a href="#best-practices" id="best-practices"></a>

* **Secure Your API Keys:** Treat API keys like passwords. Store them securely and never commit them to version control or share them publicly.
* **Use Key Expiration:** Set expiration dates on your API keys to ensure regular rotation and limit exposure if a key is compromised.
* **Monitor Key Usage:** Regularly review your active API keys and revoke any that are no longer needed.
* **Validate Data Before Sending:** Ensure dates are in YYYY-MM-DD format and metric values are valid decimal numbers before making API calls.
* **Handle Errors Gracefully:** Implement proper error handling in your integration to handle authentication failures, validation errors, and rate limiting.


---

# 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.north.cloud/docs/features/coststreams/cost-units/api-integration.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.
