{
  "openapi": "3.0.0",
  "info": {
    "title": "OurByt public API",
    "version": "1.0.0",
    "description": "Read-only, no sign-in: eSIM data destinations with prices, and the countries where OurByt sells phone numbers. Buying happens in the OurByt app. Requests are rate limited.",
    "contact": {
      "email": "support@ourbyt.com",
      "url": "https://ourbyt.com/developers"
    }
  },
  "servers": [
    {
      "url": "https://api.ourbyt.com",
      "description": "Production"
    }
  ],
  "externalDocs": {
    "url": "https://ourbyt.com/developers"
  },
  "paths": {
    "/v1/health": {
      "get": {
        "operationId": "getHealth",
        "parameters": [],
        "responses": {
          "200": {
            "description": "The Health Check is successful",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "enum": [
                        "ok",
                        "degraded"
                      ],
                      "example": "ok"
                    },
                    "info": {
                      "type": "object",
                      "example": {
                        "database": {
                          "status": "up",
                          "responseTime": 12
                        }
                      },
                      "additionalProperties": {
                        "type": "object",
                        "required": [
                          "status"
                        ],
                        "properties": {
                          "status": {
                            "type": "string",
                            "enum": [
                              "up",
                              "degraded",
                              "down"
                            ]
                          },
                          "responseTime": {
                            "type": "number",
                            "description": "Time the health indicator took to respond, in ms"
                          }
                        },
                        "additionalProperties": true
                      },
                      "nullable": true
                    },
                    "error": {
                      "type": "object",
                      "example": {},
                      "additionalProperties": {
                        "type": "object",
                        "required": [
                          "status"
                        ],
                        "properties": {
                          "status": {
                            "type": "string",
                            "enum": [
                              "up",
                              "degraded",
                              "down"
                            ]
                          },
                          "responseTime": {
                            "type": "number",
                            "description": "Time the health indicator took to respond, in ms"
                          }
                        },
                        "additionalProperties": true
                      },
                      "nullable": true
                    },
                    "details": {
                      "type": "object",
                      "example": {
                        "database": {
                          "status": "up",
                          "responseTime": 12
                        }
                      },
                      "additionalProperties": {
                        "type": "object",
                        "required": [
                          "status"
                        ],
                        "properties": {
                          "status": {
                            "type": "string",
                            "enum": [
                              "up",
                              "degraded",
                              "down"
                            ]
                          },
                          "responseTime": {
                            "type": "number",
                            "description": "Time the health indicator took to respond, in ms"
                          }
                        },
                        "additionalProperties": true
                      }
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "The Health Check is not successful",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "enum": [
                        "error",
                        "shutting_down"
                      ],
                      "example": "error"
                    },
                    "info": {
                      "type": "object",
                      "example": {
                        "database": {
                          "status": "up",
                          "responseTime": 12
                        }
                      },
                      "additionalProperties": {
                        "type": "object",
                        "required": [
                          "status"
                        ],
                        "properties": {
                          "status": {
                            "type": "string",
                            "enum": [
                              "up",
                              "degraded",
                              "down"
                            ]
                          },
                          "responseTime": {
                            "type": "number",
                            "description": "Time the health indicator took to respond, in ms"
                          }
                        },
                        "additionalProperties": true
                      },
                      "nullable": true
                    },
                    "error": {
                      "type": "object",
                      "example": {
                        "redis": {
                          "status": "down",
                          "message": "Could not connect",
                          "responseTime": 3005
                        }
                      },
                      "additionalProperties": {
                        "type": "object",
                        "required": [
                          "status"
                        ],
                        "properties": {
                          "status": {
                            "type": "string",
                            "enum": [
                              "up",
                              "degraded",
                              "down"
                            ]
                          },
                          "responseTime": {
                            "type": "number",
                            "description": "Time the health indicator took to respond, in ms"
                          }
                        },
                        "additionalProperties": true
                      },
                      "nullable": true
                    },
                    "details": {
                      "type": "object",
                      "example": {
                        "database": {
                          "status": "up",
                          "responseTime": 12
                        },
                        "redis": {
                          "status": "down",
                          "message": "Could not connect",
                          "responseTime": 3005
                        }
                      },
                      "additionalProperties": {
                        "type": "object",
                        "required": [
                          "status"
                        ],
                        "properties": {
                          "status": {
                            "type": "string",
                            "enum": [
                              "up",
                              "degraded",
                              "down"
                            ]
                          },
                          "responseTime": {
                            "type": "number",
                            "description": "Time the health indicator took to respond, in ms"
                          }
                        },
                        "additionalProperties": true
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "summary": "Liveness + dependency health (db, redis)",
        "tags": [
          "health"
        ]
      }
    },
    "/v1/catalogue/destinations": {
      "get": {
        "operationId": "listDestinations",
        "parameters": [
          {
            "name": "kind",
            "required": false,
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/DestinationKind"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DestinationListDto"
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_FAILED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponseDto"
                }
              }
            }
          }
        },
        "summary": "Destinations with a from price",
        "tags": [
          "catalogue"
        ]
      }
    },
    "/v1/catalogue/destinations/{id}": {
      "get": {
        "operationId": "getDestination",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DestinationDto"
                }
              }
            }
          },
          "404": {
            "description": "DESTINATION_NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponseDto"
                }
              }
            }
          }
        },
        "summary": "One destination",
        "tags": [
          "catalogue"
        ]
      }
    },
    "/v1/catalogue/photos/{slot}": {
      "get": {
        "operationId": "getDestinationPhoto",
        "parameters": [
          {
            "name": "slot",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The photo. Cache it for good: the URL changes with the photo."
          },
          "404": {
            "description": "PHOTO_NOT_FOUND",
            "content": {
              "image/webp": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponseDto"
                }
              },
              "image/jpeg": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponseDto"
                }
              }
            }
          }
        },
        "summary": "A destination photo (the URL in a destination's `image`)",
        "tags": [
          "catalogue"
        ]
      }
    },
    "/v1/numbers/countries": {
      "get": {
        "operationId": "listNumberCountries",
        "parameters": [],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NumberCountryListDto"
                }
              }
            }
          }
        },
        "summary": "Countries where numbers are sold",
        "tags": [
          "numbers"
        ]
      }
    },
    "/v1/numbers/countries/{code}": {
      "get": {
        "operationId": "getNumberCountry",
        "parameters": [
          {
            "name": "code",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NumberCountryDto"
                }
              }
            }
          },
          "404": {
            "description": "NUMBER_COUNTRY_NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponseDto"
                }
              }
            }
          }
        },
        "summary": "One country and its number types",
        "tags": [
          "numbers"
        ]
      }
    },
    "/v1/numbers/countries/{code}/types": {
      "get": {
        "operationId": "listNumberTypes",
        "parameters": [
          {
            "name": "code",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NumberTypeOptionListDto"
                }
              }
            }
          },
          "404": {
            "description": "NUMBER_COUNTRY_NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponseDto"
                }
              }
            }
          }
        },
        "summary": "Number types offered in a country",
        "tags": [
          "numbers"
        ]
      }
    }
  },
  "components": {
    "schemas": {
      "CoveredCountryDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "example": "ES",
            "description": "ISO 3166-1 alpha-2."
          },
          "name": {
            "type": "string",
            "example": "Spain",
            "description": "English name, for display and search."
          }
        },
        "required": [
          "code",
          "name"
        ]
      },
      "DestinationDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "jp",
            "description": "Destination code: ISO2 lowercase, a region or `global`."
          },
          "name": {
            "type": "string",
            "example": "Japan"
          },
          "kind": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DestinationKind"
              }
            ]
          },
          "countryCode": {
            "type": "object",
            "example": "JP",
            "nullable": true,
            "description": "ISO2 for a country."
          },
          "coverageCount": {
            "type": "integer",
            "example": 1,
            "description": "Number of countries covered."
          },
          "coverage": {
            "description": "The countries covered, sorted by name: lets the app find Spain inside Europe.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CoveredCountryDto"
            }
          },
          "fromPrice": {
            "description": "Cheapest active package for this destination.",
            "allOf": [
              {
                "$ref": "#/components/schemas/MoneyDto"
              }
            ]
          },
          "popular": {
            "type": "boolean"
          },
          "image": {
            "nullable": true,
            "description": "Photo for headers and tiles; null when none ships (show the flag instead).",
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/DestinationImageDto"
              }
            ]
          }
        },
        "required": [
          "id",
          "name",
          "kind",
          "coverageCount",
          "coverage",
          "fromPrice",
          "popular"
        ]
      },
      "DestinationImageDto": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "example": "/v1/catalogue/photos/jp?v=3f2a9c01de",
            "description": "A path on this API (resolve it against the API origin) or a full CDN URL. Changes when the photo does: cache it for good."
          },
          "focalX": {
            "type": "number",
            "example": 0.5,
            "description": "Focal point across, 0 (left) to 1 (right)."
          },
          "focalY": {
            "type": "number",
            "example": 0.4,
            "description": "Focal point down, 0 (top) to 1 (bottom)."
          }
        },
        "required": [
          "url",
          "focalX",
          "focalY"
        ]
      },
      "DestinationKind": {
        "type": "string",
        "enum": [
          "country",
          "region",
          "global"
        ]
      },
      "DestinationListDto": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DestinationDto"
            }
          }
        },
        "required": [
          "items"
        ]
      },
      "ErrorBodyDto": {
        "type": "object",
        "properties": {
          "code": {
            "example": "NOT_FOUND",
            "allOf": [
              {
                "$ref": "#/components/schemas/ErrorCode"
              }
            ]
          },
          "message": {
            "type": "string",
            "example": "Resource not found"
          },
          "details": {
            "type": "object",
            "description": "Extra context, e.g. field level validation errors",
            "additionalProperties": true,
            "nullable": true
          },
          "requestId": {
            "type": "string",
            "example": "4f6c1c9e-7a51-4b0e-9d7e-2a0c7b0f3c11"
          }
        },
        "required": [
          "code",
          "message",
          "requestId"
        ]
      },
      "ErrorCode": {
        "type": "string",
        "enum": [
          "BAD_REQUEST",
          "VALIDATION_FAILED",
          "UNAUTHORIZED",
          "FORBIDDEN",
          "NOT_FOUND",
          "CONFLICT",
          "TOO_MANY_REQUESTS",
          "INTERNAL_ERROR",
          "SERVICE_UNAVAILABLE",
          "IDEMPOTENCY_KEY_INVALID",
          "IDEMPOTENCY_KEY_REUSED",
          "IDEMPOTENCY_IN_PROGRESS",
          "TOKEN_EXPIRED",
          "TOKEN_INVALID",
          "REFRESH_TOKEN_REUSED",
          "CODE_INVALID",
          "CODE_EXPIRED",
          "CODE_ATTEMPTS_EXCEEDED",
          "CODE_RESEND_TOO_SOON",
          "SOCIAL_TOKEN_INVALID",
          "EMAIL_NOT_VERIFIED",
          "DEVICE_CHECK_REQUIRED",
          "ACCOUNT_SUSPENDED",
          "ACCOUNT_DELETED",
          "USER_NOT_FOUND",
          "USER_EMAIL_TAKEN",
          "DEVICE_NOT_FOUND",
          "DEVICE_UNSUPPORTED",
          "DESTINATION_NOT_FOUND",
          "PACKAGE_NOT_FOUND",
          "PHOTO_NOT_FOUND",
          "PHOTO_INVALID",
          "PACKAGE_INACTIVE",
          "PACKAGE_INCOMPATIBLE",
          "NO_ESIM",
          "ESIM_PLAN_NOT_FOUND",
          "ESIM_PRICE_CHANGED",
          "ESIM_PROVIDER_BALANCE_LOW",
          "ESIM_PLAN_NOT_REVOCABLE",
          "ESIM_REPLACE_LIMIT",
          "ESIM_REPLACE_NOT_ALLOWED",
          "ESIM_REMOVE_NOT_ALLOWED",
          "ESIM_CHECKOUT_IN_PROGRESS",
          "ESIM_USAGE_RATE_LIMITED",
          "ESIM_INVALID_TRANSITION",
          "PAYMENT_DECLINED",
          "PAYMENT_METHOD_UNSUPPORTED",
          "PAYMENT_NOT_FOUND",
          "PAYMENT_METHOD_NOT_FOUND",
          "STORE_RECEIPT_INVALID",
          "STORE_RECEIPT_USED",
          "STORE_PRODUCT_UNKNOWN",
          "CREDIT_CAP_EXCEEDED",
          "CREDIT_INSUFFICIENT",
          "NUMBER_COUNTRY_NOT_FOUND",
          "NUMBER_TYPE_NOT_FOUND",
          "NUMBER_UNAVAILABLE",
          "NUMBER_RESERVATION_EXPIRED",
          "NUMBER_RESERVATION_NOT_FOUND",
          "NUMBER_NOT_FOUND",
          "NUMBER_LIMIT_REACHED",
          "NUMBER_RELEASE_CONFIRMATION_MISMATCH",
          "NUMBER_NOT_RELEASABLE",
          "NUMBER_NOT_KEEPABLE",
          "NUMBER_NOT_RETRYABLE",
          "NUMBER_NOT_CALLABLE",
          "KYC_REQUIRED",
          "KYC_FIELDS_MISSING",
          "KYC_SUBMISSION_NOT_FOUND",
          "VOICE_NO_CREDENTIAL",
          "CALL_NOT_FOUND",
          "CALL_DESTINATION_BLOCKED",
          "CALL_EMERGENCY_NOT_SUPPORTED",
          "CALLING_UNAVAILABLE",
          "VOICEMAIL_NOT_FOUND",
          "RATE_NOT_FOUND",
          "THREAD_NOT_FOUND",
          "MESSAGING_DISABLED",
          "NOTIFICATION_NOT_FOUND",
          "TRIP_NOT_FOUND",
          "TRIP_LIMIT_REACHED",
          "WEBHOOK_SIGNATURE_INVALID",
          "PROVIDER_REJECTED",
          "ADMIN_UNAUTHORIZED",
          "ADMIN_SESSION_EXPIRED",
          "ADMIN_MFA_REQUIRED",
          "ADMIN_STEP_UP_REQUIRED",
          "ADMIN_FORBIDDEN",
          "ADMIN_LIMIT_EXCEEDED",
          "ADMIN_TOTP_INVALID",
          "ADMIN_ACCOUNT_NOT_FOUND",
          "ADMIN_ACCOUNT_EXISTS",
          "ADMIN_ROLE_NOT_FOUND",
          "ADMIN_LAST_OWNER",
          "ADMIN_SELF_CHANGE",
          "REFERRAL_CODE_INVALID",
          "REFERRAL_SELF",
          "REFERRAL_ALREADY_APPLIED",
          "REFERRAL_NOT_ELIGIBLE",
          "REFERRAL_NOT_FOUND",
          "REFERRAL_CLOSED",
          "APP_VERSION_INVALID",
          "WAITLIST_EMAIL_TAKEN",
          "WAITLIST_ENTRY_NOT_FOUND"
        ]
      },
      "ErrorResponseDto": {
        "type": "object",
        "properties": {
          "error": {
            "$ref": "#/components/schemas/ErrorBodyDto"
          }
        },
        "required": [
          "error"
        ]
      },
      "MoneyDto": {
        "type": "object",
        "properties": {
          "amountMinor": {
            "type": "integer",
            "example": 1299,
            "description": "Amount in minor units (cents, pence)."
          },
          "currency": {
            "type": "string",
            "example": "USD",
            "description": "ISO 4217 currency code."
          }
        },
        "required": [
          "amountMinor",
          "currency"
        ]
      },
      "NumberCountryDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "example": "US",
            "description": "ISO 3166-1 alpha-2."
          },
          "name": {
            "type": "string",
            "example": "United States"
          },
          "fromPrice": {
            "description": "Cheapest monthly price across the types.",
            "allOf": [
              {
                "$ref": "#/components/schemas/MoneyDto"
              }
            ]
          },
          "idRequired": {
            "type": "boolean",
            "description": "Any type in this country needs identity documents."
          },
          "types": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/NumberTypeOptionDto"
            }
          }
        },
        "required": [
          "code",
          "name",
          "fromPrice",
          "idRequired",
          "types"
        ]
      },
      "NumberCountryListDto": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/NumberCountryDto"
            }
          }
        },
        "required": [
          "items"
        ]
      },
      "NumberKind": {
        "type": "string",
        "enum": [
          "local",
          "mobile",
          "toll_free"
        ]
      },
      "NumberTextReachDto": {
        "type": "object",
        "properties": {
          "anywhere": {
            "type": "boolean",
            "description": "A number of this type could text any country we offer."
          },
          "countries": {
            "example": [
              "United States",
              "Canada"
            ],
            "description": "Countries it could text, by name, when not anywhere. Empty: it can only receive.",
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "anywhere",
          "countries"
        ]
      },
      "NumberTypeOptionDto": {
        "type": "object",
        "properties": {
          "kind": {
            "allOf": [
              {
                "$ref": "#/components/schemas/NumberKind"
              }
            ]
          },
          "label": {
            "type": "string",
            "example": "Local number"
          },
          "description": {
            "type": "string"
          },
          "monthlyPrice": {
            "$ref": "#/components/schemas/MoneyDto"
          },
          "voice": {
            "type": "boolean"
          },
          "sms": {
            "type": "boolean"
          },
          "recommended": {
            "type": "boolean"
          },
          "idRequired": {
            "type": "boolean",
            "description": "Identity documents are needed before the number goes live (N9)."
          },
          "textsTo": {
            "nullable": true,
            "description": "Where a number bought now could send texts; null without texts or when unknown.",
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/NumberTextReachDto"
              }
            ]
          }
        },
        "required": [
          "kind",
          "label",
          "description",
          "monthlyPrice",
          "voice",
          "sms",
          "recommended",
          "idRequired",
          "textsTo"
        ]
      },
      "NumberTypeOptionListDto": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/NumberTypeOptionDto"
            }
          }
        },
        "required": [
          "items"
        ]
      }
    }
  }
}
