{
  "openapi": "3.1.0",
  "info": {
    "title": "Xpress Flow Systems domains",
    "version": "1.0.0",
    "description": "Check domain names and order them for a person to approve and pay. Prices are in naira. A person always approves and pays; nothing is charged by calling this API."
  },
  "servers": [
    {
      "url": "https://www.xpressflowsystems.com.ng"
    }
  ],
  "paths": {
    "/api/domains/availability": {
      "post": {
        "operationId": "checkDomainAvailability",
        "summary": "Check one domain name",
        "description": "Answers from the public registry for the ending: available, unavailable (taken) or unknown (that ending cannot be checked here). A check does not reserve a name.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AvailabilityRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The answer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AvailabilityResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "503": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/api/orders/config": {
      "get": {
        "operationId": "getOrdersConfig",
        "summary": "Is ordering open, and what does it cost",
        "responses": {
          "200": {
            "description": "Prices are listed in both modes.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrdersConfig"
                }
              }
            }
          }
        }
      }
    },
    "/api/orders": {
      "post": {
        "operationId": "createDomainOrder",
        "summary": "Start an order for a person to approve and pay",
        "description": "Holds the name for holdMinutes. Returns a checkoutUrl that the person must open and pay. Poll the order with the statusUrl or GET /api/orders/status.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OrderRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The order was started.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreatedOrder"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          },
          "422": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          },
          "503": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/api/orders/status": {
      "get": {
        "operationId": "getOrderStatus",
        "summary": "Follow an order",
        "parameters": [
          {
            "name": "reference",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "XF-7K3Q9DFA"
          },
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The last part of statusUrl."
          }
        ],
        "responses": {
          "200": {
            "description": "The order.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrderView"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/api/esim/locations": {
      "get": {
        "operationId": "listEsimLocations",
        "summary": "List eSIM destinations",
        "description": "Every country and region we sell eSIM data plans for.",
        "responses": {
          "200": {
            "description": "Destinations.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "locations": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "code": {
                            "type": "string"
                          },
                          "name": {
                            "type": "string"
                          },
                          "kind": {
                            "type": "string",
                            "enum": [
                              "country",
                              "region"
                            ]
                          },
                          "countries": {
                            "type": "integer"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "The catalogue is unavailable."
          }
        }
      }
    },
    "/api/esim/plans": {
      "get": {
        "operationId": "listEsimPlans",
        "summary": "eSIM plans and prices for one destination",
        "parameters": [
          {
            "name": "location",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "GB"
            },
            "description": "A code from /api/esim/locations."
          }
        ],
        "responses": {
          "200": {
            "description": "Plans, cheapest first, prices in whole naira.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "location": {
                      "type": "string"
                    },
                    "currency": {
                      "type": "string"
                    },
                    "plans": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "code": {
                            "type": "string"
                          },
                          "name": {
                            "type": "string"
                          },
                          "dataGb": {
                            "type": "number"
                          },
                          "days": {
                            "type": "integer"
                          },
                          "coverage": {
                            "type": "integer"
                          },
                          "priceNgn": {
                            "type": "integer"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad location."
          },
          "503": {
            "description": "The catalogue is unavailable."
          }
        }
      }
    }
  },
  "components": {
    "responses": {
      "Error": {
        "description": "Something is wrong with the request or the service.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string",
                "example": "DOMAIN_TAKEN"
              },
              "message": {
                "type": "string"
              },
              "fields": {
                "type": "object",
                "additionalProperties": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "AvailabilityRequest": {
        "type": "object",
        "required": [
          "domainName"
        ],
        "properties": {
          "domainName": {
            "type": "string",
            "example": "yourbrand.com.ng"
          }
        }
      },
      "AvailabilityResponse": {
        "type": "object",
        "required": [
          "domainName",
          "availability"
        ],
        "properties": {
          "domainName": {
            "type": "string"
          },
          "availability": {
            "type": "string",
            "enum": [
              "available",
              "unavailable",
              "unknown"
            ]
          }
        }
      },
      "OrdersConfig": {
        "type": "object",
        "properties": {
          "ordersEnabled": {
            "type": "boolean"
          },
          "mode": {
            "type": "string",
            "enum": [
              "online",
              "manual"
            ],
            "description": "online: orders are paid on the gateway and POST /api/orders works. manual: checkout is briefly closed and POST /api/orders answers 503. Orders are never taken by email."
          },
          "currency": {
            "type": "string",
            "const": "NGN"
          },
          "holdMinutes": {
            "type": "integer"
          },
          "prices": {
            "type": "object",
            "description": "Keyed by ending, for example com.ng.",
            "additionalProperties": {
              "type": "object",
              "properties": {
                "first": {
                  "type": "integer",
                  "description": "First year, whole naira."
                },
                "renewal": {
                  "type": "integer",
                  "description": "Each later year, whole naira."
                }
              }
            }
          }
        }
      },
      "OrderRequest": {
        "type": "object",
        "required": [
          "domain",
          "name",
          "email",
          "phone",
          "address",
          "city",
          "state",
          "country",
          "acceptTerms"
        ],
        "properties": {
          "domain": {
            "type": "string",
            "example": "yourbrand.com.ng"
          },
          "name": {
            "type": "string",
            "description": "Full name of the person who will own the domain."
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "phone": {
            "type": "string",
            "example": "08012345678"
          },
          "organisation": {
            "type": "string"
          },
          "address": {
            "type": "string"
          },
          "city": {
            "type": "string"
          },
          "state": {
            "type": "string"
          },
          "country": {
            "type": "string",
            "example": "Nigeria"
          },
          "acceptTerms": {
            "type": "boolean",
            "description": "True only if the person agreed to the Terms of Use and Privacy Policy."
          }
        }
      },
      "CreatedOrder": {
        "type": "object",
        "properties": {
          "reference": {
            "type": "string"
          },
          "token": {
            "type": "string",
            "description": "Shown once. Keep it to follow the order."
          },
          "domain": {
            "type": "string"
          },
          "priceNgn": {
            "type": "integer"
          },
          "checkoutUrl": {
            "type": "string",
            "format": "uri",
            "description": "The person opens this to pay."
          },
          "statusUrl": {
            "type": "string",
            "format": "uri"
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "OrderView": {
        "type": "object",
        "properties": {
          "reference": {
            "type": "string"
          },
          "domain": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "awaiting_payment",
              "paid",
              "registered",
              "needs_attention",
              "refunded",
              "expired",
              "cancelled"
            ]
          },
          "priceNgn": {
            "type": "integer"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time"
          },
          "paidAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "registeredAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "checkoutUrl": {
            "type": [
              "string",
              "null"
            ],
            "description": "Present only while the order can still be paid."
          }
        }
      }
    }
  }
}
