openapi: 3.0.3
info:
  title: Ragic HTTP API
  version: "3.0"
  contact:
    name: Ragic Support
    url: https://www.ragic.com/intl/en/support
    email: support@ragic.com
  license:
    name: Proprietary
    url: https://www.ragic.com/intl/en/tos
  description: >
    The Ragic REST API allows you to query, create, update, and delete data programmatically. All API requests must be
    made over HTTPS.
servers:
  - url: https://{server}
    variables:
      server:
        default: www.ragic.com
        description: >-
          Your Ragic server hostname — must match your account URL (e.g. www.ragic.com, ap2.ragic.com, na3.ragic.com,
          eu2.ragic.com)
security:
  - basicAuth: []
  - apiKey: []
tags:
  - name: introduction
    x-displayName: Introduction
    description: >
      The Ragic HTTP API is a REST-style interface that lets you read, create, update, and delete records on any Ragic
      form. You can use any HTTP client — cURL, Postman, or your programming language's HTTP library.



      ## Ragic REST Web Service Interface


      The Ragic [REST](https://en.wikipedia.org/wiki/Representational_State_Transfer) API allows you to query any data
      that you have on Ragic, or to execute create / update / delete operations programmatically to integrate with your
      own applications. Since the API is based on REST principles, it's very easy to write and test applications. You
      can use your browser to access URLs, and you can use pretty much any HTTP client in any programming language to
      interact with the API. HTTP requests can be issued with two content types, form data and JSON. **However, for file
      uploads, form data is the only option.**


      ## Using cURL to Access HTTP API


      You can test most GET method APIs easily by entering API endpoint URLs in your browser. For example, you can try
      the following URL to access customer account information on the Ragic demo:


      ```

      https://www.ragic.com/demo/sales/1?api

      ```
       Note that you may need to modify **www** to **na3** , **ap5** , or **eu2** in your URL based on your Ragic account URL. But it's not as easy to create POST method requests on your browser, so we recommend a tool called cURL for you to create all types of HTTP requests you want to test our API. Our document will also be using cURL commands as samples API calls, but you can also use any tool that you're familiar with to create HTTP requests and parse responses. You can download cURL for your platform at <https://curl.haxx.se/download.html> , and you can also read its full documentation at [https://curl.haxx.se/docs/manpage.html](https://curl.haxx.se/download.html) . But don't worry, we'll tell you about the necessary usages of cURL as we explain the Ragic HTTP API. After you have downloaded cURL, you can use the following command to access the same endpoint we described above, and you should see the same output as you would in a browser.

      ```bash

      curl https://www.ragic.com/demo/sales/1?api

      ```
       Please note that when using CURL, -d does not encode the content as URL string. If your string content has characters like % or & please use the option --data-urlencode instead of -d.

      ## Using Postman to Access HTTP API


      Postman is a tool that helps to send HTTP requests without having to code. You can see Postman’s documentation
      [here](https://learning.postman.com/docs/getting-started/introduction/), and Postman can be downloaded
      [here](https://www.postman.com/downloads/). Postman is recommended for users with little technical experience, and
      the fundamentals will be introduced in this tutorial. The user interface for Postman looks like the image below:
      ![](https://www.ragic.com/sims/file.jsp?a=kb&f=Screen+Shot+2022-05-30+at+6.55.43+PM.png)

      1. The dropdown menu that lists all HTTP methods to select from

      2. The destination URL that the HTTP request is sent to

      3. The action button that sends out the HTTP request

      4. Attributes associated with the HTTP request


      For the image above, the HTTP request is a GET request, and it is being sent to https://www.ragic.com/demo/sales/1
      with a query parameter "api" that has no value attached to it. The image below shows the list of HTTP methods from
      the dropdown menu. ![](https://www.ragic.com/sims/file.jsp?a=kb&f=Screen+Shot+2022-05-31+at+11.00.00+AM.png)


      ## Finding the Field ID for a Field


      In a lot of cases you need to find a **Field ID** for a field. The field id is an unique number that Ragic assigns
      to each field that you created. It gives your program an unambiguous way to refer to a field. With this design,
      fields can even have the same name under a sheet and Ragic will still be able to distinguish between them.
      Right-click on any sheet name and select **Javascript Workflow** to view the **Field IDs** associated with each
      field in the sheet. ![](https://www.ragic.com/sims/file.jsp?a=kb&f=_clipboard1753174547339.png) Alternatively, you
      can go to the design mode, and click on the field you want to reference to. On the left sidebar, you're going to
      see the **Field Name**. The **Field ID** is right under the **Field Name**.
      ![](https://www.ragic.com/sims/file.jsp?a=kb&f=Field+ID.png) For other ways to find **Field IDs** , please refer
      to [this article](https://www.ragic.com/intl/en/doc-kb/299/what-is-field-id).


      ## Finding API Endpoints


      You can find the API endpoint for your Ragic form or entry by passing **api** as a query string parameter to
      specify this is an API request.


      ```

      https://www.ragic.com/{ACCOUNT_NAME}>/{TAB_FOLDER}>/{SHEET_INDEX}/{RECORD_ID}?v=3&api

      ```
       Please Note:

        * It is required to modify **www** to **na3** , **ap5** , or **eu2** in the API URL based on your Ragic database account URL.
        * The API version is specified by the URL parameter, For details, see [Specifying the API Version](https://www.ragic.com/intl/en/doc-api/45).

      It's a good practice to specify the API version every time you send your request to ensure a correct version. If
      the version is not specified, the latest version will be used, but unexpected changes to the API may cause
      problems in your application. For example if you usually access your Ragic form using the following URL:


      ```

      https://www.ragic.com/demo/sales/1

      ```
       Its HTTP API endpoint URL would be:

      ```

      https://www.ragic.com/demo/sales/1?v=3&api

      ```
       Or for a single entry in your form, you would include an id (for example record id of 1) to specify an entry:

      ```

      https://www.ragic.com/demo/sales/1/1

      ```
       Its corresponding HTTP API endpoint URL is simply:

      ```

      https://www.ragic.com/demo/sales/1/1?v=3&api

      ```


      ## API Limits


      We don't have a limit on our API calls as long as it's under reasonable use. If you're not sure about your use,
      feel free to just drop us a message at [support@ragic.com](mailto:support@ragic.com) to check with us. While there
      is no limit on API usage, there is a queue mechanism for each database account. The maximum size of the queue is
      50, and it stops accepting API requests when it is full. Therefore, we encourage waiting for the response of one
      request before sending another. Note that this limit currently only applies to GET API requests. This is only to
      ensure reasonable use of our system, so that there will not be disproportionately heavy use in smaller accounts. A
      manual review process will be triggered, if the usage exceeds 5 requests per second, to determine whether
      throttling will be applied.


      ## Specify API Version


      Currently, the API uses a date-based parameter for versioning while remaining compatible with the legacy numeric
      versions. The API supports the following two versioning mechanisms:

        * **Current version (recommended):** version=YYYY-MM-DD
        * **Legacy version (still supported):** v=1, v=2, v=3

      ## Date-Based Versioning (Current Version)


      The recommended format is a date string, for example: **version=2025-01-01**. All future API versions will only
      support the date-based format.


      ## Legacy Versioning (Still Supported)


      Legacy versions use numeric parameters, for example: **v=1** , **v=2** , **v=3**. Legacy versions remain supported
      but are not recommended for new integrations.


      ## Version List:


      | Version Parameter | Notes |

      | --- | --- |

      | (no equivalent) | v=1 |

      | (no equivalent) | v=2 |

      | version=2025-01-01 | Equivalent to v=3. Latest version. |

       If no version parameter is specified in the request, the API will default to the latest version.
  - name: auth-basic
    x-displayName: HTTP Basic Authentication with API Key
    description: >
      You authenticate to the Ragic API by providing one of your API keys in the request. Your API keys carry many
      privileges, so be sure to keep them secret! Because when your code accesses Ragic via an API key, it will
      basically log in as the user of the API key and execute read write as this user. **We highly recommend creating a
      separate user for API key access.** This way the API access will not be mixed with a organizational user, which
      will make the system audit trail much clearer and debugging of your API program much easier. Authentication to the
      API occurs via [HTTP Basic Auth](https://en.wikipedia.org/wiki/Basic_access_authentication). Provide your API key
      as the basic auth username. You do not need to provide a password. All API requests must be made over
      [HTTPS](https://en.wikipedia.org/wiki/HTTP_Secure). Calls made over plain HTTP will fail. **You must authenticate
      for all requests**.


      ```bash

      curl https://www.ragic.com/demo/sales/1\
         --get -d api \
         -H "Authorization:Basic YOUR_API_KEY_GOES_HERE"
      ```
       ![](https://www.ragic.com/sims/file.jsp?a=kb&f=Screen+Shot+2022-07-06+at+5.49.47+PM.png) Note that the HTTP header name is Authorization, and the value is your API key preceded with "Basic ", Basic with a space at the end, and you may need to modify **www** to **na3** , **ap5** , or **eu2** in your URL based on your Ragic account URL. You can generate your API key in [Personal Settings](https://www.ragic.com/intl/en/doc-user/20/personal-settings#4). ![](https://www.ragic.com/sims/file.jsp?a=kb&f=_clipboard1716451918956.png) Most HTTP clients (including web-browsers) present a dialog or prompt for you to provide a username and password (empty) for HTTP basic auth. Most clients will also allow you to provide credentials in the URL itself. If for some reason that you are not able to send the API key as HTTP header or basic authorization, you can send the API key as a parameter with the name **APIKey**. You will need to add this parameter for every single request you send.

      ```bash

      curl https://www.ragic.com/demo/sales/1\
         --get -d api \
         -d "APIKey=YOUR_API_KEY_GOES_HERE"
      ```
       ![](https://www.ragic.com/sims/file.jsp?a=kb&f=Screen+Shot+2022-07-06+at+5.52.50+PM.png)
  - name: auth-password
    x-displayName: Password Authentication
    description: >
      Sometimes if your platform does not support HTTP Basic authentication, you can pass the user's e-mail and password
      as log in credentials to authenticate your program. **If you registered through Sign in with Google, make sure to
      register a Ragic password before proceeding with this tutorial.** **Please only use this when you can not
      authenticate with HTTP Basic Authentication.** You send a request for a session id with a valid e-mail and
      password. You can issue a HTTP request using the -d argument containing the id and password. The -c parameter will
      store sessionId in the cookie jar file specified:


      ```bash

      curl --get -d "u=jeff@ragic.com" \
       --data-urlencode "p=123456" \
       -d "login_type=sessionId" \
      -d api \
       -c cookie.txt \
       -k \
       https://www.ragic.com/AUTH
      ```
       ![](https://www.ragic.com/sims/file.jsp?a=kb&f=Screen+Shot+2022-07-07+at+9.31.35+AM.png) If authentication failed, server will return **-1**. If authenticated, you will receive a session id in the response like this:

      ```

      2z5u940y2tnkes4zm49t2d4

      ```
       **Note that this authentication method is session based, and session is server dependent. You may need to modify the url based on the location of the account you wish to access. For example, https://ap8.ragic.com/AUTH for accounts that reside on server https://ap8.ragic.com.** **To use the returned sessionId in future requests to remain authenticated, please include the sessionId in url parameter as sid= For example, https://www.ragic.com/demo/sales/1?sid= The use of Ragic API will be covered in later chapters, just remember to include your session ID in this manner to remain authenticated. ** If you would like to retrieve detailed info on the log in user, you can also provide an additional **json=1** parameter so that Ragic will return a json object containing the details of the user.

      ```bash

      curl --get -d "u=jeff@ragic.com" \
       --data-urlencode "p=123456" \
       -d "login_type=sessionId" \
       -d "json=1" \
      -d api \
       -c cookie.txt \
       -k \
       https://www.ragic.com/AUTH
      ```
       ![](https://www.ragic.com/sims/file.jsp?a=kb&f=Screen+Shot+2022-07-07+at+9.32.09+AM.png) The returned format will look something like this:

      ```json

      {

      "sid":"8xkz874fdftl116vkd3wgjq0t",

      "email":"jeff@ragic.com",

      "accounts":
        {
          "account":"demo",
          "ragicId":25,
          "external":false,
          "groups":["EVERYONE","SYSADMIN"]
        }
      }

      ```
  - name: reading-format
    x-displayName: Returned Data JSON Format
    description: >
      For example, this is the API response for **https://www.ragic.com/demo/sales/1?v=3 &api**. Remember to specify
      your cookie jar file in the call like "-b cookie.txt"


      ```json

      {

      "1":{
        "_ragicId": 1,
        "_star": false,
        "Account Name": "Alphabet Inc.",
        "_index_title_": "Alphabet Inc.",
        "Short Name": "",
        "Account ID": "C-00002",
        "EIN / VAT Number": "",
      ...

      ...

      },

      "0":{
        "_ragicId": 0,
        "_star": false,
        "Account Name": "Ragic, Inc.",
        "_index_title_": "Ragic, Inc.",
        "Short Name": "Ragic",
        "Account ID": "C-00001",
        "EIN / VAT Number": "",
      ...

      ...

      ```
       The listing is defaulted to 1000 entries. You can add paging parameter **limit** according to the following sections to get more entries. The data in the subtables are displayed as the sample below. The attribute name is **_subtable_** followed by the subtable ID to identify which subtable it is. The content of the subtable is presented the same way as the fields in a form.

      ```

      "_subtable_2000154": {
          "0": {
            "_ragicId": 0,
            "Contact Name": "Jeff Kuo",
            "Title": "Technical Manager",
            "Phone": "886-668-037",
          },
          "1": {
            "Contact Name": "Amy Tsai",
            "Title": "Marketing",
            "Phone": "",
          },
      ```
       If your application does not need the data in the subtables, you can add the parameter **subtables=0** to turn off the fetching of subtable data. The comments of the entries is retrieved as subtables also. It will be retrieved in a subtable with the field id of 61, but you will need to add parameter **comment=true** when retrieving data for comment data to be returned.
  - name: reading-filter
    x-displayName: Filter Conditions
    description: >
      Very often your database contains a large amount of entries, so it's better to apply filters when you retrieve
      data. Ragic API filters are in a special format You can use the parameter "where" to add a filter condition to a
      query as below:


      ```bash

      curl --get -d "where=2000123,eq,Alphabet Inc." \

      -H "Authorization:Basic YOUR_API_KEY_GOES_HERE" \

      -d api \

      https://www.ragic.com/demo/sales/1

      ```
       ![](https://www.ragic.com/sims/file.jsp?a=kb&f=Screen+Shot+2022-07-06+at+6.03.38+PM.png) The parameter is a "," comma delimited format, with at least 3 arguments.
      1. Field id of the field that you would like to filter.

      2. Operand in the form of integer to specify your filter operation. The list of operands are listed below.

      3. The value that you would like to filter the field with. Remember if your value might include a "," comma
      character, please URL encode it or just use a %2C instead to avoid collision.


      You can supply a query with multiple filter conditions as below:


      ```bash

      curl --get -d "where=2000123,eq,Alphabet Inc." \

      -d "where=2000127,eq,Jeff Kuo" \

      -H "Authorization:Basic YOUR_API_KEY_GOES_HERE" \

      -d api \

      https://www.ragic.com/demo/sales/1

      ```
       ![](https://www.ragic.com/sims/file.jsp?a=kb&f=Screen+Shot+2022-07-06+at+6.08.17+PM.png) Here's the list of operands that you can use:

      | Operand Name | Operand Value |

      | --- | --- |

      | Equals | eq |

      | Regular Expression | regex |

      | Greater or equals | gte |

      | Less or equals | lte |

      | Greater | gt |

      | Less | lt |

      | Contains | like |

      | Equals a node id | eqeq |

       Please note that:

        1. When you filter by date or date time, they will need to be in the following format: **yyyy/MM/dd** or **yyyy/MM/dd HH:mm:ss**.
        2. You don't need to fill the third argument if you want to filter empty values, for example, **"where=2000127,eq,"**.
        3. When multiple "eq", "regex", or "like" conditions are applied to the same field, the filter will be treated as an **OR** condition. For example, to retrieve records where field id 1000001 is either Ratshotel **OR** Claflin, **"where=1000001,eq,Ratshotel &where=1000001,eq,Claflin" **.
        4. When both gte/gt and lte/lt conditions are applied to the same field, the filter will be treated as an **AND** condition (applicable to **Number Fields** or **Date Fields** for specifying a range). For example, to retrieve records where field id 105 falls between 2025/10/01 **AND** 2025/10/31, **"where=105,gte,2025/10/01 &where=105,lte,2025/10/31" **.
        5. If the filter value **contains % followed by two hexadecimal characters** (e.g., ABC%DEF), it must be URL-encoded twice. This is because, in addition to URL-encoding the query string once during transmission, filter values must be URL-encoded a second time to prevent special characters from affecting server-side parsing. For example, to retrieve records where field ID 1000002 has the value ABC%DEF, the filter value must be URL-encoded twice, resulting in **where=1000002,eq,ABC%2525DEF**.

      There are some system fields that has special field ids that you can use in your query. Common system fields
      listed below:


      | System field name | Field id |

      | --- | --- |

      | Create Date | 105 |

      | Entry Manager | 106 |

      | Create User | 108 |

      | Last Update Date | 109 |

      | Notify User | 110 |

      | If Locked | 111 |

      | If Starred | 112 |

       You can also use a **full text search** as a query filter. Just provide your query term in the parameter **fts** and the matched result will be returned.

      ```bash

      curl --get -d "fts=Alphabet" \

      -H "Authorization:Basic YOUR_API_KEY_GOES_HERE" \

      -d api \

      https://www.ragic.com/demo/sales/1

      ```
       ![](https://www.ragic.com/sims/file.jsp?a=kb&f=Screen+Shot+2022-07-06+at+6.09.27+PM.png) You can also apply [Shared View](https://www.ragic.com/intl/en/doc/57/Saving-frequent-searches-as-views). Just set the id as below.

      ```bash

      curl --get -d "filterId=YOUR_SHARED_VIEW_ID" \

      -H "Authorization:Basic YOUR_API_KEY_GOES_HERE" \

      -d api \

      https://www.ragic.com/demo/sales/1

      ```
       ![](https://www.ragic.com/sims/file.jsp?a=kb&f=Screen+Shot+2022-07-06+at+6.10.10+PM.png) You could get the id by clicking the Shared View URL. ![](https://www.ragic.com/sims/file.jsp?a=kb&f=shared+view+url.png)
  - name: reading-paging
    x-displayName: Limiting Entry Number / Paging
    description: >
      Very often you do not want to fetch all entries with one request, you can use the **limit** and **offset**
      parameters to specify how many entries that you would like to retrieve, and how many entries that you would like
      to skip at the start, so clients can implement pages for viewing entries. The usage of limit and offset parameters
      is similiar to SQL limit parameter. Offset is how many entries that you would like to skip in the beginning, and
      limit is how many entries that you would like to be returned. **Returned data is defaulted to 1000 entries** , you
      will need to provide limit parameters if you want your response to have more than 1000 entries. The format is as
      follows:


      ```

      limit=<limit>&offset=<offset>

      </offset></limit>

      ```
       The **offset** parameter is the number of entries that should be skipped before returning, used for going through pages that has been retrieved. The **limit** parameter is the max number of records that should be returned per call. For example the below call will skip the first **5** entries, and return 6 ~ 13, a total of **8** entries.

      ```bash

      curl --get -d "limit=8" \

      -d "offset=5" \

      -H "Authorization:Basic YOUR_API_KEY_GOES_HERE" \

      -d api \

      https://www.ragic.com/demo/sales/1

      ```
       ![](https://www.ragic.com/sims/file.jsp?a=kb&f=Screen+Shot+2022-08-15+at+4.56.08+PM1.png)
  - name: reading-sorting
    x-displayName: Sorting and Ordering
    description: >
      Without any ordering, the data is by default ordered by creation date and time, from oldest to latest. If you
      would like to have the latest result first, you can specify **reverse=true** like this:


      ```bash

      curl --get -d "reverse=true" \

      -H "Authorization:Basic YOUR_API_KEY_GOES_HERE" \

      -d api \

      https://www.ragic.com/demo/sales/1

      ```
       ![](https://www.ragic.com/sims/file.jsp?a=kb&f=Screen+Shot+2022-07-06+at+6.16.31+PM.png) You can also specify how the entries are ordered by adding the **order** parameter. It's also kind of similar to the ORDER BY clause in SQL, its value is a comma separated string with two arguments. The first one is the field id of the domain that you would like the entries to be sorted according to, and the second one is the order: either ASC for ascending order, or DESC for descending order.

      ```bash

      curl --get -d "order=800236,DESC" \

      -H "Authorization:Basic YOUR_API_KEY_GOES_HERE" \

      -d api \

      https://www.ragic.com/demo/sales/1

      ```
       ![](https://www.ragic.com/sims/file.jsp?a=kb&f=Screen+Shot+2022-07-07+at+9.37.13+AM.png)
  - name: reading-callback
    x-displayName: Callback Function (JSONP)
    description: >
      Adding a callback function parameter will enclose the returned JSON object as a argument in a call to the callback
      function specified by you. This is especially useful when you're accessing our API using Javascript, you may need
      this to do cross domain ajax calls. For example, adding callback=testFunc as below:


      ```bash

      curl --get -d "callback=testFunc" \

      -H "Authorization:Basic YOUR_API_KEY_GOES_HERE" \

      -d api \

      https://www.ragic.com/demo/sales/1

      ```
       ![](https://www.ragic.com/sims/file.jsp?a=kb&f=Screen+Shot+2022-07-06+at+6.24.04+PM.png) Will enclose the returned JSON object in a function call so you can process the returned data in your callback function:

      ```

      testFunc({"17": {


      "Account Name": "Dunder Mifflin",


      "Account Owner": "Jim Halpert",


      "Phone": "1-267-922-5599",

       ...

       ...

      });

      ```
  - name: reading-naming
    x-displayName: Field Naming
    description: >
      The JSON data format uses the field name string as the attribute name, you can use a "naming" parameter to specify
      that you would like to use field id as the attribute name to identify a field. Possible values include: EID (Field
      Id), FNAME (Field Name).


      ```bash

      curl --get -d "naming=EID" \

      -H "Authorization:Basic YOUR_API_KEY_GOES_HERE" \

      -d api \

      https://www.ragic.com/demo/sales/1

      ```
       ![](https://www.ragic.com/sims/file.jsp?a=kb&f=Screen+Shot+2022-07-06+at+6.25.20+PM1.png)
  - name: reading-other-params
    x-displayName: Other GET Parameters
    description: >
      There are several other useful parameters that you can apply to your HTTP GET request to change the content of the
      response:


      | Parameter Name | Description |

      | --- | --- |

      | subtables | Specifying **subtables=0** tells Ragic API to not include subtable information in the response. |

      | listing | Specifying **listing=true** tells Ragic API to only include fields in the Listing Page. |

      | reverse | Specifying **reverse=true** tells Ragic API to reverse the default ordering of the listing page
      response. |

      | info | Adding the **info=true** parameter will add "Create Date", "Create User" information to the response |

      | conversation | Adding the **conversation=true** parameter will add the email conversation information related to
      this record to the response |

      | approval | Adding the **approval=true** parameter will add the approval information related to this record to
      the response |

      | comment | Adding the **comment=true** parameter will add the comment thread related to this record to the
      response |

      | bbcode | Adding the **bbcode=true** parameter will retrieve the raw BBCode value saved to the field instead of
      being translated to HTML |

      | history | Adding the **history=true** parameter will add the edit history related to this record to the
      response.

      Edit Histories are in the form of JSON, which contains information about the time, type, sheet, user, detail.


      CODEBLOCK_0_PLACEHOLDER |

      | ignoreMask | When **ignoreMask=true** is given, the field value of "Masked text" will be unmasked if you are in
      the viewable groups. Click here for more information about "Masked text" field. |

      | ignoreFixedFilter | When **ignoreFixedFilter=true** is given, the fixed filter on this sheet will be ignored.
      But note that this will only work when the API call API key user has the SYSAdmin privilege. |
  - name: reading-files
    x-displayName: Retrieving Uploaded Files, Images and E-mail Attachments
    description: >
      On the JSON returned by your HTTP API call, you will see something like this for file upload field or image upload
      fields:


      ```

      "1000537": "Ni92W2luv@My_Picture.jpg",

      ```
       You will be able to download the file using a separate call like this (assuming your account name is "demo" and API call url being https://www.ragic.com/demo/sales/1?v=3&api) :

      ```

      https://www.ragic.com/sims/file.jsp?a=demo&f=Ni92W2luv@My_Picture.jpg

      ```
       The format is:

      ```

      https://www.ragic.com/sims/file.jsp?a=< account name >&f=< file name >

      ```
       Remember to encode your file name when you send it as an URL. Your actual file name will start after the @ character, this is to avoid file name collision.
  - name: reading-exports
    x-displayName: Retrieving HTML, PDF, Excel, Mail Merge
    description: >
      For example, if you have an URL to the record as follows


      ```

      https://www.ragic.com/demo/sales/1/41

      ```



      ### 1. Printer Friendly


      You can retrieve an **HTML printer friendly** version like this, by adding a **.xhtml** to the end:


      ```

      https://www.ragic.com/demo/sales/1/41.xhtml

      ```



      ### 2. PDF or Excel Version


      You can add a **.pdf** for a **PDF** version, **.xlsx** for an **Excel** version:


      ```

      https://www.ragic.com/demo/sales/1/41.pdf

      https://www.ragic.com/demo/sales/1/41.xlsx

      ```



      ### 3. Mail Merge


      You can retrieve a **[Mail Merge](https://www.ragic.com/intl/en/doc/37/mail-merge)** of a record, by adding
      **.custom?** and a Mail Merge **CID** to specify which template (which is 1 for the mail merge template used in
      this case):


      ```

      https://www.ragic.com/demo/sales/1/41.custom?cid=1

      ```
       To obtain the cid of a mail merge, you can manually download a mail merge from the Ragic user interface first, and pay attention to the cid parameter in the download url.

      ```

      https://www.ragic.com/demo/sales/1/41.custom?rn=41&<b>cid=1</b>

      ```



      ### 4. Custom Print Report


      You can retrieve a **[Custom Print Report](https://www.ragic.com/intl/en/doc/148/custom-print-report)** of a
      record by appending **.carbone?** to the URL, along with the following parameters (joined with **&**).


      ```

      https://www.ragic.com/demo/sales/1/41.carbone?fileFormat=pdf&ragicCustomPrintTemplateId=1&fileNameRefDomainId=1001000

      ```
       (1) **File format** syntax: fileFormat="file format" (e.g., pdf, png, docx). Example: **fileFormat=pdf** (2) **Custom template ID** syntax: ragicCustomPrintTemplateId="Template ID". Example: **ragicCustomPrintTemplateId=1** To obtain the "Template ID", first manually download the Custom Print Report and find the Template ID parameter in the download URL:

      ```

      https://www.ragic.com/demo/sales/1/41.carbone?fileFormat=pdf&fileNameRefDomainId=-1&<b>ragicCustomPrintTemplateId=2</b>

      ```
       (3) **File name referenced field** syntax (Optional)：fileNameRefDomainId="[Field ID](https://www.ragic.com/intl/en/doc-kb/299/What-is-Field-ID%253F)". Example: **fileNameRefDomainId=1001000**
  - name: writing-create
    x-displayName: Creating a New Entry
    description: >
      If you are not using simple HTML forms to create entries on Ragic, you will need to create API requests to create
      the entries. The endpoints for writing to a form is the same as reading them, **but you issue a POST request
      instead of a GET request.** **The API now supports JSON data, and it is the recommended way to make HTTP
      requests.** To POST JSON data, you need to change Body settings to raw JSON, as the image below.
      ![](https://www.ragic.com/sims/file.jsp?a=kb&f=Screen+Shot+2022-07-07+at+9.42.41+AM.png) What you need to do is
      use the field ids of the fields as name, and the values that you want to insert as parameter values. Please note
      that your user will need write access to the form for this to work.


      ```bash

      curl -F "2000123=Dunder Mifflin" \
       -F "2000125=1-267-922-5599" \
       -F "2000127=Jeff Kuo" \
      -F "api=" \
       -H "Authorization:Basic YOUR_API_KEY_GOES_HERE" \
       https://www.ragic.com/demo/sales/1
      ```
       ![](https://www.ragic.com/sims/file.jsp?a=kb&f=Screen+Shot+2022-07-07+at+9.46.48+AM.png) The equivalent JSON format is as below,

      ```json

      {
          "2000123": "Dunder Mifflin",
          "2000125": "1-267-922-5599",
          "2000127": "Jeff Kuo",
      }

      ```
       If the field is a **multiple selection** that can contain multiple values, you can have multiple parameters with the same field id as names. If the field is a **date field** the value will need to be in the format of **yyyy/MM/dd** or **yyyy/MM/dd HH:mm:ss** if there's a time part. So a request would look like this:

      ```bash

      curl -F "2000123=Dunder Mifflin" \
       -F "2000125=1-267-922-5599" \
       -F "2000127=Jeff Kuo" \
       -F "1000001=Customer" \
       -F "1000001=Reseller" \
       -F "2000133=2018/12/25 23:30:00" \
       -F "api=" \
       -H "Authorization:Basic YOUR_API_KEY_GOES_HERE" \
       https://www.ragic.com/demo/sales/1
      ```
       ![](https://www.ragic.com/sims/file.jsp?a=kb&f=Screen+Shot+2022-07-07+at+9.48.05+AM.png) The equivalent JSON format is as below, the squre brackets for the field ID 1000001 allows for multiple values in one statement.

      ```json

      {
          "2000123": "Dunder Mifflin",
          "2000125": "1-267-922-5599",
          "2000127": "Jim Halpert",
          "1000001": ["Customer", "Reseller"],
          "2000133": "2018/12/25 23:30:00"
      }

      ```
       If you would like to insert data into the **subtables** at the same time, you will need a slightly different format for the fields in the subtables because Ragic needs a way to determine if the field values belong to the same entry in a subtable. If the field values are in the same subtable row, assign them with the same negative row id with each other. It can be any negative integer. It's only a way to determine that they are in the same row.

      ```

      2000147_-1=Bill

      2000148_-1=Manager

      2000149_-1=billg@microsoft.com


      2000147_-2=Satya

      2000148_-2=VP

      2000149_-2=satyan@microsoft.com

      ```
       The whole request would look like this:

      ```bash

      curl -F "2000123=Dunder Mifflin" \
       -F "2000125=1-267-922-5599" \
       -F "2000127=Jeff Kuo" \
       -F "1000001=Customer" \
       -F "1000001=Reseller" \
       -F "2000133=2018/12/25 23:30:00" \
       -F "2000147_-1=Bill" \
       -F "2000148_-1=Manager" \
       -F "2000149_-1=billg@microsoft.com" \
       -F "2000147_-2=Satya" \
       -F "2000148_-2=VP" \
       -F "2000149_-2=satyan@microsoft.com" \
      -F 'api=' \
       -H "Authorization:Basic YOUR_API_KEY_GOES_HERE" \
       https://www.ragic.com/demo/sales/1
      ```
       ![](https://www.ragic.com/sims/file.jsp?a=kb&f=Screen+Shot+2022-07-07+at+9.51.52+AM.png) The equivalent JSON format is as below,

      ```json

      {

          "2000123": "Dunder Mifflin",
          "2000125": "1-267-922-5599",
          "2000127": "Jim Halpert",
          "1000001": ["Customer", "Reseller"],
          "2000133": "2018/12/25 23:30:00"
          "_subtable_2000154": {
              "-1": {
                  "2000147": "Bill",
                  "2000148": "Manager",
                  "2000149": "billg@microsoft.com"
              },
             "-2": {
                  "2000147": "Satya",
                  "2000148": "VP",
                  "2000149": "satyan@microsoft.com"
              }
          }
      }

      ```
       If you would like to populate a **file upload field** , just make sure that the request encoding type is a **multipart/form-data**. The HTML equivalent would be setting enctype='multipart/form-data' With a multipart request, you can put the file in your request, and just put the file name as the field value.

      ```

      1000088=test.jpg

      ```
  - name: writing-modify
    x-displayName: Modifying an Entry
    description: >
      Ragic supports using POST, PUT, and PATCH method to modify an entry. The endpoint for modifying an entry is the
      same as reading an existing entry. Notice that when you create an entry, the endpoint points to a Ragic sheet, but
      **when you edit an entry, your endpoint will need an extra record id to point to the exact record**.


      ```

      https://www.ragic.com/<account>/<tab folder>/<sheet index><b>/<record id></record></b>?api


      </sheet></tab></account>

      ```
       All you need to provide is the field ids of the fields that you would like to modify to. If the field is a **date field** the value will need to be in the format of **yyyy/MM/dd** or **yyyy/MM/dd HH:mm:ss** if there's a time part.

      ```bash

      curl -F "2000123=Dunder Mifflin" \
       -F "2000127=Jim Halpert" \
       -F "api=" \
       -H "Authorization:Basic YOUR_API_KEY_GOES_HERE" \
       https://www.ragic.com/demo/sales/1<b>/3</b>
      ```
       ![](https://www.ragic.com/sims/file.jsp?a=kb&f=Screen+Shot+2022-07-07+at+10.18.32+AM.png) The equivalent JSON format is as below,

      ```json

      {
          "2000123": "Dunder Mifflin",
          "2000127": "Jim Halpert"
      }

      ```
       For subtables, it's a bit more tricky. Because Ragic will need to know which row that you're editing. So you will need to find the row id of the row that you're editing. This information can be found from an API call. As we mentioned in earlier chapter, the returned format for an entry with subtables look like this:

      ```

      "_subtable_2000154": {
          "0": {
            "Contact Name": "Jeff Kuo",
            "Title": "Technical Manager",
            "Phone": "886-668-037",
            "E-mail": "jeff@ragic.com",
      ...

      ...
          },
          "1": {
            "Contact Name": "Amy Tsai",
            "Title": "Marketing",
            "Phone": "",
      ...

      ...
          },
          "2": {
            "Contact Name": "Allie Lin",
            "Title": "Purchasing",
      ...

      ...

      ```
       In the subtable, **1** is the row id for the contact Amy Tsai, and **2** is the row id for the contact Allie Lin. With this row id, you can modify data in the subtable pretty much like how you create an entry with subtable data. You use the row id as the identifier following the field id. You only need to put in the fields that you want to modify:

      ```

      2000147_1=Ms. Amy Tsai

      2000148_1=Senior Specialist


      2000148_2=Senior Manager

      ```
       The whole request would be like this:

      ```bash

      curl -F "2000123=Dunder Mifflin" \
       -F "2000127=Jim Halpert" \
       -F "2000147_1=Ms. Amy Tsai" \
       -F "2000148_1=Senior Specialist" \
       -F "2000148_2=Senior Manager" \
       -F "api=" \
       -H "Authorization:Basic YOUR_API_KEY_GOES_HERE" \
       https://www.ragic.com/demo/sales/1<b>/3</b>
      ```
       ![](https://www.ragic.com/sims/file.jsp?a=kb&f=Screen+Shot+2022-07-07+at+10.20.15+AM.png) The equivalent JSON format is as below,

      ```json

      {
          "2000123": "Dwight Schrute",
          "2000127": "Jim Halpert" ,
          "_subtable_2000154": {
              "29" :{
                  "2000147": "Ms. Amy Tsai",
                  "2000148": "Senior Specialist"
              },
              "30" :{
                  "2000148": "Senior Manager"
              }
          }
      }

      ```
       If you want to delete a subtable row, you can create a request like:

      ```

      DELSUB_<subtable key>=<subtable row id>

      </subtable></subtable>

      ```
       The equivalent JSON format is as below,

      ```

      _DELSUB_<subtable key>=[<subtable row id>,<subtable row id>,...,<subtable row id>];

      </subtable></subtable></subtable></subtable>

      ```
       For example, if you want to delete the contact Arden Jacobs, the whole request would be like this:

      ```bash

      curl -F "DELSUB_2000154=3" \
       -F "api=" \
       -H "Authorization:Basic YOUR_API_KEY_GOES_HERE" \
       https://www.ragic.com/demo/sales/1<b>/3</b>
      ```
       ![](https://www.ragic.com/sims/file.jsp?a=kb&f=Screen+Shot+2022-07-07+at+10.21.13+AM.png) The equivalent JSON format is as below,

      ```json

      {
          "_DELSUB_2000154": [3]
      }

      ```
       Using the JSON format for subtable row deletion allows you to specify multiple rows in a simple manner,

      ```json

      {
          "_DELSUB_subtable key": [<subtable row id>,..., <subtable row id>]
      }

      </subtable></subtable>

      ```
  - name: writing-params
    x-displayName: Create / Update Parameters
    description: >
      There are many useful parameters that you can use when creating or updating records on Ragic to save your time
      writing duplicate code for what can be done on Ragic.


      | Parameter Name | Description |

      | --- | --- |

      | doFormula | Specifying doFormula=true tells Ragic API to recalculate all formulas first when a record is created
      or updated. Do note that if this is set to true, the workflow scripts that you configured on the sheet will not
      run to avoid infinite loops. |

      | doDefaultValue | Specifying doDefaultValue=true tells Ragic API to load all default values when a record is
      created or updated. |

      | doLinkLoad | Specifying doLinkLoad=true tells the Ragic API to recalculate all formulas first, and then execute
      all link and load operations when a record is created or updated.


      Specifying doLinkLoad=first tells the Ragic API to execute all link and load operations first, and then
      recalculate all formulas when a record is created or updated.


      When using either of the above parameters and formula recalculation is required, you must also specify
      doFormula=true. |

      | doWorkflow | Specifying doWorkflow=true tells Ragic API to execute the workflow script associated with this API
      call. |

      | notification | Specifying notification=true tells Ragic API to send out notifications to relevant users, or
      false, otherwise. The default is true when not specified. |

      | checkLock | Specifying checkLock=true tells Ragic API to check if the record is locked before an update, and not
      edit the record if the record is locked. |
  - name: writing-delete
    x-displayName: Deleting an Entry
    description: >
      Deleting an entry is very similar to reading an entry. All you need to do is change the request method from GET to
      **DELETE**. When it's a DELETE request, the entry at the API endpoint will be deleted.


      ```bash

      curl -X DELETE \

      -H "Authorization:Basic YOUR_API_KEY_GOES_HERE" \

      -d "api"  \

      https://www.ragic.com/demo/sales/1/3

      ```
       ![](https://www.ragic.com/sims/file.jsp?a=kb&f=Screen+Shot+2022-07-06+at+6.53.07+PM.png)
  - name: writing-upload
    x-displayName: Upload Files and Images
    description: >
      Make sure your content-type is **multipart/form-data** , and you will be able to upload files.


      ```bash

      curl -F "1000088=@/your/file/path" \

      -F "api=" \

      -F "v=3" \

      -H "Authorization:Basic YOUR_API_KEY_GOES_HERE" \

      https://www.ragic.com/demo/sales/1

      ```
       After a success uploading, you will receive your file in this format.

      ```

      "1000088": "Ni92W2luv@test.jpg",

      ```
       ![](https://www.ragic.com/sims/file.jsp?a=kb&f=Screen+Shot+2022-07-07+at+10.42.52+AM.png) Hover your mouse over the boxed area to expose the drop-down list, and select the "File" option to allow file uploads. ![](https://www.ragic.com/sims/file.jsp?a=kb&f=Screen+Shot+2022-07-07+at+10.43.12+AM.png) If you want to get files just uploaded, follow instruction [here](https://www.ragic.com/intl/en/doc-api/28). If you want to upload files via link, download it first and then follow instruction above.

      ```bash

      curl -o __TEMP_FILE__ YOUR_IMAGE_LINK

      curl -F "1000002=@__TEMP_FILE__" -F "api=" -F "v=3" -H "Authorization:Basic YOUR_API_KEY"
      https://www.ragic.com/demo/sales/1

      ```
       Remember to replace **YOUR_IMAGE_LINK** and **YOUR_API_KEY** You can find your API key in your [Personal Settings](https://www.ragic.com/intl/en/doc-user/20/personal-settings#4) page.
  - name: writing-comment
    x-displayName: Comment
    description: |
      Make sure your content-type is **multipart/form-data**.

      ```bash
      curl -F "at=@/your/file/path" \
      -F "c=yourComment"
      -F "api=" \
      -H "Authorization:Basic YOUR_API_KEY_GOES_HERE" \
      https://www.ragic.com/demo/ragicsales-order-management/10001/2
      ```
       ![](https://www.ragic.com/sims/file.jsp?a=kb&f=commentApi_20250213.png) In the request body, the value of the parameter **c** is the comment(required), and the value of the parameter **at** is the attachment(optional). You can find your API key in your [Personal Settings](https://www.ragic.com/intl/en/doc-user/20/personal-settings#4) page.

      **Response:**

      ```json
      {
        "61": "2025/02/13 14:30",
        "65": "John Smith",
        "66": "Please review this order.",
        "67": "",
        "73": "1739425800000"
      }
      ```
       Field 61 is the formatted timestamp, 65 is the commenter's name, 66 is the comment text, 67 is the attachment filename (empty if none), and 73 is the raw timestamp in milliseconds.
  - name: writing-import
    x-displayName: Import From URL
    description: >
      You must have **SYSAdmin** privileges to use this API. Before using this API, please enable the "[Periodic Import
      from URL](https://www.ragic.com/intl/en/doc/83)" feature. Once the setup is complete, you can trigger the import
      by calling the following API:


      ```bash

      curl -F "importData="

      -F "api=" \

      -H "Authorization:Basic YOUR_API_KEY_GOES_HERE" \

      https://www.ragic.com/demo/ragicsales-order-management/10001

      ```
       ![](https://www.ragic.com/sims/file.jsp?a=kb&f=importData_api_postman.png) When you need to **create or update a large amount of data** , you can also use this method to import all at once instead of making multiple API calls. You can find your API key in your [Personal Settings](https://www.ragic.com/intl/en/doc-user/20/personal-settings#4) page.

      **Response:**


      ```json

      {
        "status": "SUCCESS",
        "msg": "Import completed."
      }

      ```
  - name: writing-lock
    x-displayName: Lock/Unlock
    description: >
      To lock or unlock data using the HTTP API, simply append the query strings "api" and "lock"/"unlock" to the target
      record’s URL and send the request using the POST method.


      ```bash

      curl -X POST https://www.ragic.com/demo/ragicforms23/10004/102?api&lock

      ```



      ```bash

      curl -X POST https://www.ragic.com/demo/ragicforms23/10004/102?api&unlock

      ```
       ![](https://www.ragic.com/sims/file.jsp?a=kb&f=lock_unlock.png) The permissions for locking/unlocking are the same as when performing the action through the form interface. You can find your API key in your [Personal Settings](https://www.ragic.com/intl/en/doc-user/20/personal-settings#4) page.

      **Response:**


      ```json

      {
        "status": "SUCCESS",
        "code": 200
      }

      ```
  - name: writing-action
    x-displayName: Execute Action Button
    description: >
      To execute an **Action Button** through the Http API, you first need to obtain the **Action Button ID**. Use the
      **GET method** to send the following request:


      ```bash

      curl "https://{serverName}/{accountName}{path}/{sheetIndex}/metadata/actionButton?api&category=massOperation" \
        -H "Authorization: {Basic apiKey}"
      ```
       ![](https://www.ragic.com/sims/file.jsp?a=kb&f=getButtonIdAPI1.png) After obtaining the **Action Button ID** , you can use the **POST method** to send the following request and execute the specified Action Button on the target record:

      ```bash

      curl -X POST "https://{serverName}/{accountName}{path}/{sheetIndex}/{recordId}?api&bId={buttonId}" \
        -H "Authorization: Basic apiKey"
      ```
       ![](https://www.ragic.com/sims/file.jsp?a=kb&f=actionButtonAPI.png) **Note:** In addition to having permission to execute the Action Button, you must also have **permission to view the target record** in order to use this Http API. You can find your API key in your [Personal Settings](https://www.ragic.com/intl/en/doc-user/20/personal-settings#4) page.

      **Response:**


      ```json

      {
        "status": "SUCCESS",
        "msg": "Action completed."
      }

      ```
  - name: error-responses
    x-displayName: Error Responses
    description: |
      If the request returned in error, it will look something like this:

      ```json
      {
      "status": "ERROR",
      "code": 303,
      "msg": "Your account has expired."
      }
      ```
       Here is a list of the HTTP status code that might be returned on a Ragic request:

      | HTTP Status | Description |
      | --- | --- |
      | 200 | OK - Everything worked as expected. |
      | 400 | Bad Request - Often missing a required parameter. |
      | 401 | Unauthorized - No valid API key provided. |
      | 402 | Request Failed - Parameters were valid but request failed. |
      | 404 | Not Found - The requested item doesn't exist. |
      | 500, 502, 503, 504 | Server errors - something went wrong on Ragic's end. |

       If there was an error processing your request, it will generally contain an error code and a description. Here is the list of error codes that you might receive as a response to a Ragic request:

      | Error Code Id | Error Description |
      | --- | --- |
      | 101 | Invalid Account Name: {Account_Name} |
      | 102 | Invalid Path: {Path} |
      | 103 | Invalid Form Index: {Form_Index} |
      | 104 | Cannot POST Data To A Custom Form |
      | 105 | Authentication Required Before Using API |
      | 106 | No Access Right |
      | 107 | Resource Bundle Not Found |
      | 108 | Error Loading Requested Form |
      | 109 | Cannot Create More Records |
      | 201 | Error Processing Request Parameters |
      | 202 | Error Executing Request |
      | 203 | POST Request Did Not Finish |
      | 204 | Request Frequency Too High |
      | 301 | Sid Parameter / Session Has Timed Out |
      | 303 | Account Expired |
      | 304 | Secret Key Is Invalid |
      | 402 | Record Locked |
      | 404 | Record Not Found |
  - name: mass-operations
    x-displayName: Mass Operations
    description: >
      Mass operation APIs are designed to perform the same set of operations for multiple records on a sheet in one
      single request. There are two ways of specifying the records to be updated:

        * [where](https://www.ragic.com/intl/en/doc-api/9/Filter-Conditions) filters

      ```

      https://www.ragic.com/< account >/< tab folder >/< sheet index >/massOperation/< Mass Operation Type >?api&where=<
      Field ID >,< Filter Operand >,< Value >

      ```

      - recordId in query string, recordId=< recordId >. e.g. recordId=1&recordId=2


      ```

      https://www.ragic.com/< account >/< tab folder >/< sheet index >/massOperation/< Mass Operation Type
      >?api&recordId=< recordId >

      ```



      ##  Request Format

        * Mass operation APIs are **aynschronous** operations.
        * It is required to modify www to na3, ap5, or eu2 in the API URL based on your Ragic database account URL.

      ```

      HTTP Method - POST

      URL - https://www.ragic.com/< account >/< tab folder >/< sheet index >/massOperation/< Mass Operation Type >?api


      Headers

      Authorization: Basic < API Key >


      Body

      {

      // JSON data that describes the operation to be performed

      }


      ==========


      Response

      {

      "taskId": < A UUID That Identifies The Task >

      }

      ```



      ##  Mass Lock


      The mass lock API allows locking or unlocking multiple records at once. [Mass Lock
      Document](https://www.ragic.com/intl/en/doc-user/64/batch-execute#2)


      ```

      HTTP Method - POST

      URL - https://www.ragic.com/< account >/< tab folder >/< sheet index >/massOperation/massLock?api


      {

      "action": < lock or unlock >

      }


      ==========


      Response

      {

      "taskId": "6dbc796a-07d5-475b-b578-d254eb30f7d2"

      }

      ```



      ##  Mass Approval


      The mass approval API allows approval or rejection of multiple records at once. [Mass Approval
      Document](https://www.ragic.com/intl/en/doc-user/64/batch-execute#3)


      ```

      HTTP Method - POST

      URL - https://www.ragic.com/< account >/< tab folder >/< sheet index >/massOperation/massApproval?api


      {

      "action": < approve or reject >,

      "comment": < optional comment > // optional

      }


      ==========


      Response

      {

      "taskId": "6dbc796a-07d5-475b-b578-d254eb30f7d2"

      }

      ```



      ##  Mass Action Button


      The mass action button API allows the execution of an action button on multiple records at once. [Mass Action
      Button Document](https://www.ragic.com/intl/en/doc-user/64/batch-execute#1)


      ```

      HTTP Method - POST

      URL - https://www.ragic.com/< account >/< tab folder >/< sheet index >/massOperation/massActionButton?api


      {

      "buttonId": < button ID >

      }


      ==========


      Response

      {

      "taskId": "6dbc796a-07d5-475b-b578-d254eb30f7d2"

      }

      ```
       To Fetch The List Of Available Action Buttons On A Sheet

      ```

      HTTP Method - GET

      URL - https://www.ragic.com/< account >/< tab folder >/< sheet index
      >/metadata/actionButton?api&category=massOperation


      ==========


      Response

      {

      "actionButtons": [

      {

      "id": < button ID 1 >,

      "name": < button name 1 >

      },

      .....

      ,{

      "id": < button ID 2 >,

      "name": < button name 2 >

      }

      ]

      }

      ```



      ##  Mass Update


      The mass update API allows updates of field values on multiple records at once. [Mass Update
      Document](https://www.ragic.com/intl/en/doc-user/5/mass-update-records#1)


      ```

      HTTP Method - POST

      URL - https://www.ragic.com/< account >/< tab folder >/< sheet index >/massOperation/massUpdate?api


      {
          "action": [
              {
                  "field": < Field ID >,
                  "value": < New Field Value >
              }
          ]
      }


      ==========


      Response

      {
          "taskId": "6dbc796a-07d5-475b-b578-d254eb30f7d2"
      }

      ```
       The mass update API also supports using on [Internal Users](https://www.ragic.com/intl/en/doc/42/internal-users) and [External Users](https://www.ragic.com/intl/en/doc/43/external-users), but there are some restrictions.

      The following fields cannot be mass updated:

        * E-mail (domainId: 1)
        * Full Name (domainId: 4)
        * System Log (domainId: 10)
        * Status (domainId: 31)
        * Internal/External (domainId: 43)


      Mass updating Ragic Groups (domainId: 3) has to follow the rules below:

        * The value of the key "value" has to be written in JSON Array, which has strings as its content.
        * All special characters has to be used with escape character(\\), especially " has to be used as \".

      ```

      HTTP Method - POST

      URL - https://www.ragic.com/< account >/< tab folder >/< sheet index >/massOperation/massUpdate?api


      {
          "action": [
              {
                  "field": 3,
                  "value": "[\"SYSAdmin\"]"
              }
          ]
      }


      ==========


      Response

      {
          "taskId": "6dbc796a-07d5-475b-b578-d254eb30f7d2"
      }

      ```

      - In Internal Users, it is necessary to have at least one user who's Ragic Group is SYSAdmin.
        * In External Users, the name of users' Ragic Group has to start with "x-" or "X-".

      ##  Mass Search And Replace


      The mass search and replace API allows value replacement on multiple records at once. [Mass Search And Replace
      Document](https://www.ragic.com/intl/en/doc-user/5/mass-update-records#2)


      ```

      HTTP Method - POST

      URL - https://www.ragic.com/< account >/< tab folder >/< sheet index >/massOperation/massSearchReplace?api


      {

      "action": [

      {

      "field": < Field ID >,

      "valueReplaced": < Value To Be Replaced >,

      "valueNew": < Value To Replace With >,

      }

      ]

      }


      ==========


      Response

      {

      "taskId": "6dbc796a-07d5-475b-b578-d254eb30f7d2"

      }

      ```



      ##  Task Progress Tracking


      Mass operations are asynchronous operations. The task Id of the operation can be used to monitor its progress.


      ```

      HTTP Method - GET

      URL - https://www.ragic.com/< account >?api&taskId=< task ID >


      ==========


      Response

      {
        "id": "6dbc796a-07d5-475b-b578-d254eb30f7d2",
        "ap": "myaccount",
        "taskName": "Mass Update",
        "status": "PROCESSING",
        "processed": 50,
        "success": 48,
        "fail": 2,
        "message": ""
      }

      ```
       The `status` field can be `NOT_STARTED`, `PROCESSING`, or `DONE`. The `processed`, `success`, and `fail` fields indicate the number of records handled so far.
  - name: webhooks-about
    x-displayName: What is a Webhook
    description: >
      Webhook is a way for your external application to subscribe to changes to your Ragic application. By subscribing
      to the changes, whenever a change is made on Ragic, Ragic will call the Webhook URL you provided to notify you of
      the change, including the ID of exact record that has been changed. The biggest advantage of using a webhook API
      instead of a RESTful API, is that it is a lot more efficient in processing changes. You no longer have to poll the
      API every X hours to watch for latest changes.
  - name: webhooks-ragic
    x-displayName: Webhooks on Ragic
    description: >
      You can find webhook for a sheet on Ragic by clicking on the Tools button at the top. You will find the webhook in
      the Sync section. ![](https://www.ragic.com/sims/file.jsp?a=kb&f=_clipboard1588559009475.png) Things to note on
      the webhook API:

        1. It will be triggered on create, update, and delete.
        2. It is not completely synchronized, there may be a slight delay when the loading is high.
        3. Changes will not include changes on related sheets like multiple versions.

      ![](https://www.ragic.com/sims/file.jsp?a=kb&f=_clipboard1755662616003.png) Click on the “webhook” feature and
      enter the URL that should receive this notification, and you’re done. You can also opt in to receive full
      information on the modified data by checking the checkbox "send full content on changed record". To cancel the
      webhook configuration, click on the x in the corner of the webhook configuration box. The JSON format **without
      full content** would look like


      ```json

      [1 ,2 ,4]

      ```
       For this example, it means entries with node ID 1 & 2 & 4 were changed. The JSON format **with full content** would look like

      ```json

      {
        "data": [
                < THE MODIFIED DATA ENTRY IN JSON >
         ]
        "apname": "< ACCOUNT NAME >",
        "path": "< PATH NAME >",
        "sheetIndex": < SHEET INDEX >,
        "eventType": "< EVENT TYPE CREATE/UPDATE/DELETE >"
      }

      ```
       You can also choose the types of events you want to trigger the webhook. We provide the following options: **Trigger on new entry** , **Trigger on entry update** , **Trigger on entry deletion**. Example of **Trigger on new entry** :

        1. Create a record on the form page
        2. Add a record on the list page

      (Note: since other unmodified records are also saved here, this will generate a large number of Trigger on entry
      update)
        1. Restore a record deleted
        2. Mass create
        3. Import

      Example of **Trigger on entry update** :

        1. Edit a record on the form page
        2. Edit a record on the list page

      (Note: since other unmodified records are also saved here, this will generate a large number of Event: update)
        1. Mass update
        2. Find & Replace
        3. Import

      Example of **Trigger on entry deletion** :

        1. Delete a record on the form page
        2. Delete a record on the list page
  - name: webhooks-signature
    x-displayName: Webhook Signature
    description: >
      ## Purpose of Signature


      To ensure that the Webhook request truly comes from Ragic and that its content has not been tampered with,
      Webhooks configured as "Send full content of changed record." will include a signature in the request. After
      receiving the Webhook, you can use the public key we provide to verify the signature. If verification fails, it
      means the request may have been tampered with, and it is recommended to reject processing.


      ## Verification Process


      ### 1. Obtain string-to-sign


      1.1. Extract the data property from the Webhook request. (The data property should be in JSONArray format) 1.2.
      Serialize it into a JSON string with **keys sorted alphabetically** , **no indentation** , and **no line breaks**.
      In other words, "for each object in the JSONArray, reorder all fields alphabetically, then output as a single-line
      JSON".


      ```javascript

      // Before conversion (original data property):

      [
        {
          "1001030":"banana",
          "1001029":"apple"
        }
      ]


      // After conversion (string-to-sign):

      [{"1001029":"apple","1001030":"banana"}]

      ```
       **Note:** If the serialization method is inconsistent with ours, the signature verification will fail.

      ### 2. Verify the signature


      2.1. Extract the signature property from the Webhook request. 2.2. Download the public key (see "Get Public Key").
      2.3. Use a verification tool that supports SHA256withRSA.

        1. Convert the string-to-sign into a UTF-8 byte array
        2. Verify the signature using the public key and algorithm

      2.4. If verification succeeds, it means the request is from Ragic and its content has not been tampered with.


      ## Get Public Key


      We provide two ways for you to obtain the public key. Choose the one that best fits your use case:

        1. Get the public key string directly by calling: https://www.ragic.com/api/http/getWebhookSignaturePublicKey.jsp?type=string
        2. Click [here](https://www.ragic.com/api/http/getWebhookSignaturePublicKey.jsp?type=pem) to download the PEM file.

      It is recommended to cache the public key on your server and only re-download it on startup.


      ## Other Notes

        * If you are using the Private Host version, or if "Send full content of changed record" is not enabled, the Webhook will not support signature verification.
        * Make sure your program handles JSON serialization consistently; otherwise, verification errors will occur.
x-tagGroups:
  - name: Getting Started
    tags:
      - introduction
  - name: Authentication
    tags:
      - auth-basic
      - auth-password
  - name: Reading
    tags:
      - reading-format
      - reading-filter
      - reading-paging
      - reading-sorting
      - reading-callback
      - reading-naming
      - reading-other-params
      - reading-files
      - reading-exports
  - name: Writing
    tags:
      - writing-create
      - writing-modify
      - writing-params
      - writing-delete
      - writing-upload
      - writing-comment
      - writing-import
      - writing-lock
      - writing-action
  - name: Error Responses
    tags:
      - error-responses
  - name: Mass Operations
    tags:
      - mass-operations
  - name: Webhooks
    tags:
      - webhooks-about
      - webhooks-ragic
      - webhooks-signature
paths:
  /{apname}/{path}/{sheetIndex}:
    get:
      operationId: listRecords
      tags:
        - reading-format
      parameters:
        - $ref: "#/components/parameters/apname"
        - $ref: "#/components/parameters/path"
        - $ref: "#/components/parameters/sheetIndex"
        - $ref: "#/components/parameters/where"
        - $ref: "#/components/parameters/fts"
        - $ref: "#/components/parameters/limit"
        - $ref: "#/components/parameters/offset"
        - $ref: "#/components/parameters/order"
        - $ref: "#/components/parameters/reverse"
        - $ref: "#/components/parameters/subtables"
        - $ref: "#/components/parameters/listing"
        - $ref: "#/components/parameters/naming"
        - $ref: "#/components/parameters/info"
        - $ref: "#/components/parameters/ignoreMask"
        - $ref: "#/components/parameters/ignoreFixedFilter"
        - $ref: "#/components/parameters/filterId"
        - $ref: "#/components/parameters/defaultFilter"
        - $ref: "#/components/parameters/bbcode"
        - $ref: "#/components/parameters/comment"
        - $ref: "#/components/parameters/history"
        - $ref: "#/components/parameters/approval"
        - $ref: "#/components/parameters/conversation"
        - $ref: "#/components/parameters/tz"
        - $ref: "#/components/parameters/version"
        - $ref: "#/components/parameters/v"
        - $ref: "#/components/parameters/taskId"
        - $ref: "#/components/parameters/api"
        - $ref: "#/components/parameters/callback"
      responses:
        "200":
          description: Records retrieved successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RecordList"
              examples:
                simpleList:
                  summary: List of records
                  value:
                    "12345":
                      "1000001": Acme Corp
                      "1000002": "2024-01-15"
                      "1000003": Active
                      _ragicId: 12345
                    "12346":
                      "1000001": Beta Inc
                      "1000002": "2024-01-16"
                      "1000003": Pending
                      _ragicId: 12346
                withSubtable:
                  summary: Record with subtable
                  value:
                    "12345":
                      "1000001": "Order #001"
                      _ragicId: 12345
                      _subtable_1000010:
                        "67890":
                          "1000011": Widget A
                          "1000012": 5
                          "1000013": 100
                        "67891":
                          "1000011": Widget B
                          "1000012": 3
                          "1000013": 50
                withInfo:
                  summary: Record with metadata (info=1)
                  value:
                    "12345":
                      "1000001": Sample Record
                      _ragicId: 12345
                      _seq: "001"
                      _create_date: "2024-01-15 10:30:00"
                      _create_user: user@example.com
                      _update_date: "2024-01-16 14:20:00"
                      _update_user: user@example.com
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
      summary: List records
      description: >
        Retrieve a list of records from a form/sheet.


        The listing is defaulted to 1000 entries. You can add paging parameters **limit** and **offset** to specify how
        many entries that you would like to retrieve, and how many entries that you would like to skip.


        **Example:** Get records with pagination

        ```bash

        curl -H "Authorization:Basic YOUR_API_KEY_GOES_HERE" \
          "https://www.ragic.com/demo/sales/1?api&limit=50&offset=0"
        ```


        Use `subtables=0` parameter to exclude subtable data for faster response.


        ---


        ## Check Task Progress


        When a mass operation returns a `taskId`, you can check its progress by passing the `taskId` query parameter to
        this endpoint.


        **Example:**

        ```bash

        curl -H "Authorization:Basic YOUR_API_KEY_GOES_HERE" \
          "https://www.ragic.com/demo/sales/1?api&taskId=550e8400-e29b-41d4-a716-446655440000"
        ```


        **Response:**

        ```json

        {
          "status": "RUNNING",
          "progress": 45,
          "total": 100,
          "message": "Processing records..."
        }

        ```


        When `status` is `COMPLETED` or `FAILED`, the task is finished.
    post:
      operationId: createRecord
      tags:
        - writing-create
      parameters:
        - $ref: "#/components/parameters/apname"
        - $ref: "#/components/parameters/path"
        - $ref: "#/components/parameters/sheetIndex"
        - $ref: "#/components/parameters/doFormula"
        - $ref: "#/components/parameters/doDefaultValue"
        - $ref: "#/components/parameters/doLinkLoad"
        - $ref: "#/components/parameters/doWorkflow"
        - $ref: "#/components/parameters/notification"
        - $ref: "#/components/parameters/info"
        - $ref: "#/components/parameters/importData"
        - $ref: "#/components/parameters/tz"
        - $ref: "#/components/parameters/version"
        - $ref: "#/components/parameters/v"
        - $ref: "#/components/parameters/api"
        - $ref: "#/components/parameters/callback"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/RecordInput"
            examples:
              simpleCreate:
                summary: Create a simple record
                value:
                  "1000001": New Customer
                  "1000002": "2024-01-15"
                  "1000003": Active
              withSubtable:
                summary: Create record with subtable rows
                value:
                  "1000001": New Order
                  _subtable_1000010:
                    "-1":
                      "1000011": Item A
                      "1000012": 2
                    "-2":
                      "1000011": Item B
                      "1000012": 5
          multipart/form-data:
            schema:
              $ref: "#/components/schemas/RecordInputMultipart"
      responses:
        "200":
          description: Record created successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/MutationResponse"
              examples:
                success:
                  summary: Successful creation
                  value:
                    status: SUCCESS
                    rv: "12345"
                    ragicId: 12345
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
      summary: Creating a New Entry
      description: >
        To create entries via API instead of HTML forms, use a POST request (not GET) to the same endpoint used for
        reading.


        The API now supports JSON data, and it is the recommended way to make HTTP requests.


        Field IDs serve as parameter names, with desired values as the values. Users need write access to the form for
        this to function.


        If the field is a **date field** the value will need to be in the format of **yyyy/MM/dd** or **yyyy/MM/dd
        HH:mm:ss** when time is included.


        **Example cURL request:**

        ```bash

        curl -F "1000001=New Order" \
          -F "1000002=2024/01/15" \
          -F "api=" \
          -H "Authorization:Basic YOUR_API_KEY_GOES_HERE" \
          https://www.ragic.com/demo/sales/1
        ```


        **JSON equivalent:**

        ```json

        {
          "1000001": "New Order",
          "1000002": "2024/01/15"
        }

        ```


        **With subtable rows:**

        When populating subtables simultaneously, field values in the same row must share identical negative row
        identifiers (any negative integer).

        ```json

        {
          "1000001": "New Order",
          "_subtable_1000010": {
            "-1": {"1000011": "Item A", "1000012": 2},
            "-2": {"1000011": "Item B", "1000012": 5}
          }
        }

        ```
  /{apname}/{path}/{sheetIndex}/{rootNodeId}:
    get:
      operationId: getRecord
      tags:
        - reading-format
      parameters:
        - $ref: "#/components/parameters/apname"
        - $ref: "#/components/parameters/path"
        - $ref: "#/components/parameters/sheetIndex"
        - $ref: "#/components/parameters/rootNodeId"
        - $ref: "#/components/parameters/subtables"
        - $ref: "#/components/parameters/naming"
        - $ref: "#/components/parameters/info"
        - $ref: "#/components/parameters/ignoreMask"
        - $ref: "#/components/parameters/bbcode"
        - $ref: "#/components/parameters/comment"
        - $ref: "#/components/parameters/history"
        - $ref: "#/components/parameters/approval"
        - $ref: "#/components/parameters/conversation"
        - $ref: "#/components/parameters/tz"
        - $ref: "#/components/parameters/version"
        - $ref: "#/components/parameters/v"
        - $ref: "#/components/parameters/api"
      responses:
        "200":
          description: Record retrieved successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SingleRecord"
              examples:
                simpleRecord:
                  summary: Single record
                  value:
                    "12345":
                      "1000001": Acme Corp
                      "1000002": "2024-01-15"
                      _ragicId: 12345
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
      summary: Get single record
      description: |
        Retrieve a specific record by its ID (rootNodeId).

        **Example:** Get record #12345
        ```bash
        curl -H "Authorization:Basic YOUR_API_KEY_GOES_HERE" \
          "https://www.ragic.com/demo/sales/1/12345?api"
        ```
    post:
      operationId: updateRecord
      tags:
        - writing-modify
      parameters:
        - $ref: "#/components/parameters/apname"
        - $ref: "#/components/parameters/path"
        - $ref: "#/components/parameters/sheetIndex"
        - $ref: "#/components/parameters/rootNodeId"
        - $ref: "#/components/parameters/doFormula"
        - $ref: "#/components/parameters/doDefaultValue"
        - $ref: "#/components/parameters/doLinkLoad"
        - $ref: "#/components/parameters/doWorkflow"
        - $ref: "#/components/parameters/notification"
        - $ref: "#/components/parameters/checkLock"
        - $ref: "#/components/parameters/lock"
        - $ref: "#/components/parameters/unlock"
        - $ref: "#/components/parameters/bId"
        - $ref: "#/components/parameters/info"
        - $ref: "#/components/parameters/tz"
        - $ref: "#/components/parameters/version"
        - $ref: "#/components/parameters/v"
        - $ref: "#/components/parameters/api"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/RecordInput"
            examples:
              updateFields:
                summary: Update specific fields
                value:
                  "1000003": Completed
                  "1000004": "2024-01-20"
              addSubtableRow:
                summary: Add a subtable row
                value:
                  _subtable_1000010:
                    "-1":
                      "1000011": New Item
                      "1000012": 3
              deleteSubtableRow:
                summary: Delete a subtable row
                value:
                  DELSUB: "67890"
          multipart/form-data:
            schema:
              $ref: "#/components/schemas/RecordInputMultipart"
      responses:
        "200":
          description: Record updated successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/MutationResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
      summary: Modifying an Entry
      description: >
        The Ragic API supports POST, PUT, and PATCH methods to modify entries. When you edit an entry, your endpoint
        will need an extra record id to point to the exact record.


        You only need to provide field IDs for fields you want to change. Date fields require `yyyy/MM/dd` or
        `yyyy/MM/dd HH:mm:ss` format.


        **Example cURL request:**

        ```bash

        curl -F "2000123=Dunder Mifflin" \
          -F "2000127=Jim Halpert" \
          -F "api=" \
          -H "Authorization:Basic YOUR_API_KEY_GOES_HERE" \
          https://www.ragic.com/demo/sales/1/3
        ```


        **JSON equivalent:**

        ```json

        {
          "2000123": "Dunder Mifflin",
          "2000127": "Jim Halpert"
        }

        ```


        **Subtable Modifications:**

        For subtable rows, you must identify the row ID from API responses. The format uses `fieldid_rowid` notation.

        ```json

        {
          "_subtable_2000154": {
            "29": {
              "2000147": "Ms. Amy Tsai",
              "2000148": "Senior Specialist"
            }
          }
        }

        ```


        **Deleting Subtable Rows:**

        To delete specific rows from a subtable, use `_DELSUB_{subtableFieldId}` with an array of row IDs to remove. Get
        the row IDs from a previous GET response.

        ```json

        {
          "_DELSUB_2000154": [3]
        }

        ```

        Delete multiple rows at once: `"_DELSUB_2000154": [3, 7, 12]`
    delete:
      operationId: deleteRecord
      tags:
        - writing-delete
      parameters:
        - $ref: "#/components/parameters/apname"
        - $ref: "#/components/parameters/path"
        - $ref: "#/components/parameters/sheetIndex"
        - $ref: "#/components/parameters/rootNodeId"
        - $ref: "#/components/parameters/version"
        - $ref: "#/components/parameters/v"
        - $ref: "#/components/parameters/api"
      responses:
        "200":
          description: Record deleted successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DeleteResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
      summary: Deleting an Entry
      description: |
        Delete a record by its ID.

        **Warning:** This action cannot be undone.

        **Example:**
        ```bash
        curl -X DELETE \
          -H "Authorization:Basic YOUR_API_KEY_GOES_HERE" \
          "https://www.ragic.com/demo/sales/1/12345?api"
        ```
  /sims/file.jsp:
    get:
      operationId: getFile
      tags:
        - reading-files
      parameters:
        - name: a
          in: query
          required: true
          schema:
            type: string
          example: demo
        - name: f
          in: query
          required: true
          schema:
            type: string
          example: Ni92W2luv@My_Picture.jpg
      responses:
        "200":
          description: File content
          content:
            application/octet-stream:
              schema:
                type: string
                format: binary
        "404":
          $ref: "#/components/responses/NotFound"
      summary: Retrieve uploaded file
      description: |
        Download an uploaded file, image, or email attachment.

        File references appear in JSON responses with format: `"1000537": "Ni92W2luv@My_Picture.jpg"`

        The actual filename follows the "@" character to prevent naming collisions.

        **Example:** Download a file
        ```bash
        curl "https://www.ragic.com/sims/file.jsp?a=demo&f=Ni92W2luv@My_Picture.jpg"
        ```

        Note: File names must be URL-encoded when sent as parameters.
  /{apname}/{path}/{sheetIndex}/{rootNodeId}.xhtml:
    get:
      operationId: getRecordHtml
      tags:
        - reading-exports
      parameters:
        - $ref: "#/components/parameters/apname"
        - $ref: "#/components/parameters/path"
        - $ref: "#/components/parameters/sheetIndex"
        - $ref: "#/components/parameters/rootNodeId"
      responses:
        "200":
          description: HTML printer friendly version
          content:
            text/html:
              schema:
                type: string
      summary: Get HTML printer friendly version
      description: |
        You can retrieve an HTML printer friendly version by adding `.xhtml` to the end of the record URL.

        **Example:**
        ```
        https://www.ragic.com/demo/sales/1/41.xhtml
        ```
  /{apname}/{path}/{sheetIndex}/{rootNodeId}.pdf:
    get:
      operationId: getRecordPdf
      tags:
        - reading-exports
      parameters:
        - $ref: "#/components/parameters/apname"
        - $ref: "#/components/parameters/path"
        - $ref: "#/components/parameters/sheetIndex"
        - $ref: "#/components/parameters/rootNodeId"
      responses:
        "200":
          description: PDF version of the record
          content:
            application/pdf:
              schema:
                type: string
                format: binary
      summary: Get PDF version
      description: |
        Get the PDF version of a record by adding `.pdf` to the end of the record URL.

        **Example:**
        ```
        https://www.ragic.com/demo/sales/1/41.pdf
        ```
  /{apname}/{path}/{sheetIndex}/{rootNodeId}.xlsx:
    get:
      operationId: getRecordExcel
      tags:
        - reading-exports
      parameters:
        - $ref: "#/components/parameters/apname"
        - $ref: "#/components/parameters/path"
        - $ref: "#/components/parameters/sheetIndex"
        - $ref: "#/components/parameters/rootNodeId"
      responses:
        "200":
          description: Excel version of the record
          content:
            application/vnd.openxmlformats-officedocument.spreadsheetml.sheet:
              schema:
                type: string
                format: binary
      summary: Get Excel version
      description: |
        Get the Excel version of a record by adding `.xlsx` to the end of the record URL.

        **Example:**
        ```
        https://www.ragic.com/demo/sales/1/41.xlsx
        ```
  /{apname}/{path}/{sheetIndex}/{rootNodeId}.custom:
    get:
      operationId: getRecordMailMerge
      tags:
        - reading-exports
      parameters:
        - $ref: "#/components/parameters/apname"
        - $ref: "#/components/parameters/path"
        - $ref: "#/components/parameters/sheetIndex"
        - $ref: "#/components/parameters/rootNodeId"
        - name: cid
          in: query
          required: true
          schema:
            type: integer
          example: 1
      responses:
        "200":
          description: Mail merge document
          content:
            application/octet-stream:
              schema:
                type: string
                format: binary
      summary: Get Mail Merge document
      description: >
        Mail Merge generates a document (e.g., a contract, invoice, or letter) from a template that fills in data from
        the record. Add `.custom` and a template ID (`cid`) to download the generated document.


        To find the `cid`, manually download a Mail Merge document from the Ragic interface and look for the `cid`
        parameter in the download URL.


        **Example:**

        ```

        https://www.ragic.com/demo/sales/1/41.custom?cid=1

        ```
  /{apname}/{path}/{sheetIndex}/metadata/actionButton:
    get:
      operationId: getActionButtonMetadata
      tags:
        - writing-action
      parameters:
        - $ref: "#/components/parameters/apname"
        - $ref: "#/components/parameters/path"
        - $ref: "#/components/parameters/sheetIndex"
        - name: category
          in: query
          required: false
          schema:
            type: string
            enum:
              - massOperation
        - $ref: "#/components/parameters/api"
      responses:
        "200":
          description: Action button list retrieved successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ActionButtonList"
              examples:
                buttonList:
                  summary: List of action buttons
                  value:
                    - id: btn_001
                      name: Send Notification
                    - id: btn_002
                      name: Generate Report
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
      summary: Get action button metadata
      description: |
        Retrieve a list of action buttons configured on a form/sheet.

        Use the optional `category=massOperation` parameter to filter for buttons that support mass operations.

        **Example:**
        ```bash
        curl -H "Authorization:Basic YOUR_API_KEY_GOES_HERE" \
          "https://www.ragic.com/demo/sales/1/metadata/actionButton?api"
        ```

        **Filter for mass operation buttons:**
        ```bash
        curl -H "Authorization:Basic YOUR_API_KEY_GOES_HERE" \
          "https://www.ragic.com/demo/sales/1/metadata/actionButton?api&category=massOperation"
        ```

        **Response:**
        ```json
        [
          {"id": "btn_001", "name": "Send Notification"},
          {"id": "btn_002", "name": "Generate Report"}
        ]
        ```
  /{apname}/{path}/{sheetIndex}/massOperation/{operationType}:
    post:
      operationId: executeMassOperation
      tags:
        - mass-operations
      parameters:
        - $ref: "#/components/parameters/apname"
        - $ref: "#/components/parameters/path"
        - $ref: "#/components/parameters/sheetIndex"
        - name: operationType
          in: path
          required: true
          schema:
            type: string
            enum:
              - massUpdate
              - massSearchReplace
              - massLock
              - massApproval
              - massActionButton
        - $ref: "#/components/parameters/where"
        - name: recordId
          in: query
          required: false
          schema:
            type: array
            items:
              type: integer
          style: form
          explode: true
        - $ref: "#/components/parameters/api"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
            examples:
              massUpdate:
                summary: Mass update fields
                value:
                  "1000001": New Value
                  "1000002": 2024/06/01
              massSearchReplace:
                summary: Mass search and replace
                value:
                  fieldId: "1000001"
                  search: old text
                  replace: new text
              massLock:
                summary: Mass lock records
                value:
                  lock: true
              massApproval:
                summary: Mass approval
                value:
                  action: approve
              massActionButton:
                summary: Mass action button
                value:
                  bId: btn_001
      responses:
        "200":
          description: Mass operation accepted
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/MassOperationResponse"
              examples:
                accepted:
                  summary: Operation accepted
                  value:
                    taskId: 550e8400-e29b-41d4-a716-446655440000
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
      summary: Execute mass operation
      description: >
        Execute a bulk operation on multiple records at once. All mass operations are asynchronous and return a `taskId`
        that can be used to check progress.


        **Record Selection:** Use the `where` query parameter or `recordId` query parameter to select which records to
        operate on.


        **Operation Types:**


        ### massUpdate

        Update field values across multiple records.

        ```json

        {
          "1000001": "New Value",
          "1000002": "2024/06/01"
        }

        ```


        ### massSearchReplace

        Search for text in a field and replace it across multiple records.

        ```json

        {
          "fieldId": "1000001",
          "search": "old text",
          "replace": "new text"
        }

        ```


        ### massLock

        Lock or unlock multiple records.

        ```json

        {"lock": true}

        ```


        ### massApproval

        Approve or reject multiple records at once.

        ```json

        {"action": "approve"}

        ```


        ### massActionButton

        Execute an action button across multiple records.

        ```json

        {"bId": "btn_001"}

        ```


        **Response:**

        ```json

        {"taskId": "550e8400-e29b-41d4-a716-446655440000"}

        ```


        Use the `taskId` with the List Records endpoint to check progress.
  /AUTH:
    get:
      operationId: passwordAuth
      tags:
        - auth-password
      security: []
      parameters:
        - name: u
          in: query
          required: true
          schema:
            type: string
          example: user@example.com
        - name: p
          in: query
          required: true
          schema:
            type: string
          example: password123
        - name: login_type
          in: query
          required: false
          schema:
            type: string
            enum:
              - sessionId
        - name: json
          in: query
          required: false
          schema:
            type: integer
            enum:
              - 1
        - name: api
          in: query
          required: false
          schema:
            type: string
      responses:
        "200":
          description: Authentication successful
          content:
            text/plain:
              schema:
                type: string
              examples:
                sessionId:
                  summary: Session ID response
                  value: abc123def456
            application/json:
              schema:
                $ref: "#/components/schemas/AuthResponse"
              examples:
                jsonResponse:
                  summary: JSON response (json=1)
                  value:
                    status: SUCCESS
                    sid: abc123def456
                    email: user@example.com
                    accounts:
                      - myaccount
                      - otheraccount
        "401":
          $ref: "#/components/responses/Unauthorized"
      summary: Password authentication
      description: >
        Authenticate a user with email and password to obtain a session ID. This is a secondary authentication method;
        **HTTP Basic Auth with API keys is recommended** for most use cases.


        No authentication headers are needed for this endpoint — it IS the authentication endpoint.


        **Basic usage (returns session ID as plain text):**

        ```bash

        curl "https://www.ragic.com/AUTH?u=user@example.com&p=mypassword&api"

        ```


        **With JSON response (includes account list):**

        ```bash

        curl "https://www.ragic.com/AUTH?u=user@example.com&p=mypassword&json=1&api"

        ```


        **JSON Response:**

        ```json

        {
          "status": "SUCCESS",
          "sid": "abc123def456",
          "email": "user@example.com",
          "accounts": ["myaccount", "otheraccount"]
        }

        ```


        **Using the session ID:** Pass the returned session ID as a cookie (`JSESSIONID`) or use `login_type=sessionId`
        to get a session-based cookie directly.
components:
  securitySchemes:
    basicAuth:
      type: http
      scheme: basic
      description: |
        HTTP Basic Authentication using your email and API key.
        Obtain your API key from Account Settings > API.
    apiKey:
      type: apiKey
      in: query
      name: api
      description: |
        API key passed as a query parameter.
        Less secure than Basic Auth; use only when necessary.
    sessionAuth:
      type: apiKey
      in: cookie
      name: JSESSIONID
      description: |
        Session-based authentication using a JSESSIONID cookie obtained from the /AUTH endpoint.
        Use HTTP Basic Auth with API keys for most integrations.
  parameters:
    apname:
      name: apname
      in: path
      required: true
      schema:
        type: string
        example: myaccount
      description: Your account name (the subdomain in your Ragic URL, e.g., "demo" in www.ragic.com/demo/...)
    path:
      name: path
      in: path
      required: true
      schema:
        type: string
        example: sales
      description: The folder path from your URL (e.g., "sales" or "hr/employees")
    sheetIndex:
      name: sheetIndex
      in: path
      required: true
      schema:
        type: integer
        example: 1
      description: The sheet number from your URL (the number after the folder path)
    rootNodeId:
      name: rootNodeId
      in: path
      required: true
      schema:
        type: integer
        example: 12345
      description: The record ID from your URL (shown when viewing a single record)
    where:
      name: where
      in: query
      required: false
      style: form
      explode: true
      schema:
        type: array
        items:
          type: string
      examples:
        equals:
          summary: Equals filter
          value:
            - 1000001,eq,Active
        multipleFilters:
          summary: Multiple filters (AND)
          value:
            - 1000001,eq,Active
            - 1000002,gt,100
        contains:
          summary: Contains (LIKE)
          value:
            - 1000001,lk,Corp
        dateRange:
          summary: Date range
          value:
            - 1000002,range,2024/01/01~2024/12/31
      description: >
        Filter condition with comma-delimited arguments. Format: `fieldId,operand,value`


        **Available Operands:**

        - `eq` - Equals

        - `regex` - Regular Expression

        - `gte` - Greater or equals

        - `lte` - Less or equals

        - `gt` - Greater

        - `lt` - Less

        - `like` - Contains

        - `eqeq` - Exact match by internal record ID (advanced; rarely needed)


        Multiple "eq", "regex", or "like" conditions on the same field act as OR operations.

        Combining gte/gt and lte/lt conditions on the same field creates AND operations (useful for date ranges).


        Date/datetime values must use format: `yyyy/MM/dd` or `yyyy/MM/dd HH:mm:ss`


        **Empty value filtering:** leave third argument blank, e.g., `where=2000127,eq,`


        **Commas in filter values** require URL encoding (`%2C`)


        **Double URL encoding:** If a filter value contains `%` followed by hexadecimal characters (e.g., `%20`), the
        `%` must be double URL-encoded as `%25` to prevent the server from interpreting it as an already-encoded
        character. For example, to search for the literal text `100%`, encode it as `100%2525`.


        **Example:** `where=2000123,eq,Alphabet Inc.`
    fts:
      name: fts
      in: query
      required: false
      schema:
        type: string
        example: search term
      description: |
        Full-text search for keyword matching across all searchable fields.

        **Example:** `fts=search term`
    limit:
      name: limit
      in: query
      required: false
      schema:
        type: string
      examples:
        countOnly:
          summary: First N records
          value: "50"
        offsetAndCount:
          summary: Skip then take
          value: 100,50
      description: >
        Specify how many entries that you would like to retrieve.


        Returned data is defaulted to 1000 entries, you will need to provide limit parameters if you want your response
        to have more than 1000 entries.


        **Example:** `limit=50` - Return 50 records
    offset:
      name: offset
      in: query
      required: false
      schema:
        type: integer
        example: 0
      description: >
        Specify how many entries that you would like to skip.


        Use with limit for pagination. For example, to skip the first 5 entries and return entries 6-13 (a total of 8
        entries): `limit=8&offset=5`
    order:
      name: order
      in: query
      required: false
      schema:
        type: string
      examples:
        ascending:
          summary: Ascending
          value: 1000001,ASC
        descending:
          summary: Descending
          value: 1000001,DESC
      description: |
        Sort order. Format: `fieldId,ASC` or `fieldId,DESC`

        By default, data is ordered by creation date and time, from oldest to latest entry.

        **Example:** `order=800236,DESC` - Sort by field 800236 in descending order
    subtables:
      name: subtables
      in: query
      required: false
      schema:
        type: string
        default: "1"
      description: |
        Include subtable data in the response.
        - `1` (default) - Include subtables
        - `0` - Exclude subtables (faster response for large datasets)
    listing:
      name: listing
      in: query
      required: false
      schema:
        type: string
      description: >
        Return only the fields configured to appear in the sheet's list view (the columns visible when browsing records
        in Ragic). Use this when building a table/list UI where you don't need every field — the response is smaller and
        faster.

        - Not set (default) - Full record data (all fields)

        - `1` - List view fields only
    naming:
      name: naming
      in: query
      required: false
      schema:
        type: string
        enum:
          - EID
          - FNAME
      description: >
        Choose how fields are named in the response JSON keys.

        - `EID` (default) - Use numeric field IDs (e.g., `"1000001": "Acme Corp"`). Recommended for integrations because
        IDs never change.

        - `FNAME` - Use human-readable field names (e.g., `"Customer Name": "Acme Corp"`). Useful for debugging, but may
        break if field names contain special characters or are renamed.
    info:
      name: info
      in: query
      required: false
      schema:
        type: string
      description: >
        Include record metadata (who created/modified it and when). Useful for audit logs or sync operations.

        - Not set (default) - Field values only

        - `1` - Also include `_create_date`, `_create_user`, `_update_date`, `_update_user`, `_seq` (auto-generated
        sequence number)
    ignoreMask:
      name: ignoreMask
      in: query
      required: false
      schema:
        type: string
      description: >
        Some fields in Ragic can be configured to mask sensitive data (e.g., showing a phone number as `***-**1234`).
        This parameter reveals the full unmasked values. Requires appropriate permissions.

        - Not set (default) - Apply field masking

        - `1` - Show unmasked values
    filterId:
      name: filterId
      in: query
      required: false
      schema:
        type: integer
      description: >
        Apply a saved filter by its ID. Saved filters are pre-configured search criteria created in the Ragic UI
        (accessible from the filter dropdown on any sheet). Use this instead of building complex `where` parameters.
    defaultFilter:
      name: defaultFilter
      in: query
      required: false
      schema:
        type: string
      description: >
        Apply the sheet's default filter (a pre-configured filter set by the form designer in form settings). This
        returns the same filtered results users see by default in the Ragic UI.

        - Not set (default) - No default filter applied

        - `1` - Apply the default filter
    comment:
      name: comment
      in: query
      required: false
      schema:
        type: string
      description: >
        Include the comment/note thread attached to each record. Comments are discussion notes that users add via the
        Ragic UI.

        - Not set (default) - Exclude comments

        - `1` - Include comments in the response
    history:
      name: history
      in: query
      required: false
      schema:
        type: string
      description: >
        Include the field change history for each record — a log of who changed which field, when, and what the old/new
        values were. Useful for audit trails.

        - Not set (default) - Exclude history

        - `1` - Include modification history
    approval:
      name: approval
      in: query
      required: false
      schema:
        type: string
      description: >
        Include approval workflow status. Ragic's approval feature lets you set up multi-step sign-off processes for
        records. This returns the current approval status, approver list, and approval history.

        - Not set (default) - Exclude approval info

        - `1` - Include approval status and history
    conversation:
      name: conversation
      in: query
      required: false
      schema:
        type: string
      description: >
        Include the email conversation thread tied to a record. When records have associated email threads (via Ragic's
        email features), this returns those messages.

        - Not set (default) - Exclude conversation

        - `1` - Include conversation messages
    tz:
      name: tz
      in: query
      required: false
      schema:
        type: number
        example: -8
      description: |
        Timezone offset in hours for date/time fields.

        **Example:** `tz=-8` for UTC-8 (Pacific Time)

        Date values in the response will be adjusted to this timezone.
    api:
      name: api
      in: query
      required: false
      schema:
        type: string
      description: |
        API key for authentication (alternative to HTTP Basic Auth).

        **Example:** `api=YOUR_API_KEY`
    callback:
      name: callback
      in: query
      required: false
      schema:
        type: string
      description: >
        JSONP callback function name. Adding a callback function parameter will enclose the returned JSON object as an
        argument in a call to the callback function specified by you. This is particularly valuable when you're
        accessing our API using Javascript for cross domain ajax calls.


        **Example:** `callback=testFunc`


        Response will be wrapped: `testFunc({"17": {"Account Name": "Dunder Mifflin", ...}});`
    doFormula:
      name: doFormula
      in: query
      required: false
      schema:
        type: string
        enum:
          - "true"
          - "false"
        default: "false"
      description: |
        Execute formulas after saving.
        - `false` (default for API) - Skip formula execution
        - `true` - Run formulas (may affect performance)
    doDefaultValue:
      name: doDefaultValue
      in: query
      required: false
      schema:
        type: string
        enum:
          - "true"
          - "false"
        default: "false"
      description: |
        Apply default values for empty fields.
        - `false` (default for API) - Skip default values
        - `true` - Apply configured default values
    doLinkLoad:
      name: doLinkLoad
      in: query
      required: false
      schema:
        type: string
        enum:
          - "true"
          - "false"
          - first
        default: "false"
      description: >
        Execute "Link & Load" operations. In Ragic, Link & Load automatically copies data from a linked record into the
        current record (e.g., selecting a customer auto-fills their address). By default the API skips this for
        performance.

        - `false` (default for API) - Skip link & load

        - `true` - Execute link & load for all linked fields

        - `first` - Execute link & load only for the first linked field
    doWorkflow:
      name: doWorkflow
      in: query
      required: false
      schema:
        type: string
        enum:
          - "true"
          - "false"
        default: "true"
      description: |
        Trigger workflow actions (pre-workflow, post-workflow).
        - `true` (default) - Trigger workflows
        - `false` - Skip workflow execution
    notification:
      name: notification
      in: query
      required: false
      schema:
        type: string
        enum:
          - "true"
          - "false"
        default: "true"
      description: |
        Send notifications (email, approval notifications).
        - `true` (default) - Send notifications
        - `false` - Skip all notifications
    reverse:
      name: reverse
      in: query
      required: false
      schema:
        type: string
        enum:
          - "true"
      description: |
        Reverse the default ordering of the listing page response.

        To retrieve the most recent entries first, use `reverse=true`

        **Example:** `reverse=true`
    bbcode:
      name: bbcode
      in: query
      required: false
      schema:
        type: string
        enum:
          - "true"
      description: >
        Ragic rich-text fields store formatting in BBCode syntax (e.g., `[b]bold[/b]`). By default, the API converts
        this to HTML. Use this parameter to get the raw BBCode instead.

        - Not set (default) - Return HTML-formatted content

        - `true` - Return raw BBCode formatting
    ignoreFixedFilter:
      name: ignoreFixedFilter
      in: query
      required: false
      schema:
        type: string
        enum:
          - "true"
      description: >
        Fixed filters are permanent filters set by the form designer that restrict which records all users can see
        (e.g., "only show active customers"). This parameter bypasses them. Requires SYSAdmin privileges.

        - Not set (default) - Apply fixed filters

        - `true` - Ignore fixed filters
    checkLock:
      name: checkLock
      in: query
      required: false
      schema:
        type: string
        enum:
          - "true"
      description: |
        Check if the record is locked before an update, and not edit the record if it is locked.
        - Not set (default) - Update regardless of lock status
        - `true` - Check lock status before updating
    version:
      name: version
      in: query
      required: false
      schema:
        type: string
      example: "2025-01-01"
      description: >
        API version using date-based versioning (recommended). Format: `YYYY-MM-DD`


        Using versioning ensures your integration remains stable when Ragic introduces breaking changes. The API will
        behave according to the version you specify.


        **Example:** `version=2025-01-01`
    v:
      name: v
      in: query
      required: false
      schema:
        type: integer
        enum:
          - 1
          - 2
          - 3
      description: |
        Legacy API version number. Use `version` parameter instead for new integrations.
        - `1` - Version 1
        - `2` - Version 2
        - `3` - Version 3 (latest legacy version)
    lock:
      name: lock
      in: query
      required: false
      allowEmptyValue: true
      schema:
        type: string
      description: >
        Lock a record to prevent other users from editing it. Use this parameter with a POST request to the record
        endpoint. No request body is needed.


        **Example:** `POST /demo/sales/1/12345?api&lock`
    unlock:
      name: unlock
      in: query
      required: false
      allowEmptyValue: true
      schema:
        type: string
      description: >
        Unlock a previously locked record. Use this parameter with a POST request to the record endpoint. No request
        body is needed.


        **Example:** `POST /demo/sales/1/12345?api&unlock`
    bId:
      name: bId
      in: query
      required: false
      schema:
        type: string
      description: |
        Execute an action button on a record. Pass the button ID obtained from the Action Button Metadata endpoint.

        **Example:** `POST /demo/sales/1/12345?api&bId=btn_001`
    importData:
      name: importData
      in: query
      required: false
      allowEmptyValue: true
      schema:
        type: string
      description: |
        Import data from a URL into the sheet. Requires SYSAdmin privileges.

        **Example:** `POST /demo/sales/1?api&importData`
    taskId:
      name: taskId
      in: query
      required: false
      schema:
        type: string
        format: uuid
      description: |
        Check the progress of an asynchronous mass operation. Pass the task ID returned by a mass operation endpoint.

        **Example:** `GET /demo/sales/1?api&taskId=550e8400-e29b-41d4-a716-446655440000`
  schemas:
    RecordList:
      type: object
      additionalProperties:
        $ref: "#/components/schemas/RecordData"
      description: A collection of records keyed by rootNodeId
    SingleRecord:
      type: object
      additionalProperties:
        $ref: "#/components/schemas/RecordData"
      description: A single record keyed by rootNodeId
    RecordData:
      type: object
      properties:
        _ragicId:
          type: integer
          readOnly: true
        _seq:
          type: string
          readOnly: true
        _create_date:
          type: string
          format: date-time
          readOnly: true
        _create_user:
          type: string
          readOnly: true
        _update_date:
          type: string
          format: date-time
          readOnly: true
        _update_user:
          type: string
          readOnly: true
      additionalProperties:
        oneOf:
          - type: string
          - type: number
          - type: object
          - type: array
            items:
              type: string
      description: |
        Record data with field IDs as keys.

        **System fields (read-only when using `info=1`):**
        - `_ragicId` - Record ID (same as rootNodeId)
        - `_seq` - Sequential number (auto-generated)
        - `_create_date` - Creation timestamp
        - `_create_user` - Creator's email
        - `_update_date` - Last update timestamp
        - `_update_user` - Last updater's email

        **Subtables:**
        Subtable data is nested under `_subtable_{fieldId}` keys, with subtable row IDs as nested keys.
    RecordInput:
      type: object
      additionalProperties:
        oneOf:
          - type: string
          - type: number
          - type: object
          - type: array
            items:
              type: string
      description: |
        Record data for create/update operations.

        Use field IDs as keys and field values as values.

        **For subtables:**
        ```json
        {
          "_subtable_1000010": {
            "-1": {"1000011": "Item 1", "1000012": 5},
            "-2": {"1000011": "Item 2", "1000012": 3}
          }
        }
        ```
        Use negative IDs (-1, -2, etc.) for new rows.

        **To delete subtable rows:**
        ```json
        {"DELSUB": "67890"}
        ```
    RecordInputMultipart:
      type: object
      properties:
        file:
          type: string
          format: binary
      additionalProperties:
        type: string
    MutationResponse:
      type: object
      properties:
        status:
          type: string
          enum:
            - SUCCESS
            - ERROR
        rv:
          type: string
        ragicId:
          type: integer
        msg:
          type: string
        warning:
          type: string
      description: Response from create/update operations
    DeleteResponse:
      type: object
      properties:
        status:
          type: string
          enum:
            - SUCCESS
            - ERROR
      description: Response from delete operations
    FormDefinition:
      type: object
      properties:
        sheetIndex:
          type: integer
        sheetName:
          type: string
        path:
          type: string
        fields:
          type: object
          additionalProperties:
            $ref: "#/components/schemas/FieldDefinition"
      description: |
        Form structure and field definitions.

        Contains field IDs, names, types, options (for select fields), and other metadata.
    FieldDefinition:
      type: object
      properties:
        name:
          type: string
        type:
          type: string
        inputType:
          type: string
        required:
          type: boolean
        options:
          type: array
          items:
            type: object
            properties:
              v:
                type: string
      description: |
        Individual field definition.

        **Common types:**
        - `D` - Text/Default
        - `L` - Single select
        - `M` - Multiple select
        - `U` - File upload
        - `G` - Image/Graphic
    ActionButtonList:
      type: array
      items:
        type: object
        properties:
          id:
            type: string
          name:
            type: string
      description: >
        A list of action buttons configured on a form. Each button has an `id` (used with the `bId` parameter) and a
        `name` (display label).
    MassOperationResponse:
      type: object
      properties:
        taskId:
          type: string
          format: uuid
      description: >
        Response from a mass operation request. Contains a `taskId` that can be used to check operation progress via the
        List Records endpoint with the `taskId` parameter.
    TaskProgress:
      type: object
      properties:
        status:
          type: string
          enum:
            - RUNNING
            - COMPLETED
            - FAILED
        progress:
          type: integer
        total:
          type: integer
        message:
          type: string
      description: |
        Progress information for an asynchronous mass operation.
        - `status` - Current state: `RUNNING`, `COMPLETED`, or `FAILED`
        - `progress` - Number of records processed so far
        - `total` - Total number of records to process
        - `message` - Human-readable status message
    AuthResponse:
      type: object
      properties:
        status:
          type: string
          enum:
            - SUCCESS
            - ERROR
        sid:
          type: string
        email:
          type: string
        accounts:
          type: array
          items:
            type: string
      description: |
        JSON response from the /AUTH endpoint (when `json=1` is used).
        - `status` - `SUCCESS` or `ERROR`
        - `sid` - Session ID for subsequent requests
        - `email` - Authenticated user's email
        - `accounts` - List of Ragic accounts the user has access to
    Error:
      type: object
      properties:
        status:
          type: string
          enum:
            - ERROR
        errorCode:
          type: integer
        msg:
          type: string
      description: Error response with code and message
  responses:
    BadRequest:
      description: Bad request - invalid parameters or data
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
          examples:
            invalidJson:
              summary: Invalid JSON body
              value:
                status: ERROR
                errorCode: 102
                msg: Invalid JSON post body.
            validationError:
              summary: Validation error
              value:
                status: ERROR
                errorCode: 103
                msg: "Validation failed: Field 'Customer Name' is required."
    Unauthorized:
      description: Authentication required - provide valid credentials
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
          examples:
            noAuth:
              summary: No authentication provided
              value:
                status: ERROR
                errorCode: 101
                msg: Authentication required. Please provide API key.
            invalidAuth:
              summary: Invalid credentials
              value:
                status: ERROR
                errorCode: 101
                msg: Invalid API key or password.
    Forbidden:
      description: Access denied - insufficient permissions for this operation
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
          examples:
            noAccess:
              summary: No access to sheet
              value:
                status: ERROR
                errorCode: 106
                msg: >-
                  This sheet is access right protected. You will need to provide an API key of a user who has access
                  right to this sheet.
    NotFound:
      description: Resource not found - check the URL and record ID
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
          examples:
            recordNotFound:
              summary: Record not found
              value:
                status: ERROR
                errorCode: 104
                msg: The record you are updating is not found.
            sheetNotFound:
              summary: Sheet not found
              value:
                status: ERROR
                errorCode: 105
                msg: Sheet not found.

