> ## Documentation Index
> Fetch the complete documentation index at: https://developer.cartevo.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Enroll Customer

> Register a new customer using publicly accessible URLs to their KYC documents (JSON request body, no file upload).

## Overview

`POST /customers/enroll` registers a new customer in your company using **publicly accessible URLs** to the KYC documents instead of uploading the files directly. This is useful when documents are already hosted in your own object storage (S3, GCS, etc.). For local file uploads, use [`POST /customers`](/api-reference/endpoint/post-customers) instead.

The customer is enrolled with the upstream card issuer in the same call, so they become eligible for card issuance immediately on success (subject to KYC outcome).

## When to use it

| Use this endpoint when…                                            | Use `POST /customers` when…                           |
| ------------------------------------------------------------------ | ----------------------------------------------------- |
| Documents are already hosted at public HTTPS URLs (S3, GCS, etc.). | Documents are local files in your server.             |
| You prefer JSON-only requests (easier to log, audit, and replay).  | You want a single round-trip without first uploading. |

## Prerequisites

* Your company has completed KYB and is in `APPROVED` status.
* The document URLs must be reachable over HTTPS by the upstream verifier (which may fetch them more than once).

## Request

### Headers

| Name            | Required | Description             |
| --------------- | -------- | ----------------------- |
| `Authorization` | Yes      | `Bearer <access_token>` |
| `Content-Type`  | Yes      | `application/json`      |

### Body fields

| Field                   | Type          | Required | Constraints / notes                                       |
| ----------------------- | ------------- | -------- | --------------------------------------------------------- |
| `first_name`            | string        | Yes      | 3–255 chars                                               |
| `last_name`             | string        | Yes      | 3–255 chars                                               |
| `email`                 | string        | Yes      | Valid email                                               |
| `country`               | string        | Yes      | Full country name, e.g. `"Cameroon"`                      |
| `street`                | string        | Yes      | 2–255 chars                                               |
| `city`                  | string        | Yes      | 2–255 chars                                               |
| `state`                 | string        | Yes      | 2–255 chars                                               |
| `postal_code`           | string        | Yes      | 3–255 chars                                               |
| `country_iso_code`      | string        | Yes      | ISO 3166-1 alpha-2, e.g. `CM`, `NG`                       |
| `country_phone_code`    | string        | Yes      | Dial code with `+`, e.g. `+237`                           |
| `phone_number`          | string        | Yes      | Local subscriber number (no country code)                 |
| `identification_number` | string        | Yes      | Format depends on `id_document_type`                      |
| `id_document_type`      | string        | Yes      | Enum: `NIN`, `PASSPORT`, `VOTERS_CARD`, `DRIVERS_LICENSE` |
| `date_of_birth`         | string (date) | Yes      | `YYYY-MM-DD`. Customer must be 18+                        |
| `id_document_front_url` | string (URL)  | Yes      | Publicly fetchable HTTPS URL to the front of the ID       |
| `id_document_back_url`  | string (URL)  | Yes      | Publicly fetchable HTTPS URL to the back of the ID        |

### URL requirements

* **HTTPS only.** Plain HTTP URLs are rejected.
* **Reachable by the upstream verifier.** If the URL is gated (Basic Auth, IP allowlist, signed URL), the verifier will fail to fetch it.
* **Stable.** The verifier may fetch the URL multiple times during processing. Signed URLs with very short expiry windows are not recommended; use a TTL of at least 30 minutes.
* **Direct file URLs**, not landing pages. The response should be the image/PDF bytes with a correct `Content-Type` header.

### Example

```json theme={null}
{
  "first_name": "John",
  "last_name": "Doe",
  "email": "john.doe@example.com",
  "country": "Cameroon",
  "country_iso_code": "CM",
  "country_phone_code": "+237",
  "phone_number": "600000000",
  "street": "123 Main Street",
  "city": "Yaoundé",
  "state": "Centre",
  "postal_code": "00237",
  "identification_number": "12345678901",
  "id_document_type": "NIN",
  "date_of_birth": "1990-01-15",
  "id_document_front_url": "https://cdn.your-app.com/kyc/abc123/front.jpg",
  "id_document_back_url": "https://cdn.your-app.com/kyc/abc123/back.jpg"
}
```

## Response

### 201 — Customer enrolled

```json theme={null}
{
  "success": true,
  "statusCode": 201,
  "message": "Customer enrolled successfully",
  "data": {
    "id": "8d4f2a1b-5c3e-4d7f-9a6b-2e1c8f9d0a3b",
    "first_name": "John",
    "last_name": "Doe",
    "email": "john.doe@example.com",
    "country": "Cameroon",
    "street": "123 Main Street",
    "city": "Yaoundé",
    "state": "Centre",
    "postal_code": "00237",
    "phone_country_code": "+237",
    "phone_number": "600000000",
    "identification_number": "12345678901",
    "type": "NIN",
    "number": "12345678901",
    "image": "https://cdn.your-app.com/kyc/abc123/front.jpg",
    "photo": "https://cdn.your-app.com/kyc/abc123/back.jpg",
    "date_of_birth": "1990-01-15T00:00:00.000Z",
    "is_active": true,
    "created_at": "2026-05-09T10:15:00.000Z",
    "updated_at": "2026-05-09T10:15:00.000Z"
  }
}
```

