> ## 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.

# Add collateral by paying in IDR or MYR

> The quote's pair picks the currency. `amount` is in its smallest unit: whole rupiah (at least 10000) for `USD/IDR`, sen (at least 500, RM 5) for `USD/MYR`. `method` is what the user picked, but the hold follows how they actually paid: virtual account, QRIS, FPX and DuitNow count at once, cards and e-wallets are held first (`collateral.pendingShares`).



## OpenAPI

````yaml https://api.matocard.xyz/openapi.json post /topups
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:
  /topups:
    post:
      tags:
        - Money
      summary: Add collateral by paying in IDR or MYR
      description: >-
        The quote's pair picks the currency. `amount` is in its smallest unit:
        whole rupiah (at least 10000) for `USD/IDR`, sen (at least 500, RM 5)
        for `USD/MYR`. `method` is what the user picked, but the hold follows
        how they actually paid: virtual account, QRIS, FPX and DuitNow count at
        once, cards and e-wallets are held first (`collateral.pendingShares`).
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - amount
                - method
                - quoteId
              properties:
                amount:
                  type: string
                  description: Rupiah for a `USD/IDR` quote, sen for `USD/MYR`
                method:
                  type: string
                  enum:
                    - bank
                    - card
                    - qr
                  description: '`card` limits the checkout to cards'
                quoteId:
                  type: string
                  format: uuid
                  description: A `USD/IDR` or `USD/MYR` quote
            example:
              amount: '50000'
              method: bank
              quoteId: 92d758a3-4c5b-48c4-952b-7ee932786435
      responses:
        '200':
          description: Checkout
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Checkout'
              example:
                paymentId: 765b1b01-3f7f-425d-a2b1-87635dd2ba82
                checkoutUrl: https://dev.xen.to/iCRL0isp
                fiat: '50000'
                ausd: '2785515'
        '400':
          $ref: '#/components/responses/Bad'
        '401':
          $ref: '#/components/responses/SignIn'
        '403':
          $ref: '#/components/responses/NotVerified'
        '503':
          $ref: '#/components/responses/NotConfigured'
      security:
        - session: []
components:
  schemas:
    Checkout:
      type: object
      properties:
        paymentId:
          type: string
          format: uuid
        checkoutUrl:
          type: string
          format: uri
          description: Xendit's hosted page; open it
        fiat:
          $ref: '#/components/schemas/Amount'
          description: 'Charged in the quote''s currency: rupiah or sen'
        ausd:
          $ref: '#/components/schemas/Amount'
          description: AUSD credited (top-up) or repaid (settlement)
    Amount:
      type: string
      pattern: ^[0-9]+$
      description: Smallest unit of its currency
      examples:
        - '1000000'
    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'
    SignIn:
      description: 'No session, a bad signature, or an expired one: sign again'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    NotVerified:
      description: Not verified onchain yet (KYC approved and `setVerified` confirmed)
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    NotConfigured:
      description: Xendit or Didit keys are missing on this server
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  securitySchemes:
    session:
      type: apiKey
      in: header
      name: Authorization
      description: '`Matocard <wallet>.<until>.<signature>`, see the description at the top'

````

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