Export Gradle Dependencies to Notion Database via Custom Task

I’m working on a custom gradle task that should extract all my Android project dependencies and send them to a Notion database using their API. Everything seems to be set up correctly, but when I execute the task I keep getting HTTP 400 errors from the Notion API. Strangely enough, if I test with just hardcoded values like simple strings, the API call works fine. I’m really confused about what might be causing this issue. Has anyone dealt with something similar before?

Here’s my current implementation:

abstract class ExportLibrariesToNotion : DefaultTask() {

    init {
        group = "documentation"
        description = "Send project libraries to Notion database"
    }

    @TaskAction
    fun execute() = runBlocking {
        val apiKey = System.getenv("NOTION_API_KEY") ?: error("NOTION_API_KEY not found")
        val databaseId = System.getenv("NOTION_DB_ID") ?: error("NOTION_DB_ID not found")
        val libraryNames = mutableListOf<String>()

        val configuration = project.configurations.getByName("releaseRuntimeClasspath")

        configuration.incoming.resolutionResult.allDependencies.forEach { dep ->
            when (dep) {
                is ResolvedDependencyResult -> {
                    val info = dep.selected
                    "• ${info.moduleVersion}"
                }
                else -> null
            }?.let {
                libraryNames += it
            }
        }

        val sampleData = mutableListOf("alpha", "beta", "gamma")
        val contentBlocks = mutableListOf<ContentBlock>()

        libraryNames.forEach {
            contentBlocks += ContentBlock(
                blockType = "paragraph",
                paragraphData = ParagraphContent(
                    textContent = listOf(
                        TextElement(textData = TextInfo(it))
                    )
                )
            )
        }

        val pageRequest = DatabasePageRequest(
            parentRef = DatabaseParent(db_id = databaseId),
            pageProperties = mapOf(
                "Title" to PageTitle(
                    titleText = listOf(
                        TextElement(textData = TextInfo(value = "📚 Project Libraries"))
                    )
                )
            ),
            blockContent = contentBlocks.toList()
        )

        val httpClient = HttpClient(CIO) {
            install(ContentNegotiation) {
                json(Json {
                    prettyPrint = true
                    ignoreUnknownKeys = true
                })
            }
        }

        val apiResponse: HttpResponse = httpClient.post("https://api.notion.com/v1/pages") {
            contentType(ContentType.Application.Json)
            header("Authorization", "Bearer $apiKey")
            header("Notion-Version", "2022-06-28")
            setBody(pageRequest)
        }

        println("🎉 Notion page created! Response: ${apiResponse.status}, Details: ${apiResponse}")
    }
}

@Serializable data class DatabasePageRequest(
    val parentRef: DatabaseParent,
    val pageProperties: Map<String, PageTitle>,
    val blockContent: List<ContentBlock>
)

@Serializable data class DatabaseParent(val db_id: String)
@Serializable data class PageTitle(val titleText: List<TextElement>)
@Serializable data class ContentBlock(
    val objectType: String = "block",
    val blockType: String,
    val paragraphData: ParagraphContent? = null
)
@Serializable data class ParagraphContent(val textContent: List<TextElement>)
@Serializable data class TextElement(val elementType: String = "text", val textData: TextInfo)
@Serializable data class TextInfo(val value: String)

your json field names dont match notion’s api spec. notion wants parent, properties, and children but you’re sending parentRef, pageProperties, and blockContent. also double-check that your database id has the right permissions.

Yeah, it’s definitely your serialization structure. Had the same exact issue building something similar last year. Besides the field naming stuff others mentioned, you’re missing proper nesting for block content. Notion wants blocks with the block type as a key containing the content - so paragraph blocks need to look like {“type”: “paragraph”, “paragraph”: {“rich_text”: […]}}. Your ContentBlock class won’t spit out this structure. I’d create separate data classes for each block type and go with a sealed class approach. Also watch out for dependency extraction - that moduleVersion might have characters that need JSON escaping. Log the actual JSON payload before sending so you can see what’s really going to Notion.

Been there. Your Gradle task works, but you’re making this way harder than it needs to be fighting the Notion API manually.

Extract those dependencies in Gradle, then send them to Latenode for the Notion stuff. Set up a webhook that takes your dependency list and handles all the API mess.

Latenode’s got Notion nodes that automatically handle the JSON structure. No more guessing field names or block formatting. You can add deduping, format things nicely, even pull package info from npm or Maven.

Your Gradle task stays simple - just POST the dependencies to your webhook and you’re done. Way cleaner than hardcoding API structures that’ll break when they change.

I’ve done this for similar docs workflows. Takes 10 minutes to set up vs hours debugging serialization nonsense.

Had the same problem building my Notion integration. You’ve got field naming issues, but there’s another gotcha - your data classes need @SerialName annotations to match Notion’s format exactly. Your DatabaseParent should serialize db_id as database_id, and the paragraph block needs paragraph as the key, not paragraphData. Also check if your database has all the required properties set up. I’d test with a minimal payload first - just create a page with a title, then add content blocks once that works. The 400 error usually means your request structure is malformed, not an auth problem.