{
  "openapi": "3.0.3",
  "info": {
    "title": "Phone Validation API",
    "version": "1.0.0",
    "description": "## Quick Start\n\n1. Get your `client_id` and `client_secret` from [OmaxTelecom Console](https://console.omaxtelecom.com)\n2. Run **Auth → Get Access Token** to obtain a Bearer token\n3. All other endpoints use the `access_token` in the `Authorization` header\n\n## Authentication (OAuth 2.0)\n\nThis API uses the **OAuth 2.0 Client Credentials** grant type ([RFC 6749 §4.4](https://datatracker.ietf.org/doc/html/rfc6749#section-4.4)).\n\n**Token endpoint:**\n\n```\nPOST https://api.omaxtelecom.com/auth/token\n```\n\nSend `Authorization: Bearer <access_token>` on all endpoints except health.\n\nFor M2M clients without an `organization` claim, include `X-Organization-Id: <organization_id>`.\n\nPartner API for phone number validation. Supports E.164 or national format with optional region.\n\n## Billing\n\nWhen `price_per_validation` > 0, each validation is charged via Console Wallet API, including repeat validations for the same number.\n\n## Response envelope\n\nSuccess: `{ \"success\": true, \"data\": { ... } }`\n\nError: `{ \"success\": false, \"error\": { \"code\": \"...\", \"message\": \"...\" } }`"
  },
  "tags": [
    {
      "name": "Auth",
      "description": "OAuth 2.0 authentication using the **Client Credentials** grant type ([RFC 6749 §4.4](https://datatracker.ietf.org/doc/html/rfc6749#section-4.4)). Use your **Client ID** and **Client Secret** from [OmaxTelecom Console](https://console.omaxtelecom.com) to obtain an access token."
    },
    {
      "name": "Phone Validation",
      "description": "Single and bulk phone number validation"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "paths": {
    "/auth/token": {
      "servers": [
        {
          "url": "https://api.omaxtelecom.com"
        }
      ],
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Get Access Token",
        "description": "## Get Access Token\n\nObtain a Bearer access token using the OAuth 2.0 **Client Credentials** grant ([RFC 6749 §4.4](https://datatracker.ietf.org/doc/html/rfc6749#section-4.4)).\n\n### Setup\n\n1. Get your `client_id` from [OmaxTelecom Console](https://console.omaxtelecom.com)\n2. Get your `client_secret` from [OmaxTelecom Console](https://console.omaxtelecom.com)\n\n### Request\n\n```\nPOST https://api.omaxtelecom.com/auth/token\nContent-Type: application/x-www-form-urlencoded\n\ngrant_type=client_credentials&client_id={client_id}&client_secret={client_secret}\n```\n\n### Response (200 OK)\n\n```json\n{\n  \"access_token\": \"eyJhbGciOiJSUzI1NiIs...\",\n  \"expires_in\": 300,\n  \"token_type\": \"Bearer\",\n  \"scope\": \"openid\"\n}\n```\n\n### Token Usage\n\nInclude the token in the `Authorization` header:\n\n```\nAuthorization: Bearer {access_token}\n```",
        "requestBody": {
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "properties": {
                  "grant_type": {
                    "type": "string",
                    "description": "OAuth 2.0 grant type (RFC 6749 §4.4)",
                    "example": "client_credentials"
                  },
                  "client_id": {
                    "type": "string",
                    "description": "Your Client ID",
                    "example": "{{client_id}}"
                  },
                  "client_secret": {
                    "type": "string",
                    "description": "Your Client Secret",
                    "example": "{{client_secret}}"
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "noauthAuth": []
          }
        ],
        "parameters": [
          {
            "name": "Content-Type",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "example": "application/x-www-form-urlencoded"
          },
          {
            "name": "Accept",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "example": "application/json"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {}
            }
          }
        }
      }
    },
    "/phone-validation/health": {
      "get": {
        "tags": [
          "Phone Validation"
        ],
        "summary": "Service health",
        "description": "Public endpoint. Returns whether the service is globally operational. No authentication required.",
        "operationId": "getPhoneValidationHealth",
        "security": [],
        "responses": {
          "200": {
            "description": "Service is operational",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceHealthResponse"
                },
                "example": {
                  "ok": true,
                  "timestamp": "2026-08-20T16:42:00+00:00"
                }
              }
            }
          },
          "503": {
            "description": "Service is unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceHealthResponse"
                },
                "example": {
                  "ok": false,
                  "timestamp": "2026-08-20T16:42:00+00:00"
                }
              }
            }
          }
        }
      },
      "servers": [
        {
          "url": "https://api.omaxtelecom.com/numbers",
          "description": "Phone Validation API"
        }
      ]
    },
    "/phone-validation": {
      "post": {
        "tags": [
          "Phone Validation"
        ],
        "summary": "Validate a single phone number",
        "description": "Validates a phone number in E.164 format or national format with an optional region code. When billing applies, each request is charged individually.",
        "operationId": "validatePhoneNumber",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SinglePhoneValidationRequest"
              },
              "examples": {
                "e164": {
                  "summary": "Validate E.164 number",
                  "value": {
                    "phone_number": "+38766000111",
                    "locale": "en"
                  }
                },
                "national": {
                  "summary": "Validate national number with region",
                  "value": {
                    "phone_number": "066000111",
                    "region": "BA",
                    "locale": "en"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Validation completed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SinglePhoneValidationSuccessResponse"
                },
                "examples": {
                  "validMobile": {
                    "summary": "Valid mobile number",
                    "value": {
                      "success": true,
                      "data": {
                        "valid": true,
                        "possible": true,
                        "phone_number": "+38766000111",
                        "national_format": "066 000-111",
                        "country_code": "BA",
                        "calling_code": "387",
                        "number_type": "MOBILE",
                        "geocoder": {
                          "description": "Bosnia and Herzegovina",
                          "locale": "en"
                        },
                        "time_zones": [
                          "Europe/Sarajevo"
                        ],
                        "carrier": {
                          "name": "BH Telecom",
                          "locale": "en"
                        }
                      }
                    }
                  },
                  "invalidNumber": {
                    "summary": "Invalid number",
                    "value": {
                      "success": true,
                      "data": {
                        "valid": false,
                        "possible": false,
                        "phone_number": "+15551234567",
                        "national_format": "(555) 123-4567",
                        "country_code": "US",
                        "calling_code": "1",
                        "number_type": "UNKNOWN"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenOrganization"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          }
        }
      },
      "servers": [
        {
          "url": "https://api.omaxtelecom.com/numbers",
          "description": "Phone Validation API"
        }
      ]
    },
    "/phone-validation/bulk": {
      "post": {
        "tags": [
          "Phone Validation"
        ],
        "summary": "Create bulk validation job",
        "description": "Queues an asynchronous bulk validation job. Returns a `job_id` that can be polled via `GET /phone-validation/bulk/{job_id}`.",
        "operationId": "createBulkPhoneValidation",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BulkPhoneValidationRequest"
              },
              "example": {
                "locale": "en",
                "validations": [
                  {
                    "phone_number": "+38766000111"
                  },
                  {
                    "phone_number": "066000111",
                    "region": "BA"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Bulk job accepted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkPhoneValidationAcceptedResponse"
                },
                "example": {
                  "success": true,
                  "data": {
                    "job_id": "9f3c2b1a-7d6e-4f5a-8b9c-0d1e2f3a4b5c"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenOrganization"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          }
        }
      },
      "servers": [
        {
          "url": "https://api.omaxtelecom.com/numbers",
          "description": "Phone Validation API"
        }
      ]
    },
    "/phone-validation/bulk/{job_id}": {
      "get": {
        "tags": [
          "Phone Validation"
        ],
        "summary": "Get bulk validation job status",
        "description": "Returns the current status and per-number results for a bulk validation job. Poll until `status` is `completed` or `failed`.",
        "operationId": "getBulkPhoneValidationJob",
        "parameters": [
          {
            "name": "job_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "example": "9f3c2b1a-7d6e-4f5a-8b9c-0d1e2f3a4b5c"
          }
        ],
        "responses": {
          "200": {
            "description": "Job status and results",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkPhoneValidationJobResponse"
                },
                "examples": {
                  "processing": {
                    "summary": "Job in progress",
                    "value": {
                      "success": true,
                      "data": {
                        "job_id": "9f3c2b1a-7d6e-4f5a-8b9c-0d1e2f3a4b5c",
                        "status": "processing",
                        "total_count": 2,
                        "processed_count": 1,
                        "failed_count": 0,
                        "items": [
                          {
                            "phone_number": "+38766000111",
                            "region": null,
                            "locale": "en",
                            "status": "completed",
                            "result": {
                              "valid": true,
                              "possible": true,
                              "phone_number": "+38766000111",
                              "national_format": "066 000-111",
                              "country_code": "BA",
                              "calling_code": "387",
                              "number_type": "MOBILE",
                              "geocoder": {
                                "description": "Bosnia and Herzegovina",
                                "locale": "en"
                              },
                              "time_zones": [
                                "Europe/Sarajevo"
                              ],
                              "carrier": {
                                "name": "BH Telecom",
                                "locale": "en"
                              }
                            },
                            "error": null
                          },
                          {
                            "phone_number": "066000111",
                            "region": "BA",
                            "locale": "en",
                            "status": "pending",
                            "result": null,
                            "error": null
                          }
                        ]
                      }
                    }
                  },
                  "completed": {
                    "summary": "Job completed",
                    "value": {
                      "success": true,
                      "data": {
                        "job_id": "9f3c2b1a-7d6e-4f5a-8b9c-0d1e2f3a4b5c",
                        "status": "completed",
                        "total_count": 2,
                        "processed_count": 2,
                        "failed_count": 0,
                        "items": [
                          {
                            "phone_number": "+38766000111",
                            "region": null,
                            "locale": "en",
                            "status": "completed",
                            "result": {
                              "valid": true,
                              "possible": true,
                              "phone_number": "+38766000111",
                              "national_format": "066 000-111",
                              "country_code": "BA",
                              "calling_code": "387",
                              "number_type": "MOBILE"
                            },
                            "error": null
                          },
                          {
                            "phone_number": "066000111",
                            "region": "BA",
                            "locale": "en",
                            "status": "completed",
                            "result": {
                              "valid": true,
                              "possible": true,
                              "phone_number": "+38766000111",
                              "national_format": "066 000-111",
                              "country_code": "BA",
                              "calling_code": "387",
                              "number_type": "MOBILE"
                            },
                            "error": null
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenOrganization"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "servers": [
        {
          "url": "https://api.omaxtelecom.com/numbers",
          "description": "Phone Validation API"
        }
      ]
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "OmaxTelecom ID access token issued for your organization."
      },
      "noauthAuth": {
        "type": "http",
        "scheme": "noauth"
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "Missing or invalid token",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "success": false,
              "error": {
                "code": "UNAUTHORIZED",
                "message": "Missing or invalid Authorization header."
              }
            }
          }
        }
      },
      "PaymentRequired": {
        "description": "Insufficient wallet balance",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "success": false,
              "error": {
                "code": "INSUFFICIENT_BALANCE",
                "message": "Insufficient wallet balance."
              }
            }
          }
        }
      },
      "ForbiddenOrganization": {
        "description": "Organization invalid, service disabled, or billing not configured",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "examples": {
              "organizationNotFound": {
                "value": {
                  "success": false,
                  "error": {
                    "code": "ORGANIZATION_NOT_FOUND",
                    "message": "Organization not found."
                  }
                }
              },
              "disabled": {
                "value": {
                  "success": false,
                  "error": {
                    "code": "PHONE_VALIDATION_DISABLED",
                    "message": "Phone validation is not enabled for this organization."
                  }
                }
              },
              "billing": {
                "value": {
                  "success": false,
                  "error": {
                    "code": "BILLING_NOT_CONFIGURED",
                    "message": "Billing is not configured for this organization."
                  }
                }
              }
            }
          }
        }
      },
      "ValidationError": {
        "description": "Request validation or parse error",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "success": false,
              "error": {
                "code": "VALIDATION_ERROR",
                "message": "The phone number field format is invalid."
              }
            }
          }
        }
      },
      "NotFound": {
        "description": "Job not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "success": false,
              "error": {
                "code": "NOT_FOUND",
                "message": "Bulk validation job not found."
              }
            }
          }
        }
      }
    },
    "schemas": {
      "SinglePhoneValidationRequest": {
        "type": "object",
        "required": [
          "phone_number"
        ],
        "properties": {
          "phone_number": {
            "type": "string",
            "description": "Phone number in E.164 format or national format",
            "example": "+38766000111"
          },
          "region": {
            "type": "string",
            "description": "ISO 3166-1 alpha-2 region code, required for non-E.164 numbers",
            "example": "BA"
          },
          "locale": {
            "type": "string",
            "description": "Locale for geocoder and carrier mapping",
            "example": "en"
          }
        }
      },
      "BulkPhoneValidationRequest": {
        "type": "object",
        "required": [
          "validations"
        ],
        "properties": {
          "locale": {
            "type": "string",
            "description": "Default locale for all items",
            "example": "en"
          },
          "validations": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/SinglePhoneValidationRequest"
            }
          }
        }
      },
      "PhoneValidationResult": {
        "type": "object",
        "properties": {
          "valid": {
            "type": "boolean"
          },
          "possible": {
            "type": "boolean"
          },
          "phone_number": {
            "type": "string"
          },
          "national_format": {
            "type": "string"
          },
          "country_code": {
            "type": "string"
          },
          "calling_code": {
            "type": "string"
          },
          "number_type": {
            "type": "string"
          },
          "geocoder": {
            "type": "object",
            "properties": {
              "description": {
                "type": "string"
              },
              "locale": {
                "type": "string"
              }
            }
          },
          "time_zones": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "carrier": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "locale": {
                "type": "string"
              }
            }
          }
        }
      },
      "SinglePhoneValidationSuccessResponse": {
        "type": "object",
        "required": [
          "success",
          "data"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "data": {
            "$ref": "#/components/schemas/PhoneValidationResult"
          }
        }
      },
      "BulkPhoneValidationAcceptedResponse": {
        "type": "object",
        "required": [
          "success",
          "data"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "data": {
            "type": "object",
            "required": [
              "job_id"
            ],
            "properties": {
              "job_id": {
                "type": "string",
                "format": "uuid"
              }
            }
          }
        }
      },
      "BulkPhoneValidationJobResponse": {
        "type": "object",
        "required": [
          "success",
          "data"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "data": {
            "type": "object",
            "required": [
              "job_id",
              "status",
              "total_count",
              "processed_count",
              "failed_count",
              "items"
            ],
            "properties": {
              "job_id": {
                "type": "string",
                "format": "uuid"
              },
              "status": {
                "type": "string",
                "enum": [
                  "pending",
                  "processing",
                  "completed",
                  "failed"
                ]
              },
              "total_count": {
                "type": "integer"
              },
              "processed_count": {
                "type": "integer"
              },
              "failed_count": {
                "type": "integer"
              },
              "items": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "phone_number": {
                      "type": "string"
                    },
                    "region": {
                      "type": "string",
                      "nullable": true
                    },
                    "locale": {
                      "type": "string",
                      "nullable": true
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "pending",
                        "completed",
                        "failed"
                      ]
                    },
                    "result": {
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/PhoneValidationResult"
                        }
                      ],
                      "nullable": true
                    },
                    "error": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              }
            }
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "required": [
          "success",
          "error"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "enum": [
              false
            ]
          },
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              }
            }
          }
        }
      },
      "ServiceHealthResponse": {
        "type": "object",
        "required": [
          "ok",
          "timestamp"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "description": "Whether the service is globally operational"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time",
            "description": "UTC timestamp of the health check"
          }
        }
      }
    }
  }
}
