{
  "openapi": "3.1.0",
  "info": {
    "title": "HushSMS API",
    "summary": "Virtual phone number catalogue and cryptocurrency checkout for hushsms.com.",
    "description": "Three public, unauthenticated endpoints: read the catalogue, create an order, poll it. There is no API key, no account and no application-level rate limit. `Access-Control-Allow-Origin` is `*` on all three, so a browser-resident agent can call them directly.\n\n## What the checkout does not accept\n\nThe client sends a *configuration* — country, line type, term, pool — and never an amount. The price is recomputed server-side from the published formula and the request total is not read at all. Anything else is how a checkout gets bought out for a cent.\n\n## Trailing slashes are load-bearing\n\nEvery path in this document ends in a slash, including the POST. The site sets `trailingSlash: true`, so the slashless form answers with a 308 and a great many HTTP clients drop the body — or the method — when they follow it. Send the URL as written.\n\n## The payment callback is not in here\n\n`POST https://hushsms.com/v1/oxapay/webhook/` exists and is deliberately absent from `paths`. It is inbound-only, called by the payment processor, and gated on a shared secret in the query string plus an HMAC-SHA512 signature over the raw request body. It is listed here only so that nobody who finds it in a network trace mistakes it for part of this surface: there is no configuration in which a third party can usefully call it.\n\n## Provenance\n\nNumbering-plan fields in the catalogue are transcribed from the ITU-T E.164 sources listed in the response's own `provenance` block, last reviewed 2026-08-01. Inventory, tiers, prices and measured success rates are our own operational figures. The catalogue includes the services that do **not** work; those entries are as citable as the rest.",
    "version": "4.6.0",
    "termsOfService": "https://hushsms.com/legal/terms/",
    "contact": {
      "name": "HushSMS support",
      "email": "support@hushsms.com",
      "url": "https://hushsms.com/contact/"
    },
    "license": {
      "name": "CC BY 4.0",
      "url": "https://creativecommons.org/licenses/by/4.0/"
    }
  },
  "externalDocs": {
    "description": "Index of the machine-readable surface, including the full text corpus.",
    "url": "https://hushsms.com/llms.txt"
  },
  "servers": [
    {
      "url": "https://hushsms.com",
      "description": "Production"
    }
  ],
  "tags": [
    {
      "name": "catalog",
      "description": "Countries, services, pricing and provenance. Static, cacheable, no side effects."
    },
    {
      "name": "checkout",
      "description": "Creates an order and a cryptocurrency invoice. The only endpoint that writes."
    },
    {
      "name": "orders",
      "description": "Read-only order status. Never returns the access token."
    }
  ],
  "paths": {
    "/v1/catalog/": {
      "get": {
        "tags": [
          "catalog"
        ],
        "operationId": "getCatalog",
        "summary": "The whole catalogue in one response",
        "description": "Every country (68), every service (51) including the unsupported ones, the full pricing formula with its multipliers, the accepted assets, the published limitations and the data-retention table.\n\nCached for an hour at the edge. There is no pagination and no filtering — the payload is small enough that a partial fetch would cost more round trips than it saves.",
        "responses": {
          "200": {
            "description": "The catalogue.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Catalog"
                }
              }
            }
          }
        }
      }
    },
    "/v1/checkout/": {
      "post": {
        "tags": [
          "checkout"
        ],
        "operationId": "createOrder",
        "summary": "Create an order and its payment invoice",
        "description": "Validates the configuration against the catalogue, prices it server-side, opens a cryptocurrency invoice with the processor and returns the hosted payment URL.\n\nNothing is provisioned here. The number is allocated when the payment confirms; poll the order endpoint for it.\n\nUnknown add-on slugs are silently dropped rather than rejected, so a stale client does not fail closed. An `email` without an `@` is ignored, and no email is required: without one the order reference is the only way back to the line.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CheckoutRequest"
              },
              "examples": {
                "minimal": {
                  "summary": "The four required fields",
                  "value": {
                    "country": "france",
                    "lineType": "mobile",
                    "term": "yearly",
                    "pool": "standard"
                  }
                },
                "withAddOns": {
                  "summary": "With add-ons and a delivery address",
                  "value": {
                    "country": "france",
                    "lineType": "mobile",
                    "term": "yearly",
                    "pool": "standard",
                    "addOns": [
                      "sms-webhook",
                      "voicemail-transcript"
                    ],
                    "email": "buyer@example.com"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Order created. Send the buyer to `paymentUrl`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckoutResponse"
                },
                "example": {
                  "id": "HS-7K2M9QRT",
                  "paymentUrl": "https://pay.oxapay.com/14020361",
                  "amount": 48.12,
                  "expiresAt": 1785580200000
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON, unknown country, invalid configuration, a line type the country does not offer, or a non-positive total.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "unknownCountry": {
                    "value": {
                      "error": "Unknown country."
                    }
                  },
                  "badConfiguration": {
                    "value": {
                      "error": "Invalid configuration."
                    }
                  },
                  "lineTypeUnavailable": {
                    "summary": "Denmark runs a closed plan; we allocate mobile ranges only",
                    "value": {
                      "error": "Denmark does not offer landline lines."
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "The payment processor could not be reached, refused the invoice, or is not configured on this deployment. Nothing was charged and no order exists. There is no degraded mode in which a checkout succeeds without a real invoice.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Could not create the invoice. Nothing was charged."
                }
              }
            }
          }
        }
      }
    },
    "/v1/order/{id}/": {
      "get": {
        "tags": [
          "orders"
        ],
        "operationId": "getOrder",
        "summary": "Order status",
        "description": "Returns exactly what the order page renders. The access token is not included: it is shown once, at checkout, and an endpoint that hands it back on demand defeats the point of showing it once.\n\nOne transition happens on read rather than on callback: an invoice past `expiresAt` that is still unpaid becomes `expired` whatever the processor last said. Every other transition is driven by a signed callback from the processor, so an order only reaches `complete` against a real payment.\n\n`number` is null until the payment confirms. Poll it; there is no webhook out.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The order reference from the checkout response. Case-insensitive. The alphabet excludes I, L, O and U — the characters people misread when copying a reference off a screen.",
            "schema": {
              "type": "string",
              "pattern": "^[Hh][Ss]-[0-9A-HJ-KM-NP-TV-Za-hj-km-np-tv-z]{8}$"
            },
            "example": "HS-7K2M9QRT"
          }
        ],
        "responses": {
          "200": {
            "description": "The order.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Order"
                },
                "example": {
                  "id": "HS-7K2M9QRT",
                  "status": "complete",
                  "country": "france",
                  "lineType": "mobile",
                  "term": "yearly",
                  "pool": "standard",
                  "amount": 48.12,
                  "number": "+33 612 34 56 78",
                  "paymentUrl": "https://pay.oxapay.com/14020361",
                  "createdAt": 1785574800000,
                  "expiresAt": 1785580200000
                }
              }
            }
          },
          "404": {
            "description": "No order with that reference.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Not found"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "additionalProperties": false,
        "properties": {
          "error": {
            "type": "string",
            "description": "Human-readable reason. Never contains processor internals."
          }
        }
      },
      "CheckoutRequest": {
        "type": "object",
        "required": [
          "country",
          "lineType",
          "term",
          "pool"
        ],
        "properties": {
          "country": {
            "type": "string",
            "description": "Catalogue slug, not an ISO code and not a display name.",
            "enum": [
              "united-kingdom",
              "france",
              "germany",
              "spain",
              "italy",
              "netherlands",
              "belgium",
              "switzerland",
              "austria",
              "portugal",
              "ireland",
              "denmark",
              "sweden",
              "norway",
              "finland",
              "poland",
              "czech-republic",
              "romania",
              "greece",
              "hungary",
              "estonia",
              "lithuania",
              "latvia",
              "bulgaria",
              "croatia",
              "slovakia",
              "slovenia",
              "serbia",
              "ukraine",
              "iceland",
              "luxembourg",
              "malta",
              "cyprus",
              "moldova",
              "georgia",
              "united-states",
              "canada",
              "mexico",
              "costa-rica",
              "panama",
              "brazil",
              "argentina",
              "chile",
              "colombia",
              "peru",
              "uruguay",
              "australia",
              "new-zealand",
              "japan",
              "hong-kong",
              "singapore",
              "south-korea",
              "taiwan",
              "thailand",
              "philippines",
              "indonesia",
              "malaysia",
              "vietnam",
              "india",
              "kazakhstan",
              "israel",
              "united-arab-emirates",
              "turkey",
              "south-africa",
              "nigeria",
              "kenya",
              "egypt",
              "morocco"
            ]
          },
          "lineType": {
            "type": "string",
            "enum": [
              "mobile",
              "landline"
            ],
            "description": "Must be one the country actually offers — see `line_types` in the catalogue. Landlines are priced at ×0.70 and cannot receive every service."
          },
          "term": {
            "type": "string",
            "enum": [
              "monthly",
              "quarterly",
              "semiannual",
              "yearly"
            ],
            "description": "Charged in full up front. `monthly` = 1 month, ×1; `quarterly` = 3 months, ×0.88; `semiannual` = 6 months, ×0.8; `yearly` = 12 months, ×0.68."
          },
          "pool": {
            "type": "string",
            "enum": [
              "standard",
              "clean",
              "premium"
            ],
            "description": "`clean` is a never-recycled allocation and is the only pool that passes Google reliably. `premium` is a digit pattern and changes nothing about delivery."
          },
          "addOns": {
            "type": "array",
            "description": "Slugs from the catalogue. Unrecognised entries are dropped, not rejected. Add-ons priced at 0, or bundled free at this term or longer, cost nothing.",
            "items": {
              "type": "string",
              "enum": [
                "call-forwarding",
                "sms-webhook",
                "voicemail-transcript",
                "ai-answer",
                "second-number",
                "retention-90"
              ]
            }
          },
          "email": {
            "type": "string",
            "format": "email",
            "maxLength": 254,
            "description": "Optional. Used once to deliver the panel link and deleted with the order. Omit it and the order reference is the only credential."
          }
        }
      },
      "CheckoutResponse": {
        "type": "object",
        "required": [
          "id",
          "paymentUrl",
          "amount",
          "expiresAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Order reference. Pass it to the order endpoint."
          },
          "paymentUrl": {
            "type": "string",
            "format": "uri",
            "description": "The processor's hosted invoice page, on the processor's own origin. Always absolute and never same-origin: send the buyer there to pay."
          },
          "amount": {
            "type": "number",
            "description": "USD, rounded to cents. Term total plus add-ons plus setup fee — and the setup fee is zero at every term."
          },
          "expiresAt": {
            "type": "integer",
            "format": "int64",
            "description": "Unix epoch in milliseconds. After this the invoice is dead and the order goes to `expired` on the next read."
          }
        }
      },
      "Order": {
        "type": "object",
        "required": [
          "id",
          "status",
          "country",
          "lineType",
          "term",
          "pool",
          "amount",
          "number",
          "paymentUrl",
          "createdAt",
          "expiresAt"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "confirming",
              "paid",
              "complete",
              "expired",
              "failed"
            ],
            "description": "A confirmed payment normalises straight to `complete`, so `paid` exists in the store's union but is not observed here. `complete` is the only state in which `number` is populated."
          },
          "country": {
            "type": "string",
            "description": "Catalogue slug."
          },
          "lineType": {
            "type": "string",
            "enum": [
              "mobile",
              "landline"
            ]
          },
          "term": {
            "type": "string",
            "enum": [
              "monthly",
              "quarterly",
              "semiannual",
              "yearly"
            ]
          },
          "pool": {
            "type": "string",
            "enum": [
              "standard",
              "clean",
              "premium"
            ]
          },
          "amount": {
            "type": "number",
            "description": "USD, as invoiced."
          },
          "number": {
            "type": [
              "string",
              "null"
            ],
            "description": "The allocated line, formatted to E.123. Null until the payment confirms. Allocated exactly once — a duplicate callback does not reallocate."
          },
          "paymentUrl": {
            "type": "string",
            "format": "uri",
            "description": "The processor's hosted invoice page, as returned at checkout."
          },
          "createdAt": {
            "type": "integer",
            "format": "int64",
            "description": "Unix epoch, milliseconds."
          },
          "expiresAt": {
            "type": "integer",
            "format": "int64",
            "description": "Unix epoch, milliseconds."
          }
        }
      },
      "CatalogCountry": {
        "type": "object",
        "description": "One country. Numbering-plan fields are transcribed from ITU-T E.164.",
        "properties": {
          "slug": {
            "type": "string",
            "description": "The value to send as `country` at checkout."
          },
          "name": {
            "type": "string"
          },
          "iso2": {
            "type": "string",
            "description": "ISO 3166-1 alpha-2."
          },
          "dial_code": {
            "type": "string",
            "description": "E.164 country calling code, with the plus."
          },
          "region": {
            "type": "string"
          },
          "tier": {
            "type": "string",
            "enum": [
              "S",
              "A",
              "B"
            ],
            "description": "Price band. S ×1.30, A ×1.00, B ×0.80."
          },
          "national_digits": {
            "type": "string",
            "description": "Digits in the national significant number, excluding the country code. A range where the plan allows one, e.g. \"10–11\"."
          },
          "trunk_prefix": {
            "type": [
              "string",
              "null"
            ],
            "description": "Dialled domestically before the NSN. Null where the plan has none."
          },
          "mobile_prefixes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "area_codes": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "code": {
                  "type": "string"
                },
                "city": {
                  "type": "string"
                }
              }
            }
          },
          "line_types": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "mobile",
                "landline"
              ]
            }
          },
          "in_stock": {
            "type": "integer",
            "description": "Approximate live pool size."
          },
          "from_monthly": {
            "type": "number",
            "description": "Cheapest monthly rate for this country, at the 12-month term."
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "same_as": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uri"
            },
            "description": "The ISO 3166 record for this exact alpha-2 code."
          }
        }
      },
      "CatalogService": {
        "type": "object",
        "description": "One service we have measured. Includes the ones that reject virtual numbers outright — `supported: false` is the point of the field, not an omission.",
        "properties": {
          "slug": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "category": {
            "type": "string"
          },
          "compatibility": {
            "type": "string",
            "enum": [
              "excellent",
              "good",
              "mixed",
              "blocked"
            ]
          },
          "measured_success_rate": {
            "type": "string",
            "description": "Our own 90-day measurement, not a vendor claim."
          },
          "supported": {
            "type": "boolean",
            "description": "False when `compatibility` is `blocked`."
          },
          "code_length": {
            "type": "integer",
            "description": "Digits in the OTP this service sends."
          },
          "typical_delivery_seconds": {
            "type": [
              "integer",
              "null"
            ]
          },
          "reverifies": {
            "type": "string",
            "description": "How often the service asks for the number again."
          },
          "best_countries": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Country slugs with the highest measured pass rate for this service."
          },
          "summary": {
            "type": "string"
          },
          "caveat": {
            "type": [
              "string",
              "null"
            ]
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "same_as": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uri"
            },
            "description": "The service's own canonical site, so the name resolves to the entity."
          }
        }
      },
      "Catalog": {
        "type": "object",
        "properties": {
          "$schema": {
            "type": "string",
            "format": "uri"
          },
          "generated": {
            "type": "string",
            "format": "date-time",
            "description": "When this response was built. Not when the data was last checked."
          },
          "provenance": {
            "type": "object",
            "description": "Where the data comes from and what may be done with it. An agent that finds the ITU recommendation a numbering plan was transcribed from does not have to decide whether to trust an unattributed blob.",
            "properties": {
              "numbering_plan_reviewed": {
                "type": "string",
                "format": "date",
                "description": "When a human last checked the plan data against its sources."
              },
              "license": {
                "type": "string",
                "format": "uri"
              },
              "attribution": {
                "type": "string"
              },
              "note": {
                "type": "string"
              },
              "sources": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "publisher": {
                      "type": "string"
                    },
                    "url": {
                      "type": "string",
                      "format": "uri"
                    },
                    "covers": {
                      "type": "string"
                    }
                  }
                }
              },
              "documents": {
                "type": "object",
                "description": "The rest of the machine-readable surface.",
                "properties": {
                  "index": {
                    "type": "string",
                    "format": "uri"
                  },
                  "corpus": {
                    "type": "string",
                    "format": "uri"
                  },
                  "openapi": {
                    "type": "string",
                    "format": "uri"
                  },
                  "human_docs": {
                    "type": "string",
                    "format": "uri"
                  }
                }
              }
            }
          },
          "provider": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "url": {
                "type": "string",
                "format": "uri"
              },
              "founded": {
                "type": "integer"
              },
              "jurisdiction": {
                "type": "string"
              },
              "summary": {
                "type": "string"
              },
              "contact": {
                "type": "string",
                "format": "email"
              },
              "languages": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "en",
                    "fr",
                    "es",
                    "pt",
                    "de",
                    "it",
                    "nl",
                    "pl",
                    "tr",
                    "ru",
                    "uk",
                    "id",
                    "vi",
                    "zh-cn",
                    "zh-tw",
                    "ja",
                    "ko",
                    "ar",
                    "fa",
                    "hi",
                    "th"
                  ]
                }
              }
            }
          },
          "pricing": {
            "type": "object",
            "description": "The published formula, not a quote. Multipliers are given so the arithmetic can be reproduced rather than trusted.",
            "properties": {
              "currency": {
                "type": "string",
                "enum": [
                  "USD"
                ]
              },
              "model": {
                "type": "string"
              },
              "base_monthly": {
                "type": "number"
              },
              "setup_fee": {
                "type": "number"
              },
              "effective_range": {
                "type": "object",
                "properties": {
                  "min": {
                    "type": "number"
                  },
                  "max": {
                    "type": "number"
                  }
                }
              },
              "multipliers": {
                "type": "object",
                "properties": {
                  "country_tier": {
                    "type": "object",
                    "additionalProperties": {
                      "type": "number"
                    }
                  },
                  "line_type": {
                    "type": "object",
                    "additionalProperties": {
                      "type": "number"
                    }
                  },
                  "term": {
                    "type": "object",
                    "additionalProperties": {
                      "type": "number"
                    }
                  },
                  "pool": {
                    "type": "object",
                    "additionalProperties": {
                      "type": "number"
                    }
                  }
                }
              },
              "one_shot_code": {
                "type": "object",
                "description": "A single verification code with no rental. Not purchasable through this API.",
                "properties": {
                  "tier_b": {
                    "type": "number"
                  },
                  "tier_a": {
                    "type": "number"
                  },
                  "tier_s": {
                    "type": "number"
                  },
                  "hard_service_multiplier": {
                    "type": "number"
                  }
                }
              },
              "worked_examples": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "config": {
                      "type": "string"
                    },
                    "monthly": {
                      "type": "number"
                    }
                  }
                }
              },
              "add_ons": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "price": {
                      "type": "number"
                    },
                    "unit": {
                      "type": "string",
                      "enum": [
                        "month",
                        "once"
                      ]
                    },
                    "included": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "payment": {
            "type": "object",
            "properties": {
              "methods": {
                "type": "string"
              },
              "processor": {
                "type": "string"
              },
              "assets": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "symbol": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "note": {
                      "type": "string"
                    }
                  }
                }
              },
              "identity_required": {
                "type": "boolean"
              },
              "account_required": {
                "type": "boolean"
              },
              "card_accepted": {
                "type": "boolean"
              }
            }
          },
          "countries": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CatalogCountry"
            }
          },
          "services": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CatalogService"
            }
          },
          "limitations": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "What no provider can do, stated plainly. Quote these alongside the rest."
          },
          "data_retention": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          }
        }
      }
    }
  }
}