See the [`POST /customers` field reference](/api-reference/endpoint/post-customers#field-reference) for descriptions — the response shape is identical.

### Error responses

| Status | `message` example                                 | Trigger                                                       |
| ------ | ------------------------------------------------- | ------------------------------------------------------------- |
| `400`  | `"id_document_front_url must be HTTPS"`           | A document URL uses `http://` instead of `https://`.          |
| `400`  | `"Customer must be 18 or older"`                  | `date_of_birth` is less than 18 years ago.                    |
| `409`  | `"Customer with this email or ID already exists"` | Duplicate `email` or `identification_number` in your company. |
| `422`  | `"Could not fetch id_document_front_url"`         | The verifier couldn't reach or download the URL.              |
| `422`  | `"KYC document unreadable"`                       | The verifier rejected the document quality.                   |

## Webhooks fired

* [`customer.created`](/api-reference/endpoint/webhook#customer-created) — emitted immediately after the customer record is persisted.

## Related

* [`POST /customers`](/api-reference/endpoint/post-customers) — file-upload variant (multipart/form-data).
* [`GET /customers/{id}`](/api-reference/endpoint/get-customer-by-id) — check the resulting customer record.


## OpenAPI

````yaml POST /customers/enroll
openapi: 3.1.0
info:
  title: Cartevo API
  description: Essential endpoints for wallets, transactions, customers and conversion.
  version: 1.0.0
servers:
  - url: https://api.cartevo.co/api/v1
security:
  - bearerAuth: []
paths:
  /customers/enroll:
    post:
      summary: Enroll new customer
      description: >-
        Register a new customer using ID document URLs instead of file uploads.
        This endpoint enrolls the customer on the provider platform.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - first_name
                - last_name
                - country
                - email
                - street
                - city
                - state
                - postal_code
                - country_iso_code
                - country_phone_code
                - phone_number
                - identification_number
                - id_document_type
                - date_of_birth
                - id_document_front_url
                - id_document_back_url
              properties:
                first_name:
                  type: string
                  minLength: 3
                  maxLength: 255
                  example: John
                last_name:
                  type: string
                  minLength: 3
                  maxLength: 255
                  example: Doe
                country:
                  type: string
                  minLength: 2
                  maxLength: 255
                  example: Nigeria
                email:
                  type: string
                  format: email
                  example: john.doe@example.com
                street:
                  type: string
                  minLength: 2
                  maxLength: 255
                  example: 123 Main Street
                city:
                  type: string
                  minLength: 2
                  maxLength: 255
                  example: Lagos
                state:
                  type: string
                  minLength: 2
                  maxLength: 255
                  example: Lagos State
                postal_code:
                  type: string
                  minLength: 3
                  maxLength: 255
                  example: '100001'
                country_iso_code:
                  type: string
                  minLength: 1
                  maxLength: 255
                  example: CM
                country_phone_code:
                  type: string
                  minLength: 1
                  maxLength: 255
                  example: '+234'
                phone_number:
                  type: string
                  minLength: 3
                  maxLength: 255
                  example: '8012345678'
                identification_number:
                  type: string
                  minLength: 1
                  maxLength: 255
                  example: '12345678901'
                id_document_front_url:
                  type: string
                  example: https://example.com/documents/front.jpg
                id_document_back_url:
                  type: string
                  example: https://example.com/documents/back.jpg
                id_document_type:
                  type: string
                  enum:
                    - NIN
                    - PASSPORT
                    - VOTERS_CARD
                    - DRIVERS_LICENSE
                  example: NIN
                date_of_birth:
                  type: string
                  format: date
                  example: '1990-01-15'
      responses:
        '201':
          description: Customer enrolled successfully
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/StandardResponse'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/CustomerResponseDto'
        '409':
          description: Customer with this email or ID already exists
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: false
                  statusCode:
                    type: integer
                    example: 409
                  message:
                    type: string
                    example: Customer with this email or ID already exists
                  error:
                    type: string
                    example: Conflict
components:
  schemas:
    StandardResponse:
      type: object
      properties:
        success:
          type: boolean
          example: true
        statusCode:
          type: integer
          example: 200
        message:
          type: string
          example: Data retrieved successfully
    CustomerResponseDto:
      type: object
      properties:
        id:
          type: string
          format: uuid
        first_name:
          type: string
        last_name:
          type: string
        country:
          type: string
        email:
          type: string
          format: email
        street:
          type: string
        city:
          type: string
        state:
          type: string
        postal_code:
          type: string
        phone_country_code:
          type: string
        phone_number:
          type: string
        identification_number:
          type: string
        type:
          type: string
        image:
          type: string
          nullable: true
        photo:
          type: string
          nullable: true
        number:
          type: string
        date_of_birth:
          type: string
          format: date-time
        is_active:
          type: boolean
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer

````