IRAS API Services Reference v1.3

Submission of Donation Records (Corppass)

Last updated: 23 Apr 2026  |  Version: 1.3  |  Status: Stable Production

1. Overview and Architecture

The Inland Revenue Authority of Singapore (IRAS) provides application programming interface (API) services to allow application developers and reporting entities (Institutions of a Public Character, or IPCs) to submit and validate tax-deductible donation records directly via secure HTTP JSON requests.

Submissions are validated against strict business rules, donor identification formats, and deductible receipt requirements. Communications are established via server-to-server connections through GovTech’s APEX Cloud platform.

No Partial Processing: The Donation-API enforces atomic transactions. There is no partial acceptance of records within a request payload. If a single donor detail record fails validation, the entire payload is rejected, and diagnostic field-level errors are returned.

2. Onboarding to APEX and CorpPass

Developers must authenticate to APEX via CorpPass OAuth 2.1 before consuming the Donation-API. All integrations must be tested and verified in the Sandbox environment before requesting production clearance.

  1. CorpPass Account Provisioning: Your organization must have an active CorpPass account. A CorpPass Admin or Sub-Admin must assign access to the APEX Cloud e-Service for non-government users.
  2. APEX Developer Portal Setup:
    • Log in to the APEX Developer Portal and register your Application.
    • Generate an x-apex-apikey.
    • Create an OAuth 2.1 Client.
    • Subscribe your created application to the Submission of Donation Records API.
  3. Update Notification Contacts: Maintain an updated email address in your APEX profile to receive operational downtime notifications, API deprecations, and schema change advisories.

3. Message Security & Authentication

The API endpoint must be invoked from a server-to-server connection supporting HTTP/2, TLS 1.2, or TLS 1.3. IP Whitelisting is enforced at the gateway layer.

Required HTTP Headers

Header Format / Value Description
x-apex-apikey String (UUID) API Key generated in APEX and subscribed to the Donation-API.
Authorization Bearer <JWT> CorpPass access token. Use OAuth scope DonationSub when requesting the token.
Content-Type application/json Request payload format.
Accept application/json Accepted response format.

Transacting Flow: Taxpayer vs. Tax Agent

When invoking the CorpPass OAuth authorization endpoint, you may send the optional tax_agent parameter to indicate whether the transaction is performed directly or by an appointed third party:

  • tax_agent=n: Entity is transacting for its own business donation records.
  • tax_agent=y: Entity is transacting as an authorized tax agent for its IPC business client.

4. Payload Limits, Chunking & Rate Limits

  • Record Limit: Maximum of 5,000 records per request payload.
  • Size Limit: Maximum of 2 MB per JSON payload.
  • Assembly Rate Limit: 1,000 requests per hour per application. Exceeding this threshold returns HTTP status 429 Too Many Requests with message Assembly Rate Limit exceeded.

Payload Chunking Strategy

For submissions exceeding 5,000 records (e.g., 8,000 records), partition data into multiple sequential calls:

  • Payload 1: 5,000 donation records (size < 2 MB)
  • Payload 2: 3,000 donation records (size < 2 MB)

If Payload 1 passes and Payload 2 fails validation, resolve errors in Payload 2 and resubmit only Payload 2. Do not resend Payload 1 to avoid duplicate processing.

5. Environments & Governance

Environment HTTP Verb Base Endpoint
Sandbox POST https://sandbox.api.gov.sg/iras/donation-records/v1/Submit
Production POST https://public.api.gov.sg/iras/donation-records/v1/Submit
Production Compliance: Sandbox testing must be completed with designated IRAS test entities prior to production onboarding. Performing mock submissions or running testing cycles against the production endpoint constitutes a breach of the IRAS API Terms of Use.

6. Interface Rules & Character Whitelist

All data payloads must adhere to these structural constraints:

  • Property names use camelCase (e.g., orgAndSubmissionInfo, dateOfDonation).
  • Date strings conform to ISO-8601 or the specified YYYYMMDD integer format.
  • All string values are restricted to the following approved characters:
    • Standard ASCII range: 32 through 127
    • Germanic / Umlauts: ü (Unicode: 252) and Ü (Unicode: 220)
    • Turkish dotted: İ (Unicode: 304)
    • Whitespace & controls: Line Feed (LF, Unicode: 10), Carriage Return (CR, Unicode: 13)
    • Typography: En dash (–), Em dash (—), Smart quotes (“, ”, ‘, ’)

