> For the complete documentation index, see [llms.txt](https://blufin360-api-documentation.gitbook.io/blufin360_api_documentation-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://blufin360-api-documentation.gitbook.io/blufin360_api_documentation-docs/getting-started/authentication.md).

# Authentication

Authenticate via the merchant login endpoint and generate a JWT access token for bluFin360 APIs.

Use this API authentication endpoint to sign in with email and password.

This is the access token generation flow for the merchant login API.

It returns a JWT `accessToken` for calling protected bluFin360 APIs.

Send the token as a Bearer token in the `Authorization` header.

### Endpoint (UAT / Staging)

**Base URL:** <mark style="color:$primary;">`https://authdev.blufin360.com`</mark>

**Method:** <mark style="color:$primary;">POST</mark>

**Path:** <mark style="color:$primary;">`/api/v1/merchants/login`</mark>

**Full URL:** <mark style="color:$primary;">`https://authdev.blufin360.com/api/v1/merchants/login`</mark>

### Example request

{% tabs %}
{% tab title="Shell" %}

```bash
curl --location 'https://authdev.blufin360.com/api/v1/merchants/login' \
  --header 'Content-Type: application/json' \
  --data-raw '{
    "email": "name@company.co",
    "password": "#Admin123"
  }'
```

{% endtab %}

{% tab title="Node" %}

```javascript
const url = "https://authdev.blufin360.com/api/v1/merchants/login";

const res = await fetch(url, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    email: "name@company.co",
    password: "#Admin123",
  }),
});

const data = await res.json();
console.log(data.accessToken);
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

url = "https://authdev.blufin360.com/api/v1/merchants/login"
payload = {"email": "name@company.co", "password": "#Admin123"}

resp = requests.post(url, json=payload, headers={"Content-Type": "application/json"})
data = resp.json()
print(data["accessToken"])
```

{% endtab %}

{% tab title="Go" %}

```go
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
)

func main() {
	url := "https://authdev.blufin360.com/api/v1/merchants/login"

	payload := map[string]string{
		"email":    "name@company.co",
		"password": "#Admin123",
	}

	b, _ := json.Marshal(payload)

	req, _ := http.NewRequest("POST", url, bytes.NewBuffer(b))
	req.Header.Set("Content-Type", "application/json")

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	body, _ := io.ReadAll(resp.Body)
	fmt.Println(string(body))
}
```

{% endtab %}

{% tab title="Java" %}

```java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class Main {
  public static void main(String[] args) throws Exception {
    String url = "https://authdev.blufin360.com/api/v1/merchants/login";
    String json = "{\"email\":\"name@company.co\",\"password\":\"#Admin123\"}";

    HttpRequest request = HttpRequest.newBuilder()
      .uri(URI.create(url))
      .header("Content-Type", "application/json")
      .POST(HttpRequest.BodyPublishers.ofString(json))
      .build();

    HttpClient client = HttpClient.newHttpClient();
    HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());

    System.out.println(response.body());
  }
}
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php

$url = "https://authdev.blufin360.com/api/v1/merchants/login";
$payload = json_encode([
  "email" => "name@company.co",
  "password" => "#Admin123",
]);

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Content-Type: application/json"]);
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
```

{% endtab %}
{% endtabs %}

### Request headers

| Header       | Type     | Required | Description                                  |
| ------------ | -------- | -------- | -------------------------------------------- |
| Content-Type | `string` | ✅        | Request body format. Use `application/json`. |

### Request body fields

| Field    | Type     | Required | Description                  |
| -------- | -------- | -------- | ---------------------------- |
| email    | `string` | ✅        | Merchant user email address. |
| password | `string` | ✅        | Merchant user password.      |

### Success response — 200 (example)

```json
{
  "message": "Login successful.",
  "user": {
    "createdAt": "2025-09-18T05:46:32.875Z",
    "updatedAt": "2025-09-18T05:46:32.875Z",
    "id": "8af55aa3-55cf-43d1-95ee-10d0692e2239",
    "fullName": "USER NAME",
    "email": "name@company.co",
    "contactNumber": "98765XXXXX",
    "companyName": "Company name",
    "type": "merchant"
  },
  "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI4YWY1NWFhMy01NWNmLTQzZDEtOTVlZS0xMGQwNjkyZTIyMzkiLCJlbWFpbCI6Imtpc2hvcmVAYmx1c3dhcC5jbyIsImlhdCI6MTc3MDIxMjU0NiwiZXhwIjoxNzcwMjMwNTQ2fQ.Jkj6C0dCU28mUUlBVNr4Vlw01BGkTS0j7IHegWvbAt4",
  "is_kyc_approved": true
}
```

The `accessToken` is a JWT.

Use it for API calls like this:

`Authorization: Bearer <accessToken>`

### Response fields

| Field             | Type           | Description                              |
| ----------------- | -------------- | ---------------------------------------- |
| message           | `string`       | Login status message.                    |
| user              | `object`       | Authenticated user details               |
| accessToken       | `string (JWT)` | JWT access token for API authentication. |
| is\_kyc\_approved | `boolean`      | KYC approval status for this merchant.   |

### User object schema

| Field         | Type                | Description                           |
| ------------- | ------------------- | ------------------------------------- |
| id            | `string (UUID)`     | Unique user identifier.               |
| fullName      | `string`            | Registered user name.                 |
| email         | `string`            | User email address.                   |
| contactNumber | `string`            | Registered mobile number.             |
| companyName   | `string`            | Associated business name.             |
| type          | `string`            | User classification, like `merchant`. |
| createdAt     | `string (ISO 8601)` | Account creation timestamp.           |
| updatedAt     | `string (ISO 8601)` | Last profile update timestamp.        |

### Notes for integration

* Generate a new access token after each successful login.
* Treat the JWT access token as a secret. Do not expose it in client apps.
* Use a fresh token for server-to-server API calls.

### Next steps

Use the Bearer token with these endpoints:

* [Penny Drop](/blufin360_api_documentation-docs/bank-verification/penny-drop.md)
* [Penny Less](/blufin360_api_documentation-docs/bank-verification/penny-less.md)
