openapi: 3.1.0
info:
  title: co:sim Travel eSIM API
  version: "1.0"
  description: |
    Help travelers find and buy affordable eSIM data plans for 190+ countries.

    **Workflow for AI agents:**
    1. Search destinations by country name or region
    2. List and compare packages (data, duration, price, network)
    3. Optionally calculate price with discount codes
    4. Create a checkout link — share it with the user
    5. The user clicks the link to review the order and pay via Stripe
    6. eSIM QR code is delivered to their email

    All browse endpoints require no authentication. The checkout endpoint is rate-limited by IP.

    **Required: User-Agent header** — All requests must include a User-Agent identifying your client and model:
    `{ClientName}/{ClientVersion} ({Model}/{ModelVersion})`
    Example: `ChatGPT-Plugins/1.2.0 (gpt-4o/2024-08-06)`

    Full documentation: https://cosim.io/llms-full.txt
  contact:
    name: co:sim Support
    url: https://cosim.io
    email: support@cosim.io

servers:
  - url: https://cosim.io/api/v1
    description: Production

paths:
  /esim/locations:
    get:
      operationId: searchDestinations
      summary: Search eSIM destinations by country name or region
      description: |
        Returns destinations with package counts and starting prices.
        Supports multilingual search — try "Japan", "日本", "Japon", "일본".
        Results are sorted by relevance to the user's location.
      tags: [Browse]
      parameters:
        - name: search
          in: query
          description: Country or region name in any language.
          schema:
            type: string
          example: Japan
        - name: region
          in: query
          description: Filter by geographic region.
          schema:
            type: string
            enum: [asia, europe, americas, oceania, africa, middle_east, regional]
      responses:
        "200":
          description: List of matching destinations.
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object
                    properties:
                      items:
                        type: array
                        items:
                          type: object
                          properties:
                            code:
                              type: string
                              description: "Destination code (e.g. 'JP', 'EU-42')."
                            name:
                              type: string
                            region:
                              type: string
                            isRegional:
                              type: boolean
                            packageCount:
                              type: integer
                            startPrice:
                              type: object
                              nullable: true
                              properties:
                                amount:
                                  type: number
                                currency:
                                  type: string
                      regions:
                        type: array
                        items:
                          type: object
                          properties:
                            code:
                              type: string
                            name:
                              type: string
                            count:
                              type: integer
                  meta:
                    $ref: "#/components/schemas/Meta"

  /esim/locations/{code}/packages:
    get:
      operationId: listPackages
      summary: List all eSIM packages for a destination
      description: |
        Returns detailed plan information. Use the package `id` in calculatePrice or createCheckout.
        Key fields to present to users: dataVolume.display, duration.days, price.amount, speed, supportTopup.
      tags: [Browse]
      parameters:
        - name: code
          in: path
          required: true
          description: "Destination code (e.g. 'JP', 'TH', 'EU-42')."
          schema:
            type: string
        - name: sort
          in: query
          description: Sort order for packages.
          schema:
            type: string
            enum: [price, data, validity]
            default: price
        - name: data_type
          in: query
          description: Filter by data type.
          schema:
            type: string
            enum: [total, daily]
      responses:
        "200":
          description: Packages for the destination.
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object
                    properties:
                      location:
                        type: object
                        properties:
                          code:
                            type: string
                          name:
                            type: string
                          region:
                            type: string
                          isRegional:
                            type: boolean
                      packages:
                        type: array
                        items:
                          $ref: "#/components/schemas/PackageSummary"
                  meta:
                    $ref: "#/components/schemas/Meta"
        "404":
          description: Destination not found.

  /esim/packages/{id}:
    get:
      operationId: getPackage
      summary: Get detailed info about a specific eSIM package
      tags: [Browse]
      parameters:
        - name: id
          in: path
          required: true
          description: Package ID or slug.
          schema:
            type: string
      responses:
        "200":
          description: Package details.
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object
                    properties:
                      id:
                        type: string
                      slug:
                        type: string
                        nullable: true
                      name:
                        type: string
                      destination:
                        type: object
                        properties:
                          code:
                            type: string
                          name:
                            type: string
                          region:
                            type: string
                      coverage:
                        type: array
                        items:
                          type: string
                        description: Country codes covered by this plan.
                      dataVolume:
                        type: object
                        properties:
                          mb:
                            type: integer
                          display:
                            type: string
                          type:
                            type: string
                          description:
                            type: string
                      validity:
                        type: object
                        properties:
                          days:
                            type: integer
                          display:
                            type: string
                      price:
                        type: object
                        properties:
                          amount:
                            type: number
                          currency:
                            type: string
                          formatted:
                            type: string
                            description: "Formatted price string (e.g. '$3.50')."
                      network:
                        type: object
                        properties:
                          type:
                            type: string
                            nullable: true
                          speed:
                            type: string
                            nullable: true
                      features:
                        type: object
                        properties:
                          supportTopup:
                            type: boolean
                          billingStart:
                            type: string
                            nullable: true
                  meta:
                    $ref: "#/components/schemas/Meta"
        "404":
          description: Package not found.

  /orders/data-only/calculate:
    post:
      operationId: calculatePrice
      summary: Calculate order price with optional discount codes
      description: |
        Use this to show the user a price breakdown before creating a checkout.
        Supports quantity and custom days for daily plans.
      tags: [Order]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [packageId]
              properties:
                packageId:
                  type: string
                  description: Package ID from listPackages.
                quantity:
                  type: integer
                  default: 1
                customDays:
                  type: integer
                  description: Custom validity days (for daily plans only).
                discountCodes:
                  type: array
                  items:
                    type: string
                  description: Discount/coupon codes to apply.
      responses:
        "200":
          description: Price calculation result.
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object
                    properties:
                      package:
                        type: object
                        properties:
                          id:
                            type: string
                          name:
                            type: string
                          destination:
                            type: object
                            properties:
                              id:
                                type: string
                              name:
                                type: string
                              region:
                                type: string
                          data:
                            type: object
                            properties:
                              amount:
                                type: number
                              unit:
                                type: string
                              type:
                                type: string
                          validity:
                            type: object
                            properties:
                              days:
                                type: integer
                          quantity:
                            type: integer
                          unitPrice:
                            type: number
                          subtotal:
                            type: number
                      discounts:
                        type: object
                        properties:
                          applied:
                            type: array
                            items:
                              type: object
                              properties:
                                code:
                                  type: string
                                displayName:
                                  type: string
                                discountAmount:
                                  type: number
                          rejected:
                            type: array
                            items:
                              type: object
                              properties:
                                code:
                                  type: string
                                message:
                                  type: string
                          total:
                            type: number
                      summary:
                        type: object
                        properties:
                          subtotal:
                            type: number
                          discountAmount:
                            type: number
                          total:
                            type: number
                          currency:
                            type: string
                  meta:
                    $ref: "#/components/schemas/Meta"

  /ai/checkout:
    post:
      operationId: createCheckout
      summary: Create a checkout link for the user to pay
      description: |
        Creates an order and returns a checkout URL. Share this URL with the user.
        The user opens the link, reviews the order, selects a payment method, and pays.
        The eSIM QR code is delivered to the provided email after payment.

        Rate limit: 10 requests per 5 minutes per IP.
        Orders expire after 30 minutes if not paid.
      tags: [Checkout]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [packageId, email]
              properties:
                packageId:
                  type: string
                  description: Package ID or slug from listPackages.
                email:
                  type: string
                  format: email
                  description: Email address for eSIM QR code delivery.
                quantity:
                  type: integer
                  default: 1
                  maximum: 10
                customDays:
                  type: integer
                  description: Custom validity days for daily plans.
                discountCode:
                  type: string
                  description: Optional discount code.
                locale:
                  type: string
                  enum: [en, zh-CN, zh-TW, ja, ko, fr]
                  default: en
                  description: Language for checkout page and emails.
      responses:
        "201":
          description: Checkout created. Present checkoutUrl to the user.
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object
                    properties:
                      checkoutUrl:
                        type: string
                        format: uri
                        description: URL for the user to complete payment.
                      checkoutToken:
                        type: string
                        description: Token to poll status via getCheckoutStatus.
                      expiresAt:
                        type: string
                        format: date-time
                      expiresInMinutes:
                        type: integer
                        description: Minutes until the checkout link expires.
                      summary:
                        type: object
                        properties:
                          orderId:
                            type: string
                          orderNumber:
                            type: string
                          destination:
                            type: string
                          destinationCode:
                            type: string
                          plan:
                            type: string
                            description: "Data volume display (e.g. '5GB')."
                          duration:
                            type: string
                            description: "Validity period (e.g. '7 days')."
                          networkType:
                            type: string
                          billingStart:
                            type: string
                            enum: [first_connection, first_install, purchase]
                            description: |
                              When billing begins. "purchase" means the plan starts immediately
                              and is non-refundable. Check refundPolicy.eligible.
                          quantity:
                            type: integer
                          unitPrice:
                            type: string
                            description: "Formatted price (e.g. '$3.50')."
                          subtotal:
                            type: string
                          discount:
                            type: string
                            description: "Formatted discount (e.g. '-$1.00'). Only present when discount applied."
                          total:
                            type: string
                          currency:
                            type: string
                          email:
                            type: string
                      refundPolicy:
                        type: object
                        description: |
                          IMPORTANT: AI agents MUST present this refund policy to the user
                          before they click the checkout link. The mustInformUser flag is always true.
                          When eligible is false, the plan is non-refundable (billing starts at purchase).
                        properties:
                          eligible:
                            type: boolean
                            description: |
                              Whether this order is eligible for refund. false for immediate-billing
                              plans (billingStart: "purchase"). Always check this field.
                          reason:
                            type: string
                            description: Human-readable explanation of the refund policy for this order.
                          guestOrderNote:
                            type: string
                            description: How guest/AI orders request refunds (contact support).
                          processingTime:
                            type: string
                          mustInformUser:
                            type: boolean
                            description: Always true. Agents must share this info before checkout.
                  meta:
                    $ref: "#/components/schemas/Meta"
        "400":
          description: Validation error.
        "404":
          description: Package not found.
        "429":
          description: Rate limit exceeded.

  /ai/checkout/{token}/status:
    get:
      operationId: getCheckoutStatus
      summary: Check if the user has completed payment
      description: |
        Poll this endpoint after sharing the checkout link.
        - `awaiting_payment` — waiting for user to open the link and pay
        - `paid` — payment received, eSIM being provisioned
        - `completed` — eSIM delivered to email
        - `expired` — link expired, create a new checkout
        - `cancelled` — order was cancelled
      tags: [Checkout]
      parameters:
        - name: token
          in: path
          required: true
          description: The checkoutToken from createCheckout.
          schema:
            type: string
      responses:
        "200":
          description: Current checkout status.
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object
                    properties:
                      orderNumber:
                        type: string
                      status:
                        type: string
                        enum: [awaiting_payment, paid, completed, expired, cancelled, failed]
                      total:
                        type: string
                        description: "Formatted total (e.g. '$9.99')."
                      currency:
                        type: string
                        nullable: true
                      email:
                        type: string
                        nullable: true
                      items:
                        type: array
                        items:
                          type: object
                          properties:
                            name:
                              type: string
                            description:
                              type: string
                              nullable: true
                            quantity:
                              type: integer
                            unitPrice:
                              type: string
                            total:
                              type: string
                      paidAt:
                        type: string
                        format: date-time
                        nullable: true
                      createdAt:
                        type: string
                        format: date-time
                        nullable: true
                      expiresAt:
                        type: string
                        format: date-time
                        nullable: true
                  meta:
                    $ref: "#/components/schemas/Meta"
        "404":
          description: Checkout token not found.

  /ai/checkout/{token}/pay:
    post:
      operationId: payCheckout
      summary: Initiate payment for an AI checkout order
      description: |
        Called from the AI checkout page when the user clicks "Pay".
        This endpoint is NOT typically called by AI agents directly — the user
        interacts with the checkout page UI instead.
        Supports multiple payment methods: card, alipay, wechat, amazon_pay.
      tags: [Checkout]
      parameters:
        - name: token
          in: path
          required: true
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                locale:
                  type: string
                  enum: [en, zh-CN, zh-TW, ja, ko, fr]
                  default: en
                paymentMethod:
                  type: string
                  enum: [card, alipay, wechat, amazon_pay]
                  default: card
                  description: |
                    Payment method. card uses Stripe Checkout (includes Apple Pay/Google Pay).
                    alipay and amazon_pay redirect to the provider.
                    wechat returns a QR code for inline display.
      responses:
        "200":
          description: Payment session created.
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object
                    properties:
                      paymentType:
                        type: string
                        enum: [redirect, qr_code]
                      checkoutUrl:
                        type: string
                        format: uri
                        description: Redirect URL (card, alipay, amazon_pay).
                      sessionId:
                        type: string
                        description: Stripe session ID (card only).
                      qrCodeUrl:
                        type: string
                        description: QR code image URL (wechat only).
                      qrCodeData:
                        type: string
                        description: Raw weixin:// payment URL (wechat only).
                      qrCodeExpiresAt:
                        type: integer
                        description: Unix timestamp when QR expires (wechat only).
                      orderId:
                        type: string
                        description: Order ID (wechat only, for polling).
        "400":
          description: Invalid request or payment creation failed.
        "404":
          description: Order not found.
        "410":
          description: Order expired.
        "429":
          description: Rate limit exceeded.

components:
  schemas:
    Meta:
      type: object
      properties:
        requestId:
          type: string
        timestamp:
          type: string
          format: date-time

    PackageSummary:
      type: object
      properties:
        id:
          type: string
          description: Package ID — use this in calculatePrice and createCheckout.
        name:
          type: string
        slug:
          type: string
        dataVolume:
          type: object
          properties:
            mb:
              type: integer
            display:
              type: string
              description: "Human-readable (e.g. '1GB', '500MB/day')."
            type:
              type: string
              enum: [total, daily_throttle, daily_cutoff, daily_unlimited]
              description: "total = fixed pool; daily_* = resets each day."
        duration:
          type: object
          properties:
            days:
              type: integer
            display:
              type: string
        price:
          type: object
          properties:
            amount:
              type: number
            currency:
              type: string
        networkType:
          type: string
        speed:
          type: string
          description: "Network speed tier (e.g. '4G', '3G/4G/5G')."
        supportTopup:
          type: boolean
        billingStart:
          type: string
          enum: [first_connection, first_install]
          description: When the validity timer starts.
        isFavorite:
          type: boolean
          description: Recommended/popular plan.