7. Request Data Dictionary

1. Header Object: orgAndSubmissionInfo

Field Type Req Description & Format Rules
validateOnly Boolean M true = Validation only (no submission); false = Validate and commit to IRAS.
basisYear Number(4) M Receipt calendar year (YYYY). Accepts 3 back years, current year, 1 advance year.
organisationIDType String(1) M 5: UEN-BUSINESS, 6: UEN-LOCAL CO, U: UEN-OTHERS, A: ASGD, I: ITR
organisationIDNo String(12) M Entity registration number formatted according to organization ID type.
organisationName String(60) M Registered institution/business name.
batchIndicator String(1) M O: Original submission, A: Amendment (overwrites previous submission by donor/receipt).
authorisedPersonIDNo String(12) M NRIC (prefix S/T), FIN (prefix F/G/M), ASGD (ANNNNNNNC), or ITR (NNNNNNNNNC).
authorisedPersonName String(30) M Name of officer submitting records.
authorisedPersonDesignation String(30) O Official title / job designation.
telephone String(20) M Minimum 8 digits.
authorisedPersonEmail String(50) M Valid email address for submission correspondence.
numOfRecords Number(7) M Total count of donor items in donationDonorDtl (max 5,000).
totalDonationAmount Number(12) M Sum total of donationAmount values in payload. Integers only.

2. Item Object: donationDonorDtl[]

Field Type Req Description & Format Rules
recordID Number(4) M Sequential index starting from 1, unique within payload.
idType String(1) M 1: NRIC, 2: FIN, 5: UEN-BUSINESS, 6: UEN-LOCAL CO, A: ASGD, I: ITR, U: UEN-OTHERS
idNumber String(12) M Identification matching specified idType.
individualIndicator String(3) C Mandatory if idType is A or I. Must be IND (Individual) or NON (Non-individual).
name String(80) M Donor's registered name.
postalCode String(6) O Numeric 6 digits. Preserve leading zeroes (e.g., "012345").
donationAmount Number(9) M Rounded to nearest dollar (no decimals). Must be > $0 for Original (O) batches: a zero amount voids a donation, which is valid only on an Amendment (A) batch.
dateOfDonation Number(8) M Format: YYYYMMDD (e.g., 20250105).
receiptNum String(20) M Unique receipt or transaction tracking reference number.
typeOfDonation String(1) M O: Outright Cash, S: Share/Unit Trust, A: Artifact, L: Land/Building, P: Public Sculpture, H: OHAS. If S, donor must be Individual.
namingDonation String(1) M Z: Non-naming (default), N: Named IPC, F: Named Facility.

8. Response Schema & Diagnostics

The HTTP status is not the outcome. IRAS answers 200 for a request it processed, and returnCode in the body says whether the records were accepted: a rejection is still a 200, so reading the status alone reports a rejected batch as a success. Any other status is an exception error rather than a validation outcome - the request may not have been processed at all (see 401 unchanged credentials and 429 rate limit above).

Property Type Description
returnCode String "10": Success, "30": Failure / Rejected. Both arrive with HTTP 200.
data.acknowledgementCode String IRAS system acknowledgment sequence identifier (populated when returnCode = "10").
info.messageCode String Diagnostic code:
850300: Request object is null.
850301: Arguments error / validation failed.
850302: Generic server exception.
850303: Service inactive.
850304: Unauthorized credentials.
850305: Invalid sandbox test user.
info.fieldInfoList[].recordID String Affected record identifiers. Identical errors are grouped, e.g. "3,5,7".

9. OpenAPI 3.0 Specification

This is the same document as docs/iras-donation-records.openapi.json, which the IREMS module reads at runtime to build and verify its requests. The block below is generated from that file by npm run spec:embed, and the test suite fails when the two drift apart - so copy it with confidence for Postman imports, API gateway configuration, or client code generation:

