# Authentication

Fincore uses API-key authentication to obtain client credentials and JWT bearer
tokens. Monato provides the `clientId` and `x-api-key` during onboarding. Use
the bearer token for every protected Fincore endpoint.

## Integration flow

| Step | API contract | Authentication | Result |
|  --- | --- | --- | --- |
| 1 | [Retrieve client credentials](#retrieve-client-credentials) | `x-api-key` | Returns active client credentials. |
| 2 | [Create authentication token](#create-authentication-token) | `x-api-key` | Returns a JWT bearer token. |
| 3 | Any protected endpoint | `Authorization: Bearer <token>` | Executes the operation. |


## Step 1: Retrieve client credentials

Call [Retrieve client credentials](#retrieve-client-credentials)
with your `x-api-key`.

Save `client_secret` from the successful response. Store it securely, treat it
like a password, and never log it.

## Step 2: Create a bearer token

Call [Create authentication token](#create-authentication-token)
with the `client_secret` from step 1.

Save `token` from the successful response.

The token is valid for 24 hours. `expires_at` tells you when it stops working,
in Mexico City local time (UTC-6), and is returned **without** a UTC offset
even though `created_at` and `updated_at` in the same response include `-06:00`.
Parse it as UTC-6 or your expiry check will be off by six hours. See
[Timestamps and timezone](/products/fincore/guides/concepts#timestamps-and-timezone).

## Step 3: Call protected endpoints

Send the token in the `Authorization` header for protected operations. For
example, the next step in a standard integration is usually
[Retrieve SPEI participants](/products/fincore/guides/instruments#retrieve-spei-participants)
or [Retrieve client accounts](/products/fincore/guides/accounts#retrieve-client-accounts).

If a request returns `401 Unauthorized`, first confirm the request reached the
right environment and includes `Authorization: Bearer <token>`. Then create a
new token and retry once. If the new token also fails, verify that the client,
credential, token, and environment match.

## Error responses

Authentication endpoints and protected operations return the standard Fincore
error structure when the request can be processed. See
[Error catalog](/products/fincore/guides/error-catalog) for the response body schema and additional
error messages.

| HTTP | Applies to | Cause | Action |
|  --- | --- | --- | --- |
| `400` | Credentials, token creation | Missing or malformed request data, or the credential is inactive, deleted, or from another environment. | Validate UUIDs, required fields, and JSON syntax; confirm the credential is active and belongs to the same environment. |
| `401` | Credentials, token creation, protected endpoints | Missing, invalid, expired, or environment-mismatched API key or bearer token. | Check `Authorization` or `x-api-key`, regenerate the token, verify environment, or request credential rotation. |
| `404` | Credentials | Client or active credential was not found. | Confirm the `clientId` for the target environment. |
| `500` | Credentials, token creation | Unexpected server or downstream error. | Retry after confirming the operation is safe, then contact Monato with `client_id` and timestamp. |


## API contracts

### Retrieve client credentials

Endpoint: `GET /v1/clients/{clientId}/credentials`

Returns the active credentials associated with a client. Save `client_secret`
from the response and keep it server-side.

#### Headers

```json
{
  "type": "object",
  "required": [
    "x-api-key"
  ],
  "properties": {
    "x-api-key": {
      "type": "string",
      "description": "API key provided during onboarding.",
      "example": "your_api_key"
    }
  }
}
```

#### Path parameters

```json
{
  "type": "object",
  "properties": {
    "clientId": {
      "type": "string",
      "format": "uuid",
      "example": "c2d1d1e3-3340-4170-980e-e9269bbbc551",
      "description": "The unique identifier of the client."
    }
  },
  "required": [
    "clientId"
  ]
}
```

#### Request body

No request body.

#### Request example

#### 200 response body

```json
{
  "$ref": "#/components/schemas/CredentialsResponse",
  "components": {
    "schemas": {
      "Credential": {
        "type": "object",
        "required": [
          "id",
          "client_id",
          "client_secret",
          "environment",
          "status",
          "created_at",
          "updated_at",
          "deleted_at"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "The unique identifier of the credential.",
            "example": "e981c6d8-4d49-45f2-a7ee-f956dca15500"
          },
          "client_id": {
            "type": "string",
            "format": "uuid",
            "description": "The unique identifier of the client.",
            "example": "c2d1d1e3-3340-4170-980e-e9269bbbc551"
          },
          "client_secret": {
            "type": "string",
            "description": "Secret used with `client_id` to create a bearer token. Store it securely and never expose it in frontend code or logs.\n",
            "example": "client_secret_value"
          },
          "environment": {
            "type": "string",
            "enum": [
              "staging",
              "production"
            ],
            "description": "The environment in which the credentials are valid.",
            "example": "staging"
          },
          "status": {
            "type": "string",
            "enum": [
              "ACTIVE",
              "INACTIVE"
            ],
            "description": "The status of the credentials.",
            "example": "ACTIVE"
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp when the credentials were created.",
            "example": "2025-03-05T10:27:36.888241-06:00"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp when the credentials were last updated.",
            "example": "2025-03-05T10:27:36.888241-06:00"
          },
          "deleted_at": {
            "type": [
              "null",
              "string"
            ],
            "description": "Timestamp when the credentials were deleted, or null if still active.",
            "example": null
          },
          "api_key": {
            "type": "string",
            "description": "API key associated with the credentials when returned by the environment. Send this value in the `x-api-key` header for credential and token bootstrap calls.\n",
            "example": "api_key_value"
          }
        }
      },
      "CredentialsResponse": {
        "type": "object",
        "required": [
          "data"
        ],
        "properties": {
          "data": {
            "type": "array",
            "description": "Credentials associated with the client.",
            "items": {
              "$ref": "#/components/schemas/Credential"
            }
          }
        }
      }
    }
  }
}
```

#### Response example

```json 200 application/json
{
  "data": [
    {
      "id": "e981c6d8-4d49-45f2-a7ee-f956dca15500",
      "client_id": "c2d1d1e3-3340-4170-980e-e9269bbbc551",
      "client_secret": "client_secret_value",
      "environment": "production",
      "status": "ACTIVE",
      "created_at": "2025-03-05T10:27:36.888241-06:00",
      "updated_at": "2025-03-05T10:27:36.888241-06:00",
      "deleted_at": null,
      "api_key": "api_key_value"
    }
  ]
}
```

```json 400 application/json
{
  "code": 9,
  "message": "API Error",
  "details": [
    null
  ]
}
```

```json 401 application/json
{
  "code": 9,
  "message": "API Error",
  "details": [
    null
  ]
}
```

```json 404 application/json
{
  "code": 9,
  "message": "API Error",
  "details": [
    null
  ]
}
```

```json 500 application/json
{
  "code": 9,
  "message": "API Error",
  "details": [
    null
  ]
}
```

| Error | When it happens |
|  --- | --- |
| `400` | The `clientId` path parameter or request metadata is malformed. |
| `401` | The `x-api-key` is missing, invalid, or not valid for the environment. |
| `404` | No active credentials exist for the supplied `clientId`. |
| `500` | Unexpected server error. |


### Create authentication token

Endpoint: `POST /v1/clients/{clientId}/auth/credential-tokens`

Exchanges `client_secret` for the bearer token used by protected Fincore
operations.

#### Headers

```json
{
  "type": "object",
  "required": [
    "x-api-key"
  ],
  "properties": {
    "x-api-key": {
      "type": "string",
      "description": "API key provided during onboarding.",
      "example": "your_api_key"
    }
  }
}
```

#### Path parameters

```json
{
  "type": "object",
  "properties": {
    "clientId": {
      "type": "string",
      "format": "uuid",
      "description": "Unique identifier for the client."
    }
  },
  "required": [
    "clientId"
  ]
}
```

#### Request body

```json
{
  "$ref": "#/components/schemas/AuthCredentialRequest",
  "components": {
    "schemas": {
      "AuthCredentialRequest": {
        "type": "object",
        "description": "Credentials used to create a bearer token.",
        "required": [
          "client_id",
          "client_secret"
        ],
        "properties": {
          "client_id": {
            "type": "string",
            "description": "Client UUID associated with the credential.",
            "example": "c2d1d1e3-3340-4170-980e-e9269bbbc551"
          },
          "client_secret": {
            "type": "string",
            "description": "Client secret returned by the credential bootstrap endpoint.",
            "example": "your_client_secret_here"
          }
        }
      }
    }
  }
}
```

#### Request example

```json Payload application/json
{
  "client_id": "c2d1d1e3-3340-4170-980e-e9269bbbc551",
  "client_secret": "your_client_secret_here"
}
```

#### 200 response body

```json
{
  "$ref": "#/components/schemas/AuthCredentialResponse",
  "components": {
    "schemas": {
      "AuthCredentialResponse": {
        "type": "object",
        "description": "Bearer token issued for a client credential.",
        "required": [
          "id",
          "client_id",
          "client_credential_id",
          "token",
          "status",
          "expires_at",
          "created_at",
          "updated_at",
          "deleted_at"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Unique identifier of the generated credential token.",
            "example": "1307f4e3-3960-4b98-9a14-0b6839245cc9"
          },
          "client_id": {
            "type": "string",
            "format": "uuid",
            "description": "Client UUID associated with the token.",
            "example": "c2d1d1e3-3340-4170-980e-e9269bbbc551"
          },
          "client_credential_id": {
            "type": "string",
            "format": "uuid",
            "description": "Client credential UUID used to create the token.",
            "example": "e981c6d8-4d49-45f2-a7ee-f956dca15500"
          },
          "token": {
            "type": "string",
            "description": "JWT authentication token",
            "example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRfaWQiOiJjMmQxZDFlMy0zMzQwLTQxNzAtOTgwZS1lOTI2OWJiYmM1NTEiLCJleHAiOjE3NDEyODE0MTl9.ziSqMClLqwUVfyM15bqUF_7-PINY0ZiWkH01s8pO3gA"
          },
          "status": {
            "type": "string",
            "enum": [
              "ACTIVE",
              "INACTIVE"
            ],
            "description": "Token lifecycle status.",
            "example": "ACTIVE"
          },
          "expires_at": {
            "type": "string",
            "description": "Mexico City local time (UTC-6) when the token expires. Unlike the audit timestamps in this response, this value is returned without a UTC offset. Interpret it as UTC-6; do not treat it as UTC.\n",
            "example": "2025-03-06 11:16:59.491631"
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "Mexico City local time (UTC-6) when the token was created, including the `-06:00` offset.",
            "example": "2025-03-05 11:16:59.488685-06:00"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Mexico City local time (UTC-6) when the token was last updated, including the `-06:00` offset.",
            "example": "2025-03-05 11:16:59.488685-06:00"
          },
          "deleted_at": {
            "type": [
              "null",
              "string"
            ],
            "description": "Timestamp when the token was deleted, or null if active.",
            "example": null
          }
        }
      }
    }
  }
}
```

#### Response example

```json 200 application/json
{
  "id": "1307f4e3-3960-4b98-9a14-0b6839245cc9",
  "client_id": "c2d1d1e3-3340-4170-980e-e9269bbbc551",
  "client_credential_id": "e981c6d8-4d49-45f2-a7ee-f956dca15500",
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRfaWQiOiJjMmQxZDFlMy0zMzQwLTQxNzAtOTgwZS1lOTI2OWJiYmM1NTEiLCJleHAiOjE3NDEyODE0MTl9.ziSqMClLqwUVfyM15bqUF_7-PINY0ZiWkH01s8pO3gA",
  "status": "ACTIVE",
  "expires_at": "2025-03-06 11:16:59.491631",
  "created_at": "2025-03-05 11:16:59.488685-06:00",
  "updated_at": "2025-03-05 11:16:59.488685-06:00",
  "deleted_at": null
}
```

```json 400 application/json
{
  "code": 9,
  "message": "API Error",
  "details": [
    null
  ]
}
```

```json 401 application/json
{
  "code": 9,
  "message": "API Error",
  "details": [
    null
  ]
}
```

```json 500 application/json
{
  "code": 9,
  "message": "API Error",
  "details": [
    null
  ]
}
```

| Error | When it happens |
|  --- | --- |
| `400` | Required credential fields are missing or malformed. |
| `401` | The API key, client secret, or client relationship is invalid. |
| `500` | Unexpected server error. |