{
 "openapi": "3.0.3",
 "info": {
  "title": "2FASMS API",
  "version": "1.0.0",
  "description": "Buy virtual phone numbers and receive SMS verification codes over HTTP.\n\nTwo interfaces share the same account, balance and prices:\n\n* **REST API** (`/order/api/...`): JSON in, JSON out.\n* **Compatible API** (`/stubs/handler_api.php`): the plain-text protocol used by\n  sms-activate, SMSHub and DaisySMS clients. Change the base URL and the key,\n  keep your code.\n\nGet your API key in your account settings: https://2fasms.com/app/en/change-password\nPrices are in USD. A number that receives no SMS can be cancelled and refunded.\n",
  "contact": {
   "name": "2FASMS support",
   "email": "contact@2fasms.com",
   "url": "https://2fasms.com"
  }
 },
 "externalDocs": {
  "description": "Human-readable reference",
  "url": "https://2fasms.com/app/en/api-docs"
 },
 "servers": [
  {
   "url": "https://api.2fasms.com"
  }
 ],
 "tags": [
  {
   "name": "Catalog",
   "description": "Countries, services and prices. No authentication."
  },
  {
   "name": "Account"
  },
  {
   "name": "Orders"
  },
  {
   "name": "Compatible API",
   "description": "sms-activate / DaisySMS text protocol."
  }
 ],
 "paths": {
  "/order/api/countries": {
   "get": {
    "tags": [
     "Catalog"
    ],
    "summary": "List countries",
    "operationId": "listCountries",
    "security": [],
    "responses": {
     "200": {
      "description": "Country slugs, sorted.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "status": {
           "type": "string",
           "example": "success"
          },
          "countries": {
           "type": "array",
           "items": {
            "type": "string"
           },
           "example": [
            "afghanistan",
            "albania",
            "algeria",
            "usa"
           ]
          },
          "meta": {
           "$ref": "#/components/schemas/Meta"
          }
         }
        }
       }
      }
     },
     "503": {
      "$ref": "#/components/responses/Error"
     }
    }
   }
  },
  "/order/api/services": {
   "get": {
    "tags": [
     "Catalog"
    ],
    "summary": "List services, globally or for one country",
    "operationId": "listServices",
    "security": [],
    "parameters": [
     {
      "name": "country",
      "in": "query",
      "required": false,
      "description": "Country slug from `/order/api/countries`, e.g. `usa`.",
      "schema": {
       "type": "string",
       "example": "usa"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Without `country`: one entry per service with `countries_count`.\nWith `country`: one entry per service available in that country, with\n`providers` = number of upstream providers.\n",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "status": {
           "type": "string",
           "example": "success"
          },
          "country": {
           "type": "string",
           "example": "usa"
          },
          "services": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/ServicePrice"
           }
          },
          "total": {
           "type": "integer",
           "example": 1624
          },
          "meta": {
           "$ref": "#/components/schemas/Meta"
          }
         }
        },
        "example": {
         "status": "success",
         "country": "usa",
         "services": [
          {
           "name": "whatsapp",
           "min_price": 0.12,
           "max_price": 2.89,
           "providers": 6
          },
          {
           "name": "telegram",
           "min_price": 0.263,
           "max_price": 1.83,
           "providers": 6
          }
         ],
         "total": 1624,
         "meta": {
          "from_cache": true,
          "source": "catalog_table"
         }
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/Error"
     },
     "503": {
      "$ref": "#/components/responses/Error"
     }
    }
   }
  },
  "/order/api/get_balance": {
   "get": {
    "tags": [
     "Account"
    ],
    "summary": "Get your balance",
    "operationId": "getBalance",
    "responses": {
     "200": {
      "description": "Balance in USD, as a string.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "status": {
           "type": "string",
           "example": "success"
          },
          "balance": {
           "type": "string",
           "example": "25.50"
          }
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     }
    }
   }
  },
  "/order/api/get_number": {
   "post": {
    "tags": [
     "Orders"
    ],
    "summary": "Buy a number",
    "description": "Debits the balance only when a number is delivered.\nSend `country_code` (ISO 3166-1 alpha-2): the current server expects it.\n",
    "operationId": "getNumber",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "country",
         "service",
         "country_code"
        ],
        "properties": {
         "country": {
          "type": "string",
          "example": "usa",
          "description": "Country slug"
         },
         "service": {
          "type": "string",
          "example": "whatsapp",
          "description": "Service slug"
         },
         "country_code": {
          "type": "string",
          "example": "US",
          "description": "ISO 3166-1 alpha-2"
         },
         "provider": {
          "type": "string",
          "description": "Optional. Force one upstream provider."
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Number delivered.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "orderId": {
           "type": "integer",
           "example": 12345
          },
          "number": {
           "type": "string",
           "example": "+12025550123"
          },
          "status": {
           "type": "string",
           "example": "SUCCESS"
          }
         }
        }
       }
      }
     },
     "400": {
      "description": "Missing parameters, unknown service/country, or no number available.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Message"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "406": {
      "description": "Insufficient funds.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Message"
        },
        "example": {
         "message": "Insufficient funds"
        }
       }
      }
     },
     "502": {
      "$ref": "#/components/responses/MessageError"
     },
     "503": {
      "$ref": "#/components/responses/MessageError"
     }
    }
   }
  },
  "/order/api/check_order": {
   "post": {
    "tags": [
     "Orders"
    ],
    "summary": "Poll the SMS",
    "operationId": "checkOrder",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "orderId"
        ],
        "properties": {
         "orderId": {
          "type": "integer",
          "example": 12345
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "`received` with the SMS text, or `not received`.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "status": {
           "type": "string",
           "enum": [
            "received",
            "not received"
           ]
          },
          "sms": {
           "type": "string",
           "example": "Your WhatsApp code: 123-456"
          }
         }
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/MessageError"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     }
    }
   }
  },
  "/order/api/finish_order": {
   "post": {
    "tags": [
     "Orders"
    ],
    "summary": "Close an order after the code was used",
    "operationId": "finishOrder",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "orderId"
        ],
        "properties": {
         "orderId": {
          "type": "integer",
          "example": 12345
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Finished.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Message"
        },
        "example": {
         "message": "order has been finished"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "404": {
      "$ref": "#/components/responses/MessageError"
     },
     "406": {
      "description": "Order cancelled, expired, or still waiting for its SMS.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Message"
        }
       }
      }
     }
    }
   }
  },
  "/stubs/handler_api.php": {
   "get": {
    "tags": [
     "Compatible API"
    ],
    "summary": "sms-activate compatible endpoint",
    "description": "One endpoint, selected by `action`. Responses are plain text, except\n`getPrices` / `getServices`, which return JSON.\n\n| action | extra parameters | success | errors |\n|---|---|---|---|\n| getBalance | | `ACCESS_BALANCE:25.50` | `BAD_KEY` |\n| getNumber | `service`, `country`, `max_price` (optional) | `ACCESS_NUMBER:<id>:<number>` (+ header `X-Price`) | `NO_NUMBERS`, `NO_MONEY`, `MAX_PRICE_EXCEEDED`, `BAD_SERVICE`, `BAD_ACTION` |\n| getStatus | `id` | `STATUS_OK:<code>`, `STATUS_WAIT_CODE`, `STATUS_CANCEL` | `NO_ACTIVATION` |\n| setStatus | `id`, `status` (`8` cancel and refund, `6` done) | `ACCESS_CANCEL`, `ACCESS_ACTIVATION` | `NO_ACTIVATION`, `BAD_ACTION` |\n| getPrices | | JSON catalog | |\n\nPOST with the same parameters as form fields is also accepted.\n",
    "operationId": "compatHandler",
    "security": [],
    "parameters": [
     {
      "name": "api_key",
      "in": "query",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "action",
      "in": "query",
      "required": true,
      "schema": {
       "type": "string",
       "enum": [
        "getBalance",
        "getNumber",
        "getStatus",
        "setStatus",
        "getPrices",
        "getServices"
       ]
      }
     },
     {
      "name": "service",
      "in": "query",
      "schema": {
       "type": "string",
       "example": "whatsapp"
      }
     },
     {
      "name": "country",
      "in": "query",
      "schema": {
       "type": "string",
       "example": "usa"
      }
     },
     {
      "name": "max_price",
      "in": "query",
      "schema": {
       "type": "number",
       "example": 0.5
      }
     },
     {
      "name": "id",
      "in": "query",
      "schema": {
       "type": "string",
       "example": "12345"
      }
     },
     {
      "name": "status",
      "in": "query",
      "schema": {
       "type": "integer",
       "enum": [
        6,
        8
       ]
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Plain-text status line (or JSON for getPrices).",
      "content": {
       "text/plain": {
        "schema": {
         "type": "string"
        },
        "examples": {
         "number": {
          "value": "ACCESS_NUMBER:12345:+12025550123"
         },
         "code": {
          "value": "STATUS_OK:123456"
         },
         "waiting": {
          "value": "STATUS_WAIT_CODE"
         },
         "badKey": {
          "value": "BAD_KEY"
         }
        }
       },
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     }
    }
   }
  }
 },
 "security": [
  {
   "bearerKey": []
  }
 ],
 "components": {
  "securitySchemes": {
   "bearerKey": {
    "type": "http",
    "scheme": "bearer",
    "description": "`Authorization: Bearer YOUR_API_KEY`"
   }
  },
  "schemas": {
   "Meta": {
    "type": "object",
    "properties": {
     "from_cache": {
      "type": "boolean"
     },
     "source": {
      "type": "string"
     }
    }
   },
   "ServicePrice": {
    "type": "object",
    "properties": {
     "name": {
      "type": "string",
      "example": "whatsapp"
     },
     "min_price": {
      "type": "number",
      "example": 0.12
     },
     "max_price": {
      "type": "number",
      "example": 2.89
     },
     "providers": {
      "type": "integer",
      "example": 6
     },
     "countries_count": {
      "type": "integer",
      "example": 180
     }
    }
   },
   "Message": {
    "type": "object",
    "properties": {
     "message": {
      "type": "string"
     }
    }
   }
  },
  "responses": {
   "Unauthorized": {
    "description": "Missing or invalid API key.",
    "content": {
     "application/json": {
      "schema": {
       "type": "object",
       "properties": {
        "error_message": {
         "type": "string",
         "example": "Invalid Key!"
        }
       }
      }
     }
    }
   },
   "Error": {
    "description": "Error.",
    "content": {
     "application/json": {
      "schema": {
       "type": "object",
       "properties": {
        "status": {
         "type": "string",
         "example": "error"
        },
        "message": {
         "type": "string"
        }
       }
      }
     }
    }
   },
   "MessageError": {
    "description": "Error.",
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/Message"
      }
     }
    }
   }
  }
 }
}