{
  "openapi": "3.0.3",
  "info": {
    "title": "Submission of Donation Records (Donation-API)",
    "version": "1.3.0",
    "description": "The Inland Revenue Authority of Singapore (IRAS) provides the Submission of Donation Records API (Donation-API) so Institutions of a Public Character (IPCs), Qualifying Grantmakers and government agencies can validate and submit tax-deductible donation information to IRAS directly. Submitted records are auto-included in the donors' tax returns.\n\nIntegration is through APEX (api.gov.sg): the caller signs in with CorpPass using APEX OAuth 2.1, then calls this API with that access token plus the APEX API key. See the security schemes below and the onboarding guide at https://go.gov.sg/apexonboarding-oauth.\n\nThe field-level reference is the API specification PDF: https://file.go.gov.sg/iras-donations-apispecs.pdf. This document is the machine-readable contract, and it is the one the IREMS IRAS module reads at runtime to build and verify its submission requests."
  },
  "servers": [
    {
      "url": "https://sandbox.api.gov.sg/iras/donation-records/v1",
      "description": "Sandbox environment. Test entities only."
    },
    {
      "url": "https://public.api.gov.sg/iras/donation-records/v1",
      "description": "Production gateway. Mock submissions or test cycles here breach the IRAS API Terms of Use."
    }
  ],
  "security": [
    {
      "APEXOAuth2": ["DonationSub"],
      "ApexApiKey": []
    }
  ],
  "paths": {
    "/Submit": {
      "post": {
        "summary": "Submit or validate donation records",
        "operationId": "Submit",
        "description": "Submits one payload of donation records, or validates one when validateOnly is true.\n\nThe HTTP status only distinguishes transport outcomes: 200 means IRAS processed the request, and the body field returnCode says whether the records were accepted (10) or rejected (30). Any other status is an exception error rather than a validation outcome.\n\nLimits are declared in x-iras-limits: at most 5000 records and 2 MB per request. Payloads larger than that must be split into sequential requests; if one chunk fails, resolve it and resubmit that chunk only.",
        "security": [
          {
            "APEXOAuth2": ["DonationSub"],
            "ApexApiKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DonationSubmissionPayload"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "IRAS processed the request. Read returnCode in the body: 10 is success, 30 is failure or rejection.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DonationResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized credentials. The body carries info.messageCode 850304. A non-200 status is an exception error, not a validation rejection."
          },
          "429": {
            "description": "Assembly Rate Limit exceeded. At most 1000 requests per hour per application."
          },
          "default": {
            "description": "Any other status is an exception error. Read the body for the upstream message; the payload may not have been processed at all."
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "APEXOAuth2": {
        "type": "oauth2",
        "description": "APEX CorpPass OAuth 2.1. The caller obtains an access token with the authorization code flow and PKCE (S256), requesting the DonationSub scope, and presents it as a bearer token on every call.\n\nClient authentication is a signed private_key_jwt client assertion in the token request body: iss and sub are the APEX client id, aud is the token endpoint URL being called, and exp is iat plus 300 seconds. There is no client secret.\n\ntax_agent is an optional parameter on the authorization request: y when an appointed tax agent transacts for an IPC business client, n (or omitted) when the entity transacts for its own records.\n\nThe endpoints below are the sandbox pair. Production uses https://public.api.gov.sg/oauth/cp/v3/authorize and https://public.api.gov.sg/oauth/cp/v3/token.",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://sandbox.api.gov.sg/oauth/cp/v3/authorize",
            "tokenUrl": "https://sandbox.api.gov.sg/oauth/cp/v3/token",
            "scopes": {
              "DonationSub": "Submit donation records to IRAS"
            }
          }
        },
        "x-axway": {
          "accessTokenLocation": "HEADER",
          "authorizationHeaderPrefix": "Bearer",
          "scopesMatching": "Any",
          "typeDisplayName": "OAuth 2.0"
        }
      },
      "ApexApiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "x-apex-apikey",
        "description": "API key generated in APEX and subscribed to the Donation-API. Required on every call, alongside the bearer token. Treated as a credential: it belongs in configuration, never in source."
      }
    },
    "schemas": {
      "DonationSubmissionPayload": {
        "type": "object",
        "required": ["orgAndSubmissionInfo", "donationDonorDtl"],
        "properties": {
          "orgAndSubmissionInfo": {
            "type": "object",
            "required": ["validateOnly", "basisYear", "organisationIDType", "organisationIDNo", "organisationName", "batchIndicator", "authorisedPersonIDNo", "authorisedPersonName", "telephone", "authorisedPersonEmail", "numOfRecords", "totalDonationAmount"],
            "properties": {
              "validateOnly": {
                "type": "boolean",
                "description": "true validates the payload without filing it."
              },
              "basisYear": {
                "type": "integer",
                "example": 2025,
                "description": "Basis year of the donation records."
              },
              "organisationIDType": {
                "type": "string",
                "enum": ["5", "6", "U", "A", "I"],
                "x-enum-descriptions": {
                  "5": "UEN-BUSINESS",
                  "6": "UEN-LOCAL CO",
                  "U": "UEN-OTHERS",
                  "A": "ASGD",
                  "I": "ITR"
                },
                "description": "How the organisation's registration number is issued: 5 UEN-BUSINESS, 6 UEN-LOCAL CO, U UEN-OTHERS, A ASGD, I ITR."
              },
              "organisationIDNo": {
                "type": "string",
                "maxLength": 12,
                "example": "180011032C"
              },
              "organisationName": {
                "type": "string",
                "maxLength": 60,
                "example": "ABCD Medical Institute"
              },
              "batchIndicator": {
                "type": "string",
                "enum": ["O", "A"],
                "x-enum-descriptions": {
                  "O": "original submission",
                  "A": "amendment"
                },
                "description": "O is an original submission, A is an amendment. An original submission requires every donationAmount to be greater than zero; a zero amount only voids a donation, which is valid on an amendment batch."
              },
              "authorisedPersonIDNo": {
                "type": "string",
                "maxLength": 12,
                "example": "S9991257Z"
              },
              "authorisedPersonName": {
                "type": "string",
                "maxLength": 30,
                "example": "James Tan"
              },
              "authorisedPersonDesignation": {
                "type": "string",
                "maxLength": 30,
                "example": "Manager"
              },
              "telephone": {
                "type": "string",
                "minLength": 8,
                "maxLength": 20,
                "example": "61234567"
              },
              "authorisedPersonEmail": {
                "type": "string",
                "format": "email",
                "maxLength": 50,
                "example": "[email protected]"
              },
              "numOfRecords": {
                "type": "integer",
                "maximum": 5000,
                "example": 1,
                "description": "Must equal the number of entries in donationDonorDtl."
              },
              "totalDonationAmount": {
                "type": "integer",
                "example": 2500,
                "description": "Sum of the donationAmount values in this payload, rounded to the nearest dollar."
              }
            }
          },
          "donationDonorDtl": {
            "type": "array",
            "maxItems": 5000,
            "items": {
              "type": "object",
              "required": ["recordID", "idType", "idNumber", "name", "donationAmount", "dateOfDonation", "receiptNum", "typeOfDonation", "namingDonation"],
              "properties": {
                "recordID": {
                  "type": "integer",
                  "example": 1
                },
                "idType": {
                  "type": "string",
                  "enum": ["1", "2", "5", "6", "A", "I", "U"],
                  "x-enum-descriptions": {
                    "1": "NRIC",
                    "2": "FIN",
                    "5": "UEN-BUSINESS",
                    "6": "UEN-LOCAL CO",
                    "A": "ASGD",
                    "I": "ITR",
                    "U": "UEN-OTHERS"
                  },
                  "description": "How the donor's identification number is issued: 1 NRIC, 2 FIN, 5 UEN-BUSINESS, 6 UEN-LOCAL CO, A ASGD, I ITR, U UEN-OTHERS."
                },
                "idNumber": {
                  "type": "string",
                  "maxLength": 12,
                  "example": "S1234567Z"
                },
                "individualIndicator": {
                  "type": "string",
                  "enum": ["IND", "NON", ""],
                  "x-enum-descriptions": {
                    "IND": "Individual",
                    "NON": "Non-individual"
                  },
                  "description": "Mandatory when idType is A or I. IND is an individual, NON is a non-individual."
                },
                "name": {
                  "type": "string",
                  "maxLength": 80,
                  "example": "James Zhang"
                },
                "addressLine1": {
                  "type": "string",
                  "maxLength": 30
                },
                "addressLine2": {
                  "type": "string",
                  "maxLength": 30
                },
                "postalCode": {
                  "type": "string",
                  "maxLength": 6,
                  "example": "640501"
                },
                "donationAmount": {
                  "type": "integer",
                  "example": 2500,
                  "description": "Rounded to the nearest dollar, no decimals. Greater than zero on an original (O) batch; zero only voids a donation and is valid on an amendment (A) batch."
                },
                "dateOfDonation": {
                  "type": "integer",
                  "example": 20250105,
                  "description": "Format YYYYMMDD."
                },
                "receiptNum": {
                  "type": "string",
                  "maxLength": 20,
                  "example": "RECP123",
                  "description": "Unique receipt or transaction tracking reference."
                },
                "typeOfDonation": {
                  "type": "string",
                  "enum": ["O", "S", "A", "L", "P", "H"],
                  "x-enum-descriptions": {
                    "O": "outright cash",
                    "S": "share or unit trust",
                    "A": "artifact",
                    "L": "land or building",
                    "P": "public sculpture",
                    "H": "OHAS"
                  },
                  "description": "O is outright cash, S is share or unit trust, A is artifact, L is land or building, P is public sculpture, H is OHAS. A share or unit trust donation requires an individual donor."
                },
                "namingDonation": {
                  "type": "string",
                  "enum": ["Z", "N", "F"],
                  "x-enum-descriptions": {
                    "Z": "non-naming (default)",
                    "N": "named IPC",
                    "F": "named facility"
                  },
                  "description": "Z is non-naming (default), N is a named IPC, F is a named facility."
                }
              }
            }
          }
        },
        "DonationResponse": {
          "type": "object",
          "description": "The body IRAS returns with HTTP 200. returnCode is the outcome; everything else is diagnostic.",
          "properties": {
            "returnCode": {
              "type": "string",
              "enum": ["10", "30"],
              "description": "10 means the records were accepted, 30 means they were rejected. A rejection still arrives with HTTP 200, so this field - not the status alone - decides success."
            },
            "data": {
              "type": "object",
              "properties": {
                "acknowledgementCode": {
                  "type": "string",
                  "example": "1510010493",
                  "description": "IRAS acknowledgement sequence identifier, populated when returnCode is 10."
                }
              }
            },
            "info": {
              "type": "object",
              "properties": {
                "messageCode": {
                  "type": "string",
                  "example": "850301",
                  "description": "850300 request object is null, 850301 arguments error or validation failed, 850302 generic server exception, 850303 service inactive, 850304 unauthorized credentials, 850305 invalid sandbox test user."
                },
                "message": {
                  "type": "string",
                  "example": "Arguments Error"
                },
                "warnings": {
                  "type": "array",
                  "items": {
                    "type": "object"
                  }
                },
                "fieldInfoList": {
                  "type": "array",
                  "description": "Validation failures, grouped by message. One entry can name several records.",
                  "items": {
                    "type": "object",
                    "properties": {
                      "field": {
                        "type": "string",
                        "example": "idNumber"
                      },
                      "message": {
                        "type": "string",
                        "example": "Incorrect ID Type and/or ID No"
                      },
                      "recordID": {
                        "type": "string",
                        "example": "3,5,7",
                        "description": "Comma-separated record ids the message applies to."
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "x-iras-limits": {
    "maxRecordsPerRequest": 5000,
    "maxPayloadBytes": 2097152,
    "maxRequestsPerHour": 1000,
    "note": "Split a larger submission into sequential payloads of at most 5000 records, each under 2 MB. If one payload fails validation, resolve it and resubmit that payload only - do not resend the earlier ones, to avoid duplicate processing."
  },
  "x-provenance": {
    "mergedOn": "2026-09-26",
    "mergedFrom": [
      "docs/Submission of Donation Records (Sandbox) v1.1.json - Swagger 2.0, gateway-generated: sandbox host only, OAuth 2.0 schemes, no request or response schemas",
      "docs/iras_donation_api_documentation.html - OpenAPI 3.0.3 version 1.3.0: CorpPass onboarding, full request and response schemas, operational limits"
    ],
    "supersedes": "1.1 (Swagger 2.0)",
    "changes": [
      "Adopted OpenAPI 3.0.3 and version 1.3.0 from the newer document.",
      "Servers now cover both sandbox and production; the 1.1 document described the sandbox host only.",
      "Authentication modelled as APEX CorpPass OAuth 2.1 (authorization code, PKCE S256, private_key_jwt, scope DonationSub) with the APEX API key as a second required scheme - replacing the 1.1 client_secret metadata.",
      "Added the request and response schemas, which the 1.1 document did not define.",
      "Response outcome is returnCode (10 success, 30 rejected) with HTTP 200; a non-200 status is an exception error.",
      "typeOfDonation is the letter O for outright cash, not the digit 0.",
      "Documented 401 and 429 responses, the payload limits, and the optional tax_agent authorization parameter."
    ],
    "note": "The OpenAPI block embedded in docs/iras_donation_api_documentation.html is asserted against this file byte for byte by scripts/check.js, so the two cannot drift."
  },
  "x-axway": {
    "serviceType": "rest",
    "basePaths": [
      "https://sandbox.api.gov.sg",
      "https://public.api.gov.sg"
    ],
    "expired": false,
    "customProperties": {
      "upgradeFrom": "371f8bca-1ab7-485c-b400-5c5dee427bcb",
      "upgradeFromCompletedOn": "1770036810672",
      "apiType": "sandbox+production"
    },
    "retirementDate": 0,
    "corsEnabled": true,
    "deprecated": false,
    "availableSDK": {
      "ios-swift": "/discovery/sdk/f4540e83-b3f5-47aa-8af3-452eb4e9d2a1/ios-swift",
      "android": "/discovery/sdk/f4540e83-b3f5-47aa-8af3-452eb4e9d2a1/android",
      "nodejs": "/discovery/sdk/f4540e83-b3f5-47aa-8af3-452eb4e9d2a1/nodejs"
    },
    "id": "f4540e83-b3f5-47aa-8af3-452eb4e9d2a1",
    "state": "published",
    "accessGrantedDate": 1783071053749
  }
}

10. Payload Examples

Sample Request

{
  "orgAndSubmissionInfo": {
    "validateOnly": false,
    "basisYear": 2025,
    "organisationIDType": "6",
    "organisationIDNo": "180011032C",
    "organisationName": "ABCD Medical Institute",
    "batchIndicator": "O",
    "authorisedPersonIDNo": "S9991257Z",
    "authorisedPersonName": "James Tan",
    "authorisedPersonDesignation": "Manager",
    "telephone": "61234567",
    "authorisedPersonEmail": "[email protected]",
    "numOfRecords": 2,
    "totalDonationAmount": 5000
  },
  "donationDonorDtl": [
    {
      "recordID": 1,
      "idType": "1",
      "idNumber": "S1234567Z",
      "individualIndicator": "",
      "name": "James Zhang",
      "addressLine1": "123 Orchard Road",
      "addressLine2": "#10-01",
      "postalCode": "640501",
      "donationAmount": 2500,
      "dateOfDonation": 20250105,
      "receiptNum": "RECP123",
      "typeOfDonation": "O",
      "namingDonation": "Z"
    },
    {
      "recordID": 2,
      "idType": "A",
      "idNumber": "A1234567C",
      "individualIndicator": "IND",
      "name": "Andrew Chan",
      "addressLine1": "",
      "addressLine2": "",
      "postalCode": "640501",
      "donationAmount": 2500,
      "dateOfDonation": 20250505,
      "receiptNum": "RECP128",
      "typeOfDonation": "O",
      "namingDonation": "Z"
    }
  ]
}

Sample Error Response (Lumped Field Validation Errors)

{
  "returnCode": "30",
  "info": {
    "messageCode": "850301",
    "message": "Arguments Error",
    "fieldInfoList": [
      {
        "field": "idNumber",
        "message": "Incorrect ID Type and/or ID No",
        "recordID": "3,5,7"
      },
      {
        "field": "name",
        "message": "Must not be blank",
        "recordID": "3,5,7"
      }
    ]
  }
}