> ## Documentation Index
> Fetch the complete documentation index at: https://docs.matocard.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Lock an exchange rate for 60 seconds

> Every top-up, settlement and cash-out needs a fresh quote id. Top-ups and settlements take `USD/IDR` (paid in rupiah, Indonesian channels) or `USD/MYR` (paid in ringgit: FPX, DuitNow, Malaysian cards); the pair picks the currency. Cash-outs take `USD/IDR` only.



## OpenAPI

````yaml https://api.matocard.xyz/openapi.json post /quote
openapi: 3.1.0
info:
  title: Matocard API
  version: 1.0.0
  description: >-
    The backend the app calls. Served at `/docs` (this page) and
    `/openapi.json`. Guides, concepts and the contracts are in the docs:
    https://docs.matocard.xyz


    **Amounts** are decimal strings in the currency's smallest unit, never
    floats: AUSD has 6 decimals (`"1000000"` = 1 AUSD), IDR has none (`"50000"`
    = Rp 50,000), MYR is in sen. Format them with `formatAmount` from
    `@matocard/core`.


    **Signing in.** No passwords: the account's key (the Mera passkey account)
    signs once, and the app sends the result on every signed route as


    `Authorization: Matocard <wallet>.<until>.<signature>`


    where `until` is a unix time at most 7 days ahead and `signature` is
    `personal_sign` (viem `signMessage`) of exactly:


    ```

    Sign in to Matocard

    <wallet in lowercase>

    until <until>

    ```


    The first signed call creates the user. To try a signed route here, press
    **Authorize** and paste the whole header value, `Matocard 0x….…`.


    **Errors** are `{ "error": "…" }` with a 4xx status and a message the app
    may show. 500 is `something went wrong` and is logged on the server.


    **Signed transfers (ERC-3009).** `/sends` and `/cashouts` take an AUSD
    `TransferWithAuthorization` the user signed, so the relayer pays the gas.
    EIP-712 domain on Monad testnet: `name: "Agora Dollar"`, `version: "1"`,
    `chainId: 10143`, `verifyingContract:
    0xa9012a055bd4e0eDfF8Ce09f960291C09D5322dC`. Types:
    `TransferWithAuthorization(address from, address to, uint256 value, uint256
    validAfter, uint256 validBefore, bytes32 nonce)`. Use a random 32-byte
    `nonce` per transfer.


    **Money in.** Top-ups and settlements return a Xendit `checkoutUrl`; open
    it, and the backend credits the contract when Xendit reports the payment.
    Poll `GET /me` (or `/me/activity`, whose `inFlight` lists payments not
    onchain yet) to see it land. **Which currency:** ask for a `USD/MYR` quote
    when `user.country` is `MY` (ringgit through Xendit Malaysia: FPX, DuitNow
    QR, Malaysian cards), otherwise `USD/IDR` (rupiah through Xendit Indonesia:
    virtual accounts, QRIS, cards). Cash-outs are always `USD/IDR`. In test mode
    nothing is charged: FPX and DuitNow pages have a button to succeed, and the
    Indonesian virtual account numbers are not real, so never transfer to them
    (pick one and ask the backend owner to simulate it), or pay with a Xendit
    test card. A card top-up shows in `collateral.pendingShares` until its hold
    ends (about a minute on testnet); virtual accounts, QRIS, FPX and DuitNow
    count at once.


    **Done in the app, not here:** `draw(amount, to)` (borrow, straight to
    anyone's wallet), `repay` / `repayWithPermit` (pay back in AUSD),
    `repayFromCollateral(amount)` (pay back out of collateral) and
    `withdrawCollateral` are the user's own transactions on the `MatoCreditLine`
    contract (`0x4D6279c3DD0369e788C33b3aE1297D4E9abbd01a`), paid with the MON
    the backend drips after KYC. Send each with `gas: gasLimits.<function>` from
    `@matocard/contracts`: Monad charges the gas limit, so a fixed limit is
    cheaper than a padded estimate.
servers:
  - url: https://api.matocard.xyz
    description: VPS, Monad testnet, Xendit and Didit in test mode
  - url: http://127.0.0.1:3000
    description: local docker compose
security: []
tags:
  - name: Public
  - name: Account
    description: Signed in
  - name: Money
    description: >-
      Signed in; top-ups and sends also need the account verified onchain
      (`verified` in `GET /me`)
  - name: Webhooks
    description: Called by Xendit and Didit, not by the app
paths:
  /quote:
    post:
      tags:
        - Public
      summary: Lock an exchange rate for 60 seconds
      description: >-
        Every top-up, settlement and cash-out needs a fresh quote id. Top-ups
        and settlements take `USD/IDR` (paid in rupiah, Indonesian channels) or
        `USD/MYR` (paid in ringgit: FPX, DuitNow, Malaysian cards); the pair
        picks the currency. Cash-outs take `USD/IDR` only.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - pair
              properties:
                pair:
                  type: string
                  enum:
                    - USD/IDR
                    - USD/MYR
            example:
              pair: USD/IDR
      responses:
        '200':
          description: Locked
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Quote'
        '400':
          $ref: '#/components/responses/Bad'
      security: []
components:
  schemas:
    Quote:
      type: object
      properties:
        id:
          type: string
          format: uuid
        pair:
          type: string
          enum:
            - USD/IDR
            - USD/MYR
        rate:
          type: string
          description: Units of the second currency per 1 USD (AUSD counts as USD)
          examples:
            - '17950'
        expiresAt:
          type: string
          format: date-time
          description: 60 seconds after it was made
    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: string
          examples:
            - verify your identity first
  responses:
    Bad:
      description: The request was wrong; the message says why
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.