{"id":832,"date":"2025-09-07T14:02:04","date_gmt":"2025-09-07T14:02:04","guid":{"rendered":"https:\/\/dataopsschool.com\/blog\/?p=832"},"modified":"2025-09-07T14:02:04","modified_gmt":"2025-09-07T14:02:04","slug":"databricks-dlt-scd2-scd1-table-apply-changes-cdc-back-loading-scd2-delete-truncate-scd","status":"publish","type":"post","link":"https:\/\/dataopsschool.com\/blog\/databricks-dlt-scd2-scd1-table-apply-changes-cdc-back-loading-scd2-delete-truncate-scd\/","title":{"rendered":"Databricks: DLT SCD2 &amp; SCD1 table | Apply Changes | CDC | Back-loading SCD2 | Delete\/Truncate SCD"},"content":{"rendered":"\n<h1 class=\"wp-block-heading\"><\/h1>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Introduction<\/h2>\n\n\n\n<p><strong>Goal:<\/strong> Build a CDC-ready dimension pipeline in Delta Live Tables (DLT) that supports:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>SCD Type 1 (overwrite in place)<\/li>\n\n\n\n<li>SCD Type 2 (history with start\/end validity)<\/li>\n\n\n\n<li>Deleting\/truncating target tables from source signals<\/li>\n\n\n\n<li>Back-loading \u201cout-of-order\u201d historical changes into SCD2<\/li>\n<\/ul>\n\n\n\n<p><strong>Core ideas you\u2019ll use<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>CDC (Change Data Capture):<\/strong> Detecting and applying inserts\/updates\/deletes from a source stream to one or more targets.<\/li>\n\n\n\n<li><strong>SCD Type 1:<\/strong> Latest values overwrite previous values (no history).<\/li>\n\n\n\n<li><strong>SCD Type 2:<\/strong> Track full history by closing old versions and inserting new \u201ccurrent\u201d versions with validity windows.<\/li>\n\n\n\n<li><strong>DLT <code>apply_changes<\/code>:<\/strong> A declarative API in DLT that handles SCD1\/SCD2 mechanics for you, including ordering, column exclusions, and optional delete\/truncate semantics.<\/li>\n<\/ul>\n\n\n\n<p><strong>What we\u2019ll model<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>A <strong>Customer<\/strong> dimension fed by a \u201craw\u201d Delta table\/stream.<\/li>\n\n\n\n<li>The source includes two CDC helper columns:\n<ul class=\"wp-block-list\">\n<li><code>SRC_ACTION<\/code> \u2014 one of <code>'I'<\/code> (insert\/upsert), <code>'D'<\/code> (delete), <code>'T'<\/code> (truncate).<\/li>\n\n\n\n<li><code>SRC_INSERT_DATE<\/code> \u2014 event timestamp used for change ordering.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">How to build SCD1 or SCD2 tables in DLT Pipelines?<\/h2>\n\n\n\n<p>You\u2019ll create:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>A <strong>streaming view<\/strong> of your source (DLT needs streaming input for <code>apply_changes<\/code>).<\/li>\n\n\n\n<li>An <strong>SCD1 table<\/strong> with <code>dlt.apply_changes(..., stored_as='SCD Type 1')<\/code>.<\/li>\n\n\n\n<li>An <strong>SCD2 table<\/strong> with <code>dlt.apply_changes(..., stored_as='SCD Type 2')<\/code>.<\/li>\n<\/ol>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>\u2705 DLT Edition: set your pipeline <strong>Product edition<\/strong> to <strong>Pro<\/strong> (or <strong>Advanced<\/strong>) to use <code>apply_changes<\/code>.<\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\"> Slowly Changing Dimension Type 1 table (SCD1)<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Definition:<\/strong> Keep only the current values. Every change on a key overwrites existing values.<\/li>\n\n\n\n<li><strong>When to use:<\/strong> Attributes that aren\u2019t analyzed historically (e.g., phone number, email, latest address, operational flags).<\/li>\n\n\n\n<li><strong>Pros\/Cons:<\/strong> Simple &amp; space-efficient, but no history.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Example DLT Notebook (Python)<\/h3>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>Put this in a DLT notebook file (e.g., <code>01_dlt_scd_cdc.py<\/code>). Configure the DLT pipeline to run this notebook.<\/p>\n<\/blockquote>\n\n\n\n<pre class=\"wp-block-code\"><code>import dlt\nfrom pyspark.sql import functions as F\nfrom pyspark.sql.functions import expr\n\n# --------------------------\n# CONFIG (optional helpers)\n# --------------------------\nCATALOG = \"dev\"         # your catalog\nSCHEMA  = \"etl\"         # your schema\nSRC_TBL = f\"{CATALOG}.{SCHEMA}.customer_raw\"  # the raw Delta table (upstream ingestion)\n\n# The raw table must include:\n# - business key: C_CUSTKEY\n# - SRC_ACTION: 'I' (upsert), 'D' (delete), 'T' (truncate)\n# - SRC_INSERT_DATE: event timestamp used for sequencing\n\n\n# --------------------------\n# STREAMING SOURCE VIEW\n# --------------------------\n@dlt.view(\n    comment=\"Streaming view over the raw customer table.\"\n)\ndef customer_raw_view():\n    # DLT apply_changes requires a streaming source (readStream.table).\n    # If your raw table is a Delta table that is appended over time, Spark can stream from it.\n    return (spark.readStream.table(SRC_TBL))\n\n\n# --------------------------\n# SCD1 (UPSERT) TARGET\n# --------------------------\n# Create an empty streaming target table first (DLT will manage storage).\ndlt.create_streaming_table(\n    name=\"customer_scd1_bronze\",\n    comment=\"SCD Type 1 (no history) Customer dimension built by apply_changes.\"\n)\n\n# Declarative CDC: SCD Type 1\ndlt.apply_changes(\n    target = \"customer_scd1_bronze\",\n    source = \"customer_raw_view\",         # the streaming view\n    keys   = &#91;\"C_CUSTKEY\"],               # business key(s)\n    stored_as = \"SCD Type 1\",             # explicit; default is also SCD Type 1\n    sequence_by = expr(\"SRC_INSERT_DATE\"),# ordering column (timestamp)\n    apply_as_deletes   = expr(\"SRC_ACTION = 'D'\"),  # delete rows that match key(s)\n    apply_as_truncates = expr(\"SRC_ACTION = 'T'\")   # truncate entire table\n)\n<\/code><\/pre>\n\n\n\n<p><strong>What this does<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>New keys are inserted.<\/li>\n\n\n\n<li>Existing keys are overwritten (latest wins).<\/li>\n\n\n\n<li>If any input row arrives with <code>SRC_ACTION = 'D'<\/code> \u2192 delete that key from target.<\/li>\n\n\n\n<li>If any input row arrives with <code>SRC_ACTION = 'T'<\/code> \u2192 truncate target.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">How to delete and truncate data from target table in DLT?<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Delete a single key:<\/strong> emit a record with that <code>C_CUSTKEY<\/code>, set <code>SRC_ACTION = 'D'<\/code> (other attributes can be null), and <code>SRC_INSERT_DATE = current_timestamp()<\/code>.<\/li>\n\n\n\n<li><strong>Truncate all:<\/strong> emit a record with <code>SRC_ACTION = 'T'<\/code> (other fields don\u2019t matter). Use carefully.<\/li>\n<\/ul>\n\n\n\n<p>This works for SCD1; for SCD2 you often keep history and <strong>skip<\/strong> deletes\/truncates unless you have a specific downstream contract.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Slowly Changing Dimension Type 2 table (SCD2)<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Definition:<\/strong> Preserve history. Each change creates a new version; the previous version gets an end timestamp.<\/li>\n\n\n\n<li><strong>When to use:<\/strong> Analytical attributes where historical truth matters (e.g., customer segment, region, status, marital status, VIP tier).<\/li>\n\n\n\n<li><strong>Pros\/Cons:<\/strong> Full audit\/history; larger storage &amp; more complex joins.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Example DLT (add SCD2 target in the same notebook)<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code># --------------------------\n# SCD2 (HISTORY) TARGET\n# --------------------------\ndlt.create_streaming_table(\n    name=\"customer_scd2_bronze\",\n    comment=\"SCD Type 2 (historical) Customer dimension built by apply_changes.\"\n)\n\n# For SCD2, you typically DO NOT delete or truncate.\n# You can also exclude operational columns (e.g., SRC_ACTION, SRC_INSERT_DATE)\n# so they don't participate in change comparison.\ndlt.apply_changes(\n    target = \"customer_scd2_bronze\",\n    source = \"customer_raw_view\",\n    keys   = &#91;\"C_CUSTKEY\"],\n    stored_as    = \"SCD Type 2\",\n    sequence_by  = expr(\"SRC_INSERT_DATE\"),\n    except_column_list = &#91;\"SRC_ACTION\", \"SRC_INSERT_DATE\"]\n    # Note: Omitting apply_as_deletes\/apply_as_truncates retains full history\n)\n\n# --------------------------\n# DOWNSTREAM: USING ONLY CURRENT ROWS FROM SCD2\n# --------------------------\n@dlt.view(\n    comment=\"Active (current) SCD2 rows only, for downstream joins.\"\n)\ndef customer_scd2_current():\n    # DLT SCD2 creates validity window columns: START_AT \/ END_AT.\n    # Active rows have END_AT IS NULL.\n    return spark.read.table(dlt.fqn(\"customer_scd2_bronze\")).where(F.col(\"END_AT\").isNull())\n<\/code><\/pre>\n\n\n\n<p><strong>What DLT manages for you<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Adds\/maintains <code>START_AT<\/code> and <code>END_AT<\/code> columns.<\/li>\n\n\n\n<li>On change, it \u201ccloses\u201d the previous row by filling <code>END_AT<\/code> and inserts a new \u201ccurrent\u201d row with <code>END_AT = NULL<\/code>.<\/li>\n\n\n\n<li>Respects ordering by <code>sequence_by<\/code> (the most important part for history correctness).<\/li>\n<\/ul>\n\n\n\n<p><strong>Typical downstream pattern<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Always join fact tables to <strong>current<\/strong> dimension rows (<code>END_AT IS NULL<\/code>).<\/li>\n\n\n\n<li>For point-in-time analytics, join on \u201cas of\u201d a date within <code>[START_AT, END_AT)<\/code>.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Back-loading\/filling data in SCD2 tables in DLT<\/h2>\n\n\n\n<p><strong>Problem:<\/strong> You ingest a late (older) change that should slot between two existing SCD2 versions (out-of-order arrival).<\/p>\n\n\n\n<p><strong>How DLT solves it<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Because you declare <code>sequence_by = SRC_INSERT_DATE<\/code>, DLT reshapes the SCD2 timeline correctly:\n<ul class=\"wp-block-list\">\n<li>Inserts the \u201clate\u201d version with its proper <code>START_AT<\/code>.<\/li>\n\n\n\n<li>Adjusts <code>END_AT<\/code> of the prior version.<\/li>\n\n\n\n<li>Ensures the latest version remains <code>END_AT IS NULL<\/code>.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p><strong>What you do<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Emit that late change with the <strong>actual historical timestamp<\/strong> in <code>SRC_INSERT_DATE<\/code>.<\/li>\n\n\n\n<li>DLT will re-assemble the timeline for that key. No manual MERGE gymnastics.<\/li>\n<\/ul>\n\n\n\n<p><strong>Use-case:<\/strong> Late arriving CRM updates, backfills from upstream MDM, or replays from log systems.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">How to delete data in SCD table in DLT?<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>SCD1:<\/strong> We already enabled <code>apply_as_deletes = expr(\"SRC_ACTION = 'D'\")<\/code>. Send the key + action <code>'D'<\/code> \u2192 it deletes the row.<\/li>\n\n\n\n<li><strong>SCD2 (common practice):<\/strong> do <strong>not<\/strong> hard delete; preserve history. If you must represent deletion:\n<ul class=\"wp-block-list\">\n<li><strong>Option A (preferred):<\/strong> Add a business flag column (e.g., <code>IS_ACTIVE=false<\/code>) and let that change create a final SCD2 row. Downstream uses that flag or <code>END_AT<\/code>.<\/li>\n\n\n\n<li><strong>Option B (if you truly need hard deletes):<\/strong> Add <code>apply_as_deletes<\/code> to the SCD2 definition\u2014but be aware you\u2019re throwing away history for those keys.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code># (Not recommended unless required)\n# dlt.apply_changes(\n#    ...,\n#    stored_as=\"SCD Type 2\",\n#    apply_as_deletes=expr(\"SRC_ACTION = 'D'\")\n# )\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">How to Truncate SCD table in DLT?<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>SCD1:<\/strong> <code>apply_as_truncates = expr(\"SRC_ACTION = 'T'\")<\/code> already wired. Emit <code>'T'<\/code> once \u2192 target fully truncated.<\/li>\n\n\n\n<li><strong>SCD2:<\/strong> Generally <strong>avoid truncation<\/strong> in history tables. If your contract demands it (e.g., nightly rebuild of a small dimension), you could add <code>apply_as_truncates<\/code>\u2014but you\u2019ll lose history.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Full Notebook (Put together)<\/h2>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>This notebook assumes:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Unity Catalog: <code>dev.etl<\/code> exists<\/li>\n\n\n\n<li>A Delta source table <code>dev.etl.customer_raw<\/code> is being appended with CDC style rows: <code>C_CUSTKEY<\/code>, attributes, <code>SRC_ACTION<\/code>, <code>SRC_INSERT_DATE<\/code>.<\/li>\n\n\n\n<li>Your DLT pipeline Product Edition = <strong>Pro<\/strong> (or Advanced)<\/li>\n<\/ul>\n<\/blockquote>\n\n\n\n<pre class=\"wp-block-code\"><code># Databricks Delta Live Tables (DLT) \u2014 SCD1 &amp; SCD2 with CDC\nimport dlt\nfrom pyspark.sql import functions as F\nfrom pyspark.sql.functions import expr\n\nCATALOG = \"dev\"\nSCHEMA  = \"etl\"\nSRC_TBL = f\"{CATALOG}.{SCHEMA}.customer_raw\"\n\n# 1) STREAMING SOURCE VIEW\n@dlt.view(\n    comment=\"Streaming view over raw customer data with CDC signals.\"\n)\ndef customer_raw_view():\n    return spark.readStream.table(SRC_TBL)\n\n# 2) SCD1 TABLE (UPSERTS + optional deletes\/truncate)\ndlt.create_streaming_table(\n    name=\"customer_scd1_bronze\",\n    comment=\"SCD Type 1 (overwrite) Customer dimension.\"\n)\ndlt.apply_changes(\n    target   = \"customer_scd1_bronze\",\n    source   = \"customer_raw_view\",\n    keys     = &#91;\"C_CUSTKEY\"],\n    stored_as   = \"SCD Type 1\",\n    sequence_by = expr(\"SRC_INSERT_DATE\"),\n    apply_as_deletes   = expr(\"SRC_ACTION = 'D'\"),\n    apply_as_truncates = expr(\"SRC_ACTION = 'T'\")\n)\n\n# 3) SCD2 TABLE (HISTORY), exclude operational columns from compare\ndlt.create_streaming_table(\n    name=\"customer_scd2_bronze\",\n    comment=\"SCD Type 2 (history) Customer dimension.\"\n)\ndlt.apply_changes(\n    target   = \"customer_scd2_bronze\",\n    source   = \"customer_raw_view\",\n    keys     = &#91;\"C_CUSTKEY\"],\n    stored_as   = \"SCD Type 2\",\n    sequence_by = expr(\"SRC_INSERT_DATE\"),\n    except_column_list = &#91;\"SRC_ACTION\", \"SRC_INSERT_DATE\"]\n    # Intentionally no deletes\/truncates to preserve history\n)\n\n# 4) CURRENT SNAPSHOT OF SCD2 (handy for joins)\n@dlt.view(\n    comment=\"Current (active) SCD2 snapshot; END_AT is null.\"\n)\ndef customer_scd2_current():\n    return spark.read.table(dlt.fqn(\"customer_scd2_bronze\")).where(F.col(\"END_AT\").isNull())\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Practical Use-Cases (cheat sheet)<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>SCD1 \u2013 Operational attributes<\/strong>\n<ul class=\"wp-block-list\">\n<li>Email, phone, marketing consent, preferred store\u2014only latest matters.<\/li>\n\n\n\n<li>Deletion: remove one key (GDPR delete), truncation: hard reset (sandbox\/POC).<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>SCD2 \u2013 Analytical attributes<\/strong>\n<ul class=\"wp-block-list\">\n<li>Customer segment, membership tier, region, status, relationship manager, plan type.<\/li>\n\n\n\n<li>Back-loading: legal name change backdated to its legal effective date; late MDM corrections.<\/li>\n\n\n\n<li>Current snapshot view for day-to-day joins; full table for time-travel analytics.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>CDC patterns<\/strong>\n<ul class=\"wp-block-list\">\n<li><strong>Real-time<\/strong> (streaming ingest) or <strong>micro-batch<\/strong>: both work since DLT abstracts the mechanics.<\/li>\n\n\n\n<li><strong>Deletes\/truncates controlled at source<\/strong> via <code>SRC_ACTION<\/code> so you can audit intent.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Tips &amp; Gotchas<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Always set a trustworthy <code>sequence_by<\/code> column<\/strong> (event time). If you use ingestion time instead, late events won\u2019t line up historically.<\/li>\n\n\n\n<li><strong>Backfills:<\/strong> just write the true historical timestamp into <code>SRC_INSERT_DATE<\/code>; DLT reflows SCD2 for you.<\/li>\n\n\n\n<li><strong>Column exclusions:<\/strong> use <code>except_column_list<\/code> to keep \u201coperational\/control\u201d columns (like <code>SRC_ACTION<\/code>, <code>SRC_INSERT_DATE<\/code>, file names, etc.) out of change detection.<\/li>\n\n\n\n<li><strong>Debugging:<\/strong> run in <strong>Development<\/strong> mode to iterate quickly; switch to <strong>Production<\/strong> to auto-terminate clusters after updates.<\/li>\n\n\n\n<li><strong>Deletes in SCD2:<\/strong> prefer a soft-delete attribute that creates a final historical row rather than hard delete (history loss).<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p>If you want, I can turn this into a \u201ccopy-paste\u201d DLT tutorial notebook with small helper cells that seed demo data and show sample queries (SCD1 vs SCD2, deletes, truncates, and back-loading).<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction Goal: Build a CDC-ready dimension pipeline in Delta Live Tables (DLT) that supports: Core ideas you\u2019ll use What we\u2019ll model How to build SCD1 or SCD2&#8230; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-832","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/dataopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/832","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dataopsschool.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dataopsschool.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dataopsschool.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dataopsschool.com\/blog\/wp-json\/wp\/v2\/comments?post=832"}],"version-history":[{"count":1,"href":"https:\/\/dataopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/832\/revisions"}],"predecessor-version":[{"id":833,"href":"https:\/\/dataopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/832\/revisions\/833"}],"wp:attachment":[{"href":"https:\/\/dataopsschool.com\/blog\/wp-json\/wp\/v2\/media?parent=832"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dataopsschool.com\/blog\/wp-json\/wp\/v2\/categories?post=832"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dataopsschool.com\/blog\/wp-json\/wp\/v2\/tags?post=832"